本文讲述如何使用Android标准的API (MediaCodec)实现H264的硬件解码。

  原本我们是用JNI调用平台提供的硬件解码接口得到YUV帧,再放入opengl脚本里处理渲染的。可是换了新平台之后,没有拿到底层的接口,所以这两天找在Android上的H264解码方案。前天在友人的提示下找到了MediaCodec这个类,Android developer上面有MediaCodec的描述和用法,还算详细可以慢慢摸索。但是在网上关于这个类的用法是比较少。

  那在这里贴代码介绍一下。

 // Video Constants
private final static String MIME_TYPE = "video/avc"; // H.264 Advanced Video
private final static int VIDEO_WIDTH = 1280;
private final static int VIDEO_HEIGHT = 720;
private final static int TIME_INTERNAL = 30; public void initDecoder() { mCodec = MediaCodec.createDecoderByType(MIME_TYPE);
MediaFormat mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE,
VIDEO_WIDTH, VIDEO_HEIGHT);
mCodec.configure(mediaFormat, mSurfaceView.getHolder().getSurface(),
null, 0);
mCodec.start();
}

  这是初始化解码器操作,具体要设置解码类型,高度,宽度,还有一个用于显示视频的surface。

     public boolean onFrame(byte[] buf, int offset, int length) {
Log.e("Media", "onFrame start");
Log.e("Media", "onFrame Thread:" + Thread.currentThread().getId());
// Get input buffer index
ByteBuffer[] inputBuffers = mCodec.getInputBuffers();
int inputBufferIndex = mCodec.dequeueInputBuffer(100); Log.e("Media", "onFrame index:" + inputBufferIndex);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(buf, offset, length);
mCodec.queueInputBuffer(inputBufferIndex, 0, length, mCount
* TIME_INTERNAL, 0);
mCount++;
} else {
return false;
} // Get output buffer index
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 100);
while (outputBufferIndex >= 0) {
mCodec.releaseOutputBuffer(outputBufferIndex, true);
outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 0);
}
Log.e("Media", "onFrame end");
return true;
}

具体流程:

  1.获取一个可用的inputBuffer的索引(出列)

  2.将一帧数据放入inputBuffer

  3.将inputBuffer入列进行解码

  4.获得一个outputBuffer的索引(出列)

  5.释放outputBuffer

  6.在4,5间循环直到没有outputBuffer可出列为止

  这里解码器有多个输入缓冲区(我测试是有3个),实现不卡顿。

常见的问题:

  dequeueInputBuffer和dequeueOutputBuffer经常会获取不了缓冲区(跟机器的性能有关),如果参数为-1,则会一直等待;如果参数为正数,则等待相应的微秒后返回,没有可用缓冲区就会返回-1。

结论:
  测试程序是读取一个H264裸流文件,识别每一帧然后将其放入解码器解码以及渲染。读取和识别的代码在Demo中。经测试,不同平台的解码效果还挺大。我播放的是720p的H264文件。最出色的居然是RK(瑞芯微)平台,缓冲区获取很少失败,但是会因为过热重启机器;高通平台试了几台机器(锤子、小米4、还有个别定制机),经常有拿不到缓冲区的情况。MTK的只有一台(TCL么么哒),直接初始化不了解码器。。。
  这里跟GPU性能有关,我们解的是720p8m码率的视频,换成较低码率较低分辨率的,大部分机器还是可以正常运行的(除了么么哒)。当然或许有些平台的实现是软解码(使用cpu,ffmpeg方案),这我暂时还没遇到。 Demo链接如下(注意裸流文件要放置的路径):
http://files.cnblogs.com/files/superping/H264Demo.zip

