超详细解析FFplay之数据读取线程( 四 )

/** * Find the "best" stream in the file. * The best stream is determined according to various heuristics as the most * likely to be what the user expects. * If the decoder parameter is non-NULL, av_find_best_stream will fi nd the * default decoder for the stream's codec; streams for which no deco der can * be found are ignored. * * @param ic media file handle * @param type stream type: video, audio, subtitles, et c. * @param wanted_stream_nb user-requested stream number, * or -1 for automatic selection * @param related_stream try to find a stream related (eg. in the same * program) to this one, or -1 if none * @param decoder_ret if non-NULL, returns the decoder for the* selected stream * @param flags flags; none are currently defined* @return the non-negative stream number in case of success, * AVERROR_STREAM_NOT_FOUND if no stream with the requested type * could be found, 21 * AVERROR_DECODER_NOT_FOUND if streams were found but no d ecoder* @note If av_find_best_stream returns successfully and decoder_re t is not * NULL, then *decoder_ret is guaranteed to be set to a valid AVCodec. */int av_find_best_stream(AVFormatContext *ic,enum AVMediaType type, //要选择的流类型int wanted_stream_nb, //?标流索引int related_stream, //相关流索引AVCodec **decoder_ret,int flags);具体代码流程如下:
如果是根据用户指定来查找流 。使用了正确的wanted_stream_nb,?般情况都是直接返回该指定流,即?户选择的流 。
for (i = 0; i < ic->nb_streams; i++) {AVStream *st = ic->streams[i];enum AVMediaType type = st->codecpar->codec_type;st->discard = AVDISCARD_ALL;if (type >= 0 && wanted_stream_spec[type] && st_index[type] == - 1)if (avformat_match_stream_specifier(ic, st, wanted_stream_sp ec[type]) > 0)st_index[type] = i;} for (i = 0; i < AVMEDIA_TYPE_NB; i++) {if (wanted_stream_spec[i] && st_index[i] == -1) {av_log(NULL, AV_LOG_ERROR, "Stream specifier %s does not mat ch any %s streamn", wanted_stream_spec[i], av_get_media_type_string (i));st_index[i] = INT_MAX;} }使用av_find_best_stream选择流 。如果?户没有指定流,或指定部分流,或指定流不存在,则主要由av_find_best_stream发挥作? 。
if (!video_disable)st_index[AVMEDIA_TYPE_VIDEO] =av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0); if (!audio_disable)st_index[AVMEDIA_TYPE_AUDIO] =av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,st_index[AVMEDIA_TYPE_AUDIO],st_index[AVMEDIA_TYPE_VIDEO],NULL, 0); if (!video_disable && !subtitle_disable)st_index[AVMEDIA_TYPE_SUBTITLE] =av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,st_index[AVMEDIA_TYPE_SUBTITLE],(st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?st_index[AVMEDIA_TYPE_AUDIO] :st_index[AVMEDIA_TYPE_VIDEO]),NULL, 0);如果指定了相关流,且未指定?标流的情况,会在相关流的同?个节?中查找所需类型的流,但?般结果,都是返回该类型第1个流 。
通过AVCodecParameters和av_guess_sample_aspect_ratio计算出显示窗?的宽、? 。从待处理流中获取相关参数,设置显示窗?的宽度、?度及宽?? 。由于帧宽??由解码器设置,但流宽??由解复?器设置,因此这两者可能不相等 。基本逻辑是优先使?流宽??(前提是值是合理的),其次使?帧宽??,这样,流宽??(容器设置,易于修改)可以覆盖帧宽?? 。
if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];AVCodecParameters *codecpar = st->codecpar;//根据流和帧宽??猜测帧的样本宽?? 。//此函数会尝试返回待显示帧应当使?的宽??值 。AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);if (codecpar->width) {// 设置显示窗?的??和宽??set_default_window_size(codecpar->width, codecpar->heigh t, sar);} }具体流程如上所示,这?实质只是设置了default_width、default_height变量的??,没有真正改变窗?的?? 。真正调整窗???是在视频显示调?video_open()函数进?设置 。
 
stream_component_open()
经过以上步骤,?件打开成功,且获取了流的基本信息,并选择?频流、视频流、字幕流 。接下来就可以所选流对应的解码器了 。
/* open the streams *//* 5.打开视频、?频解码器 。在此会打开相应解码器,并创建相应的解码线程 。*/ if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]); } ret = -1; if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO] );} if (is->show_mode == SHOW_MODE_NONE) {//选择怎么显示,如果视频打开成功,就显示视频画?,否则,显示?频对应的频谱图is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT; } if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]); }?频、视频、字幕等流都要调?stream_component_open,他们直接有共同的流程,也有差异化的流程,差异化流程使?switch进?区分 。


推荐阅读