]> git.sesse.net Git - ffmpeg/commitdiff
lavf: switch to AVStream.time_base as the hint for the muxer timebase
authorAnton Khirnov <anton@khirnov.net>
Sun, 18 May 2014 10:12:59 +0000 (12:12 +0200)
committerAnton Khirnov <anton@khirnov.net>
Wed, 18 Jun 2014 13:12:34 +0000 (15:12 +0200)
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).

18 files changed:
doc/APIchanges
libavformat/avformat.h
libavformat/avienc.c
libavformat/filmstripenc.c
libavformat/framehash.c
libavformat/movenc.c
libavformat/mpegtsenc.c
libavformat/mux.c
libavformat/mxfenc.c
libavformat/oggenc.c
libavformat/riffenc.c
libavformat/rmenc.c
libavformat/swf.h
libavformat/swfenc.c
libavformat/utils.c
libavformat/version.h
libavformat/yuv4mpegenc.c
tests/ref/lavf/mkv

index 952ee51556baa6cf9911d718115da4406e3efcf6..51a2ff559e9ea78edc7abbb0c97e305dc580c50b 100644 (file)
@@ -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
index b17c791eac68a2e88af7769fb7258eb37d88d709..473b8daedf67a6ec4e3ad9794818b38596198501 100644 (file)
@@ -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;
 
index 87075d4b9367f13261cf8605642a18a522b9bba1..417a8e99d2ef97bce762685d52be62f71e682456 100644 (file)
@@ -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);
index 90d9a7685c6076703b58085eabe9b379422be294..8d1d2d83657162d2c03243a5bb69cd34fc92cb20 100644 (file)
@@ -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
 
index 28e9e8407dd551b75d06caab747629965b335f53..6a6da98ae43588bebca02ae16f975704532cc23e 100644 (file)
@@ -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);
     }
index dcd3294e014a4b7d078d416cad738779419aa676..f5c36fcec1d0ea53b3bbaf8a6c1ef0af163f56b1 100644 (file)
@@ -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;
index 04cabe5f8d93b47aece5a6155df545550d18853c..838702e8fa851b2d4ef7e94af687548c46c00dcc 100644 (file)
@@ -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);
         }
     }
 
index e024a7eaea5f246b711353fb2ac486fa4faede56..9c2144acc11e05fc2a227cef10f0c3b91a77254b 100644 (file)
@@ -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");
index 66beec294011e6997ec95b28047526cc08568339..841e7277911c7cd0f9d5552ddee447f03824bd1a 100644 (file)
@@ -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;
index d148f5b7dad66dd915564d232d8c89e991586f6f..19c77595f4c32323cfaa863d9aef9696c3972c5c 100644 (file)
@@ -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  &&
index 8f0279628eddd7c64d67e6aa2801efb534f8dd57..b83533a250eaa3cf9272c3803011a65878f9a0fa 100644 (file)
@@ -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 :
index fba8feb802c7953608087a7ca41dd6bd729d708c..9ff9f318a5e924d9b83b047da9a1fb4b9d4075bb 100644 (file)
@@ -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;
index 79c3c1d033e7e88579f8cccbc08dc67d62341f6d..8eb3f70541f9760194155c4abdcc17ca2614fa50 100644 (file)
@@ -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[];
index be2e5cd7d3d5c74ff2b92bfaa23cde08bbbd0a9d..a1fc7b337c4abc805a5e545907bb8fb46f2b0b97 100644 (file)
@@ -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)
index 50661ea17c6cdcf892c276f17ee1ddd2295aed3a..ab6c6bf0c978ef53e197d40936ebf4dbde750cb1 100644 (file)
@@ -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;
index 57970cd250c2d0e42ee35baad39ab83ed477a9a3..1a017ce36280cde99cb4a610f0c71ddbd29695c0 100644 (file)
@@ -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 */
index ed1ffea87d16fbcf0105150ca47223519a50be15..abe967f1771a128a79ad5c3ec41b39792726b053 100644 (file)
@@ -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;
index e7c02d54482f7115e15bd74868553dcee58073ea..a871ea9fd9fdab0c007a0f7c841dfd2fb25b6cf5 100644 (file)
@@ -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