[FFmpeg-cvslog] lavf: switch to AVStream.time_base as the hint for the muxer timebase

Anton Khirnov git at videolan.org
Wed Jun 18 19:56:15 CEST 2014


ffmpeg | branch: master | Anton Khirnov <anton at khirnov.net> | Sun May 18 12:12:59 2014 +0200| [194be1f43ea391eb986732707435176e579265aa] | committer: Anton Khirnov

lavf: switch to AVStream.time_base as the hint for the muxer timebase

Previously, AVStream.codec.time_base was used for that purpose, which
was quite confusing for the callers. This change also opens the path for
removing AVStream.codec.

The change in the lavf-mkv test is due to the native timebase (1/1000)
being used instead of the default one (1/90000), so the packets are now
sent to the crc muxer in the same order in which they are demuxed
(previously some of them got reordered because of inexact timestamp
conversion).

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

 doc/APIchanges             |    5 +++++
 libavformat/avformat.h     |    9 ++++++---
 libavformat/avienc.c       |   15 ++++++++++-----
 libavformat/filmstripenc.c |    3 ++-
 libavformat/framehash.c    |    1 -
 libavformat/movenc.c       |   14 ++++++++------
 libavformat/mpegtsenc.c    |   13 ++++++++++---
 libavformat/mux.c          |   26 +++++++++++++++++++-------
 libavformat/mxfenc.c       |    5 +++--
 libavformat/oggenc.c       |    3 +--
 libavformat/riffenc.c      |    4 ++--
 libavformat/rmenc.c        |    5 ++++-
 libavformat/swf.h          |    1 +
 libavformat/swfenc.c       |    6 ++++--
 libavformat/utils.c        |    9 ++++++---
 libavformat/version.h      |    7 +++++--
 libavformat/yuv4mpegenc.c  |    5 +++--
 tests/ref/lavf/mkv         |    2 +-
 18 files changed, 90 insertions(+), 43 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 952ee51..51a2ff5 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,11 @@ libavutil:     2013-12-xx
 
 API changes, most recent first:
 
+2014-xx-xx - xxxxxxx - lavf 55.20.0 - avformat.h
+  The proper way for providing a hint about the desired timebase to the muxers
+  is now setting AVStream.time_base, instead of AVStream.codec.time_base as was
+  done previously. The old method is now deprecated.
+
 2014-04-xx - xxxxxxx - lavc 55.54.0 - avcodec.h
   Add AVCodecContext.side_data_only_packets to allow encoders to output packets
   with only side data. This option may become mandatory in the future, so all
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index b17c791..473b8da 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -710,9 +710,12 @@ typedef struct AVStream {
      * of which frame timestamps are represented.
      *
      * decoding: set by libavformat
-     * encoding: set by libavformat in avformat_write_header. The muxer may use the
-     * user-provided value of @ref AVCodecContext.time_base "codec->time_base"
-     * as a hint.
+     * encoding: May be set by the caller before avformat_write_header() to
+     *           provide a hint to the muxer about the desired timebase. In
+     *           avformat_write_header(), the muxer will overwrite this field
+     *           with the timebase that will actually be used for the timestamps
+     *           written into the file (which may or may not be related to the
+     *           user-provided one, depending on the format).
      */
     AVRational time_base;
 
diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index 87075d4..417a8e9 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -144,6 +144,7 @@ static int avi_write_header(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
     AVCodecContext *video_enc;
+    AVStream *video_st = NULL;
     int64_t list1, list2, strh, strf;
     AVDictionaryEntry *t = NULL;
 
@@ -172,15 +173,18 @@ static int avi_write_header(AVFormatContext *s)
     for (n = 0; n < s->nb_streams; n++) {
         AVCodecContext *codec = s->streams[n]->codec;
         bitrate += codec->bit_rate;
-        if (codec->codec_type == AVMEDIA_TYPE_VIDEO)
+        if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
             video_enc = codec;
+            video_st = s->streams[n];
+        }
     }
 
     nb_frames = 0;
 
-    if (video_enc)
-        avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_enc->time_base.num /
-                                  video_enc->time_base.den));
+    // TODO: should be avg_frame_rate
+    if (video_st)
+        avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_st->time_base.num /
+                                  video_st->time_base.den));
     else
         avio_wl32(pb, 0);
     avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */
