diff mbox series

[FFmpeg-devel,v2,6/6] avcodec/encode:: generate ICC profiles

Message ID 20220629101251.13236-7-ffmpeg@haasn.xyz
State New
Headers show
Series ICC profile support in avcodec | 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
andriy/make_armv7_RPi4 success Make finished
andriy/make_fate_armv7_RPi4 success Make fate finished

Commit Message

Niklas Haas June 29, 2022, 10:12 a.m. UTC
From: Niklas Haas <git@haasn.dev>

Only if requested, and only if the codec signals support for ICC
profiles. Implementation roughly matches the functionality of the
existing vf_iccgen filter, albeit with some reduced flexibility and no
caching.

Ideally, we'd also only do this on the first frame (e.g. mjpeg, apng),
but there's no meaningful way for us to distinguish between this case
and e.g. somebody using the image2 muxer, in which case we'd want to
attach ICC profiles to every frame in the stream.

Closes: #9672

Signed-off-by: Niklas Haas <git@haasn.dev>
---
 libavcodec/encode.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

Comments

Anton Khirnov July 6, 2022, 1:35 p.m. UTC | #1
Quoting Niklas Haas (2022-06-29 12:12:51)
> From: Niklas Haas <git@haasn.dev>
> 
> Only if requested, and only if the codec signals support for ICC
> profiles. Implementation roughly matches the functionality of the
> existing vf_iccgen filter, albeit with some reduced flexibility and no
> caching.
> 
> Ideally, we'd also only do this on the first frame (e.g. mjpeg, apng),
> but there's no meaningful way for us to distinguish between this case
> and e.g. somebody using the image2 muxer, in which case we'd want to
> attach ICC profiles to every frame in the stream.

AV_CODEC_FLAG_GLOBAL_HEADER?
Niklas Haas July 19, 2022, 12:18 p.m. UTC | #2
On Wed, 06 Jul 2022 15:35:41 +0200 Anton Khirnov <anton@khirnov.net> wrote:
> Quoting Niklas Haas (2022-06-29 12:12:51)
> > From: Niklas Haas <git@haasn.dev>
> > 
> > Only if requested, and only if the codec signals support for ICC
> > profiles. Implementation roughly matches the functionality of the
> > existing vf_iccgen filter, albeit with some reduced flexibility and no
> > caching.
> > 
> > Ideally, we'd also only do this on the first frame (e.g. mjpeg, apng),
> > but there's no meaningful way for us to distinguish between this case
> > and e.g. somebody using the image2 muxer, in which case we'd want to
> > attach ICC profiles to every frame in the stream.
> 
> AV_CODEC_FLAG_GLOBAL_HEADER?

This seems marginally unrelated - apng etc. don't have extradata, and
none of the relevant codecs set this flag either. At best we could
introduce a new flag, but to be honest I don't think it's a huge issue
because apng and mjpeg with ICC profiles are exceptionally rare, and the
worst case is merely wasting some file space.

> 
> -- 
> Anton Khirnov
diff mbox series

Patch

diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index b68bf1e184..d1fb6f3a75 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -308,6 +308,50 @@  static int encode_receive_packet_internal(AVCodecContext *avctx, AVPacket *avpkt
     return ret;
 }
 
+#if CONFIG_LCMS2
+static int encode_generate_icc_profile(AVCodecContext *avctx, AVFrame *frame)
+{
+    enum AVColorTransferCharacteristic trc = frame->color_trc;
+    enum AVColorPrimaries prim = frame->color_primaries;
+    const FFCodec *const codec = ffcodec(avctx->codec);
+    AVCodecInternal *avci = avctx->internal;
+    cmsHPROFILE profile;
+    int ret;
+
+    if (!avctx->icc_profiles || !(codec->caps_internal & FF_CODEC_CAP_ICC_PROFILES))
+        return 0; /* don't generate ICC profiles if disabled or unsupported */
+
+    if (trc == AVCOL_TRC_UNSPECIFIED)
+        trc = avctx->color_trc;
+    if (prim == AVCOL_PRI_UNSPECIFIED)
+        prim = avctx->color_primaries;
+    if (trc == AVCOL_TRC_UNSPECIFIED || prim == AVCOL_PRI_UNSPECIFIED)
+        return 0; /* can't generate ICC profile with missing csp tags */
+
+    if (av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE))
+        return 0; /* don't overwrite existing ICC profile */
+
+    if (!avci->icc.avctx) {
+        ret = ff_icc_context_init(&avci->icc, avctx);
+        if (ret < 0)
+            return ret;
+    }
+
+    ret = ff_icc_profile_generate(&avci->icc, prim, trc, &profile);
+    if (ret < 0)
+        return ret;
+
+    ret = ff_icc_profile_attach(&avci->icc, profile, frame);
+    cmsCloseProfile(profile);
+    return ret;
+}
+#else /* !CONFIG_LCMS2 */
+static int encode_generate_icc_profile(av_unused AVCodecContext *c, av_unused AVFrame *f)
+{
+    return 0;
+}
+#endif
+
 static int encode_send_frame_internal(AVCodecContext *avctx, const AVFrame *src)
 {
     AVCodecInternal *avci = avctx->internal;
@@ -352,6 +396,12 @@  static int encode_send_frame_internal(AVCodecContext *avctx, const AVFrame *src)
              return ret;
     }
 
+    if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
+        ret = encode_generate_icc_profile(avctx, dst);
+        if (ret < 0)
+            return ret;
+    }
+
     return 0;
 }