matroska (by default) uses 1/1000s timebase, so for example the PTSes of 24000/1001fps videos will be:
thus the PTS*timebase is actually
while mp4 normally won't touch timebase, so for the same example, mp4 stores 1/24000s as timebase, and uses 1001 as timebase-scale, so the PTSes are:
and the PTS*timebase*timescale is:
Obviously, matroska's timestamp suffers rounding error when muxing, while mp4 don't. There is no harm if you only need to play matroska files, since 1ms precision is accurate enough for playbacks. But when doing mkv->mp4 re-muxing or re-encoding, x264 (or FFmpeg, or any other normal tools) reads 1/1000s timebase from matroska header, and tries to use it for mp4, passing the rounding error to mp4 which normally expects accurate timebase, making the mp4 header a bullshit. Not only tMod but also vanilla x264, FFmpeg, Libav and many tools have the same problem, which is definitely not a bug of them. It is quite clear to me that matroska should be blamed.
MediaInfo does not get accurate CFR/VFR info. Neither for matroska nor for mp4. However, it sometimes gets it right, by accident. Vanilla x264 uses GPAC to generate mp4 files, while tMod uses l-smash. Generally, GPAC is famous for its not always doing things according to specifications and using its own standards, but l-smash tries to be "Loyal to Spec of Mpeg4", even if sometimes the spec does not do MediaInfo a favour. If you want to find out whether an mp4 file is VFR or CFR, use DtsEdit to extract the timecodes_v1, the results is quite clear whether fps is only one line of constant value or jittered values. Or being more accurate for research, use boxdumper ( from l-smash packet ) to extract the raw mp4 header.
There are many ways to fix the jitter in matroska when outputing mp4. If you need to deal with timecodes, there is a tiny tool named tctool
which intends to fix the jitter resaulted from rounding errors, converting
or doing v1<->v2 conversion in the same time. However, you might still need to specify --timebase to prevent x264 from reading from lavf/ffms/avs/y4m. Anyway, it is a good habbit to always tell x264 the timebase whenever one uses --tcfile-in.
If you don't need to bother with timecodes, it is much easier:
In x264, use --timebase 1001/24000 ( or 1001/120000, or 1001/360000, etc, according to your source ). For example: x264 --demuxer lavf --timebase 1001/24000 --output output.mp4 input.mkv
. x264 will recalculate the timebase and PTS for you.
In FFmpeg/Libav, use -filter:v settb=1001/24000 when re-encoding. For example: ffmpeg -i input.mkv -filter:v settb=1001/24000 output.mp4
Unfortunately, "settb" is a filter, and currently ffmpeg does not support applying filters when copying streams, so there's no easy way to remuxing mkv->mp4 in one step. I personally uses such method:
[syntax lang="winbatch"]ffmpeg.exe -i "input.mkv" -c copy "tmp.mp4"
DtsEdit.exe -tv 1 -o "tmp.tc" "tmp.mp4"
tctool.exe -v 2 "tmp.tc" > "tmp.tc2"
timelineeditor.exe --media-timebase 1001 --timecode "tmp.tc2" "tmp.mp4" "output.mp4"
[/syntax]It is rather easy to make a batch script.
Don't know about the crash in VSFilter. Seems to work good with --demuxer avs/y4m/raw --fps x, so might be a bug in vfr reading mode which lavf/ffms demuxer uses along with cfr outputing mode which --fps x forces.