Signed-off-by: Michael Niedermayer <michaelni@gmx.at>tags/n2.1
| @@ -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 | |||
| @@ -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; | |||
| @@ -31,6 +31,7 @@ | |||
| #define AVCODEC_TIFF_H | |||
| #include <stdint.h> | |||
| #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; | |||
| @@ -0,0 +1,282 @@ | |||
| /* | |||
| * TIFF Common Routines | |||
| * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ googlemail.com> | |||
| * | |||
| * 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 <thilo.borgmann _at_ googlemail.com> | |||
| */ | |||
| #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; | |||
| } | |||
| @@ -0,0 +1,146 @@ | |||
| /* | |||
| * TIFF Common Routines | |||
| * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ googlemail.com> | |||
| * | |||
| * 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 <thilo.borgmann _at_ googlemail.com> | |||
| */ | |||
| #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 */ | |||