@@ -337,7 +341,8 @@ static int avi_write_header(AVFormatContext *s)
 
             avio_wl32(pb, 0); // video format   = unknown
             avio_wl32(pb, 0); // video standard = unknown
-            avio_wl32(pb, lrintf(1.0 / av_q2d(enc->time_base)));
+            // TODO: should be avg_frame_rate
+            avio_wl32(pb, lrintf(1.0 / av_q2d(st->time_base)));
             avio_wl32(pb, enc->width);
             avio_wl32(pb, enc->height);
             avio_wl16(pb, den);
diff --git a/libavformat/filmstripenc.c b/libavformat/filmstripenc.c
index 90d9a76..8d1d2d8 100644
--- a/libavformat/filmstripenc.c
+++ b/libavformat/filmstripenc.c
@@ -64,7 +64,8 @@ static int write_trailer(AVFormatContext *s)
     avio_wb16(pb, st->codec->width);
     avio_wb16(pb, st->codec->height);
     avio_wb16(pb, 0);  // leading
-    avio_wb16(pb, 1/av_q2d(st->codec->time_base));
+    // TODO: should be avg_frame_rate
+    avio_wb16(pb, 1/av_q2d(st->time_base));
     for (i = 0; i < 16; i++)
         avio_w8(pb, 0x00);  // reserved
 
diff --git a/libavformat/framehash.c b/libavformat/framehash.c
index 28e9e84..6a6da98 100644
--- a/libavformat/framehash.c
+++ b/libavformat/framehash.c
@@ -25,7 +25,6 @@ int ff_framehash_write_header(AVFormatContext *s)
     int i;
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
-        avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
         avio_printf(s->pb, "#tb %d: %d/%d\n", i, st->time_base.num, st->time_base.den);
         avio_flush(s->pb);
     }
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index dcd3294..f5c36fc 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -814,10 +814,10 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
         else if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
         else                                                tag = MKTAG('d','v','p','p');
     else if (track->enc->height == 720) /* HD 720 line */
-        if  (track->enc->time_base.den == 50)               tag = MKTAG('d','v','h','q');
+        if  (track->st->time_base.den == 50)                tag = MKTAG('d','v','h','q');
         else                                                tag = MKTAG('d','v','h','p');
     else if (track->enc->height == 1080) /* HD 1080 line */
-        if  (track->enc->time_base.den == 25)               tag = MKTAG('d','v','h','5');
+        if  (track->st->time_base.den == 25)                tag = MKTAG('d','v','h','5');
         else                                                tag = MKTAG('d','v','h','6');
     else {
         av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
@@ -2656,10 +2656,12 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
 
 static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
 {
+    AVStream       *video_st    = s->streams[0];
     AVCodecContext *video_codec = s->streams[0]->codec;
     AVCodecContext *audio_codec = s->streams[1]->codec;
     int audio_rate = audio_codec->sample_rate;
-    int frame_rate = ((video_codec->time_base.den) * (0x10000)) / (video_codec->time_base.num);
+    // TODO: should be avg_frame_rate
+    int frame_rate = ((video_st->time_base.den) * (0x10000)) / (video_st->time_base.num);
     int audio_kbitrate = audio_codec->bit_rate / 1000;
     int video_kbitrate = FFMIN(video_codec->bit_rate / 1000, 800 - audio_kbitrate);
 
@@ -3400,7 +3402,7 @@ static int mov_write_header(AVFormatContext *s)
                 }
                 track->height = track->tag >> 24 == 'n' ? 486 : 576;
             }
-            track->timescale = st->codec->time_base.den;
+            track->timescale = st->time_base.den;
             if (track->mode == MODE_MOV && track->timescale > 100000)
                 av_log(s, AV_LOG_WARNING,
                        "WARNING codec timebase is very high. If duration is too long,\n"
@@ -3428,9 +3430,9 @@ static int mov_write_header(AVFormatContext *s)
                 goto error;
             }
         } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
