diff mbox series

[FFmpeg-devel] avcodec/pngdec: improve handling of bad cICP range tags

Message ID 20231212194101.461371-1-leo.izen@gmail.com
State Accepted
Commit 4013b8d3f04966338267aecee2ac7d23ed2064b5
Headers show
Series [FFmpeg-devel] avcodec/pngdec: improve handling of bad cICP range tags | 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 Dec. 12, 2023, 7:41 p.m. UTC
FFmpeg doesn't support tv-range RGB throughout most of its pipeline, so
we should keep the warning. However, in case something does support it
we should at least keep it tagged properly. Additionally, the encoder
writes this tag if the space is tagged as such so this makes a round
trip work as it should.

Also, PNG doesn't support nonzero matrices but we only warn and ignore
in that case, so we have no reason to error out for illegal cICP ranges
either (i.e. greater than 1).

Signed-off-by: Leo Izen <leo.izen@gmail.com>
Reported-by: Kacper Michajłow <kasper93@gmail.com>
---
 libavcodec/pngdec.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index d812ffd348..d1aae4c70e 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -661,8 +661,13 @@  static int populate_avctx_color_fields(AVCodecContext *avctx, AVFrame *frame)
             av_log(avctx, AV_LOG_WARNING, "unrecognized cICP transfer\n");
         else
             avctx->color_trc = frame->color_trc = s->cicp_trc;
-        if (s->cicp_range == 0)
-            av_log(avctx, AV_LOG_WARNING, "unsupported tv-range cICP chunk\n");
+        if (s->cicp_range == 0) {
+            av_log(avctx, AV_LOG_WARNING, "tv-range cICP tag found. Colors may be wrong\n");
+            avctx->color_range = frame->color_range = AVCOL_RANGE_MPEG;
+        } else if (s->cicp_range != 1) {
+            /* we already printed a warning when parsing the cICP chunk */
+            avctx->color_range = frame->color_range = AVCOL_RANGE_UNSPECIFIED;
+        }
     } else if (s->iccp_data) {
         AVFrameSideData *sd = av_frame_new_side_data(frame, AV_FRAME_DATA_ICC_PROFILE, s->iccp_data_len);
         if (!sd)
@@ -713,9 +718,10 @@  static int populate_avctx_color_fields(AVCodecContext *avctx, AVFrame *frame)
             avctx->color_trc = frame->color_trc = AVCOL_TRC_LINEAR;
     }
 
-    /* we only support pc-range RGB */
+    /* PNG only supports RGB */
     avctx->colorspace = frame->colorspace = AVCOL_SPC_RGB;
-    avctx->color_range = frame->color_range = AVCOL_RANGE_JPEG;
+    if (!s->have_cicp || s->cicp_range == 1)
+        avctx->color_range = frame->color_range = AVCOL_RANGE_JPEG;
 
     /*
      * tRNS sets alpha depth to full, so we ignore sBIT if set.
@@ -1455,11 +1461,8 @@  static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
             if (bytestream2_get_byte(&gb_chunk) != 0)
                 av_log(avctx, AV_LOG_WARNING, "nonzero cICP matrix\n");
             s->cicp_range = bytestream2_get_byte(&gb_chunk);
-            if (s->cicp_range != 0 && s->cicp_range != 1) {
-                av_log(avctx, AV_LOG_ERROR, "invalid cICP range: %d\n", s->cicp_range);
-                ret = AVERROR_INVALIDDATA;
-                goto fail;
-            }
+            if (s->cicp_range != 0 && s->cicp_range != 1)
+                av_log(avctx, AV_LOG_WARNING, "invalid cICP range: %d\n", s->cicp_range);
             s->have_cicp = 1;
             break;
         case MKTAG('s', 'R', 'G', 'B'):
@@ -1814,8 +1817,6 @@  static av_cold int png_dec_init(AVCodecContext *avctx)
 {
     PNGDecContext *s = avctx->priv_data;
 
-    avctx->color_range = AVCOL_RANGE_JPEG;
-
     s->avctx = avctx;
     s->last_picture.f = av_frame_alloc();
     s->picture.f = av_frame_alloc();