Opened 23 months ago

Last modified 8 months ago

#9814 open enhancement

time_scale / num_units_in_tick is not infinite precision

Reported by: Balling Owned by: Elon Musk
Priority: wish Component: avformat
Version: git-master Keywords:
Cc: Blocked By:
Blocking: Reproduced by developer: yes
Analyzed by developer: no

Description (last modified by Balling)

Summary of the bug: as you can read here https://www.ffmpeg.org/ffmpeg-bitstream-filters.html#h264_005fmetadata H.264 has time_scale / num_units_in_tick in the VUI parameters. That is how one writes frame rate (besides timing SEI that is) in Annex B files. The problem is that (not touching very broken mkv here with only ms precision and only PTS in the form of duration, no DTS) when you go to mp4 you are supposed to make it CFR and use the nice tbn. But even if you will use vfrdet on annex b file it will not be CFR. This sample in fact has even fixed_frame_rate_flag set! So this is a bug, ffplay also cannot even seek in this annex b file! Sample is here: https://github.com/wang-bin/QtAV/files/1132086/example.zip

How to reproduce:

ffmpeg -i  example.h264 -vf vfrdet -f null NUL
ffmpeg version N-107098-g4d45f5acbd-20220613 Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 11.2.0 (crosstool-NG 1.24.0.533_681aaef)
  configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --enable-shared --disable-static --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libmfx --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --disable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-ldflags=-pthread --extra-ldexeflags= --extra-libs=-lgomp --extra-version=20220613
  libavutil      57. 26.100 / 57. 26.100
  libavcodec     59. 33.100 / 59. 33.100
  libavformat    59. 24.100 / 59. 24.100
  libavdevice    59.  6.100 / 59.  6.100
  libavfilter     8. 40.100 /  8. 40.100
  libswscale      6.  6.100 /  6.  6.100
  libswresample   4.  6.100 /  4.  6.100
  libpostproc    56.  5.100 / 56.  5.100
Input #0, h264, from 'example.h264':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: h264 (Main), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 1200k tbn
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))
Press [q] to stop, [?] for help
Output #0, null, to 'NUL':
  Metadata:
    encoder         : Lavf59.24.100
  Stream #0:0: Video: wrapped_avframe, yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 29.97 fps, 29.97 tbn
    Metadata:
      encoder         : Lavc59.33.100 wrapped_avframe
frame= 1082 fps=912 q=-0.0 Lsize=N/A time=00:00:36.10 bitrate=N/A speed=30.4x
video:499kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
[Parsed_vfrdet_0 @ 000001a582b7f900] VFR:0.799260 (864/217) min: 40040 max: 40041 avg: 40040

What it should be as if -r 29.97002997 was before input.

In fact Mediainfo can see all of it (both the timetamps of mp4 and time_scale / num_units_in_tick) in -c copy to mp4 with -r 29.97002997 and without.

There were quite a lot of similar bugs in that regard, but Annex B to mp4 is a clear case and is a clear bug.

Patches should be submitted to the ffmpeg-devel mailing list and not this bug tracker.

Change History (10)

comment:1 by Balling, 23 months ago

Description: modified (diff)

comment:2 by Balling, 15 months ago

Status: newopen

What I want is the file be default be as if ffmpeg.exe -r 30000/1001 -i example.h264 -c copy fnmafa3.mp4

is used...

For that you need to increase 30000/1001 precision.

comment:3 by Elon Musk, 15 months ago

Resolution: invalid
Status: openclosed

Issue is that your timebase is generic one that can not reproduce your fps perfectly, and .h264 does not store pts or timebase at all.

ffmpeg -i example.h264 -vf settb=1001/30000,vfrdet -f null -

This shows that file is "CFR", but that is meaningless as format never store timestamps or timebase, its just put by ffmpeg code so it can process it somehow.

comment:4 by Balling, 15 months ago

Priority: normalwish
Resolution: invalid
Status: closedreopened
Type: defectenhancement

Issue is that your timebase is generic one that can not reproduce your fps perfectly

I need 30k tbn, not 1200k tbn BY DEFAULT. Nice that you understand. Changing to feature request.

Why does it report

[mp4 @ 0000022d9775a040] Timestamps are unset in a packet for stream 0. This is deprecated and will stop working in the future. Fix your code to set the timestamps properly

That is just strange. What does "Fix your code" mean??

and .h264 does not store pts or timebase at all.

It does have timing SEI, but not in my sample. Anyway, it sets fixed_frame_rate_flag, yet after this genius remux it has CFR with a different frame rate. Like how strange is that.

Your command with -c copy reports:

Filtergraph 'settb=1001/30000' was defined for video output stream 0:0 but codec copy was selected.
Filtering and streamcopy cannot be used together.

So that is useless.

Last edited 15 months ago by Balling (previous) (diff)

comment:5 by Balling, 15 months ago

Issue is that your timebase is generic one

But we have fixed_frame_rate_flag set. So in reality we can assume it is CFR and THAT IS WHAT mov/mp4 muxer does. It sets Frame rate mode: Constant. Okay? Yet, because of bad code somewhere, it does paste 29.97 instead of 29.97002997. Okay?? This is what was happening with drop-frame timecode! That is why it is not used anymore.

That is why I said

For that you need to increase 30000/1001 precision.

Last edited 15 months ago by Balling (previous) (diff)

comment:6 by Elon Musk, 15 months ago

Component: undeterminedavformat

bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=1000
30000/1001
29.97002997002997002997002997002997002997002997002997002997002997002\
99700299700299700299700299700299700299700299700299700299700299700299\
70029970029970029970029970029970029970029970029970029970029970029970\
02997002997002997002997002997002997002997002997002997002997002997002\
99700299700299700299700299700299700299700299700299700299700299700299\
70029970029970029970029970029970029970029970029970029970029970029970\
02997002997002997002997002997002997002997002997002997002997002997002\
99700299700299700299700299700299700299700299700299700299700299700299\
70029970029970029970029970029970029970029970029970029970029970029970\
02997002997002997002997002997002997002997002997002997002997002997002\
99700299700299700299700299700299700299700299700299700299700299700299\
70029970029970029970029970029970029970029970029970029970029970029970\
02997002997002997002997002997002997002997002997002997002997002997002\
99700299700299700299700299700299700299700299700299700299700299700299\
700299700299700299700299700299700299700299700299700

So timebase could be set to reverse of detected framerate. Need to inspect this.

comment:7 by Balling, 15 months ago

That is just 29.(970029), periodic... The point is at some moment this becomes 29.97 which is wrong, and it is very simple to isolate as opposed to the whole mp4 to mp4 demux.

comment:8 by Balling, 11 months ago

So can you make 30k tbn the default in this case. Please?

comment:9 by Balling, 11 months ago

Owner: set to Elon Musk
Status: reopenedopen

Please?

comment:10 by Balling, 8 months ago

[trace_headers @ 0000027e73374480] 119 num_units_in_tick 00000000000000000000111110100100 = 4004
[trace_headers @ 0000027e73374480] 151 time_scale 00000000000000111010100110000000 = 240000
[trace_headers @ 0000027e73374480] 183 fixed_frame_rate_flag 1 = 1

My file has and that means 59.94 tbr is wrong. It is 59.9400599400... tbr, not 59.94 tbr.

Note: See TracTickets for help on using tickets.