記錄一下做視訊解碼的demo:
github位址:https://github.com/whcx/AudioVideoEncoderDecoder
存儲權限申請: 目前項目targetSdkVersion 29,按之前方式動态申請權限 Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,無法在sdcard的共有目錄建立檔案。 可以使用context.getExternalFilesDir(type);擷取應用私有的檔案目錄,即:/storage/emulated/0/Android/data/com.cxd.av/files; 或者,manifest中添加android:requestLegacyExternalStorage="true",依然使用共有目錄。
1,使用MediaCodec解碼視訊檔案,
主要代碼在VideoPlayer.java,AVUtils.java中。
這裡主要是擷取到視訊的yuv資料,并沒有給出控件view顯示視訊到螢幕,用控件播放的demo後面整理下。
擷取視訊YUV資料,使用了兩種方式,
1)使用 MediaCodec.Callback,這種異步的方式,填充待解碼資料,然後擷取解碼後的資料,具體就是代碼中的
updateVideoFrame() 方法。
2)同樣是使用MediaCodec.Callback這種異步的方式,隻是YUV資料的擷取是通過Surface,使用這種方式的依據,請參考:https://developer.android.com/reference/android/media/MediaCodec
Codecs operate on three kinds of data: compressed data, raw audio data and raw video data. All three kinds of data can be processed using
ByteBuffer
, but you should use a
Surface
for raw video data to improve codec performance. Surface uses native video buffers without mapping or copying them to ByteBuffers; thus, it is much more efficient. You normally cannot access the raw video data when using a Surface, but you can use the
ImageReader
class to access unsecured decoded (raw) video frames. This may still be more efficient than using ByteBuffers, as some native buffers may be mapped into ByteBuffer#isDirect ByteBuffers. When using ByteBuffer mode, you can access raw video frames using the
Image
class and
getInput
/
OutputImage(int)
.
大意是使用surface使用了本地的video buffer可以提高解碼的性能,這種情況可以使用ImageReader來擷取視訊幀。
具體代碼是updateVideoFrameReaderAsync方法,擷取視訊幀的代碼是
image = mImageListener.getImage((long)delay);
這裡為什麼要去強調使用異步的方式呢?因為我最初使用同步的方式即:
updateVideoFrameReaderSync(),在擷取解碼後的資料時,一直沒能讀取到流結束的标記,當然,在填充帶解碼資料的最後,我肯定是queueInputBuffer中加入了
MediaCodec.BUFFER_FLAG_END_OF_STREAM的。
3)就是視訊幀YUV資料的提取:具體就是AVUtils中的
private byte[] getDataFromImage(Image image, int colorFormat),傳回的位元組數組就是YUV 資料,可以使用
dumpI420File,
dumpJpegFile儲存到本地檢視。
具體提取YUV的做法,可以去參考android cts測試的源碼:android/cts/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
2,音頻的解碼,
音頻的解碼相對比較簡單,實作音頻解碼除了播放聲音外,還有一個重要的意思就是擷取音頻的時鐘資訊,友善做音視訊同步。
具體代碼:AudioPlayer.java,播放視訊使用AudioTack.java