ffmpeg学习六avcodecopen2函数源码分析以mp4文件为例.docx
- 文档编号:11336686
- 上传时间:2023-02-27
- 格式:DOCX
- 页数:31
- 大小:176.83KB
ffmpeg学习六avcodecopen2函数源码分析以mp4文件为例.docx
《ffmpeg学习六avcodecopen2函数源码分析以mp4文件为例.docx》由会员分享,可在线阅读,更多相关《ffmpeg学习六avcodecopen2函数源码分析以mp4文件为例.docx(31页珍藏版)》请在冰豆网上搜索。
ffmpeg学习六avcodecopen2函数源码分析以mp4文件为例
ffmpeg学习六:
avcodec_open2函数源码分析(以mp4文件为例)
avformat_open_input函数的源码,这个函数的虽然比较复杂,但是它基本是围绕着创建和初始化一些数据结构来展开的,比如,avformat_open_input函数会创建和初始化AVFormatContext,AVClass,AVOption,URLContext,URLProtocol,AVInputFormat,AVStream等数据结构,这些数据结构的关系如下:
(这里的箭头是包含关系,不是继承关系)
那么,我们可以推测,同样作为Open系列的函数,avcodec_open2的使命也必然是构建和初始化一系列的数据结构,那么是不是这样呢?
avcodec_open2函数定义在libavcodec/aviocodec.h中:
/**
*InitializetheAVCodecContexttousethegivenAVCodec.Priortousingthis
*functionthecontexthastobeallocatedwithavcodec_alloc_context3().
*
*Thefunctionsavcodec_find_decoder_by_name(),avcodec_find_encoder_by_name(),
*avcodec_find_decoder()andavcodec_find_encoder()provideaneasywayfor
*retrievingacodec.
*
*@warningThisfunctionisnotthreadsafe!
*
*@noteAlwayscallthisfunctionbeforeusingdecodingroutines(suchas
*@refavcodec_receive_frame()).
*
*@code
*avcodec_register_all();
*av_dict_set(&opts,"b","2.5M",0);
*codec=avcodec_find_decoder(AV_CODEC_ID_H264);
*if(!
codec)
*exit
(1);
*
*context=avcodec_alloc_context3(codec);
*
*if(avcodec_open2(context,codec,opts)<0)
*exit
(1);
*@endcode
*
*@paramavctxThecontexttoinitialize.
*@paramcodecThecodectoopenthiscontextfor.Ifanon-NULLcodechasbeen
*previouslypassedtoavcodec_alloc_context3()or
*forthiscontext,thenthisparameterMUSTbeeitherNULLor
*equaltothepreviouslypassedcodec.
*@paramoptionsAdictionaryfilledwithAVCodecContextandcodec-privateoptions.
*Onreturnthisobjectwillbefilledwithoptionsthatwerenotfound.
*
*@returnzeroonsuccess,anegativevalueonerror
*@seeavcodec_alloc_context3(),avcodec_find_decoder(),avcodec_find_encoder(),
*av_dict_set(),av_opt_find().
*/
intavcodec_open2(AVCodecContext*avctx,constAVCodec*codec,AVDictionary**options);
从它的注释中我们可以得到如下信息:
1.使用所给的AVCodec结构体构造AVCodecContext结构体。
2.avcodec_find_decoder_by_name(),avcodec_find_encoder_by_name(),
*avcodec_find_decoder()andavcodec_find_encoder(),这几个函数提供了方便获取AVCodecContext实例的途径。
3.这个函数是线程不安全函数
4.在使用解码程序之前,必须调用此函数。
综上,avcodec_open2函数的核心人物是构造AVCodecContext结构体。
avcodec_open2函数在libavcodec/utils.c中实现:
intattribute_align_argavcodec_open2(AVCodecContext*avctx,constAVCodec*codec,AVDictionary**options)
{
intret=0;
AVDictionary*tmp=NULL;
constAVPixFmtDescriptor*pixdesc;
if(avcodec_is_open(avctx))
return0;
if((!
codec&&!
avctx->codec)){
av_log(avctx,AV_LOG_ERROR,"Nocodecprovidedtoavcodec_open2()\n");
returnAVERROR(EINVAL);
}
if((codec&&avctx->codec&&codec!
=avctx->codec)){
av_log(avctx,AV_LOG_ERROR,"ThisAVCodecContextwasallocatedfor%s,"
"but%spassedtoavcodec_open2()\n",avctx->codec->name,codec->name);
returnAVERROR(EINVAL);
}
if(!
codec)
codec=avctx->codec;
if(avctx->extradata_size<0||avctx->extradata_size>=FF_MAX_EXTRADATA_SIZE)
returnAVERROR(EINVAL);
if(options)
av_dict_copy(&tmp,*options,0);
ret=ff_lock_avcodec(avctx,codec);
if(ret<0)
returnret;
avctx->internal=av_mallocz(sizeof(AVCodecInternal));
if(!
avctx->internal){
ret=AVERROR(ENOMEM);
gotoend;
}
avctx->internal->pool=av_mallocz(sizeof(*avctx->internal->pool));
if(!
avctx->internal->pool){
ret=AVERROR(ENOMEM);
gotofree_and_end;
}
avctx->internal->to_free=av_frame_alloc();
if(!
avctx->internal->to_free){
ret=AVERROR(ENOMEM);
gotofree_and_end;
}
avctx->internal->buffer_frame=av_frame_alloc();
if(!
avctx->internal->buffer_frame){
ret=AVERROR(ENOMEM);
gotofree_and_end;
}
avctx->internal->buffer_pkt=av_packet_alloc();
if(!
avctx->internal->buffer_pkt){
ret=AVERROR(ENOMEM);
gotofree_and_end;
}
if(codec->priv_data_size>0){
if(!
avctx->priv_data){
avctx->priv_data=av_mallocz(codec->priv_data_size);
if(!
avctx->priv_data){
ret=AVERROR(ENOMEM);
gotoend;
}
if(codec->priv_class){
*(constAVClass**)avctx->priv_data=codec->priv_class;
av_opt_set_defaults(avctx->priv_data);
}
}
if(codec->priv_class&&(ret=av_opt_set_dict(avctx->priv_data,&tmp))<0)
gotofree_and_end;
}else{
avctx->priv_data=NULL;
}
if((ret=av_opt_set_dict(avctx,&tmp))<0)
gotofree_and_end;
if(avctx->codec_whitelist&&av_match_list(codec->name,avctx->codec_whitelist,',')<=0){
av_log(avctx,AV_LOG_ERROR,"Codec(%s)notonwhitelist\'%s\'\n",codec->name,avctx->codec_whitelist);
ret=AVERROR(EINVAL);
gotofree_and_end;
}
//onlycallff_set_dimensions()fornonH.264/VP6F/DXVcodecssoasnottooverwritepreviouslysetupdimensions
if(!
(avctx->coded_width&&avctx->coded_height&&avctx->width&&avctx->height&&
(avctx->codec_id==AV_CODEC_ID_H264||avctx->codec_id==AV_CODEC_ID_VP6F||avctx->codec_id==AV_CODEC_ID_DXV))){
if(avctx->coded_width&&avctx->coded_height)
ret=ff_set_dimensions(avctx,avctx->coded_width,avctx->coded_height);
elseif(avctx->width&&avctx->height)
ret=ff_set_dimensions(avctx,avctx->width,avctx->height);
if(ret<0)
gotofree_and_end;
}
if((avctx->coded_width||avctx->coded_height||avctx->width||avctx->height)
&&(av_image_check_size(avctx->coded_width,avctx->coded_height,0,avctx)<0
||av_image_check_size(avctx->width,avctx->height,0,avctx)<0)){
av_log(avctx,AV_LOG_WARNING,"Ignoringinvalidwidth/heightvalues\n");
ff_set_dimensions(avctx,0,0);
}
if(avctx->width>0&&avctx->height>0){
if(av_image_check_sar(avctx->width,avctx->height,
avctx->sample_aspect_ratio)<0){
av_log(avctx,AV_LOG_WARNING,"ignoringinvalidSAR:
%u/%u\n",
avctx->sample_aspect_ratio.num,
avctx->sample_aspect_ratio.den);
avctx->sample_aspect_ratio=(AVRational){0,1};
}
}
/*ifthedecoderinitfunctionwasalreadycalledpreviously,
*freethealreadyallocatedsubtitle_headerbeforeoverwritingit*/
if(av_codec_is_decoder(codec))
av_freep(&avctx->subtitle_header);
if(avctx->channels>FF_SANE_NB_CHANNELS){
ret=AVERROR(EINVAL);
gotofree_and_end;
}
avctx->codec=codec;
if((avctx->codec_type==AVMEDIA_TYPE_UNKNOWN||avctx->codec_type==codec->type)&&
avctx->codec_id==AV_CODEC_ID_NONE){
avctx->codec_type=codec->type;
avctx->codec_id=codec->id;
}
if(avctx->codec_id!
=codec->id||(avctx->codec_type!
=codec->type
&&avctx->codec_type!
=AVMEDIA_TYPE_ATTACHMENT)){
av_log(avctx,AV_LOG_ERROR,"Codectypeoridmismatches\n");
ret=AVERROR(EINVAL);
gotofree_and_end;
}
avctx->frame_number=0;
avctx->codec_descriptor=avcodec_descriptor_get(avctx->codec_id);
if((avctx->codec->capabilities&AV_CODEC_CAP_EXPERIMENTAL)&&
avctx->strict_std_compliance>FF_COMPLIANCE_EXPERIMENTAL){
constchar*codec_string=av_codec_is_encoder(codec)?
"encoder":
"decoder";
AVCodec*codec2;
av_log(avctx,AV_LOG_ERROR,
"The%s'%s'isexperimentalbutexperimentalcodecsarenotenabled,"
"add'-strict%d'ifyouwanttouseit.\n",
codec_string,codec->name,FF_COMPLIANCE_EXPERIMENTAL);
codec2=av_codec_is_encoder(codec)?
avcodec_find_encoder(codec->id):
avcodec_find_decoder(codec->id);
if(!
(codec2->capabilities&AV_CODEC_CAP_EXPERIMENTAL))
av_log(avctx,AV_LOG_ERROR,"Alternativelyusethenonexperimental%s'%s'.\n",
codec_string,codec2->name);
ret=AVERROR_EXPERIMENTAL;
gotofree_and_end;
}
if(avctx->codec_type==AVMEDIA_TYPE_AUDIO&&
(!
avctx->time_base.num||!
avctx->time_base.den)){
avctx->time_base.num=1;
avctx->time_base.den=avctx->sample_rate;
}
if(!
HAVE_THREADS)
av_log(avctx,AV_LOG_WARNING,"Warning:
notcompiledwiththreadsupport,usingthreademulation\n");
if(CONFIG_FRAME_THREAD_ENCODER&&av_codec_is_encoder(avctx->codec)){
ff_unlock_avcodec(codec);//wewillinstantiateafewencodersthuskickthecountertopreventfalsedetectionofaproblem
ret=ff_frame_thread_encoder_init(avctx,options?
*options:
NULL);
ff_lock_avcodec(avctx,codec);
if(ret<0)
gotofree_and_end;
}
if(HAVE_THREADS
&&!
(avctx->internal->frame_thread_encoder&&(avctx->active_thread_type&FF_THREAD_FRAME))){
ret=ff_thread_init(avctx);
if(ret<0){
gotofree_and_end;
}
}
if(!
HAVE_THREADS&&!
(codec->capabilities&AV_CODEC_CAP_AUTO_THREADS))
avctx->thread_count=1;
if(avctx->codec->max_lowres
av_log(avctx,AV_LOG_WARNING,"Themaximumvalueforlowressupportedbythedecoderis%d\n",
avctx->codec->max_lowres);
avctx->lowres=avctx->codec->max_lowres;
}
#ifFF_API_VISMV
if(avctx->debug_mv)
av_log(avctx,AV_LOG_WARNING,"The'vismv'optionisdeprecated,"
"seethecodecviewfilterinstead.\n");
#endif
if(av_codec_is_encoder(avctx->codec)){
inti;
#ifFF_API_CODED_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
avctx->coded_frame=av_frame_alloc();
if(!
avctx->coded_frame){
ret=AVERROR(ENOMEM);
gotofree_and_end;
}
FF_ENABLE_DEPRECATION_WARNINGS
#endif
if(avctx->time_base.num<=0||avctx->time_base.den<=0){
av_log(avctx,AV_LOG_ERROR,"Theencodertimebaseisnotset.\n");
ret=AVERROR(EINVAL);
gotofree_and_end;
}
if(avctx->codec->sample_fmts){
for(i=0;avctx->codec->sample_fmts[i]!
=AV_SAMPLE_FMT_NONE;i++){
if(avctx->sample_fmt==avctx->codec->sample_fmts[i])
break;
if(avctx->channels==1&&
av_get_planar_sample_fmt(avctx->sample_fmt)==
av_get_planar_sample_fmt(avctx->codec->sample_fmts[i])){
avctx->sample_fmt=avctx->codec->sample_fmts[i];
break;
}
}
if(avctx->codec->sample_fmts[i]==AV_SAMPLE_FMT_NONE){
charbuf[128];
snprintf(buf,sizeof(buf),"%d",avctx->sample_fmt);
av_log(avctx,AV_LOG_ERROR,"Specifiedsampleformat%sisinvalidornotsupported\n",
(char*)av_x_if_null(av_get_sample_fmt_name(avctx->s
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ffmpeg 学习 avcodecopen2 函数 源码 分析 mp4 文件