-            track->timescale = st->codec->time_base.den;
+            track->timescale = st->time_base.den;
         } else if (st->codec->codec_type == AVMEDIA_TYPE_DATA) {
-            track->timescale = st->codec->time_base.den;
+            track->timescale = st->time_base.den;
         }
         if (!track->height)
             track->height = st->codec->height;
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 04cabe5..838702e 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -194,6 +194,7 @@ typedef struct MpegTSWriteStream {
     int payload_flags;
     uint8_t *payload;
     AVFormatContext *amux;
+    AVRational user_tb;
 } MpegTSWriteStream;
 
 static void mpegts_write_pat(AVFormatContext *s)
@@ -480,13 +481,17 @@ static int mpegts_write_header(AVFormatContext *s)
     /* assign pids to each stream */
     for(i = 0;i < s->nb_streams; i++) {
         st = s->streams[i];
-        avpriv_set_pts_info(st, 33, 1, 90000);
+
         ts_st = av_mallocz(sizeof(MpegTSWriteStream));
         if (!ts_st) {
             ret = AVERROR(ENOMEM);
             goto fail;
         }
         st->priv_data = ts_st;
+
+        ts_st->user_tb = st->time_base;
+        avpriv_set_pts_info(st, 33, 1, 90000);
+
         ts_st->payload = av_mallocz(ts->pes_payload_size);
         if (!ts_st->payload) {
             ret = AVERROR(ENOMEM);
@@ -557,7 +562,8 @@ static int mpegts_write_header(AVFormatContext *s)
         pcr_st = s->streams[0];
         ts_st = pcr_st->priv_data;
         service->pcr_pid = ts_st->pid;
-    }
+    } else
+        ts_st = pcr_st->priv_data;
 
     if (ts->mux_rate > 1) {
         service->pcr_packet_period = (ts->mux_rate * ts->pcr_period) /
@@ -583,8 +589,9 @@ static int mpegts_write_header(AVFormatContext *s)
             }
         } else {
             // max delta PCR 0.1s
+            // TODO: should be avg_frame_rate
             service->pcr_packet_period =
-                pcr_st->codec->time_base.den/(10*pcr_st->codec->time_base.num);
+                ts_st->user_tb.den / (10 * ts_st->user_tb.num);
         }
     }
 
diff --git a/libavformat/mux.c b/libavformat/mux.c
index e024a7e..9c2144a 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -115,6 +115,25 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
         st    = s->streams[i];
         codec = st->codec;
 
