[FFmpeg-devel] [PATCH] avcodec/tiff: add limited support for ReferenceBlackWhite and YCbCrCoefficients tags
James Almer
jamrial at gmail.com
Fri Oct 4 01:16:42 EEST 2019
On 10/3/2019 3:42 PM, Skakov Pavel wrote:
> Add support for properly handling PC/TV ranges and Rec601/Rec709 color
> spaces.
> Example for PC range YUV, compare to ImageMagick decoding:
> https://samples.ffmpeg.org/image-samples/dscf0013.tif
>
> 0001-avcodec-tiff-add-limited-support-for-ReferenceBlackW.patch
>
> From 5e24edbf73f3a897fd203e36963e9cf5db5e688d Mon Sep 17 00:00:00 2001
> From: Pavel Skakov <pavelsx at gmail.com>
> Date: Thu, 3 Oct 2019 21:28:10 +0300
> Subject: [PATCH] avcodec/tiff: add limited support for ReferenceBlackWhite and
> YCbCrCoefficients tags
>
> Signed-off-by: Pavel Skakov <pavelsx at gmail.com>
> ---
> libavcodec/tiff.c | 74 ++++++++++++++++++++++++++++++++++++++++--
> tests/ref/fate/exif-image-tiff | 2 +-
> 2 files changed, 73 insertions(+), 3 deletions(-)
>
> diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c
> index 8b39ca1ebc..90215fce09 100644
> --- a/libavcodec/tiff.c
> +++ b/libavcodec/tiff.c
> @@ -1441,12 +1441,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 +1523,72 @@ 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 {
> + // LibTIFF handles rational values by converting them to/from floats, so we do the same in tests for equality
> + float coef[3];
You should use AVRationals instead. It's ideal seeing the way these
values are coded in the bitstream.
See libavutil/rational.h
> + for (i = 0; i < 3; i++) {
> + unsigned num = ff_tget(&s->gb, TIFF_LONG, s->le);
> + unsigned den = ff_tget(&s->gb, TIFF_LONG, s->le);
> + if (!den) {
> + av_log(s->avctx, AV_LOG_ERROR, "YCbCrCoefficients divisor is zero\n");
> + return AVERROR_INVALIDDATA;
> + }
> + coef[i] = (float)num/den;
coef[i] = av_make_q(num, den);
> + }
> + if (coef[0] == 0.2125f && coef[1] == 0.7154f && coef[2] == 0.0721f)
if (av_cmp_q(coef[0], (AVRational) { 17, 80 }) && ...)
> + s->avctx->colorspace = AVCOL_SPC_BT709;
> + else if (coef[0] != 0.299f || coef[1] != 0.587f || coef[2] != 0.114f) {
> + av_log(s->avctx, AV_LOG_WARNING, "Unrecognized YCbCrCoefficients values: %.4f %.4f %.4f\n", coef[0], coef[1], coef[2]);
av_log(... "%.4f %.4f %.4f\n", av_q2d(coef[0]), av_q2d(coef[1]),
av_q2d(coef[2]));
etc.
> + 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;
> + unsigned mul = 1 << (bpp - 8);
> + float max_val = (1 << bpp) - 1;
> + float coef[6];
> + for (i = 0; i < 6; i++) {
> + unsigned num = ff_tget(&s->gb, TIFF_LONG, s->le);
> + unsigned den = ff_tget(&s->gb, TIFF_LONG, s->le);
> + if (!den) {
> + av_log(s->avctx, AV_LOG_ERROR, "ReferenceBlackWhite divisor is zero\n");
> + return AVERROR_INVALIDDATA;
> + }
> + coef[i] = (float)num/den;
> + }
> + if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) {
> + if (!coef[0] && coef[1] == max_val && coef[2] == (max_val + 1)/2 && coef[3] == max_val && coef[4] == coef[2] && coef[5] == coef[3])
> + s->avctx->color_range = AVCOL_RANGE_JPEG;
> + // NOTE: TIFF 6.0 specification has an example where it mistakenly shows TV range coef[0] as 15
> + else if (coef[0] == 16*mul && coef[1] == 235*mul && coef[2] == 128*mul && coef[3] == 240*mul && coef[4] == coef[2] && coef[5] == coef[3])
> + 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", coef[0], coef[1], coef[2], coef[3], coef[4], coef[5]);
> + s->avctx->color_range = AVCOL_RANGE_UNSPECIFIED;
> + }
> + } else {
> + if (!coef[0] && coef[1] == max_val && !coef[2] && coef[3] == max_val && !coef[4] && coef[5] == max_val)
> + s->avctx->color_range = AVCOL_RANGE_JPEG;
> + else if (coef[0] == 16*mul && coef[1] == 235*mul && coef[2] == coef[0] && coef[3] == coef[1] && coef[2] == coef[0] && coef[3] == coef[1])
> + 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", coef[0], coef[1], coef[2], coef[3], coef[4], coef[5]);
> + s->avctx->color_range = AVCOL_RANGE_UNSPECIFIED;
> + }
> + }
> + }
> + break;
> case TIFF_T4OPTIONS:
> if (s->compr == TIFF_G3)
> s->fax_opts = value;
> diff --git a/tests/ref/fate/exif-image-tiff b/tests/ref/fate/exif-image-tiff
> index 51580601e1..ebf2f38d6e 100644
> --- a/tests/ref/fate/exif-image-tiff
> +++ b/tests/ref/fate/exif-image-tiff
> @@ -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
>
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
>
More information about the ffmpeg-devel
mailing list