FFmpeg 解碼 avcodec_find_decoder AVCodecContext

avcodec_find_decoder

(1)解碼模塊第一步:獲取解碼器 avcodec_find_decoder()FFmpeg的解碼器編碼器都存在avcodec的結(jié)構(gòu)體中
(2) 解碼前保證用到的解碼器已經(jīng)注冊好 avcodec_register_all();(過期)
(3)通過解封裝之后,從avstream里面獲取CodecID ,通過CodecID來查找decoder AVCodec *avcodec_find_decoder(enum AVCodecID id)
AVCodec 存放的是解碼器格式的配置信息
(4)通過解碼器名字找到解碼器 AVCodec *avcodec_find_decoder_by_name(const char
*name);
如:avcodec_find_decoder_by_name("h264_mediacodec");

AVCodecContext

(1) AVCodecContext *avcodec_alloc_context3(const AVCodec *codec) 空間申請

(2)void avcodec_free_context(AVCodecContext **avctx); 釋放

(3)int avcodec_open2(AVCodecContext *avctx, const AVCodec
*codec, AVDictionary **options) 打開 options動態(tài)設(shè)置 多線程解碼設(shè)置
? /libavcodec/options_table.h
? int thread_count CPU數(shù)量設(shè)置
? time_base 時間基數(shù)
(4)avcodec_parameters_to_context(codec, p); 把avstream中的參數(shù)復(fù)制到codec中

  //解碼器初始化
    AVCodecContext *vc = avcodec_alloc_context3(codec);
    vc->thread_count = 1;
    avcodec_parameters_to_context(vc, ic->streams[videoStream]->codecpar);
    //打開解碼器
    re = avcodec_open2(vc,0, 0);
    if (re != 0) {
         NSLog(@"avcodec_open2 video failed!");
         return;
    }
    
    ////////////////////////////////////////////////////
    //音頻解碼器
    AVCodec *acodec = avcodec_find_decoder(ic->streams[audioStream]->codecpar->codec_id);
    //硬解碼
    //    codec = avcodec_find_decoder_by_name("h264_mediacodec");
    if (!acodec) {
        NSLog(@"avcodec_find_decoder_by_name audio failed!");
        return ;
    }
    //解碼器初始化
    AVCodecContext *ac = avcodec_alloc_context3(acodec);
    ac->thread_count = 1;
    avcodec_parameters_to_context(ac, ic->streams[audioStream]->codecpar);
    //打開解碼器
    re = avcodec_open2(ac,0, 0);
    if (re != 0) {
        NSLog(@"avcodec_open2 audio failed!");
        return;
    }

AVFrame

AVFrame用于存放解碼后的數(shù)據(jù)
? AVFrame *frame = av_frame_alloc() 分配內(nèi)存空間

? void av_frame_free(AVFrame **frame) 釋放內(nèi)存空間

? int av_frame_ref(AVFrame *dst, const AVFrame *src) 引用計數(shù)+1

? AVFrame *av_frame_clone(const AVFrame *src) 重新創(chuàng)建一個空間 引用計數(shù)+1 一般不用比較耗時

? void av_frame_unref(AVFrame *frame) 引用計數(shù)減一

//////////

? uint8_t *data[AV_NUM_DATA_POINTERS]

? int linesize[AV_NUM_DATA_POINTERS]
視頻一行的數(shù)據(jù) 音頻一個通道數(shù)據(jù)大小 存放的目的主要是為了按字節(jié)對齊左右
自己做沖采樣可以按行做對比


image.png

? int width, height(寬高);int nb_samples (單通道的樣本數(shù)量)

? int64_t pts ;int64_t pkt_dts

? int sample_rate;uint64_t channel_layout;int channels

? int format; //AVPixelFormat AVSampleFormat 像素格式


avcodec_send_packet

? int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
把avpkt放入解碼隊列的緩存中 avcodec_send_packet 調(diào)用后 會創(chuàng)建一個 avpkt對象,會把實際的數(shù)據(jù) 引用數(shù)據(jù)+1 或者copy一份

avcodec_receive_frame

? int avcodec_receive_frame(AVCodecContex t *avctx, AVFrame *frame) (傳同一個對象的時候 會清掉上一個) 從解碼成功的數(shù)據(jù)中取出一個 frame 解碼的時候前幾幀的可能獲取失敗 導(dǎo)致播放的時候視頻最后的幾幀沒有播放(解決方案 結(jié)尾處的avcodec_send_packet avpkt傳NULL 一直avcodec_receive_frame,直到取不出幀為止)
avcodec_send_packet 和 avcodec_receive_frame 不是一一對應(yīng)的

        //測試音視頻解碼
        AVCodecContext *cc = vc;
        if (pkt->stream_index == audioStream) {
            cc = ac;
        }
        
        //發(fā)送的線程中解碼
        re = avcodec_send_packet(cc, pkt);\
        //解碼
        av_packet_unref(pkt);
        
        if (re != 0) {
            NSLog(@"avcodec_send_packet audio failed!");
            continue;
        }
        for (; ; ) {//保證能搜到全部的解碼數(shù)據(jù)
            re = avcodec_receive_frame(cc, frame);
            if (re != 0) {
//                NSLog(@"avcodec_receive_frame audio failed!");
                break;
            }
            NSLog(@"frame->pts %lld",frame->pts);
        }
        //最后一針的時候 avcodec_send_packet(cc, NULL)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容