[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