cdgriffith / FastFlix

FastFlix is a free GUI for H.264, HEVC and AV1 hardware and software encoding!
https://fastflix.org/
MIT License
1.14k stars 56 forks source link

How to encode HEVC HDR10 to SVT-AV1 HDR10 with HLS streams? #387

Open ghost opened 1 year ago

ghost commented 1 year ago

I'm currently trying to find a way to re-encode a HEVC HDR10 clip to SVT-AV1 HDR10 using ffmpeg but for some reason, I don't get ffmpeg to forward the HDR metadata to the AV1 clip. So the re-encoded AV1 clip always has very cold color grading, which does not make fun to watch at all...

I then checked onto FastFlix, If I select SVT-AV1 as encoder here, and I check onto the raw ffmpeg command FastFlix generates, it seems that this also includes the grading information:

-svtav1-params "color-primaries=9:transfer-characteristics=16:matrix-coefficients=9:mastering-display=G(0.2650,0.6900)B(0.1500,0.0600)R(0.6800,0.3200)WP(0.3127,0.3290)L(4000.0000,0.0050):content-light=368,226:enable-hdr=1"

The problem for me is now, how do I get these grading information with my own ffmpeg command?

Thanks in advance

cdgriffith commented 1 year ago

I grab the details from the first frame about the Mastering display metadata:

ffprobe -v quiet -loglevel panic -print_format json -select_streams 0 -show_frames -read_intervals %+#1 -show_entries frame=color_space,color_primaries,color_transfer,side_data_list,pix_fmt  <my_video>

It will have some output like:

{
    "frames": [
        {
            "pix_fmt": "yuv420p10le",
            "color_space": "bt2020nc",
            "color_primaries": "bt2020",
            "color_transfer": "smpte2084",
            "side_data_list": [
                {
                    "side_data_type": "Mastering display metadata",
                    "red_x": "34000/50000",
                    "red_y": "16000/50000",
                    "green_x": "13250/50000",
                    "green_y": "34500/50000",
                    "blue_x": "7500/50000",
                    "blue_y": "3000/50000",
                    "white_point_x": "15635/50000",
                    "white_point_y": "16450/50000",
                    "min_luminance": "50/10000",
                    "max_luminance": "10000000/10000"
                },
                {
                    "side_data_type": "Content light level metadata",
                    "max_content": 1000,
                    "max_average": 293
                }
            ]
        }
    ]
}

Then you just need to know how each encoder likes to take that data. SVT-AV1 likes it as a number not a fraction. So for example green_x of 13250/50000 becomes 13250 ÷ 50000 aka 0.265 and so on.

ghost commented 1 year ago

Adopting the following script into my codebase, has done exactly that:

https://pastebin.com/AZdKbPEL

The output will look something like this:


ffmpeghdr.py source.mkv
color_space:        bt2020nc
color_primaries:    bt2020
color_transfer:     smpte2084

x265:       G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(40000000,50):max-cll=10000,424
svt-av1:    G(0.265,0.69)B(0.15,0.06)R(0.68,0.32)WP(0.3127,0.329)L(4000.0,0.005):content-light=10000,424

What I do not understand at the moment is, that my command is now basically exactly as the one generated by FastFlix incl. grading information and just one pass not 2 pass encoding. If I chunk this into HLS segments using ffmpeg and trying to play it using VLC the color still looks way too cold compared to the HEVC output of the same encoding adaption set. Is grading information added at the end of an encoding job with AV1??? As I'm currently just pulling the first 5 seconds of the clip as it's still encoding in the background, and I'm wondering why the image looks so cold.