+#if FF_API_LAVF_CODEC_TB
+FF_DISABLE_DEPRECATION_WARNINGS
+        if (!st->time_base.num && codec->time_base.num) {
+            av_log(s, AV_LOG_WARNING, "Using AVStream.codec.time_base as a "
+                   "timebase hint to the muxer is deprecated. Set "
+                   "AVStream.time_base instead.\n");
+            avpriv_set_pts_info(st, 64, codec->time_base.num, codec->time_base.den);
+        }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+        if (!st->time_base.num) {
+            /* fall back on the default timebase values */
+            if (codec->codec_type == AVMEDIA_TYPE_AUDIO && codec->sample_rate)
+                avpriv_set_pts_info(st, 64, 1, codec->sample_rate);
+            else
+                avpriv_set_pts_info(st, 33, 1, 90000);
+        }
+
         switch (codec->codec_type) {
         case AVMEDIA_TYPE_AUDIO:
             if (codec->sample_rate <= 0) {
@@ -127,13 +146,6 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
                                      av_get_bits_per_sample(codec->codec_id) >> 3;
             break;
         case AVMEDIA_TYPE_VIDEO:
-            if (codec->time_base.num <= 0 ||
-                codec->time_base.den <= 0) { //FIXME audio too?
-                av_log(s, AV_LOG_ERROR, "time base not set\n");
-                ret = AVERROR(EINVAL);
-                goto fail;
-            }
-
             if ((codec->width <= 0 || codec->height <= 0) &&
                 !(of->flags & AVFMT_NODIMENSIONS)) {
                 av_log(s, AV_LOG_ERROR, "dimensions not set\n");
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 66beec2..841e727 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -1433,11 +1433,12 @@ static int mxf_write_header(AVFormatContext *s)
                 av_log(s, AV_LOG_ERROR, "video stream must be first track\n");
                 return -1;
             }
-            if (fabs(av_q2d(st->codec->time_base) - 1/25.0) < 0.0001) {
+            // TODO: should be avg_frame_rate
+            if (fabs(av_q2d(st->time_base) - 1/25.0) < 0.0001) {
                 samples_per_frame = PAL_samples_per_frame;
                 mxf->time_base = (AVRational){ 1, 25 };
                 mxf->timecode_base = 25;
-            } else if (fabs(av_q2d(st->codec->time_base) - 1001/30000.0) < 0.0001) {
+            } else if (fabs(av_q2d(st->time_base) - 1001/30000.0) < 0.0001) {
                 samples_per_frame = NTSC_samples_per_frame;
                 mxf->time_base = (AVRational){ 1001, 30000 };
                 mxf->timecode_base = 30;
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index d148f5b..19c7759 100644
--- a/libavformat/oggenc.c
+++ b/libavformat/oggenc.c
@@ -428,8 +428,7 @@ static int ogg_write_header(AVFormatContext *s)
                 avpriv_set_pts_info(st, 64, 1, 48000);
             else
                 avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
-        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
-            avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
+
         if (st->codec->codec_id != AV_CODEC_ID_VORBIS &&
             st->codec->codec_id != AV_CODEC_ID_THEORA &&
             st->codec->codec_id != AV_CODEC_ID_SPEEX  &&
diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c
index 8f02796..b83533a 100644
--- a/libavformat/riffenc.c
+++ b/libavformat/riffenc.c
@@ -230,8 +230,8 @@ void ff_parse_specific_params(AVStream *st, int *au_rate,
     } else if (codec->codec_type == AVMEDIA_TYPE_VIDEO ||
                codec->codec_type == AVMEDIA_TYPE_DATA ||
                codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
-        *au_scale = codec->time_base.num;
-        *au_rate  = codec->time_base.den;
+        *au_scale = st->time_base.num;
+        *au_rate  = st->time_base.den;
     } else {
         *au_scale = codec->block_align ? codec->block_align * 8 : 8;
         *au_rate  = codec->bit_rate ? codec->bit_rate :
diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c
index fba8feb..9ff9f31 100644
--- a/libavformat/rmenc.c
+++ b/libavformat/rmenc.c
@@ -310,6 +310,8 @@ static int rm_write_header(AVFormatContext *s)
     AVCodecContext *codec;
 
     for(n=0;n<s->nb_streams;n++) {
+        AVStream *st = s->streams[n];
+
         s->streams[n]->id = n;
         codec = s->streams[n]->codec;
         stream = &rm->streams[n];
@@ -329,7 +331,8 @@ static int rm_write_header(AVFormatContext *s)
             break;
         case AVMEDIA_TYPE_VIDEO:
             rm->video_stream = stream;
-            stream->frame_rate = (float)codec->time_base.den / (float)codec->time_base.num;
+            // TODO: should be avg_frame_rate
+            stream->frame_rate = (float)st->time_base.den / (float)st->time_base.num;
             /* XXX: dummy values */
             stream->packet_max_size = 4096;
             stream->nb_packets = 0;
diff --git a/libavformat/swf.h b/libavformat/swf.h
index 79c3c1d..8eb3f70 100644
--- a/libavformat/swf.h
+++ b/libavformat/swf.h
@@ -76,6 +76,7 @@ typedef struct SWFContext {
     int tag;
     AVFifoBuffer *audio_fifo;
     AVCodecContext *audio_enc, *video_enc;
+    AVStream *video_st;
 } SWFContext;
 
 extern const AVCodecTag ff_swf_codec_tags[];
diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c
index be2e5cd..a1fc7b3 100644
--- a/libavformat/swfenc.c
+++ b/libavformat/swfenc.c
@@ -207,6 +207,7 @@ static int swf_write_header(AVFormatContext *s)
             if (enc->codec_id == AV_CODEC_ID_VP6F ||
                 enc->codec_id == AV_CODEC_ID_FLV1 ||
                 enc->codec_id == AV_CODEC_ID_MJPEG) {
+                swf->video_st  = s->streams[i];
                 swf->video_enc = enc;
             } else {
                 av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n");
@@ -224,8 +225,9 @@ static int swf_write_header(AVFormatContext *s)
     } else {
         width = swf->video_enc->width;
         height = swf->video_enc->height;
-        rate = swf->video_enc->time_base.den;
-        rate_base = swf->video_enc->time_base.num;
+        // TODO: should be avg_frame_rate
+        rate = swf->video_st->time_base.den;
+        rate_base = swf->video_st->time_base.num;
     }
 
     if (!swf->audio_enc)
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 50661ea..ab6c6bf 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -2663,9 +2663,14 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
     }
 
     st->codec = avcodec_alloc_context3(c);
-    if (s->iformat)
+    if (s->iformat) {
         /* no default bitrate if decoding */
         st->codec->bit_rate = 0;
+
+        /* default pts setting is MPEG-like */
+        avpriv_set_pts_info(st, 33, 1, 90000);
+    }
+
     st->index      = s->nb_streams;
     st->start_time = AV_NOPTS_VALUE;
     st->duration   = AV_NOPTS_VALUE;
@@ -2677,8 +2682,6 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
     st->first_dts     = AV_NOPTS_VALUE;
     st->probe_packets = MAX_PROBE_PACKETS;
 
-    /* default pts setting is MPEG-like */
-    avpriv_set_pts_info(st, 33, 1, 90000);
     st->last_IP_pts = AV_NOPTS_VALUE;
     for (i = 0; i < MAX_REORDER_DELAY + 1; i++)
         st->pts_buffer[i] = AV_NOPTS_VALUE;
diff --git a/libavformat/version.h b/libavformat/version.h
index 57970cd..1a017ce 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -30,8 +30,8 @@
 #include "libavutil/version.h"
 
 #define LIBAVFORMAT_VERSION_MAJOR 55
-#define LIBAVFORMAT_VERSION_MINOR 19
-#define LIBAVFORMAT_VERSION_MICRO  1
+#define LIBAVFORMAT_VERSION_MINOR 20
+#define LIBAVFORMAT_VERSION_MICRO  0
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
@@ -57,5 +57,8 @@
 #ifndef FF_API_LAVF_FRAC
 #define FF_API_LAVF_FRAC                (LIBAVFORMAT_VERSION_MAJOR < 57)
 #endif
+#ifndef FF_API_LAVF_CODEC_TB
+#define FF_API_LAVF_CODEC_TB            (LIBAVFORMAT_VERSION_MAJOR < 57)
+#endif
 
 #endif /* AVFORMAT_VERSION_H */
diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c
index ed1ffea..abe967f 100644
--- a/libavformat/yuv4mpegenc.c
+++ b/libavformat/yuv4mpegenc.c
@@ -38,8 +38,9 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
     width  = st->codec->width;
     height = st->codec->height;
 
-    av_reduce(&raten, &rated, st->codec->time_base.den,
-              st->codec->time_base.num, (1UL << 31) - 1);
+    // TODO: should be avg_frame_rate
+    av_reduce(&raten, &rated, st->time_base.den,
+              st->time_base.num, (1UL << 31) - 1);
 
     aspectn = st->sample_aspect_ratio.num;
     aspectd = st->sample_aspect_ratio.den;
diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv
index e7c02d5..a871ea9 100644
--- a/tests/ref/lavf/mkv
+++ b/tests/ref/lavf/mkv
@@ -1,3 +1,3 @@
 268fb8f9278b0df2f87a6a9455f3cd56 *./tests/data/lavf/lavf.mkv
 320380 ./tests/data/lavf/lavf.mkv
-./tests/data/lavf/lavf.mkv CRC=0xbe7d3cda
+./tests/data/lavf/lavf.mkv CRC=0x36193cda



More information about the ffmpeg-cvslog mailing list