[FFmpeg-devel] [PATCH] Implemented arrange feature to convert from low timebase formats to high timebase
Roman Arutyunyan
arutyunyan.roman at gmail.com
Wed Oct 17 09:34:58 CEST 2012
This patch rearranges frame timestamps in muxer.
The problem: When remuxing from low-timebase-resolution formats (like RTMP with 1KHz time base)
to high-resolution formats (like MPEG-TS with 90KHz) frame timestamps are multiplied by
resolution factor (*90 in this case). That significantly increases round-off error. If you
have two audio frames next to one another that kind of remuxing may result in your second frame's
timestamp be too far from where it should be as a result of round-off error multiplication.
While I have not found a PC software sensitive to that kind of error Apple iPhone is very
much sensitive producing crackles at audio frame boundaries after such conversion (I convert
RTMP to HLS).
The patch intoduces '-arrange[:stream_specifier] arrange_threshold' option, where arrange_threshold
is max timestamp divergence in microseconds. When the argument is nonzero and current frame dts
is within arrange_threshold distance from muxer stream dts then packet dts is reset making
current frame receive the currect auto-generated dts from muxer. If new packet dts differs
too much then it's not changed in any way (that usually means a gap in audio stream).
The feature makes sence when applied to audio stream.
---
ffmpeg.h | 2 ++
ffmpeg_opt.c | 4 ++++
libavcodec/avcodec.h | 7 +++++++
libavformat/utils.c | 8 ++++++++
4 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/ffmpeg.h b/ffmpeg.h
index 56f8dfc..cadbea4 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -167,6 +167,8 @@ typedef struct OptionsContext {
int nb_pass;
SpecifierOpt *passlogfiles;
int nb_passlogfiles;
+ SpecifierOpt *arrange;
+ int nb_arrange;
} OptionsContext;
typedef struct InputFilter {
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index 2c5fbfb..a50a9cf 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -994,6 +994,8 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
st->codec->global_quality = FF_QP2LAMBDA * qscale;
}
+ MATCH_PER_STREAM_OPT(arrange, i64, st->codec->arrange_threshold, oc, st);
+
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
@@ -2343,6 +2345,8 @@ const OptionDef options[] = {
"extract an attachment into a file", "filename" },
{ "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts },
"print timestamp debugging info" },
+ { "arrange", HAS_ARG | OPT_INT64 | OPT_SPEC, { .off = OFFSET(arrange) },
+ "arrange closely spaced frames" },
/* video options */
{ "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE, { .func_arg = opt_video_frames },
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index dc317dc..5811690 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -3083,6 +3083,13 @@ typedef struct AVCodecContext {
int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far
int64_t pts_correction_last_pts; /// PTS of the last frame
int64_t pts_correction_last_dts; /// DTS of the last frame
+
+ /**
+ * Max timestamp between frames to arrange them (in microseconds)
+ * - decoding: unused
+ * - encoding: set by user
+ */
+ int64_t arrange_threshold;
} AVCodecContext;
AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx);
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 05c4b7f..0b59eeb 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3498,6 +3498,14 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){
if(pkt->pts == AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && delay==0)
pkt->pts= pkt->dts;
+ if (st->codec->arrange_threshold && pkt->dts != AV_NOPTS_VALUE && st->pts.val != AV_NOPTS_VALUE){
+ int64_t diff = pkt->dts - st->pts.val;
+ int64_t maxdiff = av_rescale(st->codec->arrange_threshold, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
+ av_dlog(s, "Arrange dts=%"PRId64" cur_dts=%"PRId64" diff=%"PRId64" maxdiff=%"PRId64"\n", pkt->dts, st->pts.val, diff, maxdiff);
+ if (diff > -maxdiff && diff < maxdiff)
+ pkt->dts = pkt->pts = AV_NOPTS_VALUE;
+ }
+
//XXX/FIXME this is a temporary hack until all encoders output pts
if((pkt->pts == 0 || pkt->pts == AV_NOPTS_VALUE) && pkt->dts == AV_NOPTS_VALUE && !delay){
static int warned;
--
1.7.1
More information about the ffmpeg-devel
mailing list