FFmpeg解析之avformat_find_stream_info函数

avformat_find_stream_info 的主要作用就是:解析媒体文件并获取相关的流信息
整体的逻辑如下图所示:

/*** Read packets of a media file to get stream information. This* is useful for file formats with no headers such as MPEG. This* function also computes the real framerate in case of MPEG-2 repeat* frame mode.* The logical file position is not changed by this function;* examined packets may be buffered for later processing.** @param ic media file handle* @param options  If non-NULL, an ic.nb_streams long array of pointers to*                 dictionaries, where i-th member contains options for*                 codec corresponding to i-th stream.*                 On return each dictionary will be filled with options that were not found.* @return >=0 if OK, AVERROR_xxx on error** @note this function isn't guaranteed to open all the codecs, so*       options being non-empty at return is a perfectly normal behavior.** @todo Let the user decide somehow what information is needed so that*       we do not waste time getting stuff the user does not need.*//*** 从注释可知道,此方法通过读取若干 packet 包来获取流信息,这对于像 MPEG 这种没有 header 的格式比较有用。此函数也计算了像 MPEG-2 这种支持 repeat mode 的真实帧率* 这个函数不会修改逻辑文件位置,所读取到的 packet 会缓存起来供后面使用。*/
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{int i, count = 0, ret = 0, j;int64_t read_size;AVStream *st;AVCodecContext *avctx;AVPacket pkt1;int64_t old_offset  = avio_tell(ic->pb);// new streams might appear, no options for thoseint orig_nb_streams = ic->nb_streams;int flush_codecs;int64_t max_analyze_duration = ic->max_analyze_duration;int64_t max_stream_analyze_duration;int64_t max_subtitle_analyze_duration;int64_t probesize = ic->probesize;int eof_reached = 0;int *missing_streams = av_opt_ptr(ic->iformat->priv_class, ic->priv_data, "missing_streams");flush_codecs = probesize > 0;av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN);max_stream_analyze_duration = max_analyze_duration;max_subtitle_analyze_duration = max_analyze_duration;if (!max_analyze_duration) {//默认5*AV_TIME_BASE,针对flv和mpeg默认90*AV_TIME_BASE和7*AV_TIME_BASEmax_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;}if (ic->pb)av_log(ic, AV_LOG_DEBUG, "Before avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d nb_streams:%d\n",avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count, ic->nb_streams);/*** -----【第一次循环遍历流】-------* 主要就是:初始化 avctx 的 time_base 等参数,初始化解析器,将编解码器的参数信息拷贝到编解码器上下文中,* 查找解码器、打开解码器*/for (i = 0; i < ic->nb_streams; i++) {const AVCodec *codec;AVDictionary *thread_opt = NULL;st = ic->streams[i];avctx = st->internal->avctx;//获取编解码器上下文if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
/*            if (!st->time_base.num)st->time_base = */if (!avctx->time_base.num)avctx->time_base = st->time_base;//设置avctx->time_base}/* check if the caller has overridden the codec id */
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGSif (st->codec->codec_id != st->internal->orig_codec_id) {st->codecpar->codec_id   = st->codec->codec_id;st->codecpar->codec_type = st->codec->codec_type;st->internal->orig_codec_id = st->codec->codec_id;}
FF_ENABLE_DEPRECATION_WARNINGS
#endif// only for the split stuffif (!st->parser && !(ic->flags & AVFMT_FLAG_NOPARSE) && st->internal->request_probe <= 0) {st->parser = av_parser_init(st->codecpar->codec_id);//解析器为空则初始化解析器if (st->parser) {if (st->need_parsing == AVSTREAM_PARSE_HEADERS) {st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;} else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) {st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;}} else if (st->need_parsing) {av_log(ic, AV_LOG_VERBOSE, "parser not found for codec ""%s, packets or times may be invalid.\n",avcodec_get_name(st->codecpar->codec_id));}}if (st->codecpar->codec_id != st->internal->orig_codec_id)st->internal->orig_codec_id = st->codecpar->codec_id;ret = avcodec_parameters_to_context(avctx, st->codecpar);//参数拷贝if (ret < 0)goto find_stream_info_err;if (st->internal->request_probe <= 0)st->internal->avctx_inited = 1;codec = find_probe_decoder(ic, st, st->codecpar->codec_id);//根据解码器id查找解码器/* Force thread count to 1 since the H.264 decoder will not extract* SPS and PPS to extradata during multi-threaded decoding. */av_dict_set(options ? &options[i] : &thread_opt, "threads", "1", 0);if (ic->codec_whitelist)av_dict_set(options ? &options[i] : &thread_opt, "codec_whitelist", ic->codec_whitelist, 0);/* Ensure that subtitle_header is properly set. */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__);}// Try to just open decoders, in case this is enough to get parameters.// 在某些场景下,只需打开解码器,就能获取到编码层的参数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__);}if (!options)av_dict_free(&thread_opt);}for (i = 0; i < ic->nb_streams; i++) {//-----【第二个循环】-------
#if FF_API_R_FRAME_RATEic->streams[i]->internal->info->last_dts = AV_NOPTS_VALUE;
#endific->streams[i]->internal->info->fps_first_dts = AV_NOPTS_VALUE;ic->streams[i]->internal->info->fps_last_dts  = AV_NOPTS_VALUE;}//  对 stream 中的数据进行 probe,读取一定的数据到内存中read_size = 0;for (;;) {//-------------------------【第三个循环】------------------const AVPacket *pkt;int analyzed_all_streams;//  ff_check_interrupt 检测是否有用户层进行中断请求,if (ff_check_interrupt(&ic->interrupt_callback)) {ret = AVERROR_EXIT;av_log(ic, AV_LOG_DEBUG, "interrupted\n");break;}/* 再次对所有的 streams 进行一次遍历,检查 stream 中 codec 信息是否完整,* 如果还有没解析出的,那么 break 跳出当前 stream 的遍历(此时还没有跳出 for(;;) 的大循环)* 在确认了 has_codec 之后,根据各种可能出现的情况设置好 fps_analyze_framecount;之后,还有一系列判断是否应该 break 遍历。*//* check if one codec still needs to be handled */for (i = 0; i < ic->nb_streams; i++) {//-----------【第三个循环的第一个嵌套循环】---------------int fps_analyze_framecount = 20;int count;st = ic->streams[i];/*** has_codec_parameters:此函数检查 codec 信息是否完整*/if (!has_codec_parameters(st, NULL))break;/* If the timebase is coarse (like the usual millisecond precision* of mkv), we need to analyze more frames to reliably arrive at* the correct fps. *///如果时基比较粗略(例如 mkv 通常的毫秒精度),我们需要分析更多帧才能可靠地获得正确的 fps,fps_analyze_framecount * 2if (av_q2d(st->time_base) > 0.0005)fps_analyze_framecount *= 2;if (!tb_unreliable(st->internal->avctx))//时间基不正常或不是 mpeg4/mpeg2/HEVC/AVC 影片,不需要分析,fps_analyze_framecount = 0fps_analyze_framecount = 0;if (ic->fps_probe_size >= 0)//设置了 fps_probe_size,则按 fps_probe_sizefps_analyze_framecount = ic->fps_probe_size;if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)//如果是音频文件附带的图片流或者是视频附带的信息流,就不需要估计帧率fps_analyze_framecount = 0;/* variable fps and no guess at the real fps */// 可变 fps 并且无法猜测真实 fpscount = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ?st->internal->info->codec_info_duration_fields/2 :st->internal->info->duration_count;//未找到帧率的视频帧,并且 count < fps_analyze_framecount,则退出循环去估算视频帧          if (!(st->r_frame_rate.num && st->avg_frame_rate.num) &&st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {if (count < fps_analyze_framecount)break;}// Look at the first 3 frames if there is evidence of frame delay// but the decoder delay is not set.//查看前 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))break;}analyzed_all_streams = 0;/* 如果循环能正常结束,说明流信息的探测完毕,此时 i == ic->nb_streams;* 如果中间 break 了,说明某个流的信息还没有完全得到,此时 i < ic->nb_streams, 需继续探测*/if (!missing_streams || !*missing_streams)if (i == ic->nb_streams) {// i == ic->nb_streams,说明所有的流都没问题了analyzed_all_streams = 1;/* NOTE: If the format has no header, then we need to read some* packets to get most of the streams, so we cannot stop here. */// 如果是像 MPEG 这种没有头的封装格式,需要解析更多的 packets; 否则 breakif (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) {/* If we found the info for all the codecs, we can stop. */ret = count;av_log(ic, AV_LOG_DEBUG, "All info found\n");flush_codecs = 0;break;}}// 下面属于继续探测的流程   /* We did not get all the codec info, but we read too much data. *///虽然流信息还没完全探测出来,但是 read_size >= probesize, 已读取到的大小超过了 probesize,则退出if (read_size >= probesize) {ret = count;av_log(ic, AV_LOG_DEBUG,"Probe buffer size limit of %"PRId64" bytes reached\n", probesize);for (i = 0; i < ic->nb_streams; i++)if (!ic->streams[i]->r_frame_rate.num &&ic->streams[i]->internal->info->duration_count <= 1 &&ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&strcmp(ic->iformat->name, "image2"))av_log(ic, AV_LOG_WARNING,"Stream #%d: not enough frames to estimate rate; ""consider increasing probesize\n", i);break;}/* NOTE: A new stream can be added there if no header in file* (AVFMTCTX_NOHEADER). */// 读取 packet ret = read_frame_internal(ic, &pkt1);if (ret == AVERROR(EAGAIN))continue;if (ret < 0) {/* EOF or error*/eof_reached = 1;break;}if (!(ic->flags & AVFMT_FLAG_NOBUFFER)) {ret = avpriv_packet_list_put(&ic->internal->packet_buffer,&ic->internal->packet_buffer_end,&pkt1, NULL, 0);if (ret < 0)goto unref_then_goto_end;pkt = &ic->internal->packet_buffer_end->pkt;} else {pkt = &pkt1;}st = ic->streams[pkt->stream_index];//更新 read_size, read_size 用于下一轮判断是否已经超过 probesizeif (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))read_size += pkt->size;avctx = st->internal->avctx;if (!st->internal->avctx_inited) {ret = avcodec_parameters_to_context(avctx, st->codecpar);if (ret < 0)goto unref_then_goto_end;st->internal->avctx_inited = 1;}if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) {/* check for non-increasing dts */if (st->internal->info->fps_last_dts != AV_NOPTS_VALUE &&st->internal->info->fps_last_dts >= pkt->dts) {av_log(ic, AV_LOG_DEBUG,"Non-increasing DTS in stream %d: packet %d with DTS ""%"PRId64", packet %d with DTS %"PRId64"\n",st->index, st->internal->info->fps_last_dts_idx,st->internal->info->fps_last_dts, st->codec_info_nb_frames,pkt->dts);st->internal->info->fps_first_dts =st->internal->info->fps_last_dts  = AV_NOPTS_VALUE;}/* Check for a discontinuity in dts. If the difference in dts* is more than 1000 times the average packet duration in the* sequence, we treat it as a discontinuity. */if (st->internal->info->fps_last_dts != AV_NOPTS_VALUE &&st->internal->info->fps_last_dts_idx > st->internal->info->fps_first_dts_idx &&(pkt->dts - (uint64_t)st->internal->info->fps_last_dts) / 1000 >(st->internal->info->fps_last_dts     - (uint64_t)st->internal->info->fps_first_dts) /(st->internal->info->fps_last_dts_idx - st->internal->info->fps_first_dts_idx)) {av_log(ic, AV_LOG_WARNING,"DTS discontinuity in stream %d: packet %d with DTS ""%"PRId64", packet %d with DTS %"PRId64"\n",st->index, st->internal->info->fps_last_dts_idx,st->internal->info->fps_last_dts, st->codec_info_nb_frames,pkt->dts);st->internal->info->fps_first_dts =st->internal->info->fps_last_dts  = AV_NOPTS_VALUE;}/* update stored dts values */if (st->internal->info->fps_first_dts == AV_NOPTS_VALUE) {st->internal->info->fps_first_dts     = pkt->dts;st->internal->info->fps_first_dts_idx = st->codec_info_nb_frames;}st->internal->info->fps_last_dts     = pkt->dts;st->internal->info->fps_last_dts_idx = st->codec_info_nb_frames;}if (st->codec_info_nb_frames>1) {int64_t t = 0;int64_t limit;//下面计算已经读取到的时间长度//codec_info_duration:已经读取到的 packet 的总时长if (st->time_base.den > 0)t = av_rescale_q(st->internal->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q);//t = 已经读取到的帧数/帧率    if (st->avg_frame_rate.num > 0)t = FFMAX(t, av_rescale_q(st->codec_info_nb_frames, av_inv_q(st->avg_frame_rate), AV_TIME_BASE_Q));//根据 fps_last_dts - fps_first_dts 来计算if (   t == 0&& st->codec_info_nb_frames>30&& st->internal->info->fps_first_dts != AV_NOPTS_VALUE&& st->internal->info->fps_last_dts  != AV_NOPTS_VALUE)t = FFMAX(t, av_rescale_q(st->internal->info->fps_last_dts - st->internal->info->fps_first_dts, st->time_base, AV_TIME_BASE_Q));// 如果所有流都探测完if (analyzed_all_streams)                                limit = max_analyze_duration;else if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) limit = max_subtitle_analyze_duration;else                                                     limit = max_stream_analyze_duration;// 当前读取到的 packet 总时长 >= limit,则 breakif (t >= limit) {av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds st:%d\n",limit,t, pkt->stream_index);if (ic->flags & AVFMT_FLAG_NOBUFFER)av_packet_unref(&pkt1);break;}// 更新已经读取到的 packet 的总时长if (pkt->duration) {if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE && pkt->pts != AV_NOPTS_VALUE && st->start_time != AV_NOPTS_VALUE && pkt->pts >= st->start_time) {st->internal->info->codec_info_duration = FFMIN(pkt->pts - st->start_time, st->internal->info->codec_info_duration + pkt->duration);} elsest->internal->info->codec_info_duration += pkt->duration;st->internal->info->codec_info_duration_fields += st->parser && st->need_parsing && avctx->ticks_per_frame ==2 ? st->parser->repeat_pict + 1 : 2;}}if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
#if FF_API_R_FRAME_RATEff_rfps_add_frame(ic, st, pkt->dts);
#endifif (pkt->dts != pkt->pts && pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE)st->internal->info->frame_delay_evidence = 1;}if (!st->internal->avctx->extradata) {ret = extract_extradata(st, pkt);if (ret < 0)goto unref_then_goto_end;}/* If still no information, we try to open the codec and to* decompress the frame. We try to avoid that in most cases as* it takes longer and uses more memory. For MPEG-4, we need to* decompress for QuickTime.** If AV_CODEC_CAP_CHANNEL_CONF is set this will force decoding of at* least one frame of codec data, this makes sure the codec initializes* the channel configuration and does not only trust the values from* the container. */// 在某些场景下,打开解码器还获取不到编码层参数,就需要尝试解码,通过解码来获取到流的解码器信息try_decode_frame(ic, st, pkt,(options && i < orig_nb_streams) ? &options[i] : NULL);if (ic->flags & AVFMT_FLAG_NOBUFFER)av_packet_unref(&pkt1);//已经探测的帧数 + 1,count 总数 + 1st->codec_info_nb_frames++;count++;}// 是否已经到达文件尾部if (eof_reached) {int stream_index;// 再遍历一次流,检查编码器参数,如果参数完整会再次调用 avcodec_open2for (stream_index = 0; stream_index < ic->nb_streams; stream_index++) {st = ic->streams[stream_index];avctx = st->internal->avctx;if (!has_codec_parameters(st, NULL)) {const AVCodec *codec = find_probe_decoder(ic, st, st->codecpar->codec_id);if (codec && !avctx->codec) {AVDictionary *opts = NULL;if (ic->codec_whitelist)av_dict_set(&opts, "codec_whitelist", ic->codec_whitelist, 0);if (avcodec_open2(avctx, codec, (options && stream_index < orig_nb_streams) ? &options[stream_index] : &opts) < 0)av_log(ic, AV_LOG_WARNING,"Failed to open codec in %s\n",__FUNCTION__);av_dict_free(&opts);}}// EOF already reached while reading the stream above.// So continue with reoordering DTS with whatever delay we have.if (ic->internal->packet_buffer && !has_decode_delay_been_guessed(st)) {update_dts_from_pts(ic, stream_index, ic->internal->packet_buffer);}}}/* * 刷新解码器* 有一些帧可能在缓存区,需要 flush*/if (flush_codecs) {AVPacket empty_pkt = { 0 };int err = 0;av_init_packet(&empty_pkt);for (i = 0; i < ic->nb_streams; i++) {//------【第四个循环】-------st = ic->streams[i];/* flush the decoders */if (st->internal->info->found_decoder == 1) {do {err = try_decode_frame(ic, st, &empty_pkt,(options && i < orig_nb_streams)? &options[i] : NULL);} while (err > 0 && !has_codec_parameters(st, NULL));if (err < 0) {av_log(ic, AV_LOG_INFO,"decoding for stream %d failed\n", st->index);}}}}ff_rfps_calculate(ic);for (i = 0; i < ic->nb_streams; i++) {st = ic->streams[i];avctx = st->internal->avctx;if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {if (avctx->codec_id == AV_CODEC_ID_RAWVIDEO && !avctx->codec_tag && !avctx->bits_per_coded_sample) {uint32_t tag= avcodec_pix_fmt_to_codec_tag(avctx->pix_fmt);if (avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), tag) == avctx->pix_fmt)avctx->codec_tag= tag;}/* estimate average framerate if not set by demuxer */if (st->internal->info->codec_info_duration_fields &&!st->avg_frame_rate.num &&st->internal->info->codec_info_duration) {int best_fps      = 0;double best_error = 0.01;AVRational codec_frame_rate = avctx->framerate;if (st->internal->info->codec_info_duration        >= INT64_MAX / st->time_base.num / 2||st->internal->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den ||st->internal->info->codec_info_duration        < 0)continue;av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,st->internal->info->codec_info_duration_fields * (int64_t) st->time_base.den,st->internal->info->codec_info_duration * 2 * (int64_t) st->time_base.num, 60000);/* Round guessed framerate to a "standard" framerate if it's* within 1% of the original estimate. */for (j = 0; j < MAX_STD_TIMEBASES; j++) {AVRational std_fps = { get_std_framerate(j), 12 * 1001 };double error       = fabs(av_q2d(st->avg_frame_rate) /av_q2d(std_fps) - 1);if (error < best_error) {best_error = error;best_fps   = std_fps.num;}if (ic->internal->prefer_codec_framerate && codec_frame_rate.num > 0 && codec_frame_rate.den > 0) {error       = fabs(av_q2d(codec_frame_rate) /av_q2d(std_fps) - 1);if (error < best_error) {best_error = error;best_fps   = std_fps.num;}}}if (best_fps)av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,best_fps, 12 * 1001, INT_MAX);}if (!st->r_frame_rate.num) {if (    avctx->time_base.den * (int64_t) st->time_base.num<= avctx->time_base.num * avctx->ticks_per_frame * (uint64_t) st->time_base.den) {av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den,avctx->time_base.den, (int64_t)avctx->time_base.num * avctx->ticks_per_frame, INT_MAX);} else {st->r_frame_rate.num = st->time_base.den;st->r_frame_rate.den = st->time_base.num;}}if (st->internal->display_aspect_ratio.num && st->internal->display_aspect_ratio.den) {AVRational hw_ratio = { avctx->height, avctx->width };st->sample_aspect_ratio = av_mul_q(st->internal->display_aspect_ratio,hw_ratio);}} else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {// 对于音频流,基于音频流服务类型初始化 dispositionif (!avctx->bits_per_coded_sample)avctx->bits_per_coded_sample =av_get_bits_per_sample(avctx->codec_id);// set stream disposition based on audio service typeswitch (avctx->audio_service_type) {case AV_AUDIO_SERVICE_TYPE_EFFECTS:st->disposition = AV_DISPOSITION_CLEAN_EFFECTS;break;case AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED:st->disposition = AV_DISPOSITION_VISUAL_IMPAIRED;break;case AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED:st->disposition = AV_DISPOSITION_HEARING_IMPAIRED;break;case AV_AUDIO_SERVICE_TYPE_COMMENTARY:st->disposition = AV_DISPOSITION_COMMENT;break;case AV_AUDIO_SERVICE_TYPE_KARAOKE:st->disposition = AV_DISPOSITION_KARAOKE;break;}}}// 计算时间相关参数if (probesize)estimate_timings(ic, old_offset);av_opt_set(ic, "skip_clear", "0", AV_OPT_SEARCH_CHILDREN);if (ret >= 0 && ic->nb_streams)/* We could not have all the codec parameters before EOF. */ret = -1;for (i = 0; i < ic->nb_streams; i++) {const char *errmsg;st = ic->streams[i];/* if no packet was ever seen, update context now for has_codec_parameters */if (!st->internal->avctx_inited) {if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&st->codecpar->format == AV_SAMPLE_FMT_NONE)st->codecpar->format = st->internal->avctx->sample_fmt;ret = avcodec_parameters_to_context(st->internal->avctx, st->codecpar);if (ret < 0)goto find_stream_info_err;}if (!has_codec_parameters(st, &errmsg)) {char buf[256];avcodec_string(buf, sizeof(buf), st->internal->avctx, 0);av_log(ic, AV_LOG_WARNING,"Could not find codec parameters for stream %d (%s): %s\n""Consider increasing the value for the 'analyzeduration' (%"PRId64") and 'probesize' (%"PRId64") options\n",i, buf, errmsg, ic->max_analyze_duration, ic->probesize);} else {ret = 0;}}ret = compute_chapters_end(ic);if (ret < 0)goto find_stream_info_err;// 更新 stream 各个结构的数据/* update the stream parameters from the internal codec contexts */for (i = 0; i < ic->nb_streams; i++) {st = ic->streams[i];if (st->internal->avctx_inited) {int orig_w = st->codecpar->width;int orig_h = st->codecpar->height;ret = avcodec_parameters_from_context(st->codecpar, st->internal->avctx);if (ret < 0)goto find_stream_info_err;ret = add_coded_side_data(st, st->internal->avctx);if (ret < 0)goto find_stream_info_err;
#if FF_API_LOWRES// The decoder might reduce the video size by the lowres factor.if (st->internal->avctx->lowres && orig_w) {st->codecpar->width = orig_w;st->codecpar->height = orig_h;}
#endif}#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGSret = avcodec_parameters_to_context(st->codec, st->codecpar);if (ret < 0)goto find_stream_info_err;#if FF_API_LOWRES// The old API (AVStream.codec) "requires" the resolution to be adjusted// by the lowres factor.if (st->internal->avctx->lowres && st->internal->avctx->width) {st->codec->lowres = st->internal->avctx->lowres;st->codec->width = st->internal->avctx->width;st->codec->height = st->internal->avctx->height;}
#endifif (st->codec->codec_tag != MKTAG('t','m','c','d')) {st->codec->time_base = st->internal->avctx->time_base;st->codec->ticks_per_frame = st->internal->avctx->ticks_per_frame;}st->codec->framerate = st->avg_frame_rate;if (st->internal->avctx->subtitle_header) {st->codec->subtitle_header = av_malloc(st->internal->avctx->subtitle_header_size);if (!st->codec->subtitle_header)goto find_stream_info_err;st->codec->subtitle_header_size = st->internal->avctx->subtitle_header_size;memcpy(st->codec->subtitle_header, st->internal->avctx->subtitle_header,st->codec->subtitle_header_size);}// Fields unavailable in AVCodecParametersst->codec->coded_width = st->internal->avctx->coded_width;st->codec->coded_height = st->internal->avctx->coded_height;st->codec->properties = st->internal->avctx->properties;
FF_ENABLE_DEPRECATION_WARNINGS
#endifst->internal->avctx_inited = 0;}find_stream_info_err:for (i = 0; i < ic->nb_streams; i++) {st = ic->streams[i];if (st->internal->info)av_freep(&st->internal->info->duration_error);avcodec_close(ic->streams[i]->internal->avctx);av_freep(&ic->streams[i]->internal->info);av_bsf_free(&ic->streams[i]->internal->extract_extradata.bsf);av_packet_free(&ic->streams[i]->internal->extract_extradata.pkt);}if (ic->pb)av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n",avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count, count);return ret;unref_then_goto_end:av_packet_unref(&pkt1);goto find_stream_info_err;
}
// 检查当前的音视频流信息是否完整
static int has_codec_parameters(AVStream *st, const char **errmsg_ptr)
{AVCodecContext *avctx = st->internal->avctx;#define FAIL(errmsg) do {                                         \if (errmsg_ptr)                                           \*errmsg_ptr = errmsg;                                 \return 0;                                                 \} while (0)if (   avctx->codec_id == AV_CODEC_ID_NONE&& avctx->codec_type != AVMEDIA_TYPE_DATA)FAIL("unknown codec");switch (avctx->codec_type) {case AVMEDIA_TYPE_AUDIO://音频的需要检测frame_size、sample_fmt、sample_rate、channels等if (!avctx->frame_size && determinable_frame_size(avctx))FAIL("unspecified frame size");if (st->internal->info->found_decoder >= 0 &&avctx->sample_fmt == AV_SAMPLE_FMT_NONE)FAIL("unspecified sample format");if (!avctx->sample_rate)FAIL("unspecified sample rate");if (!avctx->channels)FAIL("unspecified number of channels");if (st->internal->info->found_decoder >= 0 && !st->internal->nb_decoded_frames && avctx->codec_id == AV_CODEC_ID_DTS)FAIL("no decodable DTS frames");break;case AVMEDIA_TYPE_VIDEO://视频的需要检测width、pix_fmt、sample_aspect_ratio等if (!avctx->width)FAIL("unspecified size");if (st->internal->info->found_decoder >= 0 && avctx->pix_fmt == AV_PIX_FMT_NONE)FAIL("unspecified pixel format");if (st->codecpar->codec_id == AV_CODEC_ID_RV30 || st->codecpar->codec_id == AV_CODEC_ID_RV40)if (!st->sample_aspect_ratio.num && !st->codecpar->sample_aspect_ratio.num && !st->codec_info_nb_frames)FAIL("no frame in rv30/40 and no sar");break;case AVMEDIA_TYPE_SUBTITLE:if (avctx->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && !avctx->width)FAIL("unspecified size");break;case AVMEDIA_TYPE_DATA:if (avctx->codec_id == AV_CODEC_ID_NONE) return 1;}return 1;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/488642.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于Kinect 互动沙盘 深度图 Shader Graph 分层

把Kinect的深度图穿给Shader Graph using com.rfilkov.kinect; using UnityEngine; using UnityEngine.UI; public class GetDepthTex : MonoBehaviour { public Material Mat_SandTable; void Update() { Mat_SandTable.SetTexture("_MainTex"…

MongoDB实战 – 用Python访问MongoDB数据库

MongoDB实战 – 用Python访问MongoDB数据库 MongoDB in Action – Access MongoDB Databases with Python By JacksonML Python语言功能强大众所周知&#xff0c;在数据库管理领域也无所不能。MongoDB是文档数据库&#xff0c;属于NoSQL数据库的一种&#xff0c;在业界也非常…

javaEE图书馆自习室订座系统信用springmvc+springboot+mybatis

研究的内容是设计和实现图书馆自习室系统&#xff0c;便捷广大师生对自习室的使用&#xff0c;协助图书馆自习室管理。在设计过程中&#xff0c;系统的用户角色和权限分配如下&#xff1a; &#xff08;1&#xff09;馆长 用户管理&#xff1a;拥有自习室管理员、普通用户的所有…

LiveQing视频点播流媒体RTMP推流服务功能-支持配置开启 HTTPS 服务什么时候需要开启HTTPS服务

LiveQing视频点播流媒体RTMP推流服务功能支持配置开启 HTTPS 服务什么时候需要开启HTTPS服务 1、配置开启HTTPS1.1、准备https证书1.1.1、选择Nginx类型证书下载 1.2、配置 开启 HTTPS1.2.1 web页面配置1.2.2 配置文件配置 2、验证HTTPS服务3、为什么要开启HTTPS3.1、安全性要求…

访问raw.githubusercontent.com失败问题的处理

1 问题 GitHub上的项目的有些资源是放在raw.githubusercontent.com上的&#xff0c;通常我们在安装某些软件的时候会从该地址下载资源&#xff0c;直接访问的话经常容易失败。 # 安装operator kubectl apply -f https://raw.githubusercontent.com/oceanbase/ob-operator/2.1…

Element Plus 的下拉选择器el-option的字体全部蓝色,全部是选中状态

问题 原因 参考官方&#xff1a; Select 选择器 | Element Plus 解决方案1&#xff1a; 给外层el-select增加一个value-key指定值: value-key"ID" <el-select value-key"ID"ref"productName"v-model"selectedProduct.GOODS_DESC"…

uni-app 经验分享,从入门到离职(五)——由浅入深 uni-app 数据缓存

文章目录 &#x1f4cb;前言⏬关于专栏 &#x1f3af;什么是数据存储&#x1f9e9;数据存储——存储&#x1f4cc; uni.setStorage(OBJECT)&#x1f4cc; uni.setStorageSync(KEY,DATA) &#x1f9e9;数据存储——获取&#x1f4cc; uni.getStorage(OBJECT)&#x1f4cc; uni.g…

​​​​​​​Sora:OpenAI的革命性AI视频模型与其对未来影像创作的影响

随着深度学习技术和计算能力的进步&#xff0c;人工智能不仅在图像识别、自然语言处理等领域取得了卓越成就&#xff0c;同时也在不断突破视频处理和生成的边界。在这一背景下&#xff0c;OpenAI推出了Sora——一种新型的AI视频模型&#xff0c;标志着AI在视频内容创作领域的又…

Web 前端 UI 框架Bootstrap简介与基本使用

Bootstrap 是一个流行的前端 UI 框架&#xff0c;用于快速开发响应式和移动设备优先的网页。它由 Twitter 的设计师和工程师开发&#xff0c;现在由一群志愿者维护。Bootstrap 提供了一套丰富的 HTML、CSS 和 JavaScript 组件&#xff0c;可以帮助开发者轻松地构建和定制网页和…

重看LeakCanary

LeakCanary是我很久之前看的东西了&#xff0c;我当时侯对它的印象就是它可以用来检测内存泄漏&#xff0c;具体原理就是将弱引用对象延迟个5s然后看是否被回收,如果没有被回收,那么就说明发生了内存泄漏,其他的也没有仔细地看 现在就详细地梳理一遍这个流程&#xff1a; 1.L…

运维的利器–监控–zabbix–第二步:建设–部署zabbix agent--windows server系统

文章目录 在windows server 2016安装zabbix agent第一步&#xff1a;下载windows安装agent软件第二步&#xff1a;解压到指定目录第三步&#xff1a;配置zabbix-agent.win.conf第四步&#xff1a;zabbix-agent安装第五步&#xff1a;启动zabbix-agent客户端第六步&#xff1a;确…

一招解决 vue数据格式校验时候 async-validator: [‘XXXX is not a number‘]

在vue中 amt数字需要进行纯数字校验&#xff1a; 格式都没问题&#xff0c;但是输入纯数字也会报错&#xff0c;报错如下&#xff1a; async-validator:[‘amt is not a number’] 网上找了一些&#xff0c;但是均为能奏效&#xff0c;尝试如下&#xff1a; 尝试1&#x…