Search code examples
videotimeffmpegvideo-capture

Precision of timestamps by ffmpeg based on framerate?


Here is my current command based on this answer:

ffmpeg \
-hide_banner \
-r $FRAMERATE \
-s $(((WIDTH + 63) / 64 * 64))"x"$(((HEIGHT + 15) / 16 * 16)) \
-f rawvideo \
-pix_fmt yuv420p \
-i - \
-filter_complex "crop=$WIDTH:$CROPPED_HEIGHT:0:0,settb=1/1000,setpts=RTCTIME/1000-1500000000000,split[out][ts];[out]setpts=N/FRAME_RATE/TB[out]" \
-map [out] \
-c:v ffv1 \
-vsync passthrough \
-f matroska \
"$OUTPUT_PATH/${FILENAME}.mkv" \
-map [ts] \
-flush_packets 1 \
-f mkvtimestamp_v2 \
"$OUTPUT_PATH/${FILENAME}_ts2.txt"

$FRAMERATE is set to 4. Here is the _ts2.txt output:

# timecode format v2
181489707750
181489708750
181489708751
181489709000
181489709250
181489709251
181489709500
181489709501
181489709750
181489710000
181489710001
181489710250
181489710500
181489710750
181489711000
181489711250
...

As you can see, except for the hiccups at the beginning (no idea why), it only generates timestamps that are a multiple of 250ms, i.e. 1/$FRAMERATE. How can I make these timestamps more precise, ideally on milliseconds level?


Solution

  • TL;DR: Remove the /1000-1500000000000 if possible.

    I removed the -1500000000000 and compared the timestamps when using /1000 and without. I noticed, that in both cases, the numbers always end with 000, 250, ... as above. This is one output with raw RTCTIME as pts:

    # timecode format v2
    1681736801215250
    1681736802129750
    1681736802258750
    1681736802392250
    1681736802545500
    1681736802683750
    1681736802815250
    1681736802965000
    1681736803101000
    ...
    1681736809206250
    1681736809450500
    1681736809707000
    1681736809950500
    1681736810207500
    1681736810448500
    1681736810705500
    1681736810950750
    1681736811205000
    1681736811451250
    

    These values are in microseconds precision. Note how in the first block the difference between 1st and 2nd frame is ~900ms, whereas for the remaining it is ~150ms. In the second block (end of file), the differences are ~250ms, as expected for the framerate. I'm not sure what the reason for the differences in the beginning is, perhaps it is related to buffering of the input stream or ffmpeg having to "catch up" after initialization.

    Also, note that the "hiccups" are gone. Previously, with the /1000, I got this warning:

    [mkvtimestamp_v2 @ 0x55c03b1eb0] Non-monotonous DTS in output stream 1:0; previous: 1681737336750, current: 1681737336750; changing to 1681737336751. This may result in incorrect timestamps in the output file.
    

    It complains that the timestamps of two succeeding frames are the same, which is very unlikely given the very low framerate. This already indicates that these timestamps must be wrong.

    Overall, the raw RTCTIME timestamps seem plausible, and imply that the division by 1000 is not working properly for some reason. In my case, I can simply remove it, because timestamp generation seems not to be limited by precision/timestamp length (as mentioned in the reference answer) in my ffmpeg version, and my processing tools are self-written and have no problems either. Your results may vary with standard tools such as mkvtoolnix, but I haven't tried it.