Android平台对H264视频硬解码

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

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

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

 1 // Video Constants
 2     private final static String MIME_TYPE = "video/avc"; // H.264 Advanced Video
 3     private final static int VIDEO_WIDTH = 1280;
 4     private final static int VIDEO_HEIGHT = 720;
 5     private final static int TIME_INTERNAL = 30;
 6
 7     public void initDecoder() {
 8
 9         mCodec = MediaCodec.createDecoderByType(MIME_TYPE);
10         MediaFormat mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE,
11                 VIDEO_WIDTH, VIDEO_HEIGHT);
12         mCodec.configure(mediaFormat, mSurfaceView.getHolder().getSurface(),
13                 null, 0);
14         mCodec.start();
15     }

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

 1     public boolean onFrame(byte[] buf, int offset, int length) {
 2         Log.e("Media", "onFrame start");
 3         Log.e("Media", "onFrame Thread:" + Thread.currentThread().getId());
 4         // Get input buffer index
 5         ByteBuffer[] inputBuffers = mCodec.getInputBuffers();
 6         int inputBufferIndex = mCodec.dequeueInputBuffer(100);
 7
 8         Log.e("Media", "onFrame index:" + inputBufferIndex);
 9         if (inputBufferIndex >= 0) {
10             ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
11             inputBuffer.clear();
12             inputBuffer.put(buf, offset, length);
13             mCodec.queueInputBuffer(inputBufferIndex, 0, length, mCount
14                     * TIME_INTERNAL, 0);
15             mCount++;
16         } else {
17             return false;
18         }
19
20         // Get output buffer index
21         MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
22         int outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 100);
23         while (outputBufferIndex >= 0) {
24             mCodec.releaseOutputBuffer(outputBufferIndex, true);
25             outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 0);
26         }
27         Log.e("Media", "onFrame end");
28         return true;
29     }

具体流程:

  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

时间: 2024-10-13 05:11:58

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

Android 用MediaCodec实现视频硬解码

本 文向你讲述如何用android标准的API (MediaCodec)实现视频的硬件编解码.例程将从摄像头采集视频开始,然后进行H264编码,再解码,然后显示. 1.从摄像头采集视频 可以通过摄像头Preview的回调,来获取视频数据. 首先创建摄像头,并设置参数: [java] view plaincopy cam = Camera.open(); cam.setPreviewDisplay(holder); Camera.Parameters parameters = cam.getPar

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

本文向你讲述如何用android标准的API (MediaCodec)实现视频的硬件编解码.例程将从摄像头采集视频开始,然后进行H264编码,再解码,然后显示.我将尽量讲得简短而清晰,不展示 那些不相关的代码.但是,我不建议你读这篇文章,也不建议你开发这类应用,而应该转而开发一些戳鱼.打鸟.其乐融融的程序.好吧,下面的内容是写给那些执 迷不悟的人的,看完之后也许你会同意我的说法:Android只是一个玩具,很难指望它来做靠谱的应用. 1.从摄像头采集视频 可以通过摄像头Preview的回调,来获

FFMPEG+SDL2.0流媒体开发3---简易MP4视频播放器,提取MP4的H264视频序列解码并且显示

简介 之前写了一遍提取MP4中的音视频并且解码,这一篇引入SDL2.0来显示解码后的视频序列 实现一个简易的 视频播放器. 我这里用的FFMPEG和SDL2.0都是最新版的 可能网上的资料不是很多,API接口也变了很多,不过大体的思路还是一样的. 分析几个FFMPEG函数 在这之前我们分析几个代码中可能引起疑问的FFMPEG几个函数的源代码,我已经尽我的能力添加了注释,因为实在没有文档可能有的地方也不是很详尽  不过大体还是能看懂的 av_image_alloc (分配图片缓冲区) 我们在FFM

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

文章-原址 公司项目原因,接触了一下视频流H264的编解码知识,之前项目使用的是FFMpeg多媒体库,利用CPU做视频的编码和解码,俗称为软编软解.该方法比较通用,但是占用CPU资源,编解码效率不高.一般系统都会提供GPU或者专用处理器来对视频流进行编解码,也就是硬件编码和解码,简称为硬编解码.苹果在iOS 8.0系统之前,没有开放系统的硬件编码解码功能,不过Mac OS系统一直有,被称为Video ToolBox的框架来处理硬件的编码和解码,终于在iOS 8.0后,苹果将该框架引入iOS系统.

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

[GPU编解码]GPU硬解码---DXVA 前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解码可分四级:VLD,控制BitStream:IDCT,反余弦变换:Mocomp,运动补偿,Pixel Prediction:PostProc,显示后处理.其中,VLD加速等级最高,所以其包含IDCT.MoCoopm和PostProc:IDCT加速次之,包含

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

前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解码可分四级:VLD,控制BitStream:IDCT,反余弦变换:Mocomp,运动补偿,Pixel Prediction:PostProc,显示后处理.其中,VLD加速等级最高,所以其包含IDCT.MoCoopm和PostProc:IDCT加速次之,包含MoCoopm和PostProc:最后MoC

Android中软解码和硬解码的优先级

我们先来看一下Android系统中解码器的命名,软解码器通常是以OMX.google开头的.硬解码器通常是以OMX.[hardware_vendor]开头的,比如TI的解码器是以OMX.TI开头的.当然还有一些不遵守这个命名规范的,不以OMX.开头的,那也会被认为是软解码器. 判断规则见frameworks/av/media/libstagefright/OMXCodec.cpp: static bool IsSoftwareCodec(const char *componentName) {

linux下mplayer(ffmpeg)通过x264解码播放高清h264视频

系统环境: Linux inbank-GZ 2.6.24-16-generic #1 SMP Thu Apr 10 13:23:42 UTC 2008 i686 GNU/Linux Ubuntu 8.04 Genuine Intel(R) CPU   1250  @ 1.73GHz  * 2 1G内存 目标:能用mplayer播放H264格式的高清视频 下载相关软件 Mplayer1.1版本(包含了ffmpeg) 各类解码包codes x264 yasm + faac + faad 可以在这里下

转 Android视频播放软解与硬解的区别

硬解,用自带播放器播放,android中的VideoView 软解,使用音视频解码库,比如FFmpeg 一.硬解码 硬解:就是调用GPU的专门模块编码来解,减少CPU运算,对CPU等硬件要求也相对低点.软解需要CPU运算,变相加大CPU负担耗电增加很多.硬件解码是将原来全部交由CPU来处理的视频数据的一部分交由GPU来做,而GPU的并行运算能力要远远高于CPU,这样可以大大的降低对CPU的负载,CPU的占用率较低了之后就可以同时运行一些其他的程序了. 对于Android设备,目前用得比较多的so