一、硬解码
步骤:
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队列
8.
接下来调用dequeueOutputBuffer,获取解码器的输出。注意,这个函数传递以下参数:
8.1 MediaCodec.BufferInfo:这个是我们作为入参传入的,传入的时候是一个空的BufferInfo。当解码器dequeueOutputBuffer获取到输出的时候,会将解码器输出数据的metadata填充到这个对象里面
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.首先要注册解码器
2.创建ffmpeg codec:调用avcodec_find_decoder:在ffmpeg中是根据codecid(aac,h264等注册的id)寻找合适的decoder,返回AVCodec(存储编解码器信息的结构体)对象
3.创建decode的context:avcodec_alloc_context3,这函数返回的codecContext包含解码器所需要的各种配置信息,比如
对于aac decode,context可以用来设置sample_rate,channels,profile等
对于h264 decode,context可以用来设置width,height等、
4.调用avcodec_open2:用已经配置好的decoder的context,来configure解码器codec
5.调用av_init_packet(AVPacket *pkt);初始化一个pkt用于接收待解码的数据
6.用demux输出的数据,填充pkt的data,设置pkt的flag(是否包含key frame等)
7.调用avcodec_send_packet将填充满的pkt,发送给解码器
8.调用
avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
const AVPacket *avpkt);
;从解码器接收decode后的数据,填充到AVFrame中。
通过以上函数就能够得到解码后的数据了,之后根据需要,还可以继续处理:
9.对于video数据,从AVFrame中,拷贝decoded的数据成YUV格式(I420),到uint8_t数组
10.通过OpenGL的shader可以将YUV420数据画到SurfaceView的output surface上,进行渲染