Transcoding fails if machine uptime is wrong
Hi,
I've seen variations on this before, but never really as bad, and never before with the mux (only with libvpx). I have a server that sends out a stream over HTTP (in the nut mux, because seemingly that's ffmpeg's native mux, and the easiest to send e.g. uncompressed video over) that I expect VLC to be able to transcode. This works, except when machine uptime is too high (and in my case, “too high” is more than 12 hours or so, when CLOCK_MONOTONIC starts getting above MAX_INT—and I intend to stream this for three days straight). I've taken a short excerpt with wget, which suffices to demonstrate the idea (although there also was some transient corruption in my capture that I don't get during normal streaming); you can get it at http://storage.sesse.net/test.nut .
The command line I'm using (stripped down) is:
./vlc -I dummy -v test.nut vlc://quit --sout '#transcode{vcodec=h264,vb=4500,acodec=mp4a,aenc=fdkaac,ab=128}:std{mux=ffmpeg{mux=mp4},access=file,dst=test.mp4}' --sout-avformat-options '{movflags=empty_moov+frag_keyframe+default_base_moof}
The important error messages are these:
[mp4 @ 0x7f8ebc00e340] track 0: codec frame size is not set
[mp4 @ 0x7f8ebc00e340] Timestamps are unset in a packet for stream 1. This is deprecated and will stop working in the future. Fix your code to set the timestamps properl
y
[mp4 @ 0x7f8ebc00e340] Encoder did not produce proper pts, making some up.
[mp4 @ 0x7f8ebc00e340] Application provided duration: 2638009020 / timestamp: 2638009020 is out of range for mov/mp4 format
[mp4 @ 0x7f8ebc00e340] pts has no value
[mp4 @ 0x7f8ebc00e340] Application provided duration: 2638010019 / timestamp: 2638010020 is out of range for mov/mp4 format
[mp4 @ 0x7f8ebc00e340] pts has no value
[mp4 @ 0x7f8ebc00e340] Application provided duration: 2638011018 / timestamp: 2638011020 is out of range for mov/mp4 format
[mp4 @ 0x7f8ebc00e340] pts has no value
From some printf-ing and my incomplete understanding, I believe what happens is:
- Somehow, the first frame gets dts=AV_NOPTS_VALUE (a very large negative integer) in the ffmpeg demuxer. I don't know how dts in nut is supposed to work, but if I use
ffprobe -of json -show_frame test.nut
, dts==pts here, not AV_NOPTS_VALUE. The rest have reasonable pts/dts; timebase is big (60000) since that's the smallest common multiple of 50, 60 and 60/1001, so pts/dts will eventually go >2^32, but in this sample, it's much lower since I start at 0. - VLC rewrites AV_NOPTS_VALUE to VLC_TS_INVALID (0).
- VLC rewrites all the non-0 pts/dts to CLOCK_MONOTONIC-based timestamps, with timebase CLOCK_FREQ (1000000).
- After transcoding, the muxer chooses the timebase 60000 like the input (I believe this is based on a wrong idea mixing up timebase and fps twice, but in this case, it's a reasonable choice in itself). The pts/dts are now much bigger, however, and become larger then MAX_INT after rescaling.
- ffmpeg's MP4 muxer (movenc.c) sees the dts 0 followed by a huge dts, concludes the duration (subsequent dts) must be larger than MAX_INT (not supported in MP4), and sets next dts to last_dts+1 as an emergency measure. The next packet fares no better; last_dts=1 so duration is huge again, next dts becomes last_dts+1=2, and so on…
I don't really know exactly where this should be fixed; there seems to be a whole string of errors, assuming I didn't mix up anything here. But in general, I will say that if VLC didn't do pts/dts rewriting when streaming, it would make my life a lot easier in general, since these bugs tend to show up much easier when these CLOCK_MONOTONIC timestamps show up.
If I hack mux.c to hardcode a much lower timebase (e.g. 300), it streams, showing that it really is about the overflows.