PR #25528 opened by JuliusBairaktaris
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25528
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25528.patch

`av_amf_display_mastering_meta_to_hdrmeta()` converts the mastering display 
primaries, white point and luminances with a truncating cast of the `av_q2d()` 
product. Values that are exact in AMF's units therefore come out one lower: a 
red y of 0.292 (14600/50000) is written as 14599, and a white point x of 0.3127 
as 15634. A zero denominator also turns into an out-of-range float-to-int cast.

This patch converts with `av_rescale()`, which rounds to nearest, and treats a 
zero or negative value as 0.

Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029: P010 frames carrying 
BT.2020/D65 primaries and 1000/0.005 cd/m² mastering luminance, encoded through 
the API with `hevc_amf`, give a mastering display SEI with exactly those values 
(14599 and 15634 before).

I found this while looking at #24227. The AV1 part of that issue is a separate 
AMF runtime bug: the AV1 encoder copies these values into the AV1 metadata OBU 
without converting units. I reported it as GPUOpen-LibrariesAndSDKs/AMF#633.

Written with Claude Opus 5.5 in Claude Code; `Assisted-by` trailer on the 
commit.



From abccb172d82db143e28047a767b1c44c2ada7a6c Mon Sep 17 00:00:00 2001
From: Julius Bairaktaris <[email protected]>
Date: Tue, 27 Oct 2026 15:51:09 +0100
Subject: [PATCH] avutil/hwcontext_amf: round the mastering display metadata

av_amf_display_mastering_meta_to_hdrmeta() converts the primaries, white
point and luminances with a truncating cast of the av_q2d() product, so
values that are exact in AMF's units come out one lower, e.g. a red y of
0.292 (14600/50000) is written as 14599, and a white point x of 0.3127
as 15634. A zero denominator also turns into an out-of-range cast.

Convert with av_rescale(), which rounds to nearest, and treat a zero or
negative value as 0.

Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029: frames carrying
BT.2020/D65 primaries and 1000/0.005 cd/m2 luminance give an HEVC
mastering display SEI with exactly those values from hevc_amf (14599 and
15634 before).

Assisted-by: Claude Opus 5.5
Signed-off-by: Julius Bairaktaris <[email protected]>
---
 libavutil/hwcontext_amf.c | 40 +++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c
index 7f47df5b59d..c62cae7157a 100644
--- a/libavutil/hwcontext_amf.c
+++ b/libavutil/hwcontext_amf.c
@@ -21,6 +21,7 @@
 #include "pixfmt.h"
 #include "pixdesc.h"
 #include "imgutils.h"
+#include "mathematics.h"
 #include "hwcontext.h"
 #include "hwcontext_amf.h"
 #include "hwcontext_internal.h"
@@ -183,37 +184,36 @@ enum AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM 
av_amf_get_color_profile(enum AVColo
     }
 }
 
+static amf_uint32 amf_q_to_units(AVRational q, int den, amf_uint32 max)
+{
+    if (q.num <= 0 || q.den <= 0)
+        return 0;
+    return FFMIN(av_rescale(q.num, den, q.den), max);
+}
+
 int av_amf_display_mastering_meta_to_hdrmeta(const AVMasteringDisplayMetadata 
*display_meta, AMFHDRMetadata *hdrmeta)
 {
     if (!display_meta || !hdrmeta)
         return AVERROR(EINVAL);
 
     if (display_meta->has_luminance) {
-        const unsigned int luma_den = 10000;
+        const int luma_den = 10000;
         hdrmeta->maxMasteringLuminance =
-            (amf_uint32)(luma_den * av_q2d(display_meta->max_luminance));
+            amf_q_to_units(display_meta->max_luminance, luma_den, UINT32_MAX);
         hdrmeta->minMasteringLuminance =
-            FFMIN((amf_uint32)(luma_den * 
av_q2d(display_meta->min_luminance)), hdrmeta->maxMasteringLuminance);
+            amf_q_to_units(display_meta->min_luminance, luma_den, 
hdrmeta->maxMasteringLuminance);
     }
 
     if (display_meta->has_primaries) {
-        const unsigned int chroma_den = 50000;
-        hdrmeta->redPrimary[0] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->display_primaries[0][0])), chroma_den);
-        hdrmeta->redPrimary[1] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->display_primaries[0][1])), chroma_den);
-        hdrmeta->greenPrimary[0] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->display_primaries[1][0])), chroma_den);
-        hdrmeta->greenPrimary[1] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->display_primaries[1][1])), chroma_den);
-        hdrmeta->bluePrimary[0] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->display_primaries[2][0])), chroma_den);
-        hdrmeta->bluePrimary[1] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->display_primaries[2][1])), chroma_den);
-        hdrmeta->whitePoint[0] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->white_point[0])), chroma_den);
-        hdrmeta->whitePoint[1] =
-            FFMIN((amf_uint16)(chroma_den * 
av_q2d(display_meta->white_point[1])), chroma_den);
+        const int chroma_den = 50000;
+        hdrmeta->redPrimary[0]   = 
amf_q_to_units(display_meta->display_primaries[0][0], chroma_den, chroma_den);
+        hdrmeta->redPrimary[1]   = 
amf_q_to_units(display_meta->display_primaries[0][1], chroma_den, chroma_den);
+        hdrmeta->greenPrimary[0] = 
amf_q_to_units(display_meta->display_primaries[1][0], chroma_den, chroma_den);
+        hdrmeta->greenPrimary[1] = 
amf_q_to_units(display_meta->display_primaries[1][1], chroma_den, chroma_den);
+        hdrmeta->bluePrimary[0]  = 
amf_q_to_units(display_meta->display_primaries[2][0], chroma_den, chroma_den);
+        hdrmeta->bluePrimary[1]  = 
amf_q_to_units(display_meta->display_primaries[2][1], chroma_den, chroma_den);
+        hdrmeta->whitePoint[0]   = 
amf_q_to_units(display_meta->white_point[0], chroma_den, chroma_den);
+        hdrmeta->whitePoint[1]   = 
amf_q_to_units(display_meta->white_point[1], chroma_den, chroma_den);
     }
 
     return 0;
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to