From b7ba7cbd6e5a0e590a6ad018eaf3be1342e96d94 Mon Sep 17 00:00:00 2001 From: Thilo Borgmann Date: Mon, 12 Aug 2013 19:32:40 +0200 Subject: [PATCH] avcodec/tiff: Refactor TIFF tag related functions to share the code. Signed-off-by: Michael Niedermayer --- libavcodec/Makefile | 2 +- libavcodec/tiff.c | 208 ++++------------------------- libavcodec/tiff.h | 22 +-- libavcodec/tiff_common.c | 282 +++++++++++++++++++++++++++++++++++++++ libavcodec/tiff_common.h | 146 ++++++++++++++++++++ 5 files changed, 457 insertions(+), 203 deletions(-) create mode 100644 libavcodec/tiff_common.c create mode 100644 libavcodec/tiff_common.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 5c8f9d5ed5..5ba8a1ab9e 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -426,7 +426,7 @@ OBJS-$(CONFIG_TARGA_Y216_DECODER) += targa_y216dec.o OBJS-$(CONFIG_THEORA_DECODER) += xiph.o OBJS-$(CONFIG_THP_DECODER) += mjpegdec.o mjpeg.o OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.o -OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o faxcompr.o tiff_data.o +OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o faxcompr.o tiff_data.o tiff_common.o OBJS-$(CONFIG_TIFF_ENCODER) += tiffenc.o rle.o lzwenc.o tiff_data.o OBJS-$(CONFIG_TMV_DECODER) += tmv.o cga_data.o OBJS-$(CONFIG_TRUEHD_DECODER) += mlpdec.o mlpdsp.o diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 2e06e3ff0e..ac7ac6016e 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -70,38 +70,6 @@ typedef struct TiffContext { TiffGeoTag *geotags; } TiffContext; -static unsigned tget_short(GetByteContext *gb, int le) -{ - unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb); - return v; -} - -static unsigned tget_long(GetByteContext *gb, int le) -{ - unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb); - return v; -} - -static double tget_double(GetByteContext *gb, int le) -{ - av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)}; - return i.f64; -} - -static unsigned tget(GetByteContext *gb, int type, int le) -{ - switch (type) { - case TIFF_BYTE: - return bytestream2_get_byte(gb); - case TIFF_SHORT: - return tget_short(gb, le); - case TIFF_LONG: - return tget_long(gb, le); - default: - return UINT_MAX; - } -} - static void free_geotags(TiffContext *const s) { int i; @@ -245,111 +213,13 @@ static char *doubles2str(double *dp, int count, const char *sep) return ap0; } -static char *shorts2str(int16_t *sp, int count, const char *sep) -{ - int i; - char *ap, *ap0; - uint64_t component_len; - if (!sep) sep = ", "; - component_len = 7LL + strlen(sep); - if (count >= (INT_MAX - 1)/component_len) - return NULL; - ap = av_malloc(component_len * count + 1); - if (!ap) - return NULL; - ap0 = ap; - ap[0] = '\0'; - for (i = 0; i < count; i++) { - unsigned l = snprintf(ap, component_len, "%d%s", sp[i], sep); - if (l >= component_len) { - av_free(ap0); - return NULL; - } - ap += l; - } - ap0[strlen(ap0) - strlen(sep)] = '\0'; - return ap0; -} - -static int add_doubles_metadata(int count, - const char *name, const char *sep, - TiffContext *s, AVFrame *frame) -{ - char *ap; - int i; - double *dp; - - if (count >= INT_MAX / sizeof(int64_t) || count <= 0) - return AVERROR_INVALIDDATA; - if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t)) - return AVERROR_INVALIDDATA; - - dp = av_malloc(count * sizeof(double)); - if (!dp) - return AVERROR(ENOMEM); - - for (i = 0; i < count; i++) - dp[i] = tget_double(&s->gb, s->le); - ap = doubles2str(dp, count, sep); - av_freep(&dp); - if (!ap) - return AVERROR(ENOMEM); - av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL); - return 0; -} - -static int add_shorts_metadata(int count, const char *name, - const char *sep, TiffContext *s, AVFrame *frame) -{ - char *ap; - int i; - int16_t *sp; - - if (count >= INT_MAX / sizeof(int16_t) || count <= 0) - return AVERROR_INVALIDDATA; - if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int16_t)) - return AVERROR_INVALIDDATA; - - sp = av_malloc(count * sizeof(int16_t)); - if (!sp) - return AVERROR(ENOMEM); - - for (i = 0; i < count; i++) - sp[i] = tget_short(&s->gb, s->le); - ap = shorts2str(sp, count, sep); - av_freep(&sp); - if (!ap) - return AVERROR(ENOMEM); - av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL); - return 0; -} - -static int add_string_metadata(int count, const char *name, - TiffContext *s, AVFrame *frame) -{ - char *value; - - if (bytestream2_get_bytes_left(&s->gb) < count || count < 0) - return AVERROR_INVALIDDATA; - - value = av_malloc(count + 1); - if (!value) - return AVERROR(ENOMEM); - - bytestream2_get_bufferu(&s->gb, value, count); - value[count] = 0; - - av_dict_set(avpriv_frame_get_metadatap(frame), name, value, AV_DICT_DONT_STRDUP_VAL); - return 0; -} - static int add_metadata(int count, int type, const char *name, const char *sep, TiffContext *s, AVFrame *frame) { switch(type) { - case TIFF_DOUBLE: return add_doubles_metadata(count, name, sep, s, frame); - case TIFF_SHORT : return add_shorts_metadata(count, name, sep, s, frame); - case TIFF_STRING: return add_string_metadata(count, name, s, frame); + case TIFF_DOUBLE: return ff_tadd_doubles_metadata(count, name, sep, &s->gb, s->le, avpriv_frame_get_metadatap(frame)); + case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, &s->gb, s->le, avpriv_frame_get_metadatap(frame)); + case TIFF_STRING: return ff_tadd_string_metadata(count, name, &s->gb, s->le, avpriv_frame_get_metadatap(frame)); default : return AVERROR_INVALIDDATA; }; } @@ -702,14 +572,8 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) uint32_t *pal; double *dp; - tag = tget_short(&s->gb, s->le); - type = tget_short(&s->gb, s->le); - count = tget_long(&s->gb, s->le); - start = bytestream2_tell(&s->gb) + 4; - - if (type == 0 || type >= FF_ARRAY_ELEMS(type_sizes)) { - av_log(s->avctx, AV_LOG_DEBUG, "Unknown tiff type (%u) encountered\n", - type); + ret = ff_tread_tag(&s->gb, s->le, &tag, &type, &count, &start); + if (ret < 0) { goto end; } @@ -717,10 +581,10 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) switch (type) { case TIFF_BYTE: case TIFF_SHORT: - value = tget(&s->gb, type, s->le); + value = ff_tget(&s->gb, type, s->le); break; case TIFF_LONG: - off = tget_long(&s->gb, s->le); + off = ff_tget_long(&s->gb, s->le); value = off; break; case TIFF_STRING: @@ -728,14 +592,12 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) break; } default: - off = tget_long(&s->gb, s->le); + off = bytestream2_tell(&s->gb); value = UINT_MAX; - bytestream2_seek(&s->gb, off, SEEK_SET); } } else { if (type_sizes[type] * count > 4) { - off = tget_long(&s->gb, s->le); - bytestream2_seek(&s->gb, off, SEEK_SET); + off = bytestream2_tell(&s->gb); } } @@ -768,7 +630,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count) return AVERROR_INVALIDDATA; for (i = 0; i < count; i++) - s->bpp += tget(&s->gb, type, s->le); + s->bpp += ff_tget(&s->gb, type, s->le); break; default: s->bpp = -1; @@ -908,7 +770,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) for (i = 0; i < count / 3; i++) { if (k == 2) pal[i] = 0xFFU << 24; - j = (tget(&s->gb, type, s->le) >> off) << (k * 8); + j = (ff_tget(&s->gb, type, s->le) >> off) << (k * 8); pal[i] |= j; } } @@ -942,7 +804,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) case TIFF_GEO_KEY_DIRECTORY: ADD_METADATA(1, "GeoTIFF_Version", NULL); ADD_METADATA(2, "GeoTIFF_Key_Revision", "."); - s->geotag_count = tget_short(&s->gb, s->le); + s->geotag_count = ff_tget_short(&s->gb, s->le); if (s->geotag_count > count / 4 - 1) { s->geotag_count = count / 4 - 1; av_log(s->avctx, AV_LOG_WARNING, "GeoTIFF key directory buffer shorter than specified\n"); @@ -958,14 +820,14 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) goto end; } for (i = 0; i < s->geotag_count; i++) { - s->geotags[i].key = tget_short(&s->gb, s->le); - s->geotags[i].type = tget_short(&s->gb, s->le); - s->geotags[i].count = tget_short(&s->gb, s->le); + s->geotags[i].key = ff_tget_short(&s->gb, s->le); + s->geotags[i].type = ff_tget_short(&s->gb, s->le); + s->geotags[i].count = ff_tget_short(&s->gb, s->le); if (!s->geotags[i].type) - s->geotags[i].val = get_geokey_val(s->geotags[i].key, tget_short(&s->gb, s->le)); + s->geotags[i].val = get_geokey_val(s->geotags[i].key, ff_tget_short(&s->gb, s->le)); else - s->geotags[i].offset = tget_short(&s->gb, s->le); + s->geotags[i].offset = ff_tget_short(&s->gb, s->le); } break; case TIFF_GEO_DOUBLE_PARAMS: @@ -979,7 +841,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) goto end; } for (i = 0; i < count; i++) - dp[i] = tget_double(&s->gb, s->le); + dp[i] = ff_tget_double(&s->gb, s->le); for (i = 0; i < s->geotag_count; i++) { if (s->geotags[i].type == TIFF_GEO_DOUBLE_PARAMS) { if (s->geotags[i].count == 0 @@ -1075,7 +937,7 @@ static int decode_frame(AVCodecContext *avctx, TiffContext *const s = avctx->priv_data; AVFrame *const p = data; unsigned off; - int id, le, ret, plane, planes; + int le, ret, plane, planes; int i, j, entries, stride; unsigned soff, ssize; uint8_t *dst; @@ -1085,15 +947,11 @@ static int decode_frame(AVCodecContext *avctx, bytestream2_init(&s->gb, avpkt->data, avpkt->size); // parse image header - if (avpkt->size < 8) - return AVERROR_INVALIDDATA; - id = bytestream2_get_le16u(&s->gb); - if (id == 0x4949) - le = 1; - else if (id == 0x4D4D) - le = 0; - else { - av_log(avctx, AV_LOG_ERROR, "TIFF header not found\n"); + if ((ret = ff_tdecode_header(&s->gb, &le, &off))) { + av_log(avctx, AV_LOG_ERROR, "Invalid TIFF header\n"); + return ret; + } else if (off >= UINT_MAX - 14 || avpkt->size < off + 14) { + av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n"); return AVERROR_INVALIDDATA; } s->le = le; @@ -1104,23 +962,11 @@ static int decode_frame(AVCodecContext *avctx, s->fill_order = 0; free_geotags(s); - // As TIFF 6.0 specification puts it "An arbitrary but carefully chosen number - // that further identifies the file as a TIFF file" - if (tget_short(&s->gb, le) != 42) { - av_log(avctx, AV_LOG_ERROR, - "The answer to life, universe and everything is not correct!\n"); - return AVERROR_INVALIDDATA; - } // Reset these offsets so we can tell if they were set this frame s->stripsizesoff = s->strippos = 0; /* parse image file directory */ - off = tget_long(&s->gb, le); - if (off >= UINT_MAX - 14 || avpkt->size < off + 14) { - av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n"); - return AVERROR_INVALIDDATA; - } bytestream2_seek(&s->gb, off, SEEK_SET); - entries = tget_short(&s->gb, le); + entries = ff_tget_short(&s->gb, le); if (bytestream2_get_bytes_left(&s->gb) < entries * 12) return AVERROR_INVALIDDATA; for (i = 0; i < entries; i++) { @@ -1180,12 +1026,12 @@ static int decode_frame(AVCodecContext *avctx, dst = p->data[plane]; for (i = 0; i < s->height; i += s->rps) { if (s->stripsizesoff) - ssize = tget(&stripsizes, s->sstype, s->le); + ssize = ff_tget(&stripsizes, s->sstype, s->le); else ssize = s->stripsize; if (s->strippos) - soff = tget(&stripdata, s->sot, s->le); + soff = ff_tget(&stripdata, s->sot, s->le); else soff = s->stripoff; diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h index 3ea2158033..ae189b6fdd 100644 --- a/libavcodec/tiff.h +++ b/libavcodec/tiff.h @@ -31,6 +31,7 @@ #define AVCODEC_TIFF_H #include +#include "tiff_common.h" /** abridged list of TIFF tags */ enum TiffTags { @@ -97,22 +98,6 @@ enum TiffCompr { TIFF_DEFLATE = 0x80B2 }; -enum TiffTypes { - TIFF_BYTE = 1, - TIFF_STRING, - TIFF_SHORT, - TIFF_LONG, - TIFF_RATIONAL, - TIFF_SBYTE, - TIFF_UNDEFINED, - TIFF_SSHORT, - TIFF_SLONG, - TIFF_SRATIONAL, - TIFF_FLOAT, - TIFF_DOUBLE, - TIFF_IFD -}; - enum TiffGeoTagKey { TIFF_GT_MODEL_TYPE_GEOKEY = 1024, TIFF_GT_RASTER_TYPE_GEOKEY = 1025, @@ -167,11 +152,6 @@ enum TiffGeoTagType { GEOTIFF_STRING = 34737 }; -/** sizes of various TIFF field types (string size = 100)*/ -static const uint8_t type_sizes[14] = { - 0, 1, 100, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4 -}; - typedef struct TiffGeoTag { enum TiffGeoTagKey key; enum TiffTags type; diff --git a/libavcodec/tiff_common.c b/libavcodec/tiff_common.c new file mode 100644 index 0000000000..0995daea81 --- /dev/null +++ b/libavcodec/tiff_common.c @@ -0,0 +1,282 @@ +/* + * TIFF Common Routines + * Copyright (c) 2013 Thilo Borgmann + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * TIFF Common Routines + * @author Thilo Borgmann + */ + +#include "tiff_common.h" + + +int ff_tis_ifd(unsigned tag) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(ifd_tags); i++) { + if (ifd_tags[i] == tag) { + return i + 1; + } + } + return 0; +} + + +unsigned ff_tget_short(GetByteContext *gb, int le) +{ + unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb); + return v; +} + + +unsigned ff_tget_long(GetByteContext *gb, int le) +{ + unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb); + return v; +} + + +double ff_tget_double(GetByteContext *gb, int le) +{ + av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)}; + return i.f64; +} + + +unsigned ff_tget(GetByteContext *gb, int type, int le) +{ + switch (type) { + case TIFF_BYTE: + return bytestream2_get_byte(gb); + case TIFF_SHORT: + return ff_tget_short(gb, le); + case TIFF_LONG: + return ff_tget_long(gb, le); + default: + return UINT_MAX; + } +} + + +int ff_tadd_rational_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata) +{ + AVBPrint bp; + char *ap; + int32_t nom, denom; + int i; + + if (count >= INT_MAX / sizeof(int64_t) || count <= 0) + return AVERROR_INVALIDDATA; + if (bytestream2_get_bytes_left(gb) < count * sizeof(int64_t)) + return AVERROR_INVALIDDATA; + if (!sep) sep = ", "; + + av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_AUTOMATIC); + + for (i = 0; i < count; i++) { + nom = ff_tget_long(gb, le); + denom = ff_tget_long(gb, le); + av_bprintf(&bp, "%s%i:%i", (i ? sep : ""), nom, denom); + } + + if ((i = av_bprint_finalize(&bp, &ap))) { + return i; + } + if (!ap) { + return AVERROR(ENOMEM); + } + + av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL); + + return 0; +} + + +int ff_tadd_long_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata) +{ + AVBPrint bp; + char *ap; + int i; + + if (count >= INT_MAX / sizeof(int32_t) || count <= 0) + return AVERROR_INVALIDDATA; + if (bytestream2_get_bytes_left(gb) < count * sizeof(int32_t)) + return AVERROR_INVALIDDATA; + if (!sep) sep = ", "; + + av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_AUTOMATIC); + + for (i = 0; i < count; i++) { + av_bprintf(&bp, "%s%i", (i ? sep : ""), ff_tget_long(gb, le)); + } + + if ((i = av_bprint_finalize(&bp, &ap))) { + return i; + } + if (!ap) { + return AVERROR(ENOMEM); + } + + av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL); + + return 0; +} + + +int ff_tadd_doubles_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata) +{ + AVBPrint bp; + char *ap; + int i; + + if (count >= INT_MAX / sizeof(int64_t) || count <= 0) + return AVERROR_INVALIDDATA; + if (bytestream2_get_bytes_left(gb) < count * sizeof(int64_t)) + return AVERROR_INVALIDDATA; + if (!sep) sep = ", "; + + av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_AUTOMATIC); + + for (i = 0; i < count; i++) { + av_bprintf(&bp, "%s%f", (i ? sep : ""), ff_tget_double(gb, le)); + } + + if ((i = av_bprint_finalize(&bp, &ap))) { + return i; + } + if (!ap) { + return AVERROR(ENOMEM); + } + + av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL); + + return 0; +} + + +int ff_tadd_shorts_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata) +{ + AVBPrint bp; + char *ap; + int i; + + if (count >= INT_MAX / sizeof(int16_t) || count <= 0) + return AVERROR_INVALIDDATA; + if (bytestream2_get_bytes_left(gb) < count * sizeof(int16_t)) + return AVERROR_INVALIDDATA; + if (!sep) sep = ", "; + + av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_AUTOMATIC); + + for (i = 0; i < count; i++) { + av_bprintf(&bp, "%s%i", (i ? sep : ""), ff_tget_short(gb, le)); + } + + if ((i = av_bprint_finalize(&bp, &ap))) { + return i; + } + if (!ap) { + return AVERROR(ENOMEM); + } + + av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL); + + return 0; +} + + +int ff_tadd_string_metadata(int count, const char *name, + GetByteContext *gb, int le, AVDictionary **metadata) +{ + char *value; + + if (bytestream2_get_bytes_left(gb) < count || count < 0) + return AVERROR_INVALIDDATA; + + value = av_malloc(count + 1); + if (!value) + return AVERROR(ENOMEM); + + bytestream2_get_bufferu(gb, value, count); + value[count] = 0; + + av_dict_set(metadata, name, value, AV_DICT_DONT_STRDUP_VAL); + return 0; +} + + +int ff_tdecode_header(GetByteContext *gb, int *le, int *ifd_offset) +{ + if (bytestream2_get_bytes_left(gb) < 8) { + return AVERROR_INVALIDDATA; + } + + *le = bytestream2_get_le16u(gb); + if (*le == AV_RB16("II")) { + *le = 1; + } else if (*le == AV_RB16("MM")) { + *le = 0; + } else { + return AVERROR_INVALIDDATA; + } + + if (ff_tget_short(gb, *le) != 42) { + return AVERROR_INVALIDDATA; + } + + *ifd_offset = ff_tget_long(gb, *le); + + return 0; +} + + +int ff_tread_tag(GetByteContext *gb, int le, unsigned *tag, unsigned *type, + unsigned *count, int *next) +{ + int ifd_tag; + int valid_type; + + *tag = ff_tget_short(gb, le); + *type = ff_tget_short(gb, le); + *count = ff_tget_long (gb, le); + + ifd_tag = ff_tis_ifd(*tag); + valid_type = *type != 0 && *type < FF_ARRAY_ELEMS(type_sizes); + + *next = bytestream2_tell(gb) + 4; + + // check for valid type + if (!valid_type) { + return AVERROR_INVALIDDATA; + } + + // seek to offset if this is an IFD-tag or + // if count values do not fit into the offset value + if (ifd_tag || (*count > 4 || !(type_sizes[*type] * (*count) <= 4 || *type == TIFF_STRING))) { + bytestream2_seek(gb, ff_tget_long (gb, le), SEEK_SET); + } + + return 0; +} diff --git a/libavcodec/tiff_common.h b/libavcodec/tiff_common.h new file mode 100644 index 0000000000..15eeb76df6 --- /dev/null +++ b/libavcodec/tiff_common.h @@ -0,0 +1,146 @@ +/* + * TIFF Common Routines + * Copyright (c) 2013 Thilo Borgmann + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * TIFF Common Routines + * @author Thilo Borgmann + */ + +#ifndef AVCODEC_TIFF_COMMON_H +#define AVCODEC_TIFF_COMMON_H + +#include "avcodec.h" +#include "tiff.h" +#include "bytestream.h" +#include "libavutil/bprint.h" + +/** data type identifiers for TIFF tags */ +enum TiffTypes { + TIFF_BYTE = 1, + TIFF_STRING, + TIFF_SHORT, + TIFF_LONG, + TIFF_RATIONAL, + TIFF_SBYTE, + TIFF_UNDEFINED, + TIFF_SSHORT, + TIFF_SLONG, + TIFF_SRATIONAL, + TIFF_FLOAT, + TIFF_DOUBLE, + TIFF_IFD +}; + +/** sizes of various TIFF field types (string size = 100)*/ +static const uint8_t type_sizes[14] = { + 0, 1, 100, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4 +}; + +static const uint16_t ifd_tags[] = { + 0x8769, // EXIF IFD + 0x8825, // GPS IFD + 0xA005 // Interoperability IFD +}; + + +/** Returns a value > 0 if the tag is a known IFD-tag. + * The return value is the array index + 1 within ifd_tags[]. + */ +int ff_tis_ifd(unsigned tag); + +/** Reads a short from the bytestream using given endianess. */ +unsigned ff_tget_short(GetByteContext *gb, int le); + +/** Reads a long from the bytestream using given endianess. */ +unsigned ff_tget_long(GetByteContext *gb, int le); + +/** Reads a double from the bytestream using given endianess. */ +double ff_tget_double(GetByteContext *gb, int le); + +/** Reads a byte from the bytestream using given endianess. */ +unsigned ff_tget(GetByteContext *gb, int type, int le); + +/** Returns an allocated string containing count + * rational values using the given seperator. + */ +char *ff_trationals2str(int *rp, int count, const char *sep); + +/** Returns an allocated string containing count + * long values using the given seperator. + */ +char *ff_tlongs2str(int32_t *lp, int count, const char *sep); + +/** Returns an allocated string containing count + * double values using the given seperator. + */ +char *ff_tdoubles2str(double *dp, int count, const char *sep); + +/** Returns an allocated string containing count + * short values using the given seperator. + */ +char *ff_tshorts2str(int16_t *sp, int count, const char *sep); + +/** Adds count rationals converted to a string + * into the metadata dictionary. + */ +int ff_tadd_rational_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata); + +/** Adds count longs converted to a string + * into the metadata dictionary. + */ +int ff_tadd_long_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata); + +/** Adds count doubles converted to a string + * into the metadata dictionary. + */ +int ff_tadd_doubles_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata); + +/** Adds count shorts converted to a string + * into the metadata dictionary. + */ +int ff_tadd_shorts_metadata(int count, const char *name, const char *sep, + GetByteContext *gb, int le, AVDictionary **metadata); + +/** Adds a string of count characters + * into the metadata dictionary. + */ +int ff_tadd_string_metadata(int count, const char *name, + GetByteContext *gb, int le, AVDictionary **metadata); + +/** Decodes a TIFF header from the input bytestream + * and sets the endianess in *le and the offset to + * the first IFD in *ifd_offset accordingly. + */ +int ff_tdecode_header(GetByteContext *gb, int *le, int *ifd_offset); + +/** Reads the first 3 fields of a TIFF tag, which are + * the tag id, the tag type and the count of values for that tag. + * Afterwards the bytestream is located at the first value to read and + * *next holds the bytestream offset of the following tag. + */ +int ff_tread_tag(GetByteContext *gb, int le, unsigned *tag, unsigned *type, + unsigned *count, int *next); + +#endif /* AVCODEC_TIFF_COMMON_H */