最近整理了下Android端项目里硬解码与软解码的大致流程,做个笔记,方便以后review。如有错误,欢迎指正。



硬解码:



1.创建MediaCodec:如 MediaCodec.createDecoderByType(keyMime);



2.configure codec:配置format,surface等参数



3.start codec



4.从codec的inputBuffer缓冲区获取一个索引,用于传递解码前的数据(比如h264数据):dequeueInputBuffer,注意如果返回-1说明当前inputBuffer缓冲区已满了,不接收新的数据输入



5.如果获取的inputBufferIndex大于0,说明有可用的输入缓冲区,通过以下接口获取一个空的inputBuffer:



api 21以下:mediaCodec.getInputBuffers()[inputBufferIndex]



api 21以上:mCodec.getInputBuffers(inputBufferIndex);





6.从视频容器(如MP4)demux一个数据,填充到inputBuffer,如:mExtractor.readSampleData(inputBuffer, 0);



7.现在inputBuffer已经填充了数据了,通过queueInputBuffer接口将inputBuffer送入decode队列




Android 硬解码 解码成什么格式 android 软解和硬解_硬解码



8.接下来调用dequeueOutputBuffer,获取解码器的输出。注意,这个函数传递以下参数:


Android 硬解码 解码成什么格式 android 软解和硬解_ci_02



8.1 MediaCodec.BufferInfo:这个是我们作为入参传入的,传入的时候是一个空的BufferInfo。当解码器dequeueOutputBuffer获取到输出的时候,会将解码器输出数据的metadata填充到这个对象里面


meatadata结构(bufferInfo类的定义)如下:


Android 硬解码 解码成什么格式 android 软解和硬解_硬解码_03



8.2 timeoutUs自然就是等待解码器输出的超时时间了


8.3 这个函数的返回值是:成功解码的output buffer的index,可以根据这个index获取到output buffer


9.根据outputBufferIndex,从解码器输出缓冲区中获取一个outputBuffer


api 21以下:mediaCodec.getOutputBuffers()[outputBufferIndex]


api 21以上:mCodec.getOutputBuffer(outputBufferIndex);


10.有了解码的输出数据outputBuffer和数据的metadata(包括offset,pts等信息),就得到了完整的解码数据了



软解码:(FFMPEG解码)


1.创建ffmpeg codec:调用avcodec_find_decoder:在ffmpeg中是根据codecid(aac,h264等注册的id)寻找合适的decoder,返回AVCodec对象


2.创建decode的context:avcodec_alloc_context3,这函数返回的codecContext包含解码器所需要的各种配置信息,比如


对于aac decode,context可以用来设置sample_rate,channels,profile等


对于h264 decode,context可以用来设置width,height等、


3.调用avcodec_open2:用已经配置好的decoder的context,来configure解码器codec


4.调用av_init_packet(AVPacket *pkt);初始化一个pkt用于接收待解码的数据


5.用demux输出的数据,填充pkt的data,设置pkt的flag(是否包含key frame等)


6.调用avcodec_send_packet将填充满的pkt,发送给解码器


7.调用avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);从解码器接收decode后的数据,填充到AVFrame中。



通过以上函数就能够得到解码后的数据了,之后根据需要,还可以继续处理:



8.对于video数据,从AVFrame中,拷贝decoded的数据成YUV格式(I420),到uint8_t数组


Android 硬解码 解码成什么格式 android 软解和硬解_ci_04



9.通过OpenGL的shader可以将YUV420数据画到SurfaceView的output surface上,进行渲染