Opened 8 years ago

Closed 8 years ago

#5704 closed defect (fixed)

Wrong timestamps muxing theora into ogg when theora decoder is disabled

Reported by: James Owned by:
Priority: normal Component: avformat
Version: git-master Keywords: theora ogg
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Configuring ffmpeg with theora decoder disabled and stream copying a theora stream from a matroska file into ogg creates a file with wrong timestamps.

How to reproduce:

$ wget https://upload.wikimedia.org/wikipedia/commons/b/b5/I-15bis.ogg

$ ./ffmpeg -loglevel debug -i I-15bis.ogg -c:v copy -an i.mkv
ffmpeg version N-80963-gf60b549 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 5.4.0 (Rev1, Built by MSYS2 project)
  configuration: --disable-sdl --enable-gpl --disable-decoders --disable-bsfs --disable-encoders --disable-hwaccels --extra-cflags='-D_WIN32_WINNT=0x0602' --samples=../samples --prefix=/mingw64
  libavutil      55. 28.100 / 55. 28.100
  libavcodec     57. 50.100 / 57. 50.100
  libavformat    57. 41.100 / 57. 41.100
  libavdevice    57.  0.102 / 57.  0.102
  libavfilter     6. 47.100 /  6. 47.100
  libswscale      4.  1.100 /  4.  1.100
  libswresample   2.  1.100 /  2.  1.100
  libpostproc    54.  0.100 / 54.  0.100
