From 14c712eb2a7c3b92f83c6edd0115d6eefccac476 Mon Sep 17 00:00:00 2001
From: Pavel Skakov <pavelsx@gmail.com>
Date: Fri, 4 Oct 2019 21:12:19 +0300
Subject: [PATCH] avcodec/tiff: add limited support for ReferenceBlackWhite and
YCbCrCoefficients tags
Signed-off-by: Pavel Skakov <pavelsx@gmail.com>
---
libavcodec/tiff.c | 73 ++++++++++++++++++++++++++++++++++++++++--
tests/ref/fate/exif-image-tiff | 2 +-
2 files changed, 72 insertions(+), 3 deletions(-)
@@ -1216,6 +1216,13 @@ static void set_sar(TiffContext *s, unsigned tag, unsigned num, unsigned den)
}
}
+static int r_near(unsigned n1, unsigned d1, unsigned n2, unsigned d2)
+{
+ uint64_t v1 = (uint64_t)n1*d2;
+ uint64_t v2 = (uint64_t)n2*d1;
+ return v2 - d1 < v1 && v1 < v2 + d1;
+}
+
static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
{
unsigned tag, type, count, off, value = 0, value2 = 1; // value2 is a denominator so init. to 1
@@ -1441,12 +1448,16 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
break;
case TIFF_PHOTOMETRIC:
switch (value) {
+ case TIFF_PHOTOMETRIC_YCBCR:
+ s->avctx->colorspace = AVCOL_SPC_BT470BG;
+ // fallthrough
+ case TIFF_PHOTOMETRIC_RGB:
+ s->avctx->color_range = AVCOL_RANGE_JPEG;
+ // fallthrough
case TIFF_PHOTOMETRIC_WHITE_IS_ZERO:
case TIFF_PHOTOMETRIC_BLACK_IS_ZERO:
- case TIFF_PHOTOMETRIC_RGB:
case TIFF_PHOTOMETRIC_PALETTE:
case TIFF_PHOTOMETRIC_SEPARATED:
- case TIFF_PHOTOMETRIC_YCBCR:
case TIFF_PHOTOMETRIC_CFA:
case TIFF_PHOTOMETRIC_LINEAR_RAW: // Used by DNG images
s->photometric = value;
@@ -1519,6 +1530,64 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
}
}
break;
+ case TIFF_YCBCR_COEFFICIENTS:
+ if (s->photometric == TIFF_PHOTOMETRIC_YCBCR)
+ if (count != 3 || type != TIFF_RATIONAL) {
+ av_log(s->avctx, AV_LOG_ERROR, "YCbCrCoefficients are invalid\n");
+ return AVERROR_INVALIDDATA;
+ } else {
+ unsigned c[6];
+ for (i = 0; i < 6; i++)
+ c[i] = ff_tget(&s->gb, TIFF_LONG, s->le);
+ if (r_near(c[0], c[1], 2125, 10000) && r_near(c[2], c[3], 7154, 10000) && r_near(c[4], c[5], 721, 10000))
+ s->avctx->colorspace = AVCOL_SPC_BT709;
+ else if (!r_near(c[0], c[1], 299, 1000) || !r_near(c[2], c[3], 587, 1000) || !r_near(c[4], c[5], 114, 1000)) {
+ av_log(s->avctx, AV_LOG_WARNING, "Unrecognized YCbCrCoefficients values: %.4f %.4f %.4f\n", (float)c[0]/c[1], (float)c[2]/c[3], (float)c[4]/c[5]);
+ s->avctx->colorspace = AVCOL_SPC_UNSPECIFIED;
+ }
+ }
+ break;
+ case TIFF_REFERENCE_BW:
+ if (s->photometric == TIFF_PHOTOMETRIC_YCBCR || s->photometric == TIFF_PHOTOMETRIC_RGB)
+ if (count != 6 || type != TIFF_RATIONAL) {
+ av_log(s->avctx, AV_LOG_ERROR, "ReferenceBlackWhite is invalid\n");
+ return AVERROR_INVALIDDATA;
+ } else {
+ unsigned bpp = s->bpp/s->bppcount;
+ uint64_t mul = 1 << (bpp - 8);
+ uint64_t max_val = (1 << bpp) - 1;
+ uint64_t mid_val = 1 << (bpp - 1);
+ unsigned c[12];
+ for (i = 0; i < 12; i++)
+ c[i] = ff_tget(&s->gb, TIFF_LONG, s->le);
+ if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) {
+ if (!c[0] && c[2] == max_val*c[3] && c[4] == mid_val*c[5] && c[6] == max_val*c[7] && c[8] == mid_val*c[9] && c[10] == max_val*c[11])
+ s->avctx->color_range = AVCOL_RANGE_JPEG;
+ // NOTE: TIFF 6.0 specification has an example where it mistakenly shows TV range c[0] as 15
+ else if (c[0] == 16*mul*c[1] && c[ 2] == 235*mul*c[3] &&
+ c[4] == 128*mul*c[5] && c[ 6] == 240*mul*c[7] &&
+ c[8] == 128*mul*c[9] && c[10] == 240*mul*c[11])
+ s->avctx->color_range = AVCOL_RANGE_MPEG;
+ else {
+ av_log(s->avctx, AV_LOG_WARNING, "Unrecognized ReferenceBlackWhite values: [%g;%g] [%g;%g] [%g;%g]\n",
+ (float)c[0]/c[1], (float)c[2]/c[3], (float)c[4]/c[5], (float)c[6]/c[7], (float)c[8]/c[9], (float)c[10]/c[11]);
+ s->avctx->color_range = AVCOL_RANGE_UNSPECIFIED;
+ }
+ } else {
+ if (!c[0] && c[2] == max_val*c[3] && !c[4] && c[6] == max_val*c[7] && !c[8] && c[10] == max_val*c[11])
+ s->avctx->color_range = AVCOL_RANGE_JPEG;
+ else if (c[0] == 16*mul*c[1] && c[ 2] == 235*mul*c[3] &&
+ c[4] == 16*mul*c[5] && c[ 6] == 235*mul*c[7] &&
+ c[8] == 16*mul*c[9] && c[10] == 235*mul*c[11])
+ s->avctx->color_range = AVCOL_RANGE_MPEG;
+ else {
+ av_log(s->avctx, AV_LOG_WARNING, "Unrecognized ReferenceBlackWhite values: [%g;%g] [%g;%g] [%g;%g]\n",
+ (float)c[0]/c[1], (float)c[2]/c[3], (float)c[4]/c[5], (float)c[6]/c[7], (float)c[8]/c[9], (float)c[10]/c[11]);
+ s->avctx->color_range = AVCOL_RANGE_UNSPECIFIED;
+ }
+ }
+ }
+ break;
case TIFF_T4OPTIONS:
if (s->compr == TIFF_G3)
s->fax_opts = value;
@@ -22,7 +22,7 @@ display_picture_number=0
interlaced_frame=0
top_field_first=0
repeat_pict=0
-color_range=unknown
+color_range=pc
color_space=unknown
color_primaries=unknown
color_transfer=unknown
--
2.13.2.windows.1