SETTINGS
Appearance
Language
About

Settings

Select a category to the left.

Appearance

Theme

Light or dark? Choose how the site looks to you by clicking an image below.

Light Dark AMOLED

Language

Preferred Language

All content on blog.claranguyen.me is originally in UK English. However, if content exists in your preferred language, it will display as that instead. Feel free to choose that below. This will require a page refresh to take effect.

About

"blog.claranguyen.me" details

Domain Name: claranguyen.me
Site Version: 1.0.0
Last Updated: 2020/12/29
A software "solution" to recording HDR10 via Dxtory & FFmpeg
Thursday, May 28, 2020

On Black Friday last year, I got a pretty nice deal on an ultrawide HDR10 supported monitor by LG... so I bought two of them. One for my office at work, and one for home. It's definitely not a monitor used for mastering content, but it's a nice way to get into the world of HDR content creation. So, what can we do?

Well, as it turns out, there isn't a real way to record HDR at the moment via software (EDIT: Ok, maybe "Action!" can do it. I'll test that later). Content creators out there resort to using high quality capture cards to capture HDR10 gameplay. But why is there no software solution? Well, there is... sorta. But you have to get creative with it and manually do everything. For me, this is fine. I prefer being in full control in post. Let's experiment.

Extracting HDR Metadata from the monitor

Before mastering can be done on this monitor, we need to extract Colour Primaries and Display Luminance values from the monitor. Windows doesn't make this very obvious, but you can run dxdiag.exe via the command line and extract it from there. This can be done via:

Windows Batch Command
dxdiag.exe -t diagnostic.txt

Next, open up diagnostic.txt and search for "Display Luminance". If you have multiple monitors, this will appear multiple times. You can easily tell which is which by looking at nearby lines like "HDR Support", "Current Mode" (Screen Resolution), etc.

Generating HDR metadata string for FFmpeg

Now we have exactly what we need to embed HDR metadata into a final video file if gameplay is recorded onto this monitor. However, FFmpeg requires it to be in a specific format. Specifically this:

diagnostic.txt
  Color Primaries: Red(0.651367,0.332031), Green(0.306641,0.630859), Blue(0.150391,0.059570), White Point(0.313477,0.329102)
Display Luminance: Min Luminance = 0.010000, Max Luminance = 1499.000000, MaxFullFrameLuminance = 799.000000

will become this:

FFmpeg "master-display" string
G(15332,31543)B(7520,2978)R(32568,16602)WP(15674,16455)L(14990000,100)

Yikes!! What math is required to get those numbers? Well, don't worry about it. Instead, I wrote a nice little tool to generate the string for you with the dxdiag information. It's in my render_tools GitHub repo here. If you want to run this online (where you can put your monitor information in), here's a cpp.sh link.

Recording gameplay

We'll get back to FFmpeg in a bit. For now, we need footage to encode. I use Dxtory to record my gameplays. It is the closest a software recorder gets to capturing the original footage correctly. For video codec, I use UtVideo for "lossless" capture (more on this later). I use the default settings on it. For audio, I have a 7.1 setup, and a lot of games out there utilise all 8 channels (Modern Warfare supports up to 16). Dxtory can capture this losslessly as well via IEEE Float. Set it and you're good to go.

Here's my configuration. You don't need to understand the language. The UI is the same in English.

Now just go into a game and record some test footage. You'll get something that looks like this:

Does something look a little off to you? Maybe the footage is a little washed out? This is normal. In fact, it's the raw stream that is being sent to your monitor. The only problem is that it's lacking the HDR metadata, hence why it looks this way. Gee, don't we have that information? Yes we do. Let's embed it via FFmpeg.

Encoding via FFmpeg

Now for the fun part. Let's generate a MKV file straight from the AVI master with the HDR metadata embedded. For reference, this is all open source and available in my render_tools repo on GitHub here. If you don't want to hear an explanation, just scroll to the end of this section. I post the final command there that you can modify for your monitor.

This is not an FFmpeg tutorial. But for those who don't know how FFmpeg works, it's a command line swiss-army knife for media streams like video and audio. It supports basically every format I've thrown at it. If you need an AVI file converted to MP4, consider it done. WAV to MP3? Done. In a basic sense, it looks like this:

