MediaCodec

MediaCodec 是 Android 提供的硬件编解码器,通常配合 MediaExtractor(用于解析媒体文件,获取音视频数据), MediaMuxer(用于封装已编码的音视频数据到文件中), Image, Surface, AudioTrack(用于播放 PCM 数据) 等类一起使用。相关辅助类有 MediaFormat, MediaCodec.BufferInfo, MediaCodecInfo, MediaCodecList 等。

它使用了一系列 input buffer 和 output buffer,异步地处理数据。简单来说,你首先要请求(或接收)一个空的 input buffer,然后向里面填充数据并发送给编解码器进行处理,编解码器消耗(解码/编码)数据并把数据迁移到它其中一个 ouput buffer 中。

使用流程(以解码为例,编码基本类似):
1) MediaCodec.createDecoderByType(),创建解码器
2) decoder.configure(),配置解码器
3) decoder.start(),开始运行,MediaCodec 会在这里创建 inputBuffers、outputBuffers 两个 buffer 数组
4) decoder.dequeueInputBuffer(),获取一个 InputBuffer,用于填充未解码的数据
5) decoder.queueIntputBuffer(),填充数据完毕后,把这个 buffer 放进 MediaCodec 里面,让它进行解码操作
6) decoder.dequeueOutputbuffer(),获取一个 OutputBuffer,此时已解码成功,可以使用解码后的数据了
7) decoder.releaseOutputbuffer(),如果不再需要这个 OutputBuffer,就释放它,可以关联一个 Surface,调用这句代码的同时把解码后的数据渲染到 Surface 上面,Surface 使用完毕后会释放该 Buffer

流程图如下:

MediaCodec 的使用方式有三种:
1) 使用 Buffer 数组同步处理(deprecated),本文使用的是这种方式
2) 使用 Buffers 同步处理
3) 使用 Buffers 异步处理

因为第二、第三种方式要求 API 21 以上,因此这篇文章用的是第一种,其它两种方式有兴趣的可以自己研究:MediaCodec | Android Developers

另外,我在使用 MediaCodec 的时候发现了很多问题,有些是兼容性问题,有些我也不懂是什么问题,感觉很不稳定,因此我用得更多的是 FFmpeg,MediaCodec 没有深入研究,这里仅作为一个代码示例供大家参考。

解码

public class HWCodec {private static final String TAG = "HWCodec";private static final long DEFAULT_TIMEOUT = 10 * 1000;private static final int MEDIA_TYPE_VIDEO = 1;private static final int MEDIA_TYPE_AUDIO = 2;private static final int MEDIA_TYPE_UNKNOWN = 0;private static final String MIME_TYPE_AVC = "video/avc";private static final String MIME_TYPE_AAC = "audio/mp4a-latm";public static boolean decode(String srcFilePath, String yuvDst, String pcmDst) {boolean vsucceed = decodeVideo(srcFilePath, yuvDst);boolean asucceed = decodeAudio(srcFilePath, pcmDst);return vsucceed && asucceed;}public static boolean decodeVideo(String srcFilePath, String dstFilePath) {return doDecode(srcFilePath, dstFilePath, MEDIA_TYPE_VIDEO);}public static boolean decodeAudio(String srcFilePath, String dstFilePath) {return doDecode(srcFilePath, dstFilePath, MEDIA_TYPE_AUDIO);}private static boolean doDecode(String src, String dst, int mediaType) {MediaExtractor extractor = null;MediaCodec decoder = null;FileOutputStream fos = null;boolean decodeSucceed = false;boolean exceptionOccur = false;try {extractor = new MediaExtractor();extractor.setDataSource(src);fos = new FileOutputStream(dst);decoder = doDecode(extractor, fos, mediaType);} catch (IOException e) {Log.e(TAG, "doDecode exception: " + e);exceptionOccur = true;} finally {if (extractor != null) {extractor.release();}if (decoder != null) {decodeSucceed = true;decoder.stop();decoder.release();}if (fos != null) {try {fos.flush();fos.close();} catch (IOException e) {Log.e(TAG, "doDecode close fos error: " + e.getLocalizedMessage());}}}return !exceptionOccur && decodeSucceed;}private static MediaCodec doDecode(MediaExtractor extractor, FileOutputStream fos,int mediaType) throws IOException {MediaFormat format = selectTrack(extractor, mediaType);if (format == null) {Log.e(TAG, "doDecode no " + mediaType + " track");return null;}Log.d(TAG, "docde format: " + format.toString());MediaCodec decoder = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME));decoder.configure(format, null, null, 0);decoder.start();ByteBuffer[] inputBuffers = decoder.getInputBuffers();ByteBuffer[] outputBuffers = decoder.getOutputBuffers();MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();boolean inputEof = false;boolean outputEof = false;while (!outputEof) {if (!inputEof) {int inIndex = decoder.dequeueInputBuffer(DEFAULT_TIMEOUT);if (inIndex >= 0) {ByteBuffer inputBuffer = inputBuffers[inIndex];inputBuffer.clear();int size = extractor.readSampleData(inputBuffer, 0);if (size < 0) {inputEof = true;decoder.queueInputBuffer(inIndex, 0, 0,0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);} else {decoder.queueInputBuffer(inIndex, 0, size, extractor.getSampleTime(), 0);extractor.advance();}}}int outIndex = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_TIMEOUT);if (outIndex >= 0) {if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {decoder.releaseOutputBuffer(outIndex, false);continue;}if (bufferInfo.size != 0) {ByteBuffer outputBuffer = outputBuffers[outIndex];outputBuffer.position(bufferInfo.offset);outputBuffer.limit(bufferInfo.offset + bufferInfo.size);byte[] data = new byte[bufferInfo.size];outputBuffer.get(data);fos.write(data);}decoder.releaseOutputBuffer(outIndex, false);if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {outputEof = true;}} else if (outIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {outputBuffers = decoder.getOutputBuffers();Log.d(TAG, "decoder output buffer have changed");} else if (outIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {MediaFormat tmp = decoder.getOutputFormat();Log.d(TAG, "decoder output format change to " + tmp.toString());}}return decoder;}private static MediaFormat selectTrack(MediaExtractor extractor, int mediaType) {MediaFormat format = null;int trackCount = extractor.getTrackCount();for (int i = 0; i < trackCount; ++i) {MediaFormat tmpFormat = extractor.getTrackFormat(i);if (getMediaType(tmpFormat) == mediaType) {format = tmpFormat;extractor.selectTrack(i);break;}}return format;}private static int getMediaType(MediaFormat format) {String mime = format.getString(MediaFormat.KEY_MIME);if (mime.startsWith("video/")) {return MEDIA_TYPE_VIDEO;} else if (mime.startsWith("audio/")) {return MEDIA_TYPE_AUDIO;}return MEDIA_TYPE_UNKNOWN;}
}

