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://xiahunao.cn/news/2804798.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode206: 反转链表.

题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 解题方法 假设链表为 1→2→3→∅&#xff0c;我们想要把它改成∅←1←2←3。在遍历链表时&#xff0c;将当前节点的 next指针改为指向前一个节点。由于节点没有引用其前一…

挑战杯 基于大数据的时间序列股价预测分析与可视化 - lstm

文章目录 1 前言2 时间序列的由来2.1 四种模型的名称&#xff1a; 3 数据预览4 理论公式4.1 协方差4.2 相关系数4.3 scikit-learn计算相关性 5 金融数据的时序分析5.1 数据概况5.2 序列变化情况计算 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &…

电表(2)stm32学习笔记-STLINK使用

stm32学习笔记-STLINK使用 使用ST-LINK调试程序进度表格 使用ST-LINK调试程序 说明 组成 总结 记录使用STLINK进行项目的烧写和调试&#xff0c;旨在高效的进行代码调试学习工具包括笔记本、keil5MDK、stm32f030c8t6电表主机、STLINK V2、导线、电表代码总的来说&#xff0…

yolov8-seg dnn调用

接上篇一直更换torch、opencv版本都无法解决这个问题&#xff08;seg调用dnn报错&#xff09;。那问题会不会出在yolov8源码本身呢。yolov8的讨论区基本都看过了&#xff0c;我决定尝试在其前身yolov5的讨论区上找找我不信没人遇到这个问题。很快找到下面的讨论第一个帖子&…

Project_Euler-03 题解

Project_Euler-03 题解 题目 思路 首先排除掉暴力求解&#xff0c;虽然也可以得出答案&#xff0c;但是我在我仅仅只有二颗核心的服务器上跑了很久很久… 尝试另一种方法&#xff1a; 首先要知道一个知识&#xff0c;所有的数都可以拆解成为素数因子平方连乘的形式&#xff…

Spring Boot与HikariCP:性能卓越的数据库连接池

点击下载《Spring Boot与HikariCP&#xff1a;性能卓越的数据库连接池》 1. 前言 本文将详细介绍Spring Boot中如何使用HikariCP作为数据库连接池&#xff0c;包括其工作原理、优势分析、配置步骤以及代码示例。通过本文&#xff0c;读者将能够轻松集成HikariCP到Spring Boot…

PCIe P2P DMA全景解读

温馨提醒&#xff1a;本文主要分为5个部分&#xff0c;总计4842字&#xff0c;需要时间较长&#xff0c;建议先收藏&#xff01; P2P DMA简介 P2P DMA软硬件支持 CXL P2P DMA原理差异 P2P DMA应用场景 P2P DMA技术挑战 一、P2P DMA简介 P2P DMA&#xff08;Peer-to-Peer…

解决ubuntu系统cannot find -lc++abi: No such file or directory

随着CentOS的没落&#xff0c;使用ubuntu的越来越多&#xff0c;而且国外貌似也比较流行使用ubuntu&#xff0c;像LLVM/Clang就有专门针对ubuntu编译二进制发布文件&#xff1a; ubuntu本身也可以直接通过apt install命令来安装编译好的clang编译器。不过目前22.04版本下最高…

SpringMVC 学习(二)之第一个 SpringMVC 案例

目录 1 通过 Maven 创建一个 JavaWeb 工程 2 配置 web.xml 文件 3 创建 SpringMVC 配置文件 spring-mvc.xml 4 创建控制器 HelloController 5 创建视图 index.jsp 和 success.jsp 6 运行过程 7 参考文档 1 通过 Maven 创建一个 JavaWeb 工程 可以参考以下博文&#x…

java——File类和字符集

目录 File类File类的常用操作&#xff1a;案例&#xff1a;文件搜索的实现案例&#xff1a;递归文件夹删除 字符集几种常见的字符集总结字符集的编码和解码 File类 File是java.io.包下的类&#xff0c;File类的对象&#xff0c;用于代表当前操作系统的文件&#xff08;可以是文…

成功解决TypeError: can‘t multiply sequence by non-int of type ‘float‘

