使用mediacodec做视频解码 深碍√TFBOYSˉ_ 2022-12-03 00:45 203阅读 0赞 记录一下做视频解码的demo: github地址:[https://github.com/whcx/AudioVideoEncoderDecoder][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][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][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 [https_github.com_whcx_AudioVideoEncoderDecoder]: https://github.com/whcx/AudioVideoEncoderDecoder [https_developer.android.com_reference_android_media_MediaCodec]: https://developer.android.com/reference/android/media/MediaCodec [ByteBuffer_isDirect]: https://developer.android.com/reference/java/nio/ByteBuffer#isDirect%28%29
还没有评论,来说两句吧...