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_THEORA_DECODER) += xiph.o | ||||
| OBJS-$(CONFIG_THP_DECODER) += mjpegdec.o mjpeg.o | OBJS-$(CONFIG_THP_DECODER) += mjpegdec.o mjpeg.o | ||||
| OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.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_TIFF_ENCODER) += tiffenc.o rle.o lzwenc.o tiff_data.o | ||||
| OBJS-$(CONFIG_TMV_DECODER) += tmv.o cga_data.o | OBJS-$(CONFIG_TMV_DECODER) += tmv.o cga_data.o | ||||
| OBJS-$(CONFIG_TRUEHD_DECODER) += mlpdec.o mlpdsp.o | OBJS-$(CONFIG_TRUEHD_DECODER) += mlpdec.o mlpdsp.o | ||||
| @@ -70,38 +70,6 @@ typedef struct TiffContext { | |||||
| TiffGeoTag *geotags; | TiffGeoTag *geotags; | ||||
| } TiffContext; | } 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) | static void free_geotags(TiffContext *const s) | ||||
| { | { | ||||
| int i; | int i; | ||||
| @@ -245,111 +213,13 @@ static char *doubles2str(double *dp, int count, const char *sep) | |||||
| return ap0; | 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, | static int add_metadata(int count, int type, | ||||
| const char *name, const char *sep, TiffContext *s, AVFrame *frame) | const char *name, const char *sep, TiffContext *s, AVFrame *frame) | ||||
| { | { | ||||
| switch(type) { | 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; | default : return AVERROR_INVALIDDATA; | ||||
| }; | }; | ||||
| } | } | ||||
| @@ -702,14 +572,8 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) | |||||
| uint32_t *pal; | uint32_t *pal; | ||||
| double *dp; | 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; | goto end; | ||||
| } | } | ||||
| @@ -717,10 +581,10 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) | |||||
| switch (type) { | switch (type) { | ||||
| case TIFF_BYTE: | case TIFF_BYTE: | ||||
| case TIFF_SHORT: | case TIFF_SHORT: | ||||
| value = tget(&s->gb, type, s->le); | |||||
| value = ff_tget(&s->gb, type, s->le); | |||||
| break; | break; | ||||
| case TIFF_LONG: | case TIFF_LONG: | ||||
| off = tget_long(&s->gb, s->le); | |||||
| off = ff_tget_long(&s->gb, s->le); | |||||
| value = off; | value = off; | ||||
| break; | break; | ||||
| case TIFF_STRING: | case TIFF_STRING: | ||||
| @@ -728,14 +592,12 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) | |||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| off = tget_long(&s->gb, s->le); | |||||
| off = bytestream2_tell(&s->gb); | |||||
| value = UINT_MAX; | value = UINT_MAX; | ||||
| bytestream2_seek(&s->gb, off, SEEK_SET); | |||||
| } | } | ||||
| } else { | } else { | ||||
| if (type_sizes[type] * count > 4) { | 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) | if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count) | ||||
| return AVERROR_INVALIDDATA; | return AVERROR_INVALIDDATA; | ||||
| for (i = 0; i < count; i++) | for (i = 0; i < count; i++) | ||||
| s->bpp += tget(&s->gb, type, s->le); | |||||
| s->bpp += ff_tget(&s->gb, type, s->le); | |||||
| break; | break; | ||||
| default: | default: | ||||
| s->bpp = -1; | s->bpp = -1; | ||||
| @@ -908,7 +770,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) | |||||
| for (i = 0; i < count / 3; i++) { | for (i = 0; i < count / 3; i++) { | ||||
| if (k == 2) | if (k == 2) | ||||
| pal[i] = 0xFFU << 24; | 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; | pal[i] |= j; | ||||
| } | } | ||||
| } | } | ||||
| @@ -942,7 +804,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) | |||||
| case TIFF_GEO_KEY_DIRECTORY: | case TIFF_GEO_KEY_DIRECTORY: | ||||
| ADD_METADATA(1, "GeoTIFF_Version", NULL); | ADD_METADATA(1, "GeoTIFF_Version", NULL); | ||||
| ADD_METADATA(2, "GeoTIFF_Key_Revision", "."); | 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) { | if (s->geotag_count > count / 4 - 1) { | ||||
| 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"); | 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; | goto end; | ||||
| } | } | ||||
| for (i = 0; i < s->geotag_count; i++) { | 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) | 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 | else | ||||
| s->geotags[i].offset = tget_short(&s->gb, s->le); | |||||
| s->geotags[i].offset = ff_tget_short(&s->gb, s->le); | |||||
| } | } | ||||
| break; | break; | ||||
| case TIFF_GEO_DOUBLE_PARAMS: | case TIFF_GEO_DOUBLE_PARAMS: | ||||
| @@ -979,7 +841,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) | |||||
| goto end; | goto end; | ||||
| } | } | ||||
| for (i = 0; i < count; i++) | 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++) { | for (i = 0; i < s->geotag_count; i++) { | ||||
| if (s->geotags[i].type == TIFF_GEO_DOUBLE_PARAMS) { | if (s->geotags[i].type == TIFF_GEO_DOUBLE_PARAMS) { | ||||
| if (s->geotags[i].count == 0 | if (s->geotags[i].count == 0 | ||||
| @@ -1075,7 +937,7 @@ static int decode_frame(AVCodecContext *avctx, | |||||
| TiffContext *const s = avctx->priv_data; | TiffContext *const s = avctx->priv_data; | ||||
| AVFrame *const p = data; | AVFrame *const p = data; | ||||
| unsigned off; | unsigned off; | ||||
| int id, le, ret, plane, planes; | |||||
| int le, ret, plane, planes; | |||||
| int i, j, entries, stride; | int i, j, entries, stride; | ||||
| unsigned soff, ssize; | unsigned soff, ssize; | ||||
| uint8_t *dst; | uint8_t *dst; | ||||
| @@ -1085,15 +947,11 @@ static int decode_frame(AVCodecContext *avctx, | |||||
| bytestream2_init(&s->gb, avpkt->data, avpkt->size); | bytestream2_init(&s->gb, avpkt->data, avpkt->size); | ||||
| // parse image header | // 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; | return AVERROR_INVALIDDATA; | ||||
| } | } | ||||
| s->le = le; | s->le = le; | ||||
| @@ -1104,23 +962,11 @@ static int decode_frame(AVCodecContext *avctx, | |||||
| s->fill_order = 0; | s->fill_order = 0; | ||||
| free_geotags(s); | 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 | // Reset these offsets so we can tell if they were set this frame | ||||
| s->stripsizesoff = s->strippos = 0; | s->stripsizesoff = s->strippos = 0; | ||||
| /* parse image file directory */ | /* 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); | 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) | if (bytestream2_get_bytes_left(&s->gb) < entries * 12) | ||||
| return AVERROR_INVALIDDATA; | return AVERROR_INVALIDDATA; | ||||
| for (i = 0; i < entries; i++) { | for (i = 0; i < entries; i++) { | ||||
| @@ -1180,12 +1026,12 @@ static int decode_frame(AVCodecContext *avctx, | |||||
| dst = p->data[plane]; | dst = p->data[plane]; | ||||
| for (i = 0; i < s->height; i += s->rps) { | for (i = 0; i < s->height; i += s->rps) { | ||||
| if (s->stripsizesoff) | if (s->stripsizesoff) | ||||
| ssize = tget(&stripsizes, s->sstype, s->le); | |||||
| ssize = ff_tget(&stripsizes, s->sstype, s->le); | |||||
| else | else | ||||
| ssize = s->stripsize; | ssize = s->stripsize; | ||||
| if (s->strippos) | if (s->strippos) | ||||
| soff = tget(&stripdata, s->sot, s->le); | |||||
| soff = ff_tget(&stripdata, s->sot, s->le); | |||||
| else | else | ||||
| soff = s->stripoff; | soff = s->stripoff; | ||||
| @@ -31,6 +31,7 @@ | |||||
| #define AVCODEC_TIFF_H | #define AVCODEC_TIFF_H | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include "tiff_common.h" | |||||
| /** abridged list of TIFF tags */ | /** abridged list of TIFF tags */ | ||||
| enum TiffTags { | enum TiffTags { | ||||
| @@ -97,22 +98,6 @@ enum TiffCompr { | |||||
| TIFF_DEFLATE = 0x80B2 | 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 { | enum TiffGeoTagKey { | ||||
| TIFF_GT_MODEL_TYPE_GEOKEY = 1024, | TIFF_GT_MODEL_TYPE_GEOKEY = 1024, | ||||
| TIFF_GT_RASTER_TYPE_GEOKEY = 1025, | TIFF_GT_RASTER_TYPE_GEOKEY = 1025, | ||||
| @@ -167,11 +152,6 @@ enum TiffGeoTagType { | |||||
| GEOTIFF_STRING = 34737 | 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 { | typedef struct TiffGeoTag { | ||||
| enum TiffGeoTagKey key; | enum TiffGeoTagKey key; | ||||
| enum TiffTags type; | 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 */ | |||||