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é)對齊左右
自己做沖采樣可以按行做對比

? 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)