FFmpeg在调用avformat_open_input()之后,可能码流信息不够完整,可以使用avformat_find_stream_info()获取更多的码流信息。比如获取视频帧率、视频宽高,重新计算最大分析时长,打开解码器解码获取codec数据。具体流程如下图所示:
avformat_find_stream_info方法位于libavformat/utils.c,具体代码如下(部分删减):
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
// 针对flv/mpeg/mpegts格式,max_analyze_duration另外赋值
if (!max_analyze_duration) {
max_stream_analyze_duration =
max_analyze_duration = 5*AV_TIME_BASE;
max_subtitle_analyze_duration = 30*AV_TIME_BASE;
if (!strcmp(ic->iformat->name, "flv"))
max_stream_analyze_duration = 90*AV_TIME_BASE;
if (!strcmp(ic->iformat->name, "mpeg") || !strcmp(ic->iformat->name, "mpegts"))
max_stream_analyze_duration = 7*AV_TIME_BASE;
}
for (i = 0; i < ic->nb_streams; i++) {
// 查找解码器
codec = find_probe_decoder(ic, st, st->codecpar->codec_id);
// 确保字幕头信息已正确设置
if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE
&& codec && !avctx->codec) {
if (avcodec_open2(avctx, codec, options ? &options[i] : &thread_opt) < 0)
av_log(ic, AV_LOG_WARNING, "Failed to open codec in %s\n",__FUNCTION__);
}
// 尝试打开解码器
if (!has_codec_parameters(st, NULL) && st->internal->request_probe <= 0) {
if (codec && !avctx->codec)
if (avcodec_open2(avctx, codec, options ? &options[i] : &thread_opt) < 0)
av_log(ic, AV_LOG_WARNING, "Failed to open codec in %s\n",__FUNCTION__);
}
}
......
for (;;) {
for (i = 0; i < ic->nb_streams; i++) {
int fps_analyze_framecount = 20;
int count;
st = ic->streams[i];
if (!has_codec_parameters(st, NULL))
break;
// 如果时间基是粗糙的,比如mkv采用ms作为单位
// 需要分析更多帧数据来获取帧率
if (av_q2d(st->time_base) > 0.0005)
fps_analyze_framecount *= 2;
if (!tb_unreliable(st->internal->avctx))
fps_analyze_framecount = 0;
if (ic->fps_probe_size >= 0)
fps_analyze_framecount = ic->fps_probe_size;
if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
fps_analyze_framecount = 0;
count = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ?
st->internal->info->codec_info_duration_fields/2 :
st->internal->info->duration_count;
if (!(st->r_frame_rate.num && st->avg_frame_rate.num) &&
st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
if (count < fps_analyze_framecount)
break;
}
// 如果存在帧延时,查看前3帧
if (st->internal->info->frame_delay_evidence && count < 2 && st->internal->avctx->has_b_frames == 0)
break;
if (!st->internal->avctx->extradata &&
(!st->internal->extract_extradata.inited ||
st->internal->extract_extradata.bsf) &&
extract_extradata_check(st))
break;
if (st->first_dts == AV_NOPTS_VALUE &&
!(ic->iformat->flags & AVFMT_NOTIMESTAMPS) &&
st->codec_info_nb_frames < ((st->disposition & AV_DISPOSITION_ATTACHED_PIC) ? 1 : ic->max_ts_probe) &&
(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO