[FFmpeg-devel] codec & streams time bases transcode

Clément Bœsch ubitux at gmail.com
Fri Aug 3 15:51:08 CEST 2012


On Fri, Aug 03, 2012 at 03:29:02PM +0200, Michael Niedermayer wrote:
> On Wed, Aug 01, 2012 at 05:27:41PM +0200, Clément Bœsch wrote:
> > Hi,
> > 
> > I'm working on ticket¹ about an issue while transmuxing a MOV. The
> > original file contains a timecode, which is transmitted through metadata
> > and thus a timecode track is written as well in the output.
> > 
> > Unfortunately, the codec time base received in the MOV muxer is invalid:
> > 2997/1 instead of 1001/30000 (or something like 2997/100), which make the
> > timecode init fails (can be workarounded with -r 30000/1001 for example).
> > 
> > This happens because of the heuristics around line 3000 in ffmpeg.c where
> > the codec time base copy is not triggered (it will work if transmuxing to
> > MXF on the other hand). Reverting 618fb9cc fixes the issue, but will break
> > some other stuff, so it's not a solution.
> > 
> > All of this time base copies and heuristics look pretty fragile to me (and
> > are actually broken in this case); anyone has any thoughts about what
> > could be done here, and this is supposed to be fixed?
> 
> The stream copy timebase heuristics have the goal to select a timebase
> that allows efficient representation of the input.
> 
> While 1576 is about a input file with timebase 2997 or 2997/100 and
> you want the output to have a different timebase namely 30000/1001
> 
> I would say, its not a failure of the heuristics but rather that you
> want them to do something they had not been designed to do at all.
> They could be changed to do that of course ...
> 
> also theres another question, should 2997/100 always be replaced by
> 30000/1001 or not ? if not then when should it ? the question matters
> for improving the heuristics
> 

2997/100 is fine; I'm using the timebase to compute the frame rate and
this value will be rounded to 30 (which is assumed to be NTSC,
30000/1001). OTOH 2997/1 isn't since it's not a valid frame rate.

Indeed maybe I'm wrong using time base for this. The two attached patches
propose an alternative solution: if the time base looks wrong, fallback on
the average frame rate for the stream. Maybe I should use the average
frame rate unconditionally all the time?

-- 
Clément B.
-------------- next part --------------
From 1ddc3886dc5bc9e60af777a09f60ec417439bedc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= <clement.boesch at smartjog.com>
Date: Fri, 3 Aug 2012 15:40:15 +0200
Subject: [PATCH 1/2] timecode: add av_timecode_check_frame_rate().

---
 libavutil/timecode.c |   26 ++++++++++++++++++--------
 libavutil/timecode.h |    7 +++++++
 libavutil/version.h  |    2 +-
 3 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/libavutil/timecode.c b/libavutil/timecode.c
index c74abf2..fcbd00d 100644
--- a/libavutil/timecode.c
+++ b/libavutil/timecode.c
@@ -146,6 +146,17 @@ char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit)
     return buf;
 }
 
+static int check_fps(int fps)
+{
+    int i;
+    static const int supported_fps[] = {24, 25, 30, 50, 60};
+
+    for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++)
+        if (fps == supported_fps[i])
+            return 0;
+    return -1;
+}
+
 static int check_timecode(void *log_ctx, AVTimecode *tc)
 {
     if (tc->fps <= 0) {
@@ -156,18 +167,12 @@ static int check_timecode(void *log_ctx, AVTimecode *tc)
         av_log(log_ctx, AV_LOG_ERROR, "Drop frame is only allowed with 30000/1001 FPS\n");
         return AVERROR(EINVAL);
     }
-    switch (tc->fps) {
-    case 24:
-    case 25:
-    case 30:
-    case 50:
-    case 60: return  0;
-
-    default:
+    if (check_fps(tc->fps) < 0) {
         av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate %d/%d not supported\n",
                tc->rate.num, tc->rate.den);
         return AVERROR_PATCHWELCOME;
     }
+    return 0;
 }
 
 static int fps_from_frame_rate(AVRational rate)
@@ -177,6 +182,11 @@ static int fps_from_frame_rate(AVRational rate)
     return (rate.num + rate.den/2) / rate.den;
 }
 
+int av_timecode_check_frame_rate(AVRational rate)
+{
+    return check_fps(fps_from_frame_rate(rate));
+}
+
 int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx)
 {
     memset(tc, 0, sizeof(*tc));
diff --git a/libavutil/timecode.h b/libavutil/timecode.h
index be4102e..17d6b95 100644
--- a/libavutil/timecode.h
+++ b/libavutil/timecode.h
@@ -140,4 +140,11 @@ int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start
  */
 int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx);
 
+/**
+ * Check if the timecode feature is available for the given frame rate
+ *
+ * @return 0 if supported, <0 otherwise
+ */
+int av_timecode_check_frame_rate(AVRational rate);
+
 #endif /* AVUTIL_TIMECODE_H */
diff --git a/libavutil/version.h b/libavutil/version.h
index 04d111b..ebc782d 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -39,7 +39,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR 51
-#define LIBAVUTIL_VERSION_MINOR 66
+#define LIBAVUTIL_VERSION_MINOR 67
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
-- 
1.7.10.4

-------------- next part --------------
From fc97ca9d396280d21039761351c814253986b2e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= <clement.boesch at smartjog.com>
Date: Fri, 3 Aug 2012 15:40:48 +0200
Subject: [PATCH 2/2] lavf/movenc: add frame rate heuristic for timecode frame
 rate.

---
 libavformat/movenc.c |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index e086b3a..57c2d16 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -3244,6 +3244,13 @@ static int mov_create_timecode_track(AVFormatContext *s, int index, int src_inde
     AVPacket pkt    = {.stream_index = index, .flags = AV_PKT_FLAG_KEY, .size = 4};
     AVRational rate = {src_st->codec->time_base.den, src_st->codec->time_base.num};
 
+    /* if the codec time base makes no sense, try to fallback on stream frame rate */
+    if (av_timecode_check_frame_rate(rate) < 0) {
+        av_log(s, AV_LOG_DEBUG, "timecode: tbc=%d/%d invalid, fallback on %d/%d\n",
+               rate.num, rate.den, src_st->avg_frame_rate.num, src_st->avg_frame_rate.den);
+        rate = src_st->avg_frame_rate;
+    }
+
     /* compute the frame number */
     int ret = av_timecode_init_from_string(&tc, rate, tcstr, s);
     if (ret < 0)
-- 
1.7.10.4

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120803/fd2934c7/attachment.asc>


More information about the ffmpeg-devel mailing list