Splitting the commandline.
Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'.
Reading option '-i' ... matched as input file with argument 'I-15bis.ogg'.
Reading option '-c:v' ... matched as option 'c' (codec name) with argument 'copy'.
Reading option '-an' ... matched as option 'an' (disable audio) with argument '1'.
Reading option 'i.mkv' ... matched as output file.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option loglevel (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input file I-15bis.ogg.
Successfully parsed a group of options.
Opening an input file: I-15bis.ogg.
[file @ 00000000006e85c0] Setting default whitelist 'file,crypto'
[ogg @ 00000000006e71e0] Format ogg probed with size=2048 and score=100
[ogg @ 00000000006e71e0] Before avformat_find_stream_info() pos: 15388 bytes read:163611 seeks:4 nb_streams:2
[ogg @ 00000000006e71e0] All info found
[ogg @ 00000000006e71e0] After avformat_find_stream_info() pos: 45119 bytes read:196379 seeks:4 frames:11
Guessed Channel Layout for Input Stream #0.1 : stereo
Input #0, ogg, from 'I-15bis.ogg':
  Duration: 00:01:41.72, start: 0.000000, bitrate: 514 kb/s
    Stream #0:0, 10, 1/25: Video: theora, 1 reference frame, none, 320x240 (0x0), 0/1, SAR 1:1 DAR 4:3, 25 fps, 25 tbr, 25 tbn, 25 tbc
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
    Stream #0:1, 1, 1/48000: Audio: vorbis, 48000 Hz, 2 channels, 112 kb/s
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
Successfully opened the file.
Parsing a group of options: output file i.mkv.
Applying option c:v (codec name) with argument copy.
Applying option an (disable audio) with argument 1.
Successfully parsed a group of options.
Opening an output file: i.mkv.
[file @ 00000000026166a0] Setting default whitelist 'file,crypto'
Successfully opened the file.
[matroska @ 0000000002638b80] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
Output #0, matroska, to 'i.mkv':
  Metadata:
    encoder         : Lavf57.41.100
    Stream #0:0, 0, 1/1000: Video: theora, 1 reference frame (theo / 0x6F656874), none, 320x240 (0x0) [SAR 1:1 DAR 4:3], 0/1, q=2-31, 25 fps, 25 tbr, 1k tbn, 25 tbc
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[matroska @ 0000000002638b80] Writing block at offset 3432, size 5889, pts 0, dts 0, duration 40, keyframe 1
[matroska @ 0000000002638b80] Writing block at offset 9328, size 4345, pts 40, dts 40, duration 40, keyframe 0
[matroska @ 0000000002638b80] Writing block at offset 13680, size 2342, pts 80, dts 80, duration 40, keyframe 0

//"Writing block" spam stripped

[matroska @ 0000000002638b80] Writing block at offset 5368113, size 2953, pts 101600, dts 101600, duration 40, keyframe 0
[matroska @ 0000000002638b80] Writing block at offset 5371073, size 527, pts 101640, dts 101640, duration 40, keyframe 0
[matroska @ 0000000002638b80] Writing block at offset 5371607, size 3011, pts 101680, dts 101680, duration 40, keyframe 0
No more output streams to write to, finishing.
[matroska @ 0000000002638b80] end duration = 101720
[matroska @ 0000000002638b80] stream 0 end duration = 101720
frame= 2543 fps=0.0 q=-1.0 Lsize=    5249kB time=00:01:41.68 bitrate= 422.9kbits/s speed= 308x
video:5227kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.425205%
Input file #0 (I-15bis.ogg):
  Input stream #0:0 (video): 2543 packets read (5352706 bytes);
  Input stream #0:1 (audio): 7507 packets read (1113781 bytes);
  Total: 10050 packets (6466487 bytes) demuxed
Output file #0 (i.mkv):
  Output stream #0:0 (video): 2543 packets muxed (5352706 bytes);
  Total: 2543 packets (5352706 bytes) muxed
0 frames successfully decoded, 0 decoding errors
[AVIOContext @ 0000000002642e80] Statistics: 277 seeks, 2730 writeouts
[AVIOContext @ 00000000006e87e0] Statistics: 6694248 bytes read, 4 seeks



$ ./ffmpeg -loglevel debug -i i.mkv -c:v copy i.ogv
ffmpeg version N-80963-gf60b549 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 5.4.0 (Rev1, Built by MSYS2 project)
  configuration: --disable-sdl --enable-gpl --disable-decoders --disable-bsfs --disable-encoders --disable-hwaccels --extra-cflags='-D_WIN32_WINNT=0x0602' --samples=../samples --prefix=/mingw64
  libavutil      55. 28.100 / 55. 28.100
  libavcodec     57. 50.100 / 57. 50.100
  libavformat    57. 41.100 / 57. 41.100
  libavdevice    57.  0.102 / 57.  0.102
  libavfilter     6. 47.100 /  6. 47.100
  libswscale      4.  1.100 /  4.  1.100
  libswresample   2.  1.100 /  2.  1.100
  libpostproc    54.  0.100 / 54.  0.100
Splitting the commandline.
Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'.
Reading option '-i' ... matched as input file with argument 'i.mkv'.
Reading option '-c:v' ... matched as option 'c' (codec name) with argument 'copy'.
Reading option 'i.ogv' ... matched as output file.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option loglevel (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input file i.mkv.
Successfully parsed a group of options.
Opening an input file: i.mkv.
[file @ 0000000000d08560] Setting default whitelist 'file,crypto'
[matroska,webm @ 0000000000d07160] Format matroska,webm probed with size=2048 and score=100
st:0 removing common factor 1000000 from timebase
[matroska,webm @ 0000000000d07160] Before avformat_find_stream_info() pos: 3421 bytes read:32768 seeks:0 nb_streams:1
[matroska,webm @ 0000000000d07160] All info found
[matroska,webm @ 0000000000d07160] After avformat_find_stream_info() pos: 9328 bytes read:32768 seeks:0 frames:1
Input #0, matroska,webm, from 'i.mkv':
  Metadata:
    ENCODER         : Lavf57.41.100
  Duration: 00:01:41.72, start: 0.000000, bitrate: 422 kb/s
    Stream #0:0, 1, 1/1000: Video: theora, 1 reference frame, none, 320x240 (0x0), 0/1, SAR 1:1 DAR 4:3, 25 fps, 25 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
      DURATION        : 00:01:41.720000000
Successfully opened the file.
Parsing a group of options: output file i.ogv.
Applying option c:v (codec name) with argument copy.
Successfully parsed a group of options.
Opening an output file: i.ogv.
[file @ 00000000024381c0] Setting default whitelist 'file,crypto'
Successfully opened the file.
[ogg @ 0000000002436bc0] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
[ogg @ 0000000002436bc0] theora kfgshift 6, vrev 0
Output #0, ogg, to 'i.ogv':
  Metadata:
    encoder         : Lavf57.41.100
    Stream #0:0, 0, 1/1000: Video: theora, 1 reference frame, none, 320x240 (0x0) [SAR 1:1 DAR 4:3], 0/1, q=2-31, 25 fps, 25 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
      DURATION        : 00:01:41.720000000
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
No more output streams to write to, finishing.
frame= 2543 fps=0.0 q=-1.0 Lsize=    5319kB time=00:01:41.68 bitrate= 428.5kbits/s speed=1.5e+003x
video:5227kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.751544%
Input file #0 (i.mkv):
  Input stream #0:0 (video): 2543 packets read (5352706 bytes);
  Total: 2543 packets (5352706 bytes) demuxed
Output file #0 (i.ogv):
  Output stream #0:0 (video): 2543 packets muxed (5352706 bytes);
  Total: 2543 packets (5352706 bytes) muxed
0 frames successfully decoded, 0 decoding errors
[AVIOContext @ 00000000024382a0] Statistics: 0 seeks, 2545 writeouts
[AVIOContext @ 0000000000d08720] Statistics: 5375466 bytes read, 0 seeks

The resulting i.ogv file is a slideshow, because the timestamps are written using the 1/1000 timebase from Matroska, while the Ogg demuxer reads the time base from the Theora stream header (1/25 in this case).

Remuxing with Theora decoder compiled in looks like this:

$ ./ffmpeg -loglevel debug -i I-15bis.ogg -c:v copy -an i.mkv
ffmpeg version N-80963-gf60b549 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 5.4.0 (Rev1, Built by MSYS2 project)
  configuration: --enable-gpl --extra-cflags='-D_WIN32_WINNT=0x0602' --samples=../samples --prefix=/mingw64
  libavutil      55. 28.100 / 55. 28.100
  libavcodec     57. 50.100 / 57. 50.100
  libavformat    57. 41.100 / 57. 41.100
  libavdevice    57.  0.102 / 57.  0.102
  libavfilter     6. 47.100 /  6. 47.100
  libswscale      4.  1.100 /  4.  1.100
  libswresample   2.  1.100 /  2.  1.100
  libpostproc    54.  0.100 / 54.  0.100
Splitting the commandline.
Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'.
Reading option '-i' ... matched as input file with argument 'I-15bis.ogg'.
Reading option '-c:v' ... matched as option 'c' (codec name) with argument 'copy'.
Reading option '-an' ... matched as option 'an' (disable audio) with argument '1'.
Reading option 'i.mkv' ... matched as output file.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option loglevel (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input file I-15bis.ogg.
Successfully parsed a group of options.
Opening an input file: I-15bis.ogg.
[file @ 00000000024e3c80] Setting default whitelist 'file,crypto'
[ogg @ 00000000024e2c80] Format ogg probed with size=2048 and score=100
[ogg @ 00000000024e2c80] Before avformat_find_stream_info() pos: 15388 bytes read:163611 seeks:4 nb_streams:2
[theora @ 0000000002504c60] Theora bitstream version 30200
[theora @ 0000000002504c60] 7 bits left in packet 82
[ogg @ 00000000024e2c80] All info found
[ogg @ 00000000024e2c80] After avformat_find_stream_info() pos: 45119 bytes read:196379 seeks:4 frames:11
Input #0, ogg, from 'I-15bis.ogg':
  Duration: 00:01:41.72, start: 0.000000, bitrate: 514 kb/s
    Stream #0:0, 10, 1/25: Video: theora, 1 reference frame, yuv420p(bt470bg/bt470bg/bt709, center), 320x240 [SAR 1:1 DAR 4:3], 0/1, 25 fps, 25 tbr, 25 tbn, 25 tbc
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
    Stream #0:1, 1, 1/48000: Audio: vorbis, 48000 Hz, stereo, fltp, 112 kb/s
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
Successfully opened the file.
Parsing a group of options: output file i.mkv.
Applying option c:v (codec name) with argument copy.
Applying option an (disable audio) with argument 1.
Successfully parsed a group of options.
Opening an output file: i.mkv.
[file @ 00000000010cce40] Setting default whitelist 'file,crypto'
Successfully opened the file.
[matroska @ 000000000251f980] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
Output #0, matroska, to 'i.mkv':
  Metadata:
    encoder         : Lavf57.41.100
    Stream #0:0, 0, 1/1000: Video: theora, 1 reference frame (theo / 0x6F656874), yuv420p(bt470bg/bt470bg/bt709, center), 320x240 (0x0) [SAR 1:1 DAR 4:3], 0/1, q=2-31, 25 fps, 25 tbr, 1k tbn, 25 tbc
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[matroska @ 000000000251f980] Writing block at offset 3432, size 5889, pts 0, dts 0, duration 40, keyframe 1
[matroska @ 000000000251f980] Writing block at offset 9328, size 4345, pts 40, dts 40, duration 40, keyframe 0
[matroska @ 000000000251f980] Writing block at offset 13680, size 2342, pts 80, dts 80, duration 40, keyframe 0

//"Writing block" spam stripped

[matroska @ 000000000251f980] Writing block at offset 5368113, size 2953, pts 101600, dts 101600, duration 40, keyframe 0
[matroska @ 000000000251f980] Writing block at offset 5371073, size 527, pts 101640, dts 101640, duration 40, keyframe 0
[matroska @ 000000000251f980] Writing block at offset 5371607, size 3011, pts 101680, dts 101680, duration 40, keyframe 0
No more output streams to write to, finishing.
[matroska @ 000000000251f980] end duration = 101720
[matroska @ 000000000251f980] stream 0 end duration = 101720
frame= 2543 fps=0.0 q=-1.0 Lsize=    5249kB time=00:01:41.68 bitrate= 422.9kbits/s speed= 277x
video:5227kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.425205%
Input file #0 (I-15bis.ogg):
  Input stream #0:0 (video): 2543 packets read (5352706 bytes);
  Input stream #0:1 (audio): 7507 packets read (1113781 bytes);
  Total: 10050 packets (6466487 bytes) demuxed
Output file #0 (i.mkv):
  Output stream #0:0 (video): 2543 packets muxed (5352706 bytes);
  Total: 2543 packets (5352706 bytes) muxed
0 frames successfully decoded, 0 decoding errors
[AVIOContext @ 00000000010cee60] Statistics: 277 seeks, 2730 writeouts
[AVIOContext @ 00000000024ebec0] Statistics: 6694248 bytes read, 4 seeks



$ ./ffmpeg -loglevel debug -i i.mkv -c:v copy i.ogv
ffmpeg version N-80963-gf60b549 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 5.4.0 (Rev1, Built by MSYS2 project)
  configuration: --enable-gpl --extra-cflags='-D_WIN32_WINNT=0x0602' --samples=../samples --prefix=/mingw64
  libavutil      55. 28.100 / 55. 28.100
  libavcodec     57. 50.100 / 57. 50.100
  libavformat    57. 41.100 / 57. 41.100
  libavdevice    57.  0.102 / 57.  0.102
  libavfilter     6. 47.100 /  6. 47.100
  libswscale      4.  1.100 /  4.  1.100
  libswresample   2.  1.100 /  2.  1.100
  libpostproc    54.  0.100 / 54.  0.100
Splitting the commandline.
Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'.
Reading option '-i' ... matched as input file with argument 'i.mkv'.
Reading option '-c:v' ... matched as option 'c' (codec name) with argument 'copy'.
Reading option 'i.ogv' ... matched as output file.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option loglevel (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input file i.mkv.
Successfully parsed a group of options.
Opening an input file: i.mkv.
[file @ 0000000000dd3c00] Setting default whitelist 'file,crypto'
[matroska,webm @ 0000000000dd2c00] Format matroska,webm probed with size=2048 and score=100
st:0 removing common factor 1000000 from timebase
[matroska,webm @ 0000000000dd2c00] Before avformat_find_stream_info() pos: 3421 bytes read:32768 seeks:0 nb_streams:1
[theora @ 0000000000eda820] Theora bitstream version 30200
[theora @ 0000000000eda820] 7 bits left in packet 82
[matroska,webm @ 0000000000dd2c00] All info found
[matroska,webm @ 0000000000dd2c00] After avformat_find_stream_info() pos: 9328 bytes read:32768 seeks:0 frames:1
Input #0, matroska,webm, from 'i.mkv':
  Metadata:
    ENCODER         : Lavf57.41.100
  Duration: 00:01:41.72, start: 0.000000, bitrate: 422 kb/s
    Stream #0:0, 1, 1/1000: Video: theora, 1 reference frame, yuv420p(bt470bg/bt470bg/bt709, center), 320x240 [SAR 1:1 DAR 4:3], 0/1, 25 fps, 25 tbr, 1k tbn, 25 tbc (default)
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
      DURATION        : 00:01:41.720000000
Successfully opened the file.
Parsing a group of options: output file i.ogv.
Applying option c:v (codec name) with argument copy.
Successfully parsed a group of options.
Opening an output file: i.ogv.
[file @ 0000000002bd3800] Setting default whitelist 'file,crypto'
Successfully opened the file.
[ogg @ 0000000002bd2580] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
[ogg @ 0000000002bd2580] theora kfgshift 6, vrev 0
Output #0, ogg, to 'i.ogv':
  Metadata:
    encoder         : Lavf57.41.100
    Stream #0:0, 0, 1/25: Video: theora, 1 reference frame, yuv420p(bt470bg/bt470bg/bt709, center), 320x240 (0x0) [SAR 1:1 DAR 4:3], 0/1, q=2-31, 25 fps, 25 tbr, 25 tbn, 25 tbc (default)
    Metadata:
      ENCODER         : ffmpeg2theora 0.17
      DURATION        : 00:01:41.720000000
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
No more output streams to write to, finishing.
frame= 2543 fps=0.0 q=-1.0 Lsize=    5256kB time=00:01:41.72 bitrate= 423.3kbits/s speed=2.93e+003x
video:5227kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.554056%
Input file #0 (i.mkv):
  Input stream #0:0 (video): 2543 packets read (5352706 bytes);
  Total: 2543 packets (5352706 bytes) demuxed
Output file #0 (i.ogv):
  Output stream #0:0 (video): 2543 packets muxed (5352706 bytes);
  Total: 2543 packets (5352706 bytes) muxed
0 frames successfully decoded, 0 decoding errors
[AVIOContext @ 0000000002bd3880] Statistics: 0 seeks, 257 writeouts
[AVIOContext @ 0000000000ddbe00] Statistics: 5375466 bytes read, 0 seeks

The resulting i.ogv file plays fine and has correct timestamps.

Change History (4)

comment:1 by James, 8 years ago

This technically would also happen with other video codecs muxed into Ogg, like VP8 and Daala, since all of them store timestamps using the least common multiple framerate, where pts increases by 1 per frame.
Based on that, fixing this moving the relevant code from the Theora decoder to the parser, assuming it's possible, wouldn't solve the core issue of the muxer allowing any kind of timestamp and time base.

One solution could be using the lowest common multiple framerate if it differs from st->time_base, then rebase all the timestamps as the frames are muxed.
For Theora (and in the future Daala) this is as simple as using the time base reported by the stream header in st->codecpar->extradata, but for other codecs using st->r_frame_rate or similar will be necessary.

in reply to:  description ; comment:2 by Carl Eugen Hoyos, 8 years ago

Replying to jamrial:

Configuring ffmpeg with theora decoder disabled and stream copying a theora stream from a matroska file into ogg creates a file with wrong timestamps.

Isn't this expected or at least it can happen for some combinations of muxers and (missing) decoders?

in reply to:  2 comment:3 by James, 8 years ago

Replying to cehoyos:

Replying to jamrial:

Configuring ffmpeg with theora decoder disabled and stream copying a theora stream from a matroska file into ogg creates a file with wrong timestamps.

Isn't this expected or at least it can happen for some combinations of muxers and (missing) decoders?

Expecting muxers to create broken files in cases where it can be avoided is not something that should be done. Parsers for example were made among other things to remove dependency some muxers had on decoders to get timestamps and frame durations.
If i write a libavformat-based application dedicated exclusively to remux files i expect it to create valid files, or fail if it can't.

In this particular case, changes to the muxer can fix the issue.

comment:4 by James, 8 years ago

Keywords: theora ogg added
Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.