diff --git a/ffmpeg.c b/ffmpeg.c index b29d8350a8..8519159bd5 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -600,6 +600,7 @@ static int ffmpeg_exit(int ret) for(j=0;jnb_streams;j++) { av_metadata_free(&s->streams[j]->metadata); av_free(s->streams[j]->codec); + av_free(s->streams[j]->info); av_free(s->streams[j]); } for(j=0;jnb_programs;j++) { diff --git a/libavformat/avformat.h b/libavformat/avformat.h index b08f758d0f..a5c745bb78 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -617,6 +617,18 @@ typedef struct AVStream { * Number of frames that have been demuxed during av_find_stream_info() */ int codec_info_nb_frames; + + /** + * Stream informations used internally by av_find_stream_info() + */ +#define MAX_STD_TIMEBASES (60*12+5) + struct { + int64_t last_dts; + int64_t duration_gcd; + int duration_count; + double duration_error[MAX_STD_TIMEBASES]; + int64_t codec_info_duration; + } *info; } AVStream; #define AV_PROGRAM_RUNNING 1 diff --git a/libavformat/utils.c b/libavformat/utils.c index 9f6b1509e0..8a08557890 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -489,6 +489,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, av_free(st->priv_data); av_free(st->codec->extradata); av_free(st->codec); + av_free(st->info); } av_free(st); } @@ -2138,7 +2139,6 @@ static void compute_chapters_end(AVFormatContext *s) } } -#define MAX_STD_TIMEBASES (60*12+5) static int get_std_framerate(int i){ if(i<60*12) return i*1001; else return ((const int[]){24,30,60,12,15})[i-60*12]*1000*12; @@ -2170,18 +2170,6 @@ int av_find_stream_info(AVFormatContext *ic) AVStream *st; AVPacket pkt1, *pkt; int64_t old_offset = url_ftell(ic->pb); - unsigned int nb_streams = ic->nb_streams; - struct { - int64_t last_dts; - int64_t duration_gcd; - int duration_count; - double duration_error[MAX_STD_TIMEBASES]; - int64_t codec_info_duration; - } *info, *tmp_info; - - if (ic->nb_streams >= INT_MAX/sizeof(*info) || - !(info = av_mallocz(ic->nb_streams * sizeof(*info)))) - return AVERROR(ENOMEM); for(i=0;inb_streams;i++) { AVCodec *codec; @@ -2222,7 +2210,7 @@ int av_find_stream_info(AVFormatContext *ic) } for (i=0; inb_streams; i++) { - info[i].last_dts= AV_NOPTS_VALUE; + ic->streams[i]->info->last_dts = AV_NOPTS_VALUE; } count = 0; @@ -2241,7 +2229,7 @@ int av_find_stream_info(AVFormatContext *ic) break; /* variable fps and no guess at the real fps */ if( tb_unreliable(st->codec) && !(st->r_frame_rate.num && st->avg_frame_rate.num) - && info[i].duration_count<20 && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + && st->info->duration_count<20 && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) break; if(st->parser && st->parser->parser->split && !st->codec->extradata) break; @@ -2285,39 +2273,25 @@ int av_find_stream_info(AVFormatContext *ic) break; } - if (ic->nb_streams > nb_streams) { - if (ic->nb_streams >= INT_MAX/sizeof(*info) || - !(tmp_info = av_realloc(info, ic->nb_streams*sizeof(*info)))) { - av_free(info); - return AVERROR(ENOMEM); - } - info = tmp_info; - memset(info + nb_streams, 0, (ic->nb_streams - nb_streams) * sizeof(*info)); - nb_streams = ic->nb_streams; - } - if (ret == AVERROR(EAGAIN)) continue; pkt= add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end); - if(av_dup_packet(pkt) < 0) { - av_free(info); - return AVERROR(ENOMEM); - } + if ((ret = av_dup_packet(pkt)) < 0) + goto find_stream_info_err; read_size += pkt->size; st = ic->streams[pkt->stream_index]; - if(st->codec_info_nb_frames>1) { - if (st->time_base.den > 0 && av_rescale_q(info[st->index].codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration){ + if (st->codec_info_nb_frames>1) { + if (st->time_base.den > 0 && av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) { av_log(ic, AV_LOG_WARNING, "max_analyze_duration reached\n"); break; } - info[st->index].codec_info_duration += pkt->duration; + st->info->codec_info_duration += pkt->duration; } { - int index= pkt->stream_index; - int64_t last= info[index].last_dts; + int64_t last = st->info->last_dts; int64_t duration= pkt->dts - last; if(pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && duration>0){ @@ -2325,21 +2299,21 @@ int av_find_stream_info(AVFormatContext *ic) // if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) // av_log(NULL, AV_LOG_ERROR, "%f\n", dur); - if(info[index].duration_count < 2) - memset(info[index].duration_error, 0, sizeof(info[index].duration_error)); - for(i=1; iinfo->duration_count < 2) + memset(st->info->duration_error, 0, sizeof(st->info->duration_error)); + for (i=1; iinfo->duration_error); i++) { int framerate= get_std_framerate(i); int ticks= lrintf(dur*framerate/(1001*12)); double error= dur - ticks*1001*12/(double)framerate; - info[index].duration_error[i] += error*error; + st->info->duration_error[i] += error*error; } - info[index].duration_count++; + st->info->duration_count++; // ignore the first 4 values, they might have some random jitter - if (info[index].duration_count > 3) - info[index].duration_gcd = av_gcd(info[index].duration_gcd, duration); + if (st->info->duration_count > 3) + st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration); } - if(last == AV_NOPTS_VALUE || info[index].duration_count <= 1) - info[pkt->stream_index].last_dts = pkt->dts; + if (last == AV_NOPTS_VALUE || st->info->duration_count <= 1) + st->info->last_dts = pkt->dts; } if(st->parser && st->parser->parser->split && !st->codec->extradata){ int i= st->parser->parser->split(st->codec, pkt->data, pkt->size); @@ -2370,10 +2344,10 @@ int av_find_stream_info(AVFormatContext *ic) } for(i=0;inb_streams;i++) { st = ic->streams[i]; - if(st->codec_info_nb_frames>2 && !st->avg_frame_rate.num && info[i].codec_info_duration) + if (st->codec_info_nb_frames>2 && !st->avg_frame_rate.num && st->info->codec_info_duration) av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, (st->codec_info_nb_frames-2)*(int64_t)st->time_base.den, - info[i].codec_info_duration*(int64_t)st->time_base.num, 60000); + st->info->codec_info_duration*(int64_t)st->time_base.num, 60000); if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); @@ -2381,18 +2355,18 @@ int av_find_stream_info(AVFormatContext *ic) // the check for tb_unreliable() is not completely correct, since this is not about handling // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g. // ipmovie.c produces. - if (tb_unreliable(st->codec) && info[i].duration_count > 15 && info[i].duration_gcd > 1 && !st->r_frame_rate.num) - av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * info[i].duration_gcd, INT_MAX); - if(info[i].duration_count && !st->r_frame_rate.num + if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > 1 && !st->r_frame_rate.num) + av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX); + if (st->info->duration_count && !st->r_frame_rate.num && tb_unreliable(st->codec) /*&& //FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ... - st->time_base.num*duration_sum[i]/info[i].duration_count*101LL > st->time_base.den*/){ + st->time_base.num*duration_sum[i]/st->info->duration_count*101LL > st->time_base.den*/){ int num = 0; double best_error= 2*av_q2d(st->time_base); - best_error= best_error*best_error*info[i].duration_count*1000*12*30; + best_error = best_error*best_error*st->info->duration_count*1000*12*30; - for(j=1; jinfo->duration_error); j++) { + double error = st->info->duration_error[j] * get_std_framerate(j); // if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) // av_log(NULL, AV_LOG_ERROR, "%f %f\n", get_std_framerate(j) / 12.0/1001, error); if(error < best_error){ @@ -2450,7 +2424,9 @@ int av_find_stream_info(AVFormatContext *ic) } #endif - av_free(info); + find_stream_info_err: + for (i=0; i < ic->nb_streams; i++) + av_freep(&ic->streams[i]->info); return ret; } @@ -2496,6 +2472,7 @@ void av_close_input_stream(AVFormatContext *s) av_free(st->filename); #endif av_free(st->priv_data); + av_free(st->info); av_free(st); } for(i=s->nb_programs-1; i>=0; i--) { @@ -2555,6 +2532,10 @@ AVStream *av_new_stream(AVFormatContext *s, int id) st = av_mallocz(sizeof(AVStream)); if (!st) return NULL; + if (!(st->info = av_mallocz(sizeof(*st->info)))) { + av_free(st); + return NULL; + } st->codec= avcodec_alloc_context(); if (s->iformat) {