UNIX Command
UNIX> ffmpeg -i video.avi video.mp4

For archival of gameplay, I use the MKV container and encode videos via libx265 at CRF 16 with FLAC audio. YouTube accepts these. For that, you'll want a command that looks like this:

UNIX Command
UNIX> ffmpeg -i video.avi -c:v libx265 -pix_fmt yuv420p10le -crf 16 -c:a flac video.mkv

This command has a problem... it doesn't embed the HDR metadata. Recall that string we generated earlier? Now is the time to use it. That FFmpeg command is about to get very lengthy.

First, the HDR10 standard requires BT.2020 with a bit depth of 10. So we need to make sure the video outputs proper BT.2020 instead of BT.709. For this, we'll need the following arguments added to the ffmpeg command (put it after -pix_fmt yuv420p10le):

FFmpeg Command Line Arguments
-vf scale=out_color_matrix=bt2020:out_h_chr_pos=0:out_v_chr_pos=0,format=yuv420p10

Finally, we'll embed the HDR metadata extracted at the very beginning of this blog post. FFmpeg can pass parameters to the internal x265 encoder via -x265-params. We'll pass in the metadata there. Add this in the FFmpeg command after the previous addition that converted the colour space to BT.2020:

FFmpeg Command Line Arguments
-x265-params "colorprim=bt2020:colormatrix=bt2020nc:transfer=smpte2084:colormatrix=bt2020nc:hdr=1:info=1:repeat-headers=1:max-cll=0,0:master-display=G(15332,31543)B(7520,2978)R(32568,16602)WP(15674,16455)L(14990000,100)"

If you're lost, here is the final command:

UNIX Command
UNIX> ffmpeg -i video.avi -c:v libx265 -pix_fmt yuv420p10le -vf scale=out_color_matrix=bt2020:out_h_chr_pos=0:out_v_chr_pos=0,format=yuv420p10 -x265-params "colorprim=bt2020:colormatrix=bt2020nc:transfer=smpte2084:colormatrix=bt2020nc:hdr=1:info=1:repeat-headers=1:max-cll=0,0:master-display=G(15332,31543)B(7520,2978)R(32568,16602)WP(15674,16455)L(14990000,100)" -crf 16 -c:a flac video.mkv

Quite lengthy huh? I warned you. However, let's look at the MKV file it exported on the HDR display. Because HDR screenshots can't be displayed properly on an SDR monitor, this was converted from HDR10 back into SDR. Definitely not a perfect conversion, but you can see the difference.

Only one problem...

This method of capturing and encoding HDR10 video via Dxtory is not perfect. Far from it. Dxtory reads the screen as an 8 bit buffer. Meanwhile, the output bit depth the monitor gives is 10 bit. So we're already losing a lot of detail, going from 1024 levels of colour per channel (red, green, and blue) down to 256. For scenes in-game where there's lots of colour variety, the trained eye is going to see banding of colours. This is why I encourage recording to UtVideo over something like x264vfw. We're losing a lot of detail. No need to lose even more. For a way to visually see this, here's a diagram for 8 bit going to 4 bit and back:

Obviously, with 10 bit going to 8 bit and back won't have much of a dramatic impact unlike the one shown above. But it's still a loss of colour information. If there's a software recorder out there that can capture the screen buffer in 10 bit, that'll solve this. Until then, the only proper solution I can think of is to use a dedicated capture card that was made to capture HDR signals. But until then, it's a valid solution to recording HDR video with software and not a dedicated capture card. I'll take it.

Example Clip

Here is a test clip I recorded from when I unlocked a gold Model 680 shotgun in Modern Warfare. It was encoded with the very command shown above. YouTube accepts HDR10 videos and will generate SDR versions for people without HDR displays. It also allows surround sound (It stores a 5.1 stream that plays on TVs). If you have an iPhone X (or more recent), or a Samsung Galaxy S8/Note 8 (or more recent), those have HDR certified displays. It does make a difference.




Clara Nguyễn
Hi! I am a Vietnamese/Italian mix with a Master's Degree in Computer Science from UTK. I have been programming since I was 6 and love to write apps and tools to make people's lives easier. I also love to do photography and media production. Nice to meet you!


Blog Links
Post Archive
Affiliates/Cool People
Nigoli's Blog
Raas's Blog