Android平台对H264视频硬解码的更多相关文章

  1. Android 用MediaCodec实现视频硬解码

    http://blog.csdn.net/halleyzhang3/article/details/11473961 http://www.360doc.com/content/14/0119/10/ ...

  2. Android 用MediaCodec实现视频硬解码(转)

    本文向你讲述如何用android标准的API (MediaCodec)实现视频的硬件编解码.例程将从摄像头采集视频开始,然后进行H264编码,再解码,然后显示.我将尽量讲得简短而清晰,不展示 那些不相 ...

  3. 【Android 直播软件开发:音视频硬解码篇】

    开篇 炙手可热,望而生畏的音视频开发 时至今日,短视频App可谓是如日中天,一片兴兴向荣.随着短视频的兴起,音视频开发也越来越受到重视,但是由于音视频开发涉及知识面比较广,入门门槛相对较高,让许许多多 ...

  4. MediaCodec在Android视频硬解码组件的应用

    https://yq.aliyun.com/articles/632892 云栖社区> 博客列表> 正文 MediaCodec在Android视频硬解码组件的应用   cheenc 201 ...

  5. WPF 视频硬解码渲染播放(无空域)(支持4K、8K、高帧率视频)

    MediaWPF 基于 .NET 6 实现视频硬解码渲染Demo(无空域问题) 代码实现仅供学习参考 本项目视频渲染通过显卡进行视频解码,CPU几乎不参与工作,并且不存在令人烦躁的空域问题. 在播放摄 ...

  6. 【GPU编解码】GPU硬解码---DXVA

    前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...

  7. 【GPU编解码】GPU硬解码---DXVA (转)

    前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...

  8. 【计算机视觉】【并行计算与CUDA开发】GPU硬解码---DXVA

    前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...

  9. iOS8系统H264视频硬件编解码说明

    公司项目原因,接触了一下视频流H264的编解码知识,之前项目使用的是FFMpeg多媒体库,利用CPU做视频的编码和解码,俗称为软编软解.该方法比较通用,但是占用CPU资源,编解码效率不高.一般系统都会 ...

随机推荐

  1. Python学习(五) Python数据类型:列表(重要)

    列表: list是一组有序项目的数据结构. 列表是可变类型的数据,列表用[]进行表示,包含了多个以","分隔的项目. list=[] type(list) //<type ' ...

  2. mysql中的意向锁IS,IX

    知识储备: 1.官方文档上说mysql是支持非锁定读的:这个功能是这样实现的,如果事务a 要对行的数据进行更新的话,那么事务a要得到行的x锁,并把这一行  之前的样子记录在undo log里面,这样一 ...

  3. T-SQL 语法元素

    一.标识符 在T-SQL语言中,对SQLServer数据库及其数据对象(比如表.索引.视图.存储过程.触发器等)需要以名称来进行命名并加以区分,这些名称就称为标识符. 通常情况下,SQLServer数 ...

  4. WPF笔记(1.3 属性元素)——Hello,WPF!

    原文:WPF笔记(1.3 属性元素)--Hello,WPF! 这一节中“属性元素”的概念可以用匪夷所思形容.1.WPF用标签元素实现对象建模,有两种:Control和Container,都用来装载内容 ...

  5. logstash 处理tomcat日志

    [root@dr-mysql01 tomcat]# cat logstash_tomcat.conf input { file { type => "zj_api" path ...

  6. Jquery时间快捷控件(Jtime)配置v1.1

    1.插件代码 /** * @title 时间工具类 * @note 本类一律违规验证返回false * @author {boonyachengdu@gmail.com} * @date 2013-0 ...

  7. Linux开机禁用开启防火墙

    1.# chkconfig --list:显示开机可以自动启动的服务 结果:iptables    0:off    1:off    2:on    3:on    4:on    5:on     ...

  8. 【转】通过 ulimit 改善系统性能

    概述 系统性能一直是一个受关注的话题,如何通过最简单的设置来实现最有效的性能调优,如何在有限资源的条件下保证程序的运作,ulimit 是我们在处理这些问题时,经常使用的一种简单手段.ulimit 是一 ...

  9. Android开发之Intent.Action

    1 Intent.ACTION_MAIN String: android.intent.action.MAIN 标识Activity为一个程序的開始.比較经常使用. Input:nothing Out ...

  10. poj1184 聪明的打字员(BFS剪枝)

    http://poj.org/problem?id=1184 用字符串s存下数字,并把光标位置做一个字符加到s末尾,用map做标记状态是否出现过,然后bfs即可. 不剪枝是过不了的,考虑的两种交换操作 ...