[FFmpeg-cvslog] lavf: use dts difference instead of AVPacket.duration in find_stream_info()

Anton Khirnov git at videolan.org
Sun Jul 29 23:09:04 CEST 2012


ffmpeg | branch: master | Anton Khirnov <anton at khirnov.net> | Thu Jun 28 15:49:51 2012 +0200| [fe1c1198e670242f3cf9e3e1eef27cff77f3ee23] | committer: Anton Khirnov

lavf: use dts difference instead of AVPacket.duration in find_stream_info()

AVPacket.duration is mostly made up and thus completely useless, this is
especially true for video streams.
Therefore use dts difference for framerate estimation and
the max_analyze_duration check.

The asyncts test now needs -analyzeduration, because the default is 5
seconds and the audio stream in the sample appears at ~10 seconds.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=fe1c1198e670242f3cf9e3e1eef27cff77f3ee23
---

 libavformat/avformat.h |   10 +++++++++-
 libavformat/utils.c    |   38 ++++++++++++++++++++++++++++++++------
 tests/fate/filter.mak  |    2 +-
 3 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 7c97ada..0e50487 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -718,9 +718,17 @@ typedef struct AVStream {
         int64_t duration_gcd;
         int duration_count;
         double duration_error[MAX_STD_TIMEBASES];
-        int64_t codec_info_duration;
         int nb_decoded_frames;
         int found_decoder;
+
+        /**
+         * Those are used for average framerate estimation.
+         */
+        int64_t fps_first_dts;
+        int     fps_first_dts_idx;
+        int64_t fps_last_dts;
+        int     fps_last_dts_idx;
+
     } *info;
 
     int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 149913c..bd94f7d 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -2288,6 +2288,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
 
     for (i=0; i<ic->nb_streams; i++) {
         ic->streams[i]->info->last_dts = AV_NOPTS_VALUE;
+        ic->streams[i]->info->fps_first_dts = AV_NOPTS_VALUE;
+        ic->streams[i]->info->fps_last_dts  = AV_NOPTS_VALUE;
     }
 
     count = 0;
@@ -2395,12 +2397,31 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
         read_size += pkt->size;
 
         st = ic->streams[pkt->stream_index];
-        if (st->codec_info_nb_frames>1) {
-            if (av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) {
+        if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) {
+            /* check for non-increasing dts */
+            if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
+                st->info->fps_last_dts >= pkt->dts) {
+                av_log(ic, AV_LOG_WARNING, "Non-increasing DTS in stream %d: "
+                       "packet %d with DTS %"PRId64", packet %d with DTS "
+                       "%"PRId64"\n", st->index, st->info->fps_last_dts_idx,
+                       st->info->fps_last_dts, st->codec_info_nb_frames, pkt->dts);
+                st->info->fps_first_dts = st->info->fps_last_dts = AV_NOPTS_VALUE;
+            }
+
+            /* update stored dts values */
+            if (st->info->fps_first_dts == AV_NOPTS_VALUE) {
+                st->info->fps_first_dts     = pkt->dts;
+                st->info->fps_first_dts_idx = st->codec_info_nb_frames;
+            }
+            st->info->fps_last_dts = pkt->dts;
+            st->info->fps_last_dts_idx = st->codec_info_nb_frames;
+
+            /* check max_analyze_duration */
+            if (av_rescale_q(pkt->dts - st->info->fps_first_dts, st->time_base,
+                             AV_TIME_BASE_Q) >= ic->max_analyze_duration) {
                 av_log(ic, AV_LOG_WARNING, "max_analyze_duration reached\n");
                 break;
             }
-            st->info->codec_info_duration += pkt->duration;
         }
         {
             int64_t last = st->info->last_dts;
@@ -2460,10 +2481,15 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
     for(i=0;i<ic->nb_streams;i++) {
         st = ic->streams[i];
         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-            if (st->codec_info_nb_frames>2 && !st->avg_frame_rate.num && st->info->codec_info_duration)
+            /* estimate average framerate if not set by demuxer */
+            if (!st->avg_frame_rate.num && st->info->fps_last_dts != st->info->fps_first_dts) {
+                int64_t delta_dts = st->info->fps_last_dts - st->info->fps_first_dts;
+                int delta_packets = st->info->fps_last_dts_idx - st->info->fps_first_dts_idx;
+
                 av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
-                          (st->codec_info_nb_frames-2)*(int64_t)st->time_base.den,
-                          st->info->codec_info_duration*(int64_t)st->time_base.num, 60000);
+                          delta_packets*(int64_t)st->time_base.den,
+                          delta_dts*(int64_t)st->time_base.num, 60000);
+            }
             // 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.
diff --git a/tests/fate/filter.mak b/tests/fate/filter.mak
index f847a66..7c1170f 100644
--- a/tests/fate/filter.mak
+++ b/tests/fate/filter.mak
@@ -22,7 +22,7 @@ FATE_SAMPLES_AVCONV += $(FATE_AMIX)
 
 FATE_ASYNCTS += fate-filter-asyncts
 fate-filter-asyncts: SRC = $(SAMPLES)/nellymoser/nellymoser-discont.flv
-fate-filter-asyncts: CMD = pcm -i $(SRC) -af asyncts
+fate-filter-asyncts: CMD = pcm -analyzeduration 10000000 -i $(SRC) -af asyncts
 fate-filter-asyncts: CMP = oneoff
 fate-filter-asyncts: REF = $(SAMPLES)/nellymoser/nellymoser-discont.pcm
 



More information about the ffmpeg-cvslog mailing list