源码已上传到 GitHub

MediaCodec 实现硬件解码相关推荐

  1. Mediacodec 如何硬件解码到纹理的

    Mediacodec 如何硬件解码到纹理的 背景: 网上很多关于mediacodec,surface ,surfacetexture的源码分析,以及内部原理,但是都局限于各自的内容,今天我们就从med ...

  2. Android MediaCodec硬件解码视频播放

    1.MediaCodec 是什么 MediaCodec类可以访问底层媒体编解码器框架(StageFright 或 OpenMAX),即编解码组件.是Android 的低层多媒体基础设施的一部分(通常与 ...

  3. 【AVD】FFmpeg + MediaCodec 实现 Android 硬件解码,中间有个大坑

    最近在做移动端音视频编解码,首先要实现的是移动端视频的解码功能.纯的 FFmpeg 方法在移动端也能实现,但是效率上的确要慢一些,1080p 的视频还好,但是上到 2k.4k,那个解码速度(以肉眼可见 ...

  4. 全平台硬件解码渲染方法与优化实践

    硬件解码后不恰当地使用OpenGL渲染会导致性能下降,甚至不如软解.本文来自PPTV移动端研发经理王斌在LiveVideoStackCon 2017大会上的分享,并由LiveVideoStack整理而 ...

  5. android ndk之opencv+MediaCodec硬编解码来处理视频动态时间水印

    android ndk之opencv+MediaCodec硬编解码来处理视频水印学习笔记 android视频处理学习笔记.以前android增加时间水印的需求,希望多了解视频编解码,直播,特效这一块, ...

  6. IOS硬件解码VTDecompressionSession失效

    原文:http://blog.5ibc.net/p/33817.html 编码.解码失效都可以restart一下. IOS硬件解码VideoToolbox在应用中进入后台VTDecompression ...

  7. RIoTBoard开发板系列笔记(四)—— 使用VPU硬件解码

    视频解码分为软解和硬解两种,简单的来说纯粹依靠CPU来解码的称为软解,而使用GPU/VPU解码的称为硬解.常规地直接用CPU解码会极大地消耗CPU的运算能力,硬件解码是通过显卡的视频加速功能对高清视频 ...

  8. RIoTBoard开发板系列笔记(十二)—— gstreamer + vpu实现视频硬件解码播放

    i.mx6 solo芯片中包含一个VPU (video processing unit),可以进行视频硬件编解码加速,之前RIoTBoard开发板系列笔记(四)-- 使用VPU硬件解码文章简单的记录了 ...

  9. android MediaCodec 音频编解码的实现——转码

    转载请标明出处http://blog.csdn.net/tinsanmr/article/details/51049179 ,本文出自:[Tinsan的博客] 从今天开始 每周不定期更新博客,把这一周 ...

最新文章

  1. 二、JavaWeb总结:Tomcat服务器的学习和使用
  2. Device Tree(三):代码分析【转】
  3. java8 接口调用默认方法_Java8接口里的默认方法特性
  4. Python小游戏(消消乐)
  5. Linux软件安装管理 - CentOS (三) ---- 源码包管理
  6. leetcode1169. 查询无效交易
  7. HTML5 3D爱心动画及其制作过程
  8. vm15安装MACOS
  9. python的os,commands,subprocess启动进程调用的几种方法
  10. 列举微型计算机的主要性能指标,计算机基础考试纲.ppt
  11. java定时器 多线程_Java多线程 定时器
  12. 域名购买之后怎么使用
  13. 最全的【英语词根词缀思维导图总结】
  14. flex布局中的align-content属性
  15. PanDownload 3.5.1 卢本伟修改版
  16. dreamweaver CS5安装
  17. 深入理解JVM(三)——JVM之判断对象是否存活(引用计数算法、可达性分析算法,最终判定),Eclipse设置GC日志输出,引用
  18. 阵阵的挫败感,让我痛苦迷茫
  19. 解决WIn7无线网图标显示不正确的问题
  20. SVN设置忽略文件和文件夹

热门文章

  1. 2.shell语法:shell变量定义和使用
  2. libnet编译linux,Linux 网络编程—— libnet 使用指南
  3. 五个常用计算机应用软件6,信息技术应用--常用计算机工具软件5常用工具软件单元五.pdf...
  4. kettle安装与配置
  5. windows平台上的密码算法识别工具
  6. Android之图片工具
  7. BTS7960大功率直流电机驱动(含原理图+PCB)
  8. 统信UOS桌面操作系统专业版安装(版本号:V20.1043)
  9. Python模块的搜索路径
  10. FM铁电存储器 eg:fm24cl16等等