Four problems have been brought up regarding HuffYUV encoding:
- Slow load time of long Matroska videos
- Slow seeking and editing of Matroska videos
- Preserve color space in metadata (AVI does not)
- Preserve color range in metadata (AVI does not)
I count four popular containers that can hold metadata:
- MP4 - But it can’t contain HuffYUV.
- MOV - But it doesn’t have a color range flag.
- MKV - But it’s horrifically slow at loading and editing.
- MXF - But it won’t do HuffYUV or store a color range flag.
I have tried every parameter that the Matroska muxer supports in ffmpeg, and none of them are a complete solution. The -live
option will load a 50 minute video instantly, but it is not seekable. So the next question is whether Matroska is really this slow as an overall format, or if the slowness is due to using Video for Windows codecs like HuffYUV.
I tested this by encoding the same 50 minute video as full-range DNxHR in MKV.
Trivia time: If you write HuffYUV or DNxHR into a Matroska file using ffmpeg, it’s actually making a MOV file with a Matroska wrapper. Matroska has explicit support for several popular containers including MPEG-4, MPEG-2, MOV, etc, and it’s actually the headers in those containers that hold the bulk of the metadata. Matroska’s EBML picks up wherever the stream headers leave off. See https://matroska.org/technical/specs/index.html
Since DNxHR is very MOV compatible and doesn’t go through VfW, I hoped it would edit faster in Matroska than HuffYUV. Nope, same slowness.
So, what if we cut out the Matroska middleman by writing HuffYUV directly to a MOV container? Bingo… It loads instantly, seeks instantly, and has color space metadata if you add movflags=+faststart+write_colr+use_metadata_tags
and write_tmcd=0
to the export preset. But there are two big problems… first, all video in a MOV file should be limited range because there is no flag to indicate full range, and second, the media players I tried were unable to play this HuffYUV-in-MOV file directly. It plays fine in Shotcut, though.
The MOV specification’s lack of support for color range signaling is the only thing stopping us from using it with HuffYUV and calling it a day. To get color range support, we need the EBML extension from Matroska. But then Matroska is too slow to edit. We’re basically stuck in a bad loop.
I see only two ways of getting everything we want on the wish list:
- DNxHR in a MOV, which allows for full or limited range
- Ut Video in an AVI, with all YUV video forced to limited range
Wait, full range DNxHR in a MOV? Yes, because DNxHR has its own ability to store color range without relying on the container. The other codecs do not (specifically the lossless VfW ones). Those codecs will let you store full-range data just fine, but then it gets interpreted as limited range when played back since MOV has no official way to indicate otherwise. That’s where the EBML tags in Matroska would have overridden to indicate full range.
As for Ut Video, we already know color space is indicated by the FourCC code. So long as all video is forced into limited range at time of encode, there will never be a color shift problem when decoding. HuffYUV will not work at lower resolutions because the lack of metadata will cause it to be interpreted as BT.601 color space when it might be BT.709 instead.
Overall, it may be time to give DNxHR more love than it’s gotten so far. It produces 4:2:2 files that are 50% smaller than HuffYUV, and playback uses 5-10% less CPU. The image quality is fantastic, it takes a heavy color grade before banding appears, and the output can survive several generations of transcoding. There’s a lot to like about it. Just remember to add the same two lines to the export preset that I listed above for HuffYUV in MOV.
@pdr, does all of this jive with your understanding, or did I give up too easily on Matroska and HuffYUV?
Last question… Does Shotcut happen to use swscale error diffusion or something similar to reduce banding when compressing full range sources to legal range during the export? I haven’t found a way to get the AviSynth SmoothLevels filter accessible in ffmpeg, which would be a cool option.
Random trick I learned along the way… I can use this ffmpeg command to quickly look at the raw luma samples in a YUV video to determine if the data itself is in full or limited range:
ffmpeg -hide_banner -ss 0:10 -i "input.mp4" -map 0:v:0 -frames:v 1 -filter:v? signalstats,metadata=mode=print:file=- -f null -
I run this command on the original and the transcoded videos. If the YLOW and YHIGH values are the same between videos, no range compression happened during the transcode.
References to MOV specification with no color range flag:
https://www.mail-archive.com/ffmpeg-user@ffmpeg.org/msg19491.html
https://www.mail-archive.com/ffmpeg-user@ffmpeg.org/msg19495.html
https://developer.apple.com/library/archive/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG7-SCHEME_B___VIDEO_RANGE__MAPPING_WITH_UNSIGNED_Y____OFFSET_BINARY_CB__CR