[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