Pete Eberlein <[email protected]> added the comment:
I've been struggling with this problem as well, with a MPEG4-ES stream from a TI
encoder similar to the thread linked above this message. I can upload the file
if needed.
Here is the output:
$ ffmpeg -f m4v -r 30 -i output.m4v -vcodec copy -y output_mpeg4.avi
FFmpeg version SVN-r19352-4:0.5+svn20090706-2ubuntu2.2, Copyright (c) 2000-2009
Fabrice Bellard, et al.
configuration: --extra-version=4:0.5+svn20090706-2ubuntu2.2 --prefix=/usr
--enable-avfilter --enable-avfilter-lavf --enable-vdpau --enable-bzlib
--enable-libgsm --enable-libschroedinger --enable-libspeex --enable-libtheora
--enable-libvorbis --enable-pthreads --enable-zlib --disable-stripping
--disable-vhook --enable-gpl --enable-postproc --enable-swscale --enable-x11grab
--enable-libdc1394
--extra-cflags=-I/build/buildd/ffmpeg-0.5+svn20090706/debian/include
--enable-shared --disable-static
libavutil 49.15. 0 / 49.15. 0
libavcodec 52.20. 0 / 52.20. 0
libavformat 52.31. 0 / 52.31. 0
libavdevice 52. 1. 0 / 52. 1. 0
libavfilter 0. 4. 0 / 0. 4. 0
libswscale 0. 7. 1 / 0. 7. 1
libpostproc 51. 2. 0 / 51. 2. 0
built on Apr 23 2010 15:38:06, gcc: 4.4.1
Input #0, m4v, from 'output.m4v':
Duration: N/A, bitrate: N/A
Stream #0.0: Video: mpeg4, yuv420p, 640x480 [PAR 1:1 DAR 4:3], 30k tbr,
1200k tbn, 30k tbc
Output #0, avi, to 'output_mpeg4.avi':
Stream #0.0: Video: mpeg4, yuv420p, 640x480 [PAR 1:1 DAR 4:3], q=2-31, 90k
tbn, 30k tbc
Stream mapping:
Stream #0.0 -> #0.0
Press [q] to stop encoding
[NULL @ 0x19b7130]error, non monotone timestamps 50 >= 50
av_interleaved_write_frame(): Error while opening file
There are a few problems with this:
* The frame rate should not be 30k, it should be 30.
* The stream time_base should not be 1200k, it should be the same as the codec,
30k.
* The non monotone timestamps error occurs because the stream time_base is
wrong.
I've created a patch that does several things:
* calculates the ticks_per_frame when parsing the mpeg4 vol header
* reads the bitrate when parsing the mpeg4 vol header
* copies the pts from the current picture to the stream pts
* copies the time_base from the codec to the stream when the ticks_per_frame > 2
The patched output is:
FFmpeg version SVN-r24716, Copyright (c) 2000-2010 the FFmpeg developers
built on Aug 6 2010 09:54:55 with gcc 4.4.1
configuration:
libavutil 50.23. 0 / 50.23. 0
libavcore 0. 3. 0 / 0. 3. 0
libavcodec 52.84. 3 / 52.84. 3
libavformat 52.78. 0 / 52.78. 0
libavdevice 52. 2. 1 / 52. 2. 1
libavfilter 1.27. 1 / 1.27. 1
libswscale 0.11. 0 / 0.11. 0
[m4v @ 0x24bc470] Estimating duration from bitrate, this may be inaccurate
Input #0, m4v, from 'output.m4v':
Duration: 00:00:04.78, start: 0.000000, bitrate: 2000 kb/s
Stream #0.0: Video: mpeg4, yuv420p, 640x480 [PAR 1:1 DAR 4:3], 2000 kb/s, 30
tbr, 30k tbn, 30k tbc
Output #0, avi, to 'output_mpeg4.avi':
Metadata:
ISFT : Lavf52.78.0
Stream #0.0: Video: mpeg4, yuv420p, 640x480 [PAR 1:1 DAR 4:3], q=2-31, 2000
kb/s, 30 tbn, 30 tbc
Stream mapping:
Stream #0.0 -> #0.0
Press [q] to stop encoding
frame= 145 fps= 0 q=-1.0 Lsize= 1178kB time=4.83 bitrate=1996.2kbits/s
video:1169kB audio:0kB global headers:0kB muxing overhead 0.781340%
The resulting file plays back at the correct speed.
I'm not sure if this patch is the best way to solve this problem, but it works
for me. I'm a little concerned about copying the codec time_base to the stream
time_base based on the ticks_per_frame, and how that might affect other codecs.
Perhaps the devs can think of a better solution.
----------
nosy: +peberlein2
________________________________________________
FFmpeg issue tracker <[email protected]>
<https://roundup.ffmpeg.org/issue1210>
________________________________________________Index: libavcodec/mpeg4video_parser.c
===================================================================
--- libavcodec/mpeg4video_parser.c (revision 24716)
+++ libavcodec/mpeg4video_parser.c (working copy)
@@ -87,6 +87,7 @@
avcodec_set_dimensions(avctx, s->width, s->height);
}
s1->pict_type= s->pict_type;
+ s1->pts = s->current_picture_ptr->pts;
pc->first_picture = 0;
return ret;
}
Index: libavcodec/mpeg4videodec.c
===================================================================
--- libavcodec/mpeg4videodec.c (revision 24716)
+++ libavcodec/mpeg4videodec.c (working copy)
@@ -1519,7 +1519,8 @@
}
static int decode_vol_header(MpegEncContext *s, GetBitContext *gb){
- int width, height, vo_ver_id;
+ int width, height, vo_ver_id, bit_rate;
+ AVRational frame_rate;
/* vol header */
skip_bits(gb, 1); /* random access */
@@ -1545,9 +1546,10 @@
}
s->low_delay= get_bits1(gb);
if(get_bits1(gb)){ /* vbv parameters */
- get_bits(gb, 15); /* first_half_bitrate */
+ bit_rate = get_bits(gb, 15) << 15; /* first_half_bitrate */
skip_bits1(gb); /* marker */
- get_bits(gb, 15); /* latter_half_bitrate */
+ bit_rate += get_bits(gb, 15); /* latter_half_bitrate */
+ s->avctx->bit_rate = bit_rate * 400;
skip_bits1(gb); /* marker */
get_bits(gb, 15); /* first_half_vbv_buffer_size */
skip_bits1(gb); /* marker */
@@ -1572,6 +1574,8 @@
check_marker(gb, "before time_increment_resolution");
+ frame_rate = s->avctx->time_base; // set previously by raw.c:video_read_header()
+
s->avctx->time_base.den = get_bits(gb, 16);
if(!s->avctx->time_base.den){
av_log(s->avctx, AV_LOG_ERROR, "time_base.den==0\n");
@@ -1588,6 +1592,7 @@
s->avctx->time_base.num = get_bits(gb, s->time_increment_bits);
}else
s->avctx->time_base.num = 1;
+ s->avctx->ticks_per_frame = frame_rate.num * s->avctx->time_base.den / (frame_rate.den * s->avctx->time_base.num);
s->t_frame=0;
Index: libavformat/utils.c
===================================================================
--- libavformat/utils.c (revision 24716)
+++ libavformat/utils.c (working copy)
@@ -2343,6 +2343,9 @@
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample)
st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
+ // some MPEG4 codecs use large ticks per frame so the codec timebase should be used for the stream
+ if (st->codec->ticks_per_frame > 2)
+ st->time_base = st->codec->time_base;
// the check for tb_unreliable() is not completely correct, since this is not about handling
// a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.