summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Izen <leo.izen@gmail.com>2024-02-04 04:35:58 -0500
committerLeo Izen <leo.izen@gmail.com>2024-02-11 08:58:00 -0500
commit78949041417caaef0c82b2b23d7defdd88aa2378 (patch)
tree1537cd4b7b0155a3eb5effcc835e67b58898e886
parentc7a57b0f70f8d1574aa0f0dbe98db85d8ac91c76 (diff)
avcodec/pngenc: write cLLi and mDVc chunks
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>
-rw-r--r--libavcodec/pngenc.c32
1 files changed, 29 insertions, 3 deletions
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))