Message ID | 20220629101251.13236-7-ffmpeg@haasn.xyz |
---|---|
State | New |
Headers | show |
Series | ICC profile support in avcodec | expand |
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 |
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?
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 --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; }