[FFmpeg-devel] [PATCH] lavf: accept time base from untrusted codecs if it matches timings
Anssi Hannula
anssi.hannula
Sun Feb 6 07:32:54 CET 2011
If the first 4 frames contain timestamps that closely match the codec
time base, accept the codec time base in tb_unreliable() even if the
codec is blacklisted (currently MPEG-2 and H.264).
---
Anssi Hannula wrote:
> Here's a new patch that checks the timestamps of the first 4 frames
> (using the same method which is used in the guess-framerate code) and
> uses codec time base for r_frame_rate if the timestamps fit to it.
>
> I tested also with several other files, including H.264 PAFF, MVE
> (ipmovie.c), and spotted no regressions.
>
> What do you think?
Ping. Also, I noticed an extra added newline in the patch, now removed.
libavformat/avformat.h | 2 ++
libavformat/utils.c | 37 ++++++++++++++++++++++++++-----------
2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 83289e4..cf3b8fd 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -627,6 +627,8 @@ typedef struct AVStream {
int64_t last_dts;
int64_t duration_gcd;
int duration_count;
+ int codec_tb_matches_dts;
+ double codec_tb_dur_error;
double duration_error[MAX_STD_TIMEBASES];
int64_t codec_info_duration;
} *info;
diff --git a/libavformat/utils.c b/libavformat/utils.c
index d12bbc2..b044f4d 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -2189,15 +2189,20 @@ static int get_std_framerate(int i){
* MPEG-2 commonly misuses field repeat flags to store different framerates.
* And there are "variable" fps files this needs to detect as well.
*/
-static int tb_unreliable(AVCodecContext *c){
- if( c->time_base.den >= 101L*c->time_base.num
- || c->time_base.den < 5L*c->time_base.num
-/* || c->codec_tag == AV_RL32("DIVX")
- || c->codec_tag == AV_RL32("XVID")*/
- || c->codec_id == CODEC_ID_MPEG2VIDEO
- || c->codec_id == CODEC_ID_H264
- )
+static int tb_unreliable(AVStream *st){
+ if( st->codec->time_base.den >= 101L*st->codec->time_base.num
+ || st->codec->time_base.den < 5L*st->codec->time_base.num)
return 1;
+
+ if(st->info->codec_tb_matches_dts)
+ return 0;
+
+ if(/* st->codec->codec_tag == AV_RL32("DIVX")
+ || st->codec->codec_tag == AV_RL32("XVID") ||*/
+ st->codec->codec_id == CODEC_ID_MPEG2VIDEO
+ || st->codec->codec_id == CODEC_ID_H264)
+ return 1;
+
return 0;
}
@@ -2271,7 +2276,7 @@ int av_find_stream_info(AVFormatContext *ic)
if (!has_codec_parameters(st->codec))
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)
+ if( tb_unreliable(st) && !(st->r_frame_rate.num && st->avg_frame_rate.num)
&& st->info->duration_count<20 && st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
break;
if(st->parser && st->parser->parser->split && !st->codec->extradata)
@@ -2351,6 +2356,16 @@ int av_find_stream_info(AVFormatContext *ic)
st->info->duration_error[i] += error*error;
}
st->info->duration_count++;
+
+ if (st->info->duration_count <= 4) {
+ double codec_tb_rate = st->codec->time_base.den / (double)st->codec->time_base.num * st->codec->ticks_per_frame;
+ double error = dur - lrintf(dur * codec_tb_rate) / codec_tb_rate;
+ st->info->codec_tb_dur_error += error*error;
+
+ if (st->info->duration_count == 4 && st->info->codec_tb_dur_error * codec_tb_rate < 0.0001)
+ st->info->codec_tb_matches_dts = 1;
+ }
+
// ignore the first 4 values, they might have some random jitter
if (st->info->duration_count > 3)
st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration);
@@ -2398,10 +2413,10 @@ 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) && st->info->duration_count > 15 && st->info->duration_gcd > 1 && !st->r_frame_rate.num)
+ if (tb_unreliable(st) && 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) /*&&
+ && tb_unreliable(st) /*&&
//FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ...
st->time_base.num*duration_sum[i]/st->info->duration_count*101LL > st->time_base.den*/){
int num = 0;
--
1.7.3
More information about the ffmpeg-devel
mailing list