1. 程式人生 > >Android軟解碼與硬解碼流程概述

Android軟解碼與硬解碼流程概述

最近整理了下Android端專案裡硬解碼與軟解碼的大致流程,做個筆記,方便以後review。如有錯誤,歡迎指正。硬解碼:1.建立MediaCodec:如 MediaCodec.createDecoderByType(keyMime);2.configure codec:配置format,surface等引數3.start codec4.從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填充到這個物件裡面 meatadata結構(bufferInfo類的定義)如下:
8.2 timeoutUs自然就是等待解碼器輸出的超時時間了8.3 這個函式的返回值是:成功解碼的output buffer的index,可以根據這個index獲取到output buffer9.根據outputBufferIndex,從解碼器輸出緩衝區中獲取一個outputBufferapi 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解碼器codec4.呼叫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陣列

9.通過OpenGL的shader可以將YUV420資料畫到SurfaceView的output surface上,進行渲染