MediaCodec解码过程
1解码流程
解码流程大致分为创建解码器,配置解码器,解码操作,释放解码器。
1.1创建解码器
创建解码器可以直接创建默认的,也可以通过两种方式来创建,分别是:视频类型和解码器名。
指定视频类型的创建接口是:createDecoderByType(type),示例代码:
try { mCodec = MediaCodec.createDecoderByType("video/avc"); } catch (IOException e) { throw new RuntimeException("Failed to create codec", e); }
指定解码器创建接口是:createByCodecName(decoderName)。示例代码:
try { mCodec = MediaCodec.createByCodecName("OMX.ffmpeg.h264.decoder"); } catch (IOException e) { throw new RuntimeException("Failed to create codec", e); }
这一步调用了MediaCodec的private构造函数创建了MediaCodec对象,并调用native_setup来初始化native_setup<->android_media_MediaCodec_native_setup,这里创建JMediaCodec对象,JMediaCodec实例对应的接口调到真正的MediaCodec.cpp相关借口,真正实现编解码相关流程是在MediaCodec.cpp中实现。
1.2配置解码器
配置解码器需要构造一个MediaFormat对象作为参数,MediaFormat需要指定视频的格式,width和height,以及sps,这个是编码时产生的第一帧数据,配置帧csd-0。如果需要将解码后的数据直接输出到Surface,则需要传入一个Surface对象。示例代码:
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height); // little tricky here, csd-0 is required in order to configure the codec properly // it is basically the first sample from encoder with flag: BUFFER_FLAG_CODEC_CONFIG format.setByteBuffer("csd-0", csd0); mCodec.configure(format, surface, null, 0);
这一步会把MediaFormat所携带的各种信息,通过native_configure方法传递到JNI层,对应android_media_MediaCodec.cpp的方法是android_media_MediaCodec_native_configure,该接口会调用到MediaCodec.cpp的configure,完成解码器的配置。大致流程如下
configure(format, surface, null, 0)(MediaCodec.java)
->native_configure(keys, values, surface, crypto, descramblerBinder, flags)(MediaCodec.java)
->android_media_MediaCodec_native_configure(android_media_MediaCodec.cpp)
->JMediaCodec.configure(format, bufferProducer, crypto, descrambler, flags)(android_media_MediaCodec.cpp)
->configure(format, mSurfaceTextureClient, crypto, descrambler, flags)
(MediaCodec.cpp)
mCodec是MediaCodec.cpp实例进入MediaCodec的configure函数,只能配置一次,如果需要重新配置需要调用stop接口,让解码器进入Uninitialized状态,才可以进行重新配置,不然设置会报错误码-38。MediaFormat对象在MediaCodec.cpp的configure函数中,被重新封装成一个AMessage对象。
本步骤结束后,解码器进入Configured状态。
1.3解码操作
在解码器配置号以后,可以调用mCodec.start()接口,Codec会转入 Executing 状态。start后Codec立即进入 Flushed 子状态,此时的Codec拥有所有的input and output buffers,Client无法操作这些buffers。在 Executing状态下可以调用 MediaCodec.flush()方法使MediaCodec进入 Flushed 子状态。
解码分为两个平行的过程,1.填充已编码的数据;2.获取已解码的数据。一般会分为两个线程来实现,一个填充线程,一个消费线程,当然也支持一个线程搞定,先填充后解码,一帧一帧的处理(我们在云手机项目上的相机就是使用的该方案)。
1.3.1填充数据
Client通过调用 MediaCodec.dequeueInputBuffer(...)请求得到了一个有效的input buffer index,Codec进入到 Running 子状态,这个状态下Codec会进行实际的数据处理。获取到buffer的index之后,需要调用MediaCodec.getInputBuffer(index)来直接获取到ByteBuffer,然后把需要解码的数据填充到ByteBuffer里,再调用MediaCodec.queueInputBuffer(...)进行解码。实例代码:
int index = mCodec.dequeueInputBuffer(mTimeoutUs); if (index >= 0) { ByteBuffer buffer; // since API 21 we have new API to use if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { buffer = mCodec.getInputBuffers()[index]; buffer.clear(); } else { buffer = mCodec.getInputBuffer(index); } if (buffer != null) { buffer.put(data, offset, size);//填充数据 mCodec.queueInputBuffer(index, 0, size, 0, 0); } }
每个MediaCodec的操作,最终都会通过JNI层android_media_MediaCodec.cpp调到native层的MediaCodec.cpp中,至于最终用的哪个解码器,是由系统自动决定的,如果是指定了解码器(常用的OMX.ffmpeg.h264.decoder,OMX.google.h264.decoder),则会使用Client端指定的解码器。是硬解码还是软解码,这个也是由系统决定的,如果没有硬件解码则会转为软件解码(x86的PC上使用时,没有软解码,FFMPG同时支持软解码和硬解码)
1.3.2消费解码数据
Client通过调用MediaCodec.dequeueOutputBuffer(...)请求得到了一个有效的output buffer index,需要传入一个MediaCodec.BufferInfo实例,用以存储解码数据,获取到buffer的index后调用MediaCodec.releaseOutputBuffer(...)来释放缓冲区数据到Surface或者你的BufferInfo。实例代码:
if (index >= 0) { // setting true is telling system to render frame onto Surface mCodec.releaseOutputBuffer(index, true); if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == MediaCodec.BUFFER_FLAG_END_OF_STREAM) { break; } }
1.4释放解码器
当MediaCodec数据处理任务完成时或不再需要MediaCodec时,可使用 MediaCodec.release()方法释放其资源。实例代码:
if (mConfigured) { mCodec.stop(); mCodec.release(); }
相关推荐
Android MediaCodec 硬解码H264,包括h264文件,以及另一个硬解码例子。
MediaCodec 实现h264硬编解码全过程,视频数据从摄像头读出 yv12格式,转换为I420,投递给encoder,再从encoder取出编码后的h264数据投递给decoder后显示到surfaceView; 实现了udp将h264数据发送到指定主机,可通过...
1 MediaCodec硬解码demo 2 包含h264码流资源 3 包含如何处理硬解码过程中出现的各种crash/anr/黑屏
本Demo使用MediaCodec解码AAC音频数据,解码之后直接使用AudioTrack播放PCM音频数据
具有硬解的能力,但是需要android 4.1以上才能支持。 这个demo主要是测试硬解和软解h265裸流的能力,有一些手机可能不...硬解H265使用的是MediaCodec+ffmpeg方案,ffmepg负责拆包,MediaCodec负责解码和渲染,祝你愉快
实时MediaCodec音频硬编解码,音频录制,编码,解码,播放都正常,本人已亲自测试
Android利用MediaCodec硬解码H264,AAC文件并播放Demo。相关博客:http://blog.csdn.net/a512337862/article/details/72629755和http://blog.csdn.net/a512337862/article/details/72629755
android 使用MediaCodec 编解码总结.pdf
Android RTSP H264播放客户端。自己组包,喂给Android MediaCodec解码器,实时播放直播流。史上最简单的demo。亲测在三星S8+,小米平板,华为平板,摩托罗拉手机可用。
Android MediaCodec 实现Camera预览帧数据编解码并投射至另外的SurfaceView显示,另外附加Camera2的使用。
Android 用MediaCodec实现视频硬解码 发送视频流 写文件 可播放
试试ANDOIRD mediacodec硬解码
Android利用MediaCodec硬解码H264,AAC文件并播放Demo [注:本内容来自网络,在此分享仅为帮助有需要的网友,如果侵犯了您的权利,麻烦联系我,我会第一时间删除,谢谢您。]
使用MediaCodec播放文件,PES转为ES流注入MediaCodec解码渲染,通过surfaceview显示出来
android mediacodec解码MP4文件H264视频的示例代码,音频解码后续加上
将Camera数据显示到OpenGL ES渲染的图像中,并通过MediaCodeC 将 OpenGL ES 缓冲数据,硬编码写入到 mp4 视频文件中,完成视频的录制。 文件介绍请见: https://xiaxl.blog.csdn.net/article/details/72530314 ...
title: 保存Android-MediaCodec解码的图像Android: MediaCodec视频文件硬件解码,高效率得到YUV格式帧,快速保存JPEG
实现mediacodec硬编解码,支持预览和解码图像同时在2个surface显示。三星s6亲测有效,有需要的就拿去吧。
在android 6.0上测试MediaCodec的H.264硬解码,在多个硬件平台测试过,能正常播放,包含h.264文件
利用MediaCodec解码H264原始视频数据,通过socket实时传输