diff mbox series

[FFmpeg-devel,v2,2/2] avcodec/pngenc: write cLLi and mDVc chunks

Message ID 20240204093558.793427-3-leo.izen@gmail.com
State Accepted
Commit 78949041417caaef0c82b2b23d7defdd88aa2378
Headers show
Series PNG cLLi and mDVc chunk support | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Leo Izen Feb. 4, 2024, 9:35 a.m. UTC
These chunks contain the Content Light Level Information and the
Mastering Display Color Volume information that FFmpeg already supports
as AVFrameSideData. This patch adds support for the png encoder to save
this metadata as the corresponding chunks in the PNG stream.

Signed-off-by: Leo Izen <leo.izen@gmail.com>
---
 libavcodec/pngenc.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c
index f0650962d2..50689cb50c 100644
--- a/libavcodec/pngenc.c
+++ b/libavcodec/pngenc.c
@@ -32,6 +32,7 @@ 
 #include "libavutil/crc.h"
 #include "libavutil/csp.h"
 #include "libavutil/libm.h"
+#include "libavutil/mastering_display_metadata.h"
 #include "libavutil/opt.h"
 #include "libavutil/rational.h"
 #include "libavutil/stereo3d.h"
@@ -294,8 +295,9 @@  static int png_write_row(AVCodecContext *avctx, const uint8_t *data, int size)
     return 0;
 }
 
-#define AV_WB32_PNG(buf, n) AV_WB32(buf, lrint((n) * 100000))
-#define AV_WB32_PNG_D(buf, d) AV_WB32_PNG(buf, av_q2d(d))
+#define PNG_LRINT(d, divisor) lrint((d) * (divisor))
+#define PNG_Q2D(q, divisor) PNG_LRINT(av_q2d(q), (divisor))
+#define AV_WB32_PNG_D(buf, q) AV_WB32(buf, PNG_Q2D(q, 100000))
 static int png_get_chrm(enum AVColorPrimaries prim,  uint8_t *buf)
 {
     const AVColorPrimariesDesc *desc = av_csp_primaries_desc_from_id(prim);
@@ -320,7 +322,7 @@  static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf)
     if (gamma <= 1e-6)
         return 0;
 
-    AV_WB32_PNG(buf, 1.0 / gamma);
+    AV_WB32(buf, PNG_LRINT(1.0 / gamma, 100000));
     return 1;
 }
 
@@ -437,6 +439,30 @@  static int encode_headers(AVCodecContext *avctx, const AVFrame *pict)
         png_write_chunk(&s->bytestream, MKTAG('c', 'I', 'C', 'P'), s->buf, 4);
     }
 
+    side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
+    if (side_data) {
+        AVContentLightMetadata *clli = (AVContentLightMetadata *) side_data->data;
+        AV_WB32(s->buf, clli->MaxCLL * 10000);
+        AV_WB32(s->buf + 4, clli->MaxFALL * 10000);
+        png_write_chunk(&s->bytestream, MKTAG('c', 'L', 'L', 'i'), s->buf, 8);
+    }
+
+    side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
+    if (side_data) {
+        AVMasteringDisplayMetadata *mdvc = (AVMasteringDisplayMetadata *) side_data->data;
+        if (mdvc->has_luminance && mdvc->has_primaries) {
+            for (int i = 0; i < 3; i++) {
+                AV_WB16(s->buf + 2*i, PNG_Q2D(mdvc->display_primaries[i][0], 50000));
+                AV_WB16(s->buf + 2*i + 2, PNG_Q2D(mdvc->display_primaries[i][1], 50000));
+            }
+            AV_WB16(s->buf + 12, PNG_Q2D(mdvc->white_point[0], 50000));
+            AV_WB16(s->buf + 14, PNG_Q2D(mdvc->white_point[1], 50000));
+            AV_WB32(s->buf + 16, PNG_Q2D(mdvc->max_luminance, 10000));
+            AV_WB32(s->buf + 20, PNG_Q2D(mdvc->min_luminance, 10000));
+            png_write_chunk(&s->bytestream, MKTAG('m', 'D', 'V', 'c'), s->buf, 24);
+        }
+    }
+
     if (png_get_chrm(pict->color_primaries, s->buf))
         png_write_chunk(&s->bytestream, MKTAG('c', 'H', 'R', 'M'), s->buf, 32);
     if (png_get_gama(pict->color_trc, s->buf))