&#x1f525; 成功解决TypeError: can’t multiply sequence by non-int of type ‘float’ &#x1f4c5; 日期&#xff1a;2024年2月23日 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化…

大数据-数据可视化-环境部署vue+echarts+显示案例

文章目录 一、安装node.js1 打开火狐浏览器,下载Node.js2 进行解压3 配置环境变量4 配置生效二、安装vue脚手架1 下载vue脚手架,耐心等待。三、创建vue项目并启动1 创建2 启动四、下载echarts.js与axios.js到本地。五、图表显示demo【以下所有操作均在centos上进行】 一、安…

【高德地图】Android高德地图控件交互详细介绍

&#x1f4d6;第5章 与地图控件交互 ✅控件交互&#x1f9ca;缩放按钮&#x1f9ca;指南针&#x1f9ca;定位按钮&#x1f9ca;地图Logo ✅手势交互&#x1f9ca;缩放手势&#x1f9ca;滑动手势&#x1f9ca;旋转手势&#x1f9ca;倾斜手势&#x1f9ca;指定屏幕中心点的手势操…

啊丢的刷题记录手册

1.洛谷题P1923 求第k小的数 题目描述 输入 n&#xff08;1≤n<5000000 且 n 为奇数&#xff09;个数字ai​&#xff08;1≤ai​<109&#xff09;&#xff0c;输出这些数字的第 k 小的数。最小的数是第 0 小。 请尽量不要使用 nth_element 来写本题&#xff0c;因为本题…

Spring及工厂模式概述

文章目录 Spring 身世什么是 Spring什么是设计模式工厂设计模式什么是工厂设计模式简单的工厂设计模式通用的工厂设计 总结 在 Spring 框架出现之前&#xff0c;Java 开发者使用的主要是传统的 Java EE&#xff08;Java Enterprise Edition&#xff09;平台。Java EE 是一套用于…

JavaWeb——004Maven SpringBootWeb入门

一、Maven 1、什么是maven&#xff1f; 2、Maven的作用是什么&#xff1f;&#xff08;3种&#xff09; 1.1、方便的依赖管理 依赖管理&#xff1a;有了Maven&#xff0c;我们就不用再手动导入Jar包了&#xff0c;我们只需要在配置文件当中&#xff0c;简单描述一下项目所需要…

windows11本地深度学习环境搭建Anacond,keras,tensorflow,pytorch, jupyter notebook

前言 工欲善其事&#xff0c;必先利其器。 第一步 安装Anaconda 下载地址&#xff1a; https://www.anaconda.com/download 路径默认 这里都勾选上 然后会卡在这里&#xff0c;卡很久&#xff0c;不用管&#xff0c;等着就行 第二步 配置环境 conda env list 列出所有…

fpga_直方图均衡

直方图均衡是一种用于图像增强和对比度调整的图像处理技术。它通过重新分配图像中像素的灰度级分布&#xff0c;使得图像的直方图变得更加均衡&#xff0c;从而增强图像的视觉效果。 一 直方图 直方图源于柱状图 二 数字图像与灰度直方图 如图所示&#xff0c;灰度直方图是读…

详解AP3216C(三合一sensor: 光照、距离、照射强度)驱动开发

目录 概述 1 认识AP3216C 1.1 AP3216C特性 1.2 AP3216C内部结构 1.3 AP3216C 硬件电路 1.4 AP3216C工作时序 1.4.1 I2C 写数据协议 1.4.2 I2C 读数据协议 1.5 重要的寄存器 1.5.1 系统配置寄存器 1.5.2 和中断相关寄存器 1.5.3 IR数据寄存器 1.5.4 ALS 数据寄存器 …

HTML+CSS:动态搜索框

效果演示 这段代码实现了一个简单的搜索栏效果。页面背景为从天蓝色到深蓝色的渐变色&#xff0c;搜索栏包括一个圆形背景的搜索图标和一个输入框。当用户点击搜索图标时&#xff0c;输入框会从搜索图标的位置滑出&#xff0c;显示一个输入框和一个清除按钮。用户可以在输入框中…