-
Notifications
You must be signed in to change notification settings - Fork 0
/
hdr-diff.lavfi
87 lines (74 loc) · 4.05 KB
/
hdr-diff.lavfi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# This is a ffmpeg filtergraph: https://ffmpeg.org/ffmpeg-filters.html
#
# Note that the usual filtergraph "language" doesn't support comments. Lines
# beginning with "#", such as these, need to be filtered out before parsing.
[vid1] null@rename_hdr [hdr_original];
[vid2] null@rename_sdr [sdr_original];
[hdr_original]
scale@scale_hdr = width=1920:height=-1,
# Force `scale` to preserve 10-bit bit depth; it outputs 8-bit otherwise.
format@scale_hdr_preserve_10bit = yuv420p10,
# Handle weird heights by adding black bars so that the output is a
# predicable, fixed size.
pad@pad_hdr = height=1080:y=in_h/2
[hdr_scaled];
[sdr_original]
# This is expected to be a no-op since the SDR input is likely already
# 1080p, but let's make sure of it.
scale@scale_sdr = width=1920:height=-1,
format@scale_sdr_preserve_10bit = yuv420p10,
pad@pad_sdr = height=1080:y=in_h/2
[sdr_scaled];
[sdr_scaled]
# Convert the SDR video to HDR10 (as is - no expansion).
#
# `npl` is the luminance that 100% SDR white will be mapped to and
# determines the overall brightness of the SDR side.
#
# TODO: zimg explicitly states that it is not a "color management system"
# and should not be used for "drastic" gamut changes, so the accuracy of
# this transform is unlikely to be good. Unfortunately it doesn't look like
# we have any other choice, aside from perhaps generating our own LUTs on
# the side.
zscale@convert_sdr_to_hdr10 = npl=150 : primaries=2020 : transfer=smpte2084 : matrix=2020_ncl,
# Force `zscale` to output 10-bit to avoid banding during the conversion.
format@sdr_hdr10_force_10bit = yuv420p10
[sdr_scaled_hdr10];
[hdr_scaled] split@split_hdr [hdr_scaled_planes] [hdr_scaled_monitor];
[sdr_scaled_hdr10] split@split_sdr [sdr_scaled_hdr10_planes] [sdr_scaled_hdr10_monitor];
[hdr_scaled_planes] extractplanes@extractplanes_hdr = y+u+v [hdr_scaled_y] [hdr_scaled_u] [hdr_scaled_v];
[sdr_scaled_hdr10_planes] extractplanes@extractplanes_sdr = y+u+v [sdr_scaled_y] [sdr_scaled_u] [sdr_scaled_v];
[hdr_scaled_y] split@split_hdr_y [hdr_scaled_y1] [hdr_scaled_y2];
[hdr_scaled_y1] [sdr_scaled_y]
blend@diff_y = subtract,
# Make the luma difference more obvious.
lut@brighten_diff_y = y=val*2
[diff_y];
# Generate a saturation stream from the two chroma planes.
# This is done by calculating the 2D distance to the UV center point (i.e.
# white).
# TODO: this is likely overly naive from a perceptual perspective.
# We then apply a multiplicative factor to make better use of the available
# dynamic range. TODO: it might be simpler (and certainly more accurate!) to use
# a floating point pixel format.
[hdr_scaled_u] [hdr_scaled_v] lut2@saturation_hdr = c0=(sqrt((x-2^(bdx-1))^2+(y-2^(bdy-1))^2))*10 [hdr_scaled_saturation];
[sdr_scaled_u] [sdr_scaled_v] lut2@saturation_sdr = c0=(sqrt((x-2^(bdx-1))^2+(y-2^(bdy-1))^2))*10 [sdr_scaled_saturation];
[hdr_scaled_saturation] [sdr_scaled_saturation]
blend@diff_saturation = subtract,
# Make the saturation difference more obvious.
lut@brighten_diff_saturation = y=val*20,
# The saturation stream has the same size as chroma planes, which are
# smaller than the video. Scale it back.
scale@scale_diff_saturation = size=hd1080,
format@scale_diff_saturation_format = yuv420p10
[diff_saturation];
# Scale the saturation difference using HDR luma. This emphasizes saturation
# differences in bright pixels (more noticeable) while avoiding noise caused by
# differences in dark pixels (not noticeable).
# TODO: once again this is perceptually dubious. At the end of the day, what
# would be ideal would be to simply compute the color dE for every pixel...
[hdr_scaled_y2] lut@brighten_hdr_for_sat = y=val/4 [hdr_scaled_y2_adjusted];
[diff_saturation] [hdr_scaled_y2_adjusted] blend@adjust_saturation = multiply [diff_saturation_adjusted];
[hdr_scaled_monitor] [sdr_scaled_hdr10_monitor] vstack@stack_monitor_column [monitor_column];
[diff_y] [diff_saturation_adjusted] vstack@stack_diff_column [diff_column];
[monitor_column] [diff_column] hstack@stack_columns [vo]