View Full Version : Unable to detect frame count from Y4M header?
kypec
29th September 2017, 18:34
Hello guys,
I only recently started to use VapourSynth as a source for my encoding jobs and although pipe output from vspipe with Y4M header includes all necessary metadata about the video:Width: 720
Height: 576
Frames: 7625
FPS: 25/1 (25.000 fps)
Format Name: YUV420P8
Color Family: YUV
Sample Type: Integer
Bits: 8
SubSampling W: 1
SubSampling H: 1
x265 encoder complains that frame count is unknown when feeding from stdin. This is my command line:vspipe.exe --y4m video.vpy - | x265.exe --input - --y4m --preset veryslow --output-depth 10 --bitrate 200 --sar 64:45 --no-sao
and this is what encoder reports upon start:y4m [info]: 720x576 fps 25/1 i420p8 sar 64:45 unknown frame count
Can somebody explain why is it that x265 can't detect frame count from input Y4M header?
I'm running on Windows 8.1 64-bit. :thanks:
sneaker_ger
29th September 2017, 18:43
Y4M header doesn't include frame count. So vspipe knows but cannot pass this information on.
https://wiki.multimedia.cx/index.php/YUV4MPEG2
kypec
29th September 2017, 18:49
Aha, I see. What a shame though that developers didn't include such a basic meta information in the header. Anyway, I resolved that by using --frames argument for encoder.
nevcairiel
29th September 2017, 23:18
Why does the encoder even need to know this, anyway? :)
kypec
30th September 2017, 10:13
Why does the encoder even need to know this, anyway? :)
I would assume that knowing total count of frames allows encoder to better predict/distribute available bits across the whole video clip.
sneaker_ger
30th September 2017, 10:23
Neither x265 nor x264 make use of the frame count in that way. Using --frames doesn't change quality whatsoever.
MasterNobody
30th September 2017, 10:30
Mostly encoder needs it only to show progress % (and little bit for very short sequences ratecontrol and 2pass frame numbers check).
kypec
2nd October 2017, 08:50
Well, since I'm using 2-pass and want to have progress displayed and logged nicely during encoding I'll keep using --frames option. Also, I noticed that target bitrate was hit more precisely when encoder knew the frame count in advance.
littlepox
2nd October 2017, 09:16
Y4M is not a container format; use-cases for Y4M include serving streaming/recording...purposes, when naturally you don't know the exact frame count, or the true frame-count can easily deviate from what you indicated at the very beginning. So this is not a shame or bug that developers didn't include such a basic meta information in the header; this is a feature.
--frames is what you should use if you know the exact frame count ahead.
sneaker_ger
2nd October 2017, 09:34
Also, I noticed that target bitrate was hit more precisely when encoder knew the frame count in advance.
It isn't.
kypec
2nd October 2017, 13:48
Seems that you are right, this time my tests finished another way round i.e. encoding without --frames switch hit the target bitrate more precisely.
Anyway, I remember that x264 processing should be deterministic when no VBV related options are specified. However, my two consecutive tests, both using the same source and same command line options:x264 --demuxer y4m - --preset veryslow --tune animation --bitrate 320 --sar 64:45 yielded slightly different results, especially in macroblock distribution:
first test roundy4m [info]: 720x576p 64:45 @ 25/1 fps (cfr)
x264 [info]: using SAR=64/45
x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
x264 [info]: profile High, level 4.0
x264 [info]: frame I:67 Avg QP:12.63 size: 34462
x264 [info]: frame P:2022 Avg QP:18.67 size: 3595
x264 [info]: frame B:5536 Avg QP:20.44 size: 483
x264 [info]: consecutive B-frames: 5.8% 5.5% 11.7% 30.9% 14.6% 13.2% 5.7% 1.7% 2.2% 1.4% 7.2%
x264 [info]: mb I I16..4: 50.3% 18.8% 30.9%
x264 [info]: mb P I16..4: 0.5% 1.9% 0.7% P16..4: 8.8% 3.4% 3.1% 0.5% 0.2% skip:81.0%
x264 [info]: mb B I16..4: 0.0% 0.1% 0.0% B16..8: 6.6% 1.2% 0.3% direct: 0.1% skip:91.5% L0:54.5% L1:40.8% BI: 4.8%
x264 [info]: 8x8 transform intra:39.8% inter:21.8%
x264 [info]: direct mvs spatial:94.4% temporal:5.6%
x264 [info]: coded y,uvDC,uvAC intra: 20.9% 32.7% 30.3% inter: 1.3% 2.5% 2.1%
x264 [info]: i16 v,h,dc,p: 87% 8% 5% 0%
x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 24% 8% 64% 1% 1% 1% 1% 1% 1%
x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 32% 14% 20% 7% 6% 6% 5% 6% 5%
x264 [info]: i8c dc,h,v,p: 62% 20% 17% 2%
x264 [info]: Weighted P-Frames: Y:0.3% UV:0.1%
x264 [info]: ref P L0: 53.1% 3.7% 14.2% 6.5% 4.4% 3.7% 3.2% 2.1% 1.6% 1.5% 1.2% 1.1% 1.0% 0.9% 0.8% 0.7%
x264 [info]: ref B L0: 61.7% 15.1% 7.6% 3.7% 2.5% 2.2% 1.7% 1.0% 0.9% 0.8% 0.7% 0.6% 0.6% 0.4% 0.3%
x264 [info]: ref B L1: 94.6% 5.4%
x264 [info]: kb/s:321.31
encoded 7625 frames, 49.47 fps, 321.31 kb/s
second test roundy4m [info]: 720x576p 64:45 @ 25/1 fps (cfr)
x264 [info]: using SAR=64/45
x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
x264 [info]: profile High, level 4.0
x264 [info]: frame I:67 Avg QP:12.73 size: 34682
x264 [info]: frame P:2023 Avg QP:18.55 size: 3581
x264 [info]: frame B:5535 Avg QP:20.31 size: 486
x264 [info]: consecutive B-frames: 5.8% 5.5% 11.7% 31.0% 14.6% 13.2% 5.7% 1.7% 2.1% 1.4% 7.2%
x264 [info]: mb I I16..4: 47.1% 21.9% 30.9%
x264 [info]: mb P I16..4: 0.5% 1.8% 0.6% P16..4: 8.8% 3.4% 3.1% 0.5% 0.2% skip:81.1%
x264 [info]: mb B I16..4: 0.0% 0.1% 0.0% B16..8: 6.7% 1.2% 0.3% direct: 0.1% skip:91.5% L0:54.8% L1:40.4% BI: 4.8%
x264 [info]: 8x8 transform intra:41.0% inter:21.8%
x264 [info]: direct mvs spatial:94.2% temporal:5.8%
x264 [info]: coded y,uvDC,uvAC intra: 20.8% 32.7% 30.3% inter: 1.3% 2.5% 2.1%
x264 [info]: i16 v,h,dc,p: 87% 8% 6% 0%
x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 25% 7% 64% 1% 1% 1% 1% 0% 1%
x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 32% 14% 20% 7% 6% 6% 5% 6% 5%
x264 [info]: i8c dc,h,v,p: 62% 20% 17% 2%
x264 [info]: Weighted P-Frames: Y:0.3% UV:0.1%
x264 [info]: ref P L0: 53.1% 3.8% 14.2% 6.5% 4.5% 3.7% 3.1% 2.0% 1.6% 1.5% 1.3% 1.1% 1.0% 0.9% 0.8% 0.7%
x264 [info]: ref B L0: 61.6% 15.3% 7.6% 3.7% 2.5% 2.2% 1.6% 1.0% 0.9% 0.8% 0.8% 0.6% 0.6% 0.4% 0.3%
x264 [info]: ref B L1: 94.6% 5.4%
x264 [info]: kb/s:321.61
encoded 7625 frames, 46.87 fps, 321.61 kb/s
How come? :stupid:
sneaker_ger
2nd October 2017, 16:08
Good question. I don't think that's supposed to happen. Are you sure everything was 100% identical? Same x264 binary? Your hardware is ok? The script wasn't changed? The source filter is stable/frame-accurate?
Seems that you are right, this time my tests finished another way round i.e. encoding without --frames switch hit the target bitrate more precisely.
No, I mean there should be no difference at all. (Except frame number written as metadata with x265. You can turn off with --no-info for tests.)
LoRd_MuldeR
2nd October 2017, 17:25
Aha, I see. What a shame though that developers didn't include such a basic meta information in the header. Anyway, I resolved that by using --frames argument for encoder.
Y4M is an uncompressed format, which (except for the header) only contains "raw" data. Therefore it is trivial to compute the total number of frames from the file size - which, of course, is only possible with physical files. But with pipes you have another problem anyway: Most encoders/muxers are implemented with a "stream" API. This means that you can feed the encoder/muxer with an arbitrary number frames without the need to "announce" the total number of frames beforehand. You just repeatedly call processNextFrame(), or the like, until you are done. This, of course, means that the encoder/muxer won't know the total number of frames until the very end! So, if the file format requires that the total number of frames is stored in a header at the beginning of the file, the encoder/muxer will have to seek back to the beginning of the file and "update" the size field - once all frames have been processed. Clearly, seeking backwards is only possible with physical files, not pipes. Therefore, file formats that require the total number of frames to be stored at the beginning are inappropriate for streaming (e.g. passing via pipe). Or they require some very ugly hacks to make streaming (e.g. passing via pipe) possible - such as passing a "fake" size field and sincerely hoping that the reading application will do the "right" thing. AVI and WAV format are some examples here. Y4M was probably designed in such a way to avoid this kind of problems/hacks...
kypec
2nd October 2017, 19:31
Good question. I don't think that's supposed to happen. Are you sure everything was 100% identical? Same x264 binary? Your hardware is ok? The script wasn't changed? The source filter is stable/frame-accurate?
Yes, the same binary and the same VS script was used:import vapoursynth as vs
core = vs.get_core()
video = core.ffms2.Source(source)
video = core.std.SetFieldBased(video, 0)
video = core.std.Crop(video, 0, 0, 0, 2)
video = core.resize.Spline36(video, 720, 576)
video.set_output()
The source filter is stable/frame-accurate?
Hard to say but I have used the latest experimental FFMS2 (https://forum.doom9.org/showthread.php?p=1802130#post1802130) build by Myrsloik. Input file is matroska MPEG2 ripped from DVD with MakeMKV tool. Hence, I'd suppose it should be fairly stable & accurate.:(
sneaker_ger
2nd October 2017, 20:04
You could write to an y4m file to rule out such problems.
kypec
3rd October 2017, 08:31
Yep, it looks like FFMS2 source filter is not deterministic i.e. stable and frame-accurate even though no seeking was involved, just a linear feed...
I ran two tests:vspipe.exe --arg "source=title01.mkv" --y4m video_720x576.vpy test.y4m
and result Y4M files differ according to MD5 or SHA-256 hashes. :mad:
What other VapourSynth source filter do you recommend to use for MKV inputs?
nevcairiel
3rd October 2017, 08:33
Unless VS uses dithering as part of its scaling operation (which often uses random data), that doesn't really make sense. Video decoding should be quite deterministic, even if you were to seek.
kypec
3rd October 2017, 09:44
Good idea nev, but it just looks that FFMS2 plugin is indeed not stable/frame-accurate. I have disabled dithering explicitly (because it is not clear which dithering method is used by default)video = core.resize.Spline36(video, 720, 576, dither_type="none") yet output file checksums were still different.
Then I have tried to replace the source filter with latest L-SMASHvideo = core.lsmas.LWLibavSource('title01.mkv') and finally the output files were giving consistent checksums. ;)
Well, further testing proved that default resizer dithering method is "none" which simplifies script writing a bit.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.