ffplay debug 03
过年最后一天了啧啧啧,今天也怕是看不完这个的。
开始吧。
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
打开指定stream_index
的流,并将流里的内容放到is
里,就是这么回事儿吧。
开局又是先对一堆变量声明初始化之类的。
然后判断了下stream_index
是否正常(在is->ic->nb_streams)之内,不正常直接return -1。
avctx = avcodec_alloc_context3(NULL);
if (!avctx)
return AVERROR(ENOMEM);
ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar);
if (ret < 0)
goto fail;
avctx->pkt_timebase = ic->streams[stream_index]->time_base;
初始化编解码器上下文AVCodecContext
。先分配空间,然后根据stream的codecpar
即编解码器参数,来初始化avctx的内容。然后并设置了timebase
。
codec = avcodec_find_decoder(avctx->codec_id);
switch(avctx->codec_type){
case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; forced_codec_name = audio_codec_name; break;
case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = subtitle_codec_name; break;
case AVMEDIA_TYPE_VIDEO : is->last_video_stream = stream_index; forced_codec_name = video_codec_name; break;
}
if (forced_codec_name)
codec = avcodec_find_decoder_by_name(forced_codec_name);
if (!codec) {
if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,
"No codec could be found with name '%s'\n", forced_codec_name);
else av_log(NULL, AV_LOG_WARNING,
"No decoder could be found for codec %s\n", avcodec_get_name(avctx->codec_id));
ret = AVERROR(EINVAL);
goto fail;
}
avctx->codec_id = codec->id;
获取解码器的部分,并且这里还会记录一下上一个使用的流last_xxx_stream
。还有会设置是否有强制使用的编解码器,应该是ffplay的选项设置的。
最后查看下是否找到。并赋上codec id。
if (stream_lowres > codec->max_lowres) {
av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
codec->max_lowres);
stream_lowres = codec->max_lowres;
}
avctx->lowres = stream_lowres;
lowers
,即low resolution
,低分辨率。很明显是video领域的东西,所以这里直接跳过了。
if (fast)
avctx->flags2 |= AV_CODEC_FLAG2_FAST;
这是个不符合规范的编解码加速方式,AV_CODEC_FLAG2_FAST
,需要fast来启用,应该也是个ffplay option。
碎碎念,工作太难了,更没时间干别的事了。虽然ffplay debug系列的最初设想是一天一个板块,01 02 03,这种跟记日记的方式一样,但看来现在一天之内是没有时间做的了,所以一个部分的内容只能分散到一段时间内来做了,所以不是日记喽。我这么说的时候就说明今天已经要结束了。还有,我讨厌工作啧啧啧…
啊哈,时隔16日,我又回来辣。
昨天和今晚又把之前debug的部分回顾了一下,今天继续继续。
ret = filter_codec_opts(codec_opts, avctx->codec_id, ic,
ic->streams[stream_index], codec, &opts, NULL);
if (ret < 0)
goto fail;
很好,第一个就没动力看了,十一点了,睡了先。
filter_codec_opts
用于筛选options,符合给定codec_id
的options,从codec_opts中。
if (!av_dict_get(opts, "threads", NULL, 0))
av_dict_set(&opts, "threads", "auto", 0);
if (stream_lowres)
av_dict_set_int(&opts, "lowres", stream_lowres, 0);
av_dict_set(&opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY);
然后看得到的opts中有没有threads,没有就设为auto,还有lowres,以及设了个flags为+copy_opaque的项。
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
ret = create_hwaccel(&avctx->hw_device_ctx);
if (ret < 0)
goto fail;
}
查看是不是video流,是的话用硬件加速。
if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) {
goto fail;
}
ret = check_avoptions(opts);
if (ret < 0)
goto fail;
avcodec_open2
打开编解码器,用codec接收,并用opts选项设置codec属性。
check_avoptions
用来看是否还存在opts没用。
is->eof = 0;
ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
eof设为0,当前流的discard设为default,default即丢弃无用的packet,如size为0的。
然后是一段switch处理,这里就只看audio的了。
is->audio_filter_src.freq = avctx->sample_rate;
ret = av_channel_layout_copy(&is->audio_filter_src.ch_layout, &avctx->ch_layout);
if (ret < 0)
goto fail;
is->audio_filter_src.fmt = avctx->sample_fmt;
这里是依次获取采样率,通道布局,样本格式。
AVFilterContext *sink;
if ((ret = configure_audio_filters(is, afilters, 0)) < 0)
configure_audio_filters
很好,又是个大的。