avcodec/decode: parse ICC profiles

Implementation for the decode side of the ICC profile API, roughly
matching the behavior of the existing vf_iccdetect filter.

Closes: #9673

Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
Niklas Haas 2022-06-28 15:15:40 +02:00
parent c688ddc067
commit 77f8dcb265
1 changed files with 56 additions and 5 deletions

View File

@ -49,10 +49,6 @@
#include "internal.h"
#include "thread.h"
#if CONFIG_LCMS2
# include "fflcms2.h"
#endif
static int apply_param_change(AVCodecContext *avctx, const AVPacket *avpkt)
{
int ret;
@ -508,6 +504,54 @@ FF_ENABLE_DEPRECATION_WARNINGS
return ret < 0 ? ret : 0;
}
#if CONFIG_LCMS2
static int detect_colorspace(AVCodecContext *avctx, AVFrame *frame)
{
AVCodecInternal *avci = avctx->internal;
enum AVColorTransferCharacteristic trc;
AVColorPrimariesDesc coeffs;
enum AVColorPrimaries prim;
cmsHPROFILE profile;
AVFrameSideData *sd;
int ret;
if (!(avctx->flags2 & AV_CODEC_FLAG2_ICC_PROFILES))
return 0;
sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE);
if (!sd || !sd->size)
return 0;
if (!avci->icc.avctx) {
ret = ff_icc_context_init(&avci->icc, avctx);
if (ret < 0)
return ret;
}
profile = cmsOpenProfileFromMemTHR(avci->icc.ctx, sd->data, sd->size);
if (!profile)
return AVERROR_INVALIDDATA;
ret = ff_icc_profile_read_primaries(&avci->icc, profile, &coeffs);
if (!ret)
ret = ff_icc_profile_detect_transfer(&avci->icc, profile, &trc);
cmsCloseProfile(profile);
if (ret < 0)
return ret;
prim = av_csp_primaries_id_from_desc(&coeffs);
if (prim != AVCOL_PRI_UNSPECIFIED)
frame->color_primaries = prim;
if (trc != AVCOL_TRC_UNSPECIFIED)
frame->color_trc = trc;
return 0;
}
#else /* !CONFIG_LCMS2 */
static int detect_colorspace(av_unused AVCodecContext *c, av_unused AVFrame *f)
{
return 0;
}
#endif
static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame)
{
int ret;
@ -528,7 +572,7 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
{
AVCodecInternal *avci = avctx->internal;
const FFCodec *const codec = ffcodec(avctx->codec);
int ret;
int ret, ok;
av_assert0(!frame->buf[0]);
@ -542,6 +586,13 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
if (ret == AVERROR_EOF)
avci->draining_done = 1;
/* preserve ret */
ok = detect_colorspace(avctx, frame);
if (ok < 0) {
av_frame_unref(frame);
return ok;
}
if (!(codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS) &&
IS_EMPTY(avci->last_pkt_props)) {
// May fail if the FIFO is empty.