Message ID | 20190528183442.12376-1-velocityra@gmail.com |
---|---|
State | New |
Headers | show |
On 5/28/19, velocityra@gmail.com <velocityra@gmail.com> wrote: > From: Nick Renieris <velocityra@gmail.com> > > In DNG images with the .tiff extension, it solves the issue where the > TIFF thumbnail in IFD 0 was incorrectly parsed (related confusion: [1]). > Embedded thumbnails for DNG images can still be decoded with the added > "-dng_thumb" option. > > Additionally: > - Renamed TIFF_WHITE_LEVEL to DNG_WHITE_LEVEL since it is specified > in the DNG spec. > - Added/changed some comments to be more precise in differentiating > between TIFF, TIFF/EP and DNG values. > > Related to ticket: https://trac.ffmpeg.org/ticket/4364 > This patch breaks decoding DNGs which are already supported. > --- > > [1]: > https://superuser.com/questions/546879/creating-video-from-dng-images-with-ffmpeg > > Signed-off-by: Nick Renieris <velocityra@gmail.com> > --- > libavcodec/tiff.c | 36 +++++++++++++++++++++++++++++++++++- > libavcodec/tiff.h | 18 +++++++++++++----- > libavformat/img2.c | 1 + > 3 files changed, 49 insertions(+), 6 deletions(-) > > diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c > index 79e6242549..9575fe92ce 100644 > --- a/libavcodec/tiff.c > +++ b/libavcodec/tiff.c > @@ -56,6 +56,7 @@ typedef struct TiffContext { > > int get_subimage; > uint16_t get_page; > + int get_dng_thumb; > > int width, height; > unsigned int bpp, bppcount; > @@ -70,7 +71,9 @@ typedef struct TiffContext { > int predictor; > int fill_order; > uint32_t res[4]; > + int is_thumbnail; > > + int dng_mode; /** denotes that this is a DNG image */ > int is_bayer; > uint8_t pattern[4]; > unsigned white_level; > @@ -948,6 +951,8 @@ static int tiff_decode_tag(TiffContext *s, AVFrame > *frame) > } > > switch (tag) { > + case TIFF_SUBFILE: > + s->is_thumbnail = (value != 0); > case TIFF_WIDTH: > s->width = value; > break; > @@ -1088,7 +1093,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame > *frame) > case TIFF_SUB_IFDS: > s->sub_ifd = value; > break; > - case TIFF_WHITE_LEVEL: > + case DNG_WHITE_LEVEL: > s->white_level = value; > break; > case TIFF_CFA_PATTERN_DIM: > @@ -1339,6 +1344,20 @@ static int tiff_decode_tag(TiffContext *s, AVFrame > *frame) > case TIFF_SOFTWARE_NAME: > ADD_METADATA(count, "software", NULL); > break; > + case DNG_VERSION: > + if (count == 4) { > + unsigned int ver[4]; > + ver[0] = ff_tget(&s->gb, type, s->le); > + ver[1] = ff_tget(&s->gb, type, s->le); > + ver[2] = ff_tget(&s->gb, type, s->le); > + ver[3] = ff_tget(&s->gb, type, s->le); > + > + av_log(s->avctx, AV_LOG_DEBUG, "DNG file, version > %u.%u.%u.%u\n", > + ver[0], ver[1], ver[2], ver[3]); > + > + s->dng_mode = 1; > + } > + break; > default: > if (s->avctx->err_recognition & AV_EF_EXPLODE) { > av_log(s->avctx, AV_LOG_ERROR, > @@ -1387,6 +1406,7 @@ static int decode_frame(AVCodecContext *avctx, > s->le = le; > // TIFF_BPP is not a required tag and defaults to 1 > again: > + s->is_thumbnail = 0; > s->bppcount = s->bpp = 1; > s->photometric = TIFF_PHOTOMETRIC_NONE; > s->compr = TIFF_RAW; > @@ -1394,6 +1414,7 @@ again: > s->white_level = 0; > s->is_bayer = 0; > s->cur_page = 0; > + s->dng_mode = 0; > free_geotags(s); > > // Reset these offsets so we can tell if they were set this frame > @@ -1408,6 +1429,18 @@ again: > return ret; > } > > + if (s->dng_mode) { > + if (!s->get_dng_thumb) { > + av_log(avctx, AV_LOG_ERROR, "DNG images are not supported\n"); > + av_log(avctx, AV_LOG_INFO, "You can use -dng_thumb to decode an > embedded TIFF thumbnail (if any) instead\n"); > + return AVERROR_INVALIDDATA; > + } > + if (!s->is_thumbnail) { > + av_log(avctx, AV_LOG_INFO, "No embedded thumbnail present\n"); > + return AVERROR_EOF; > + } > + } > + > /** whether we should look for this IFD's SubIFD */ > retry_for_subifd = s->sub_ifd && s->get_subimage; > /** whether we should look for this multi-page IFD's next page */ > @@ -1671,6 +1704,7 @@ static av_cold int tiff_end(AVCodecContext *avctx) > static const AVOption tiff_options[] = { > { "subimage", "decode subimage instead if available", > OFFSET(get_subimage), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, > AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, > { "page", "page number of multi-page image to decode (starting from > 1)", OFFSET(get_page), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, > AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, > + { "dng_thumb", "decode TIFF thumbnail of DNG image", > OFFSET(get_dng_thumb), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, > AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, > { NULL }, > }; > > diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h > index 4b08650108..3cede299f6 100644 > --- a/libavcodec/tiff.h > +++ b/libavcodec/tiff.h > @@ -20,7 +20,7 @@ > > /** > * @file > - * TIFF tables > + * TIFF constants & data structures > * > * For more information about the TIFF format, check the official docs at: > * http://partners.adobe.com/public/developer/tiff/index.html > @@ -33,7 +33,7 @@ > #include <stdint.h> > #include "tiff_common.h" > > -/** abridged list of TIFF tags */ > +/** abridged list of TIFF and TIFF/EP tags */ > enum TiffTags { > TIFF_SUBFILE = 0xfe, > TIFF_WIDTH = 0x100, > @@ -85,10 +85,17 @@ enum TiffTags { > TIFF_GEO_KEY_DIRECTORY = 0x87AF, > TIFF_GEO_DOUBLE_PARAMS = 0x87B0, > TIFF_GEO_ASCII_PARAMS = 0x87B1, > - TIFF_WHITE_LEVEL = 0xC61D, > }; > > -/** list of TIFF compression types */ > +/** abridged list of DNG tags */ > +enum DngTags > +{ > + DNG_VERSION = 0xC612, > + DNG_BACKWARD_VERSION = 0xC613, > + DNG_WHITE_LEVEL = 0xC61D, > +}; > + > +/** list of TIFF, TIFF/EP and DNG compression types */ > enum TiffCompr { > TIFF_RAW = 1, > TIFF_CCITT_RLE, > @@ -151,6 +158,7 @@ enum TiffGeoTagKey { > TIFF_VERTICAL_UNITS_GEOKEY = 4099 > }; > > +/** list of TIFF, TIFF/AP and DNG PhotometricInterpretation > (TIFF_PHOTOMETRIC) values */ > enum TiffPhotometric { > TIFF_PHOTOMETRIC_NONE = -1, > TIFF_PHOTOMETRIC_WHITE_IS_ZERO, /* mono or grayscale, 0 is white > */ > @@ -163,7 +171,7 @@ enum TiffPhotometric { > TIFF_PHOTOMETRIC_CIE_LAB = 8, /* 1976 CIE L*a*b* */ > TIFF_PHOTOMETRIC_ICC_LAB, /* ICC L*a*b* */ > TIFF_PHOTOMETRIC_ITU_LAB, /* ITU L*a*b* */ > - TIFF_PHOTOMETRIC_CFA = 32803, /* Color Filter Array (DNG) */ > + TIFF_PHOTOMETRIC_CFA = 32803, /* Color Filter Array (TIFF/AP and > DNG) */ > TIFF_PHOTOMETRIC_LOG_L = 32844, /* CIE Log2(L) */ > TIFF_PHOTOMETRIC_LOG_LUV, /* CIE Log L*u*v* */ > TIFF_PHOTOMETRIC_LINEAR_RAW = 34892, /* Linear Raw (DNG) */ > diff --git a/libavformat/img2.c b/libavformat/img2.c > index 8432cc0955..16bc9d2abd 100644 > --- a/libavformat/img2.c > +++ b/libavformat/img2.c > @@ -51,6 +51,7 @@ const IdStrMap ff_img_tags[] = { > { AV_CODEC_ID_TARGA, "tga" }, > { AV_CODEC_ID_TIFF, "tiff" }, > { AV_CODEC_ID_TIFF, "tif" }, > + { AV_CODEC_ID_TIFF, "dng" }, > { AV_CODEC_ID_SGI, "sgi" }, > { AV_CODEC_ID_PTX, "ptx" }, > { AV_CODEC_ID_PCX, "pcx" }, > -- > 2.21.0.windows.1 > >
diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 79e6242549..9575fe92ce 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -56,6 +56,7 @@ typedef struct TiffContext { int get_subimage; uint16_t get_page; + int get_dng_thumb; int width, height; unsigned int bpp, bppcount; @@ -70,7 +71,9 @@ typedef struct TiffContext { int predictor; int fill_order; uint32_t res[4]; + int is_thumbnail; + int dng_mode; /** denotes that this is a DNG image */ int is_bayer; uint8_t pattern[4]; unsigned white_level; @@ -948,6 +951,8 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } switch (tag) { + case TIFF_SUBFILE: + s->is_thumbnail = (value != 0); case TIFF_WIDTH: s->width = value; break; @@ -1088,7 +1093,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) case TIFF_SUB_IFDS: s->sub_ifd = value; break; - case TIFF_WHITE_LEVEL: + case DNG_WHITE_LEVEL: s->white_level = value; break; case TIFF_CFA_PATTERN_DIM: @@ -1339,6 +1344,20 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) case TIFF_SOFTWARE_NAME: ADD_METADATA(count, "software", NULL); break; + case DNG_VERSION: + if (count == 4) { + unsigned int ver[4]; + ver[0] = ff_tget(&s->gb, type, s->le); + ver[1] = ff_tget(&s->gb, type, s->le); + ver[2] = ff_tget(&s->gb, type, s->le); + ver[3] = ff_tget(&s->gb, type, s->le); + + av_log(s->avctx, AV_LOG_DEBUG, "DNG file, version %u.%u.%u.%u\n", + ver[0], ver[1], ver[2], ver[3]); + + s->dng_mode = 1; + } + break; default: if (s->avctx->err_recognition & AV_EF_EXPLODE) { av_log(s->avctx, AV_LOG_ERROR, @@ -1387,6 +1406,7 @@ static int decode_frame(AVCodecContext *avctx, s->le = le; // TIFF_BPP is not a required tag and defaults to 1 again: + s->is_thumbnail = 0; s->bppcount = s->bpp = 1; s->photometric = TIFF_PHOTOMETRIC_NONE; s->compr = TIFF_RAW; @@ -1394,6 +1414,7 @@ again: s->white_level = 0; s->is_bayer = 0; s->cur_page = 0; + s->dng_mode = 0; free_geotags(s); // Reset these offsets so we can tell if they were set this frame @@ -1408,6 +1429,18 @@ again: return ret; } + if (s->dng_mode) { + if (!s->get_dng_thumb) { + av_log(avctx, AV_LOG_ERROR, "DNG images are not supported\n"); + av_log(avctx, AV_LOG_INFO, "You can use -dng_thumb to decode an embedded TIFF thumbnail (if any) instead\n"); + return AVERROR_INVALIDDATA; + } + if (!s->is_thumbnail) { + av_log(avctx, AV_LOG_INFO, "No embedded thumbnail present\n"); + return AVERROR_EOF; + } + } + /** whether we should look for this IFD's SubIFD */ retry_for_subifd = s->sub_ifd && s->get_subimage; /** whether we should look for this multi-page IFD's next page */ @@ -1671,6 +1704,7 @@ static av_cold int tiff_end(AVCodecContext *avctx) static const AVOption tiff_options[] = { { "subimage", "decode subimage instead if available", OFFSET(get_subimage), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, { "page", "page number of multi-page image to decode (starting from 1)", OFFSET(get_page), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, + { "dng_thumb", "decode TIFF thumbnail of DNG image", OFFSET(get_dng_thumb), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, { NULL }, }; diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h index 4b08650108..3cede299f6 100644 --- a/libavcodec/tiff.h +++ b/libavcodec/tiff.h @@ -20,7 +20,7 @@ /** * @file - * TIFF tables + * TIFF constants & data structures * * For more information about the TIFF format, check the official docs at: * http://partners.adobe.com/public/developer/tiff/index.html @@ -33,7 +33,7 @@ #include <stdint.h> #include "tiff_common.h" -/** abridged list of TIFF tags */ +/** abridged list of TIFF and TIFF/EP tags */ enum TiffTags { TIFF_SUBFILE = 0xfe, TIFF_WIDTH = 0x100, @@ -85,10 +85,17 @@ enum TiffTags { TIFF_GEO_KEY_DIRECTORY = 0x87AF, TIFF_GEO_DOUBLE_PARAMS = 0x87B0, TIFF_GEO_ASCII_PARAMS = 0x87B1, - TIFF_WHITE_LEVEL = 0xC61D, }; -/** list of TIFF compression types */ +/** abridged list of DNG tags */ +enum DngTags +{ + DNG_VERSION = 0xC612, + DNG_BACKWARD_VERSION = 0xC613, + DNG_WHITE_LEVEL = 0xC61D, +}; + +/** list of TIFF, TIFF/EP and DNG compression types */ enum TiffCompr { TIFF_RAW = 1, TIFF_CCITT_RLE, @@ -151,6 +158,7 @@ enum TiffGeoTagKey { TIFF_VERTICAL_UNITS_GEOKEY = 4099 }; +/** list of TIFF, TIFF/AP and DNG PhotometricInterpretation (TIFF_PHOTOMETRIC) values */ enum TiffPhotometric { TIFF_PHOTOMETRIC_NONE = -1, TIFF_PHOTOMETRIC_WHITE_IS_ZERO, /* mono or grayscale, 0 is white */ @@ -163,7 +171,7 @@ enum TiffPhotometric { TIFF_PHOTOMETRIC_CIE_LAB = 8, /* 1976 CIE L*a*b* */ TIFF_PHOTOMETRIC_ICC_LAB, /* ICC L*a*b* */ TIFF_PHOTOMETRIC_ITU_LAB, /* ITU L*a*b* */ - TIFF_PHOTOMETRIC_CFA = 32803, /* Color Filter Array (DNG) */ + TIFF_PHOTOMETRIC_CFA = 32803, /* Color Filter Array (TIFF/AP and DNG) */ TIFF_PHOTOMETRIC_LOG_L = 32844, /* CIE Log2(L) */ TIFF_PHOTOMETRIC_LOG_LUV, /* CIE Log L*u*v* */ TIFF_PHOTOMETRIC_LINEAR_RAW = 34892, /* Linear Raw (DNG) */ diff --git a/libavformat/img2.c b/libavformat/img2.c index 8432cc0955..16bc9d2abd 100644 --- a/libavformat/img2.c +++ b/libavformat/img2.c @@ -51,6 +51,7 @@ const IdStrMap ff_img_tags[] = { { AV_CODEC_ID_TARGA, "tga" }, { AV_CODEC_ID_TIFF, "tiff" }, { AV_CODEC_ID_TIFF, "tif" }, + { AV_CODEC_ID_TIFF, "dng" }, { AV_CODEC_ID_SGI, "sgi" }, { AV_CODEC_ID_PTX, "ptx" }, { AV_CODEC_ID_PCX, "pcx" },