So, here is the result of my experimentation on orientexpress.hevc. In all cases, I am testing with plplay defaults and HDR peak detection enabled. I kept the peak percentile at 100.0%, to make sure we get only exact (not approximated) values.
Measured values:
- Max: 291.00 cd/mē (61.86% PQ)
- Avg: 4.34 cd/mē (23.80% PQ)
- (99.995% estimate: 263.55 cd/mē (60.81% PQ))
I then took the image and passed it through a grayscale operator using ImageMagick for analysis. For lack of anything better, I used the Rec709Luminance option, even though this is not entirely accurate (wrong gamma, wrong matrix coefficients on the BT.2020 image). So it should be taken only with a grain of salt. They are also only accurate to 8 bits (I disabled dithering to get consistent values), so there is about ~10 nits of rounding error towards the top end. Regardless, here are the measured values:
BT.2020 PQ input file:
Channel statistics:
Pixels: 2674210
Gray:
min: 11 (0.0431373)
max: 158 (0.619608)
mean: 60.9368 (0.238968)
median: 45 (0.176471)
standard deviation: 39.9296 (0.156587)
kurtosis: -0.991433
skewness: 0.709792
entropy: 0.93231
So the true maximum as measured by this method is 61.96% PQ. Slightly higher than what libplacebo was measuring, but given the inaccuracies inherent in the IM method, alongside the 8 bit rounding, the libplacebo result is more likely to be accurate. The mean as estimated by this process is 23.89% PQ, again matching (if slightly too high) what libplacebo measures.
Gamut mapped BT.709, output in PQ:
Channel statistics:
Pixels: 2674210
Gray:
min: 10 (0.0392157)
max: 158 (0.619608)
mean: 60.8102 (0.238471)
median: 45 (0.176471)
standard deviation: 39.9282 (0.156581)
kurtosis: -0.986014
skewness: 0.71678
entropy: 0.930441
After gamut mapping from BT.2020 to BT.709 we see that the max is still 61.96% and the mean is 23.84%. This is now a bit closer to the libplacebo measured values, probably because now we're using the correct matrix coefficients for the grayscale operator (BT.709) - even if the gamma is still wrong.
Tone mapped to SDR BT.2020, output in PQ:
Channel statistics:
Pixels: 2674210
Gray:
min: 10 (0.0392157)
max: 148 (0.580392)
mean: 58.6171 (0.229871)
median: 44 (0.172549)
standard deviation: 38.0244 (0.149115)
kurtosis: -1.04137
skewness: 0.679
entropy: 0.933258
The max has been reduced to 58.0392% PQ, or about 202.42 nits. This tracks well onto the 203 nits target. The new frame average brightness is 22.9871%, or 3.85 nits (down from 4.34 nits). This steps seems to be working as intended.
Gamut mapped SDR BT.709, output in PQ:
Channel statistics:
Pixels: 2674210
Gray:
min: 10 (0.0392157)
max: 146 (0.572549)
mean: 58.5102 (0.229452)
median: 44 (0.172549)
standard deviation: 38.0216 (0.149104)
kurtosis: -1.03707
skewness: 0.684922
entropy: 0.935584
After gamut mapping to BT.709 it appears the maximum has dropped down to 57.25% PQ, or 187.76 nits. This is substantially lower than 203 nits, but was evidently introduced as part of the headroom needed for perceptual gamut mapping. (In terms of 8 bit PQ values it is only lower by 2, so it's probably also distorted by rounding error) The frame average remains almost unchanged at around 22.94% PQ, or 3.83 nits.
Final SDR output:
Channel statistics:
Pixels: 2674210
Gray:
min: 4 (0.0156863)
max: 248 (0.972549)
mean: 59.4856 (0.233277)
median: 28 (0.109804)
standard deviation: 60.3931 (0.236836)
kurtosis: -0.468588
skewness: 1.03268
entropy: 0.868375
And in full color RGB:
Channel statistics:
Pixels: 2674210
Red:
min: 6 (0.0235294)
max: 255 (1)
mean: 67.0188 (0.262819)
median: 37 (0.145098)
standard deviation: 59.135 (0.231902)
kurtosis: -0.525254
skewness: 0.924761
entropy: 0.884698
Green:
min: 3 (0.0117647)
max: 255 (1)
mean: 56.4452 (0.221354)
median: 22 (0.0862745)
standard deviation: 61.4242 (0.240879)
kurtosis: -0.463476
skewness: 1.0606
entropy: 0.849128
Blue:
min: 0 (0)
max: 240 (0.941176)
mean: 55.7532 (0.21864)
median: 21 (0.0823529)
standard deviation: 62.118 (0.2436)
kurtosis: -0.118993
skewness: 1.2104
entropy: 0.819895
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 59.739 (0.234271)
median: 26.6667 (0.104575)
standard deviation: 60.8924 (0.238794)
kurtosis: -0.404202
skewness: 1.05152
entropy: 0.85124
So the final SDR output perfectly spans the pixel range 0-255, with the average pixel being 59.739 (or about 23.42% of the available value range, which is exactly what we'd expect given the input scene distribution).