yading@10: /* yading@10: * Copyright (c) 2006 Konstantin Shishkov yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * TIFF image decoder yading@10: * @author Konstantin Shishkov yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: #include "bytestream.h" yading@10: #include "config.h" yading@10: #if CONFIG_ZLIB yading@10: #include yading@10: #endif yading@10: #include "lzw.h" yading@10: #include "tiff.h" yading@10: #include "tiff_data.h" yading@10: #include "faxcompr.h" yading@10: #include "internal.h" yading@10: #include "mathops.h" yading@10: #include "libavutil/attributes.h" yading@10: #include "libavutil/intreadwrite.h" yading@10: #include "libavutil/imgutils.h" yading@10: #include "libavutil/avstring.h" yading@10: yading@10: typedef struct TiffContext { yading@10: AVCodecContext *avctx; yading@10: GetByteContext gb; yading@10: yading@10: int width, height; yading@10: unsigned int bpp, bppcount; yading@10: uint32_t palette[256]; yading@10: int palette_is_set; yading@10: int le; yading@10: enum TiffCompr compr; yading@10: int invert; yading@10: int fax_opts; yading@10: int predictor; yading@10: int fill_order; yading@10: yading@10: int strips, rps, sstype; yading@10: int sot; yading@10: int stripsizesoff, stripsize, stripoff, strippos; yading@10: LZWState *lzw; yading@10: yading@10: uint8_t *deinvert_buf; yading@10: int deinvert_buf_size; yading@10: yading@10: int geotag_count; yading@10: TiffGeoTag *geotags; yading@10: } TiffContext; yading@10: yading@10: static unsigned tget_short(GetByteContext *gb, int le) yading@10: { yading@10: unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb); yading@10: return v; yading@10: } yading@10: yading@10: static unsigned tget_long(GetByteContext *gb, int le) yading@10: { yading@10: unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb); yading@10: return v; yading@10: } yading@10: yading@10: static double tget_double(GetByteContext *gb, int le) yading@10: { yading@10: av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)}; yading@10: return i.f64; yading@10: } yading@10: yading@10: static unsigned tget(GetByteContext *gb, int type, int le) yading@10: { yading@10: switch (type) { yading@10: case TIFF_BYTE : return bytestream2_get_byte(gb); yading@10: case TIFF_SHORT: return tget_short(gb, le); yading@10: case TIFF_LONG : return tget_long(gb, le); yading@10: default : return UINT_MAX; yading@10: } yading@10: } yading@10: yading@10: static void free_geotags(TiffContext *const s) yading@10: { yading@10: int i; yading@10: for (i = 0; i < s->geotag_count; i++) { yading@10: if (s->geotags[i].val) yading@10: av_freep(&s->geotags[i].val); yading@10: } yading@10: av_freep(&s->geotags); yading@10: } yading@10: yading@10: #define RET_GEOKEY(TYPE, array, element)\ yading@10: if (key >= TIFF_##TYPE##_KEY_ID_OFFSET &&\ yading@10: key - TIFF_##TYPE##_KEY_ID_OFFSET < FF_ARRAY_ELEMS(ff_tiff_##array##_name_type_map))\ yading@10: return ff_tiff_##array##_name_type_map[key - TIFF_##TYPE##_KEY_ID_OFFSET].element; yading@10: yading@10: static const char *get_geokey_name(int key) yading@10: { yading@10: RET_GEOKEY(VERT, vert, name); yading@10: RET_GEOKEY(PROJ, proj, name); yading@10: RET_GEOKEY(GEOG, geog, name); yading@10: RET_GEOKEY(CONF, conf, name); yading@10: yading@10: return NULL; yading@10: } yading@10: yading@10: static int get_geokey_type(int key) yading@10: { yading@10: RET_GEOKEY(VERT, vert, type); yading@10: RET_GEOKEY(PROJ, proj, type); yading@10: RET_GEOKEY(GEOG, geog, type); yading@10: RET_GEOKEY(CONF, conf, type); yading@10: yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: static int cmp_id_key(const void *id, const void *k) yading@10: { yading@10: return *(const int*)id - ((const TiffGeoTagKeyName*)k)->key; yading@10: } yading@10: yading@10: static const char *search_keyval(const TiffGeoTagKeyName *keys, int n, int id) yading@10: { yading@10: TiffGeoTagKeyName *r = bsearch(&id, keys, n, sizeof(keys[0]), cmp_id_key); yading@10: if(r) yading@10: return r->name; yading@10: yading@10: return NULL; yading@10: } yading@10: yading@10: static char *get_geokey_val(int key, int val) yading@10: { yading@10: char *ap; yading@10: yading@10: if (val == TIFF_GEO_KEY_UNDEFINED) yading@10: return av_strdup("undefined"); yading@10: if (val == TIFF_GEO_KEY_USER_DEFINED) yading@10: return av_strdup("User-Defined"); yading@10: yading@10: #define RET_GEOKEY_VAL(TYPE, array)\ yading@10: if (val >= TIFF_##TYPE##_OFFSET &&\ yading@10: val - TIFF_##TYPE##_OFFSET < FF_ARRAY_ELEMS(ff_tiff_##array##_codes))\ yading@10: return av_strdup(ff_tiff_##array##_codes[val - TIFF_##TYPE##_OFFSET]); yading@10: yading@10: switch (key) { yading@10: case TIFF_GT_MODEL_TYPE_GEOKEY: yading@10: RET_GEOKEY_VAL(GT_MODEL_TYPE, gt_model_type); yading@10: break; yading@10: case TIFF_GT_RASTER_TYPE_GEOKEY: yading@10: RET_GEOKEY_VAL(GT_RASTER_TYPE, gt_raster_type); yading@10: break; yading@10: case TIFF_GEOG_LINEAR_UNITS_GEOKEY: yading@10: case TIFF_PROJ_LINEAR_UNITS_GEOKEY: yading@10: case TIFF_VERTICAL_UNITS_GEOKEY: yading@10: RET_GEOKEY_VAL(LINEAR_UNIT, linear_unit); yading@10: break; yading@10: case TIFF_GEOG_ANGULAR_UNITS_GEOKEY: yading@10: case TIFF_GEOG_AZIMUTH_UNITS_GEOKEY: yading@10: RET_GEOKEY_VAL(ANGULAR_UNIT, angular_unit); yading@10: break; yading@10: case TIFF_GEOGRAPHIC_TYPE_GEOKEY: yading@10: RET_GEOKEY_VAL(GCS_TYPE, gcs_type); yading@10: RET_GEOKEY_VAL(GCSE_TYPE, gcse_type); yading@10: break; yading@10: case TIFF_GEOG_GEODETIC_DATUM_GEOKEY: yading@10: RET_GEOKEY_VAL(GEODETIC_DATUM, geodetic_datum); yading@10: RET_GEOKEY_VAL(GEODETIC_DATUM_E, geodetic_datum_e); yading@10: break; yading@10: case TIFF_GEOG_ELLIPSOID_GEOKEY: yading@10: RET_GEOKEY_VAL(ELLIPSOID, ellipsoid); yading@10: break; yading@10: case TIFF_GEOG_PRIME_MERIDIAN_GEOKEY: yading@10: RET_GEOKEY_VAL(PRIME_MERIDIAN, prime_meridian); yading@10: break; yading@10: case TIFF_PROJECTED_CS_TYPE_GEOKEY: yading@10: ap = av_strdup(search_keyval(ff_tiff_proj_cs_type_codes, FF_ARRAY_ELEMS(ff_tiff_proj_cs_type_codes), val)); yading@10: if(ap) return ap; yading@10: break; yading@10: case TIFF_PROJECTION_GEOKEY: yading@10: ap = av_strdup(search_keyval(ff_tiff_projection_codes, FF_ARRAY_ELEMS(ff_tiff_projection_codes), val)); yading@10: if(ap) return ap; yading@10: break; yading@10: case TIFF_PROJ_COORD_TRANS_GEOKEY: yading@10: RET_GEOKEY_VAL(COORD_TRANS, coord_trans); yading@10: break; yading@10: case TIFF_VERTICAL_CS_TYPE_GEOKEY: yading@10: RET_GEOKEY_VAL(VERT_CS, vert_cs); yading@10: RET_GEOKEY_VAL(ORTHO_VERT_CS, ortho_vert_cs); yading@10: break; yading@10: yading@10: } yading@10: yading@10: ap = av_malloc(14); yading@10: if (ap) yading@10: snprintf(ap, 14, "Unknown-%d", val); yading@10: return ap; yading@10: } yading@10: yading@10: static char *doubles2str(double *dp, int count, const char *sep) yading@10: { yading@10: int i; yading@10: char *ap, *ap0; yading@10: uint64_t component_len; yading@10: if (!sep) sep = ", "; yading@10: component_len = 15LL + strlen(sep); yading@10: if (count >= (INT_MAX - 1)/component_len) yading@10: return NULL; yading@10: ap = av_malloc(component_len * count + 1); yading@10: if (!ap) yading@10: return NULL; yading@10: ap0 = ap; yading@10: ap[0] = '\0'; yading@10: for (i = 0; i < count; i++) { yading@10: unsigned l = snprintf(ap, component_len, "%f%s", dp[i], sep); yading@10: if(l >= component_len) { yading@10: av_free(ap0); yading@10: return NULL; yading@10: } yading@10: ap += l; yading@10: } yading@10: ap0[strlen(ap0) - strlen(sep)] = '\0'; yading@10: return ap0; yading@10: } yading@10: yading@10: static char *shorts2str(int16_t *sp, int count, const char *sep) yading@10: { yading@10: int i; yading@10: char *ap, *ap0; yading@10: uint64_t component_len; yading@10: if (!sep) sep = ", "; yading@10: component_len = 7LL + strlen(sep); yading@10: if (count >= (INT_MAX - 1)/component_len) yading@10: return NULL; yading@10: ap = av_malloc(component_len * count + 1); yading@10: if (!ap) yading@10: return NULL; yading@10: ap0 = ap; yading@10: ap[0] = '\0'; yading@10: for (i = 0; i < count; i++) { yading@10: unsigned l = snprintf(ap, component_len, "%d%s", sp[i], sep); yading@10: if (l >= component_len) { yading@10: av_free(ap0); yading@10: return NULL; yading@10: } yading@10: ap += l; yading@10: } yading@10: ap0[strlen(ap0) - strlen(sep)] = '\0'; yading@10: return ap0; yading@10: } yading@10: yading@10: static int add_doubles_metadata(int count, yading@10: const char *name, const char *sep, yading@10: TiffContext *s, AVFrame *frame) yading@10: { yading@10: char *ap; yading@10: int i; yading@10: double *dp; yading@10: yading@10: if (count >= INT_MAX / sizeof(int64_t) || count <= 0) yading@10: return AVERROR_INVALIDDATA; yading@10: if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t)) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: dp = av_malloc(count * sizeof(double)); yading@10: if (!dp) yading@10: return AVERROR(ENOMEM); yading@10: yading@10: for (i = 0; i < count; i++) yading@10: dp[i] = tget_double(&s->gb, s->le); yading@10: ap = doubles2str(dp, count, sep); yading@10: av_freep(&dp); yading@10: if (!ap) yading@10: return AVERROR(ENOMEM); yading@10: av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL); yading@10: return 0; yading@10: } yading@10: yading@10: static int add_shorts_metadata(int count, const char *name, yading@10: const char *sep, TiffContext *s, AVFrame *frame) yading@10: { yading@10: char *ap; yading@10: int i; yading@10: int16_t *sp; yading@10: yading@10: if (count >= INT_MAX / sizeof(int16_t) || count <= 0) yading@10: return AVERROR_INVALIDDATA; yading@10: if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int16_t)) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: sp = av_malloc(count * sizeof(int16_t)); yading@10: if (!sp) yading@10: return AVERROR(ENOMEM); yading@10: yading@10: for (i = 0; i < count; i++) yading@10: sp[i] = tget_short(&s->gb, s->le); yading@10: ap = shorts2str(sp, count, sep); yading@10: av_freep(&sp); yading@10: if (!ap) yading@10: return AVERROR(ENOMEM); yading@10: av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL); yading@10: return 0; yading@10: } yading@10: yading@10: static int add_string_metadata(int count, const char *name, yading@10: TiffContext *s, AVFrame *frame) yading@10: { yading@10: char *value; yading@10: yading@10: if (bytestream2_get_bytes_left(&s->gb) < count || count < 0) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: value = av_malloc(count + 1); yading@10: if (!value) yading@10: return AVERROR(ENOMEM); yading@10: yading@10: bytestream2_get_bufferu(&s->gb, value, count); yading@10: value[count] = 0; yading@10: yading@10: av_dict_set(avpriv_frame_get_metadatap(frame), name, value, AV_DICT_DONT_STRDUP_VAL); yading@10: return 0; yading@10: } yading@10: yading@10: static int add_metadata(int count, int type, yading@10: const char *name, const char *sep, TiffContext *s, AVFrame *frame) yading@10: { yading@10: switch(type) { yading@10: case TIFF_DOUBLE: return add_doubles_metadata(count, name, sep, s, frame); yading@10: case TIFF_SHORT : return add_shorts_metadata(count, name, sep, s, frame); yading@10: case TIFF_STRING: return add_string_metadata(count, name, s, frame); yading@10: default : return AVERROR_INVALIDDATA; yading@10: }; yading@10: } yading@10: yading@10: #if CONFIG_ZLIB yading@10: static int tiff_uncompress(uint8_t *dst, unsigned long *len, const uint8_t *src, yading@10: int size) yading@10: { yading@10: z_stream zstream = { 0 }; yading@10: int zret; yading@10: yading@10: zstream.next_in = (uint8_t *)src; yading@10: zstream.avail_in = size; yading@10: zstream.next_out = dst; yading@10: zstream.avail_out = *len; yading@10: zret = inflateInit(&zstream); yading@10: if (zret != Z_OK) { yading@10: av_log(NULL, AV_LOG_ERROR, "Inflate init error: %d\n", zret); yading@10: return zret; yading@10: } yading@10: zret = inflate(&zstream, Z_SYNC_FLUSH); yading@10: inflateEnd(&zstream); yading@10: *len = zstream.total_out; yading@10: return zret == Z_STREAM_END ? Z_OK : zret; yading@10: } yading@10: #endif yading@10: yading@10: static void av_always_inline horizontal_fill(unsigned int bpp, uint8_t* dst, yading@10: int usePtr, const uint8_t *src, yading@10: uint8_t c, int width, int offset) yading@10: { yading@10: switch (bpp) { yading@10: case 1: yading@10: while (--width >= 0) { yading@10: dst[(width+offset)*8+7] = (usePtr ? src[width] : c) & 0x1; yading@10: dst[(width+offset)*8+6] = (usePtr ? src[width] : c) >> 1 & 0x1; yading@10: dst[(width+offset)*8+5] = (usePtr ? src[width] : c) >> 2 & 0x1; yading@10: dst[(width+offset)*8+4] = (usePtr ? src[width] : c) >> 3 & 0x1; yading@10: dst[(width+offset)*8+3] = (usePtr ? src[width] : c) >> 4 & 0x1; yading@10: dst[(width+offset)*8+2] = (usePtr ? src[width] : c) >> 5 & 0x1; yading@10: dst[(width+offset)*8+1] = (usePtr ? src[width] : c) >> 6 & 0x1; yading@10: dst[(width+offset)*8+0] = (usePtr ? src[width] : c) >> 7; yading@10: } yading@10: break; yading@10: case 2: yading@10: while (--width >= 0) { yading@10: dst[(width+offset)*4+3] = (usePtr ? src[width] : c) & 0x3; yading@10: dst[(width+offset)*4+2] = (usePtr ? src[width] : c) >> 2 & 0x3; yading@10: dst[(width+offset)*4+1] = (usePtr ? src[width] : c) >> 4 & 0x3; yading@10: dst[(width+offset)*4+0] = (usePtr ? src[width] : c) >> 6; yading@10: } yading@10: break; yading@10: case 4: yading@10: while (--width >= 0) { yading@10: dst[(width+offset)*2+1] = (usePtr ? src[width] : c) & 0xF; yading@10: dst[(width+offset)*2+0] = (usePtr ? src[width] : c) >> 4; yading@10: } yading@10: break; yading@10: default: yading@10: if (usePtr) { yading@10: memcpy(dst + offset, src, width); yading@10: } else { yading@10: memset(dst + offset, c, width); yading@10: } yading@10: } yading@10: } yading@10: yading@10: static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride, yading@10: const uint8_t *src, int size, int lines) yading@10: { yading@10: int c, line, pixels, code, ret; yading@10: const uint8_t *ssrc = src; yading@10: int width = ((s->width * s->bpp) + 7) >> 3; yading@10: yading@10: if (size <= 0) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: #if CONFIG_ZLIB yading@10: if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE) { yading@10: uint8_t *src2 = NULL, *zbuf; yading@10: unsigned long outlen; yading@10: int i, ret; yading@10: outlen = width * lines; yading@10: zbuf = av_malloc(outlen); yading@10: if (!zbuf) yading@10: return AVERROR(ENOMEM); yading@10: if (s->fill_order) { yading@10: src2 = av_malloc((unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE); yading@10: if (!src2) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); yading@10: av_free(zbuf); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: for (i = 0; i < size; i++) yading@10: src2[i] = ff_reverse[src[i]]; yading@10: memset(src2 + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); yading@10: src = src2; yading@10: } yading@10: ret = tiff_uncompress(zbuf, &outlen, src, size); yading@10: if (ret != Z_OK) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Uncompressing failed (%lu of %lu) with error %d\n", outlen, yading@10: (unsigned long)width * lines, ret); yading@10: av_free(src2); yading@10: av_free(zbuf); yading@10: return AVERROR_UNKNOWN; yading@10: } yading@10: src = zbuf; yading@10: for (line = 0; line < lines; line++) { yading@10: if(s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8){ yading@10: horizontal_fill(s->bpp, dst, 1, src, 0, width, 0); yading@10: }else{ yading@10: memcpy(dst, src, width); yading@10: } yading@10: dst += stride; yading@10: src += width; yading@10: } yading@10: av_free(src2); yading@10: av_free(zbuf); yading@10: return 0; yading@10: } yading@10: #endif yading@10: if (s->compr == TIFF_LZW) { yading@10: if (s->fill_order) { yading@10: int i; yading@10: av_fast_padded_malloc(&s->deinvert_buf, &s->deinvert_buf_size, size); yading@10: if (!s->deinvert_buf) yading@10: return AVERROR(ENOMEM); yading@10: for (i = 0; i < size; i++) yading@10: s->deinvert_buf[i] = ff_reverse[src[i]]; yading@10: src = s->deinvert_buf; yading@10: ssrc = src; yading@10: } yading@10: if (size > 1 && !src[0] && (src[1]&1)) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Old style LZW is unsupported\n"); yading@10: } yading@10: if ((ret = ff_lzw_decode_init(s->lzw, 8, src, size, FF_LZW_TIFF)) < 0) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Error initializing LZW decoder\n"); yading@10: return ret; yading@10: } yading@10: } yading@10: if (s->compr == TIFF_CCITT_RLE || s->compr == TIFF_G3 yading@10: || s->compr == TIFF_G4) { yading@10: int i, ret = 0; yading@10: uint8_t *src2 = av_malloc((unsigned)size + yading@10: FF_INPUT_BUFFER_PADDING_SIZE); yading@10: yading@10: if (!src2) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Error allocating temporary buffer\n"); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: if (s->fax_opts & 2) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Uncompressed fax mode is not supported (yet)\n"); yading@10: av_free(src2); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (!s->fill_order) { yading@10: memcpy(src2, src, size); yading@10: } else { yading@10: for (i = 0; i < size; i++) yading@10: src2[i] = ff_reverse[src[i]]; yading@10: } yading@10: memset(src2 + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); yading@10: switch (s->compr) { yading@10: case TIFF_CCITT_RLE: yading@10: case TIFF_G3: yading@10: case TIFF_G4: yading@10: ret = ff_ccitt_unpack(s->avctx, src2, size, dst, lines, stride, yading@10: s->compr, s->fax_opts); yading@10: break; yading@10: } yading@10: if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) yading@10: for (line = 0; line < lines; line++) { yading@10: horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0); yading@10: dst += stride; yading@10: } yading@10: av_free(src2); yading@10: return ret; yading@10: } yading@10: for (line = 0; line < lines; line++) { yading@10: if (src - ssrc > size) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: switch (s->compr) { yading@10: case TIFF_RAW: yading@10: if (ssrc + size - src < width) yading@10: return AVERROR_INVALIDDATA; yading@10: if (!s->fill_order) { yading@10: horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), yading@10: dst, 1, src, 0, width, 0); yading@10: } else { yading@10: int i; yading@10: for (i = 0; i < width; i++) yading@10: dst[i] = ff_reverse[src[i]]; yading@10: } yading@10: src += width; yading@10: break; yading@10: case TIFF_PACKBITS: yading@10: for (pixels = 0; pixels < width;) { yading@10: if (ssrc + size - src < 2) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Read went out of bounds\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: code = (int8_t) * src++; yading@10: if (code >= 0) { yading@10: code++; yading@10: if (pixels + code > width) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Copy went out of bounds\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (ssrc + size - src < code) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Read went out of bounds\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), yading@10: dst, 1, src, 0, code, pixels); yading@10: src += code; yading@10: pixels += code; yading@10: } else if (code != -128) { // -127..-1 yading@10: code = (-code) + 1; yading@10: if (pixels + code > width) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Run went out of bounds\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: c = *src++; yading@10: horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), yading@10: dst, 0, NULL, c, code, pixels); yading@10: pixels += code; yading@10: } yading@10: } yading@10: break; yading@10: case TIFF_LZW: yading@10: pixels = ff_lzw_decode(s->lzw, dst, width); yading@10: if (pixels < width) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n", yading@10: pixels, width); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) yading@10: horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0); yading@10: break; yading@10: } yading@10: dst += stride; yading@10: } yading@10: return 0; yading@10: } yading@10: yading@10: static int init_image(TiffContext *s, AVFrame *frame) yading@10: { yading@10: int i, ret; yading@10: uint32_t *pal; yading@10: yading@10: switch (s->bpp * 10 + s->bppcount) { yading@10: case 11: yading@10: if (!s->palette_is_set) { yading@10: s->avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; yading@10: break; yading@10: } yading@10: case 21: yading@10: case 41: yading@10: case 81: yading@10: s->avctx->pix_fmt = AV_PIX_FMT_PAL8; yading@10: break; yading@10: case 243: yading@10: s->avctx->pix_fmt = AV_PIX_FMT_RGB24; yading@10: break; yading@10: case 161: yading@10: s->avctx->pix_fmt = s->le ? AV_PIX_FMT_GRAY16LE : AV_PIX_FMT_GRAY16BE; yading@10: break; yading@10: case 162: yading@10: s->avctx->pix_fmt = AV_PIX_FMT_GRAY8A; yading@10: break; yading@10: case 324: yading@10: s->avctx->pix_fmt = AV_PIX_FMT_RGBA; yading@10: break; yading@10: case 483: yading@10: s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGB48BE; yading@10: break; yading@10: case 644: yading@10: s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_RGBA64BE; yading@10: break; yading@10: default: yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "This format is not supported (bpp=%d, bppcount=%d)\n", yading@10: s->bpp, s->bppcount); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (s->width != s->avctx->width || s->height != s->avctx->height) { yading@10: if ((ret = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0) yading@10: return ret; yading@10: avcodec_set_dimensions(s->avctx, s->width, s->height); yading@10: } yading@10: if ((ret = ff_get_buffer(s->avctx, frame, 0)) < 0) yading@10: return ret; yading@10: if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8) { yading@10: if (s->palette_is_set) { yading@10: memcpy(frame->data[1], s->palette, sizeof(s->palette)); yading@10: } else { yading@10: /* make default grayscale pal */ yading@10: pal = (uint32_t *) frame->data[1]; yading@10: for (i = 0; i < 1<bpp; i++) yading@10: pal[i] = 0xFFU << 24 | i * 255 / ((1<bpp) - 1) * 0x010101; yading@10: } yading@10: } yading@10: return 0; yading@10: } yading@10: yading@10: static int tiff_decode_tag(TiffContext *s, AVFrame *frame) yading@10: { yading@10: unsigned tag, type, count, off, value = 0; yading@10: int i, j, k, pos, start; yading@10: int ret; yading@10: uint32_t *pal; yading@10: double *dp; yading@10: yading@10: tag = tget_short(&s->gb, s->le); yading@10: type = tget_short(&s->gb, s->le); yading@10: count = tget_long(&s->gb, s->le); yading@10: off = tget_long(&s->gb, s->le); yading@10: start = bytestream2_tell(&s->gb); yading@10: yading@10: if (type == 0 || type >= FF_ARRAY_ELEMS(type_sizes)) { yading@10: av_log(s->avctx, AV_LOG_DEBUG, "Unknown tiff type (%u) encountered\n", yading@10: type); yading@10: return 0; yading@10: } yading@10: yading@10: if (count == 1) { yading@10: switch (type) { yading@10: case TIFF_BYTE: yading@10: case TIFF_SHORT: yading@10: bytestream2_seek(&s->gb, -4, SEEK_CUR); yading@10: value = tget(&s->gb, type, s->le); yading@10: break; yading@10: case TIFF_LONG: yading@10: value = off; yading@10: break; yading@10: case TIFF_STRING: yading@10: if (count <= 4) { yading@10: bytestream2_seek(&s->gb, -4, SEEK_CUR); yading@10: break; yading@10: } yading@10: default: yading@10: value = UINT_MAX; yading@10: bytestream2_seek(&s->gb, off, SEEK_SET); yading@10: } yading@10: } else { yading@10: if (count <= 4 && type_sizes[type] * count <= 4) { yading@10: bytestream2_seek(&s->gb, -4, SEEK_CUR); yading@10: } else { yading@10: bytestream2_seek(&s->gb, off, SEEK_SET); yading@10: } yading@10: } yading@10: yading@10: switch (tag) { yading@10: case TIFF_WIDTH: yading@10: s->width = value; yading@10: break; yading@10: case TIFF_HEIGHT: yading@10: s->height = value; yading@10: break; yading@10: case TIFF_BPP: yading@10: s->bppcount = count; yading@10: if (count > 4) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "This format is not supported (bpp=%d, %d components)\n", yading@10: s->bpp, count); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (count == 1) yading@10: s->bpp = value; yading@10: else { yading@10: switch (type) { yading@10: case TIFF_BYTE: yading@10: s->bpp = (off & 0xFF) + ((off >> 8) & 0xFF) + yading@10: ((off >> 16) & 0xFF) + ((off >> 24) & 0xFF); yading@10: break; yading@10: case TIFF_SHORT: yading@10: case TIFF_LONG: yading@10: s->bpp = 0; yading@10: if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count) yading@10: return AVERROR_INVALIDDATA; yading@10: for (i = 0; i < count; i++) yading@10: s->bpp += tget(&s->gb, type, s->le); yading@10: break; yading@10: default: yading@10: s->bpp = -1; yading@10: } yading@10: } yading@10: break; yading@10: case TIFF_SAMPLES_PER_PIXEL: yading@10: if (count != 1) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Samples per pixel requires a single value, many provided\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (value > 4U) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Samples per pixel %d is too large\n", value); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (s->bppcount == 1) yading@10: s->bpp *= value; yading@10: s->bppcount = value; yading@10: break; yading@10: case TIFF_COMPR: yading@10: s->compr = value; yading@10: s->predictor = 0; yading@10: switch (s->compr) { yading@10: case TIFF_RAW: yading@10: case TIFF_PACKBITS: yading@10: case TIFF_LZW: yading@10: case TIFF_CCITT_RLE: yading@10: break; yading@10: case TIFF_G3: yading@10: case TIFF_G4: yading@10: s->fax_opts = 0; yading@10: break; yading@10: case TIFF_DEFLATE: yading@10: case TIFF_ADOBE_DEFLATE: yading@10: #if CONFIG_ZLIB yading@10: break; yading@10: #else yading@10: av_log(s->avctx, AV_LOG_ERROR, "Deflate: ZLib not compiled in\n"); yading@10: return AVERROR(ENOSYS); yading@10: #endif yading@10: case TIFF_JPEG: yading@10: case TIFF_NEWJPEG: yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "JPEG compression is not supported\n"); yading@10: return AVERROR_PATCHWELCOME; yading@10: default: yading@10: av_log(s->avctx, AV_LOG_ERROR, "Unknown compression method %i\n", yading@10: s->compr); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: break; yading@10: case TIFF_ROWSPERSTRIP: yading@10: if (type == TIFF_LONG && value == UINT_MAX) yading@10: value = s->height; yading@10: if (value < 1) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Incorrect value of rows per strip\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: s->rps = value; yading@10: break; yading@10: case TIFF_STRIP_OFFS: yading@10: if (count == 1) { yading@10: s->strippos = 0; yading@10: s->stripoff = value; yading@10: } else yading@10: s->strippos = off; yading@10: s->strips = count; yading@10: if (s->strips == 1) yading@10: s->rps = s->height; yading@10: s->sot = type; yading@10: if (s->strippos > bytestream2_size(&s->gb)) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Tag referencing position outside the image\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: break; yading@10: case TIFF_STRIP_SIZE: yading@10: if (count == 1) { yading@10: s->stripsizesoff = 0; yading@10: s->stripsize = value; yading@10: s->strips = 1; yading@10: } else { yading@10: s->stripsizesoff = off; yading@10: } yading@10: s->strips = count; yading@10: s->sstype = type; yading@10: if (s->stripsizesoff > bytestream2_size(&s->gb)) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Tag referencing position outside the image\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: break; yading@10: case TIFF_TILE_BYTE_COUNTS: yading@10: case TIFF_TILE_LENGTH: yading@10: case TIFF_TILE_OFFSETS: yading@10: case TIFF_TILE_WIDTH: yading@10: av_log(s->avctx, AV_LOG_ERROR, "Tiled images are not supported\n"); yading@10: return AVERROR_PATCHWELCOME; yading@10: break; yading@10: case TIFF_PREDICTOR: yading@10: s->predictor = value; yading@10: break; yading@10: case TIFF_INVERT: yading@10: switch (value) { yading@10: case 0: yading@10: s->invert = 1; yading@10: break; yading@10: case 1: yading@10: s->invert = 0; yading@10: break; yading@10: case 2: yading@10: case 3: yading@10: break; yading@10: default: yading@10: av_log(s->avctx, AV_LOG_ERROR, "Color mode %d is not supported\n", yading@10: value); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: break; yading@10: case TIFF_FILL_ORDER: yading@10: if (value < 1 || value > 2) { yading@10: av_log(s->avctx, AV_LOG_ERROR, yading@10: "Unknown FillOrder value %d, trying default one\n", value); yading@10: value = 1; yading@10: } yading@10: s->fill_order = value - 1; yading@10: break; yading@10: case TIFF_PAL: yading@10: pal = (uint32_t *) s->palette; yading@10: off = type_sizes[type]; yading@10: if (count / 3 > 256 || bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3) yading@10: return AVERROR_INVALIDDATA; yading@10: off = (type_sizes[type] - 1) << 3; yading@10: for (k = 2; k >= 0; k--) { yading@10: for (i = 0; i < count / 3; i++) { yading@10: if (k == 2) yading@10: pal[i] = 0xFFU << 24; yading@10: j = (tget(&s->gb, type, s->le) >> off) << (k * 8); yading@10: pal[i] |= j; yading@10: } yading@10: } yading@10: s->palette_is_set = 1; yading@10: break; yading@10: case TIFF_PLANAR: yading@10: if (value == 2) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Planar format is not supported\n"); yading@10: return AVERROR_PATCHWELCOME; yading@10: } yading@10: break; yading@10: case TIFF_T4OPTIONS: yading@10: if (s->compr == TIFF_G3) yading@10: s->fax_opts = value; yading@10: break; yading@10: case TIFF_T6OPTIONS: yading@10: if (s->compr == TIFF_G4) yading@10: s->fax_opts = value; yading@10: break; yading@10: #define ADD_METADATA(count, name, sep)\ yading@10: if ((ret = add_metadata(count, type, name, sep, s, frame)) < 0) {\ yading@10: av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");\ yading@10: return ret;\ yading@10: } yading@10: case TIFF_MODEL_PIXEL_SCALE: yading@10: ADD_METADATA(count, "ModelPixelScaleTag", NULL); yading@10: break; yading@10: case TIFF_MODEL_TRANSFORMATION: yading@10: ADD_METADATA(count, "ModelTransformationTag", NULL); yading@10: break; yading@10: case TIFF_MODEL_TIEPOINT: yading@10: ADD_METADATA(count, "ModelTiepointTag", NULL); yading@10: break; yading@10: case TIFF_GEO_KEY_DIRECTORY: yading@10: ADD_METADATA(1, "GeoTIFF_Version", NULL); yading@10: ADD_METADATA(2, "GeoTIFF_Key_Revision", "."); yading@10: s->geotag_count = tget_short(&s->gb, s->le); yading@10: if (s->geotag_count > count / 4 - 1) { yading@10: s->geotag_count = count / 4 - 1; yading@10: av_log(s->avctx, AV_LOG_WARNING, "GeoTIFF key directory buffer shorter than specified\n"); yading@10: } yading@10: if (bytestream2_get_bytes_left(&s->gb) < s->geotag_count * sizeof(int16_t) * 4) { yading@10: s->geotag_count = 0; yading@10: return -1; yading@10: } yading@10: s->geotags = av_mallocz(sizeof(TiffGeoTag) * s->geotag_count); yading@10: if (!s->geotags) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); yading@10: s->geotag_count = 0; yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: for (i = 0; i < s->geotag_count; i++) { yading@10: s->geotags[i].key = tget_short(&s->gb, s->le); yading@10: s->geotags[i].type = tget_short(&s->gb, s->le); yading@10: s->geotags[i].count = tget_short(&s->gb, s->le); yading@10: yading@10: if (!s->geotags[i].type) yading@10: s->geotags[i].val = get_geokey_val(s->geotags[i].key, tget_short(&s->gb, s->le)); yading@10: else yading@10: s->geotags[i].offset = tget_short(&s->gb, s->le); yading@10: } yading@10: break; yading@10: case TIFF_GEO_DOUBLE_PARAMS: yading@10: if (count >= INT_MAX / sizeof(int64_t)) yading@10: return AVERROR_INVALIDDATA; yading@10: if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t)) yading@10: return AVERROR_INVALIDDATA; yading@10: dp = av_malloc(count * sizeof(double)); yading@10: if (!dp) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: for (i = 0; i < count; i++) yading@10: dp[i] = tget_double(&s->gb, s->le); yading@10: for (i = 0; i < s->geotag_count; i++) { yading@10: if (s->geotags[i].type == TIFF_GEO_DOUBLE_PARAMS) { yading@10: if (s->geotags[i].count == 0 yading@10: || s->geotags[i].offset + s->geotags[i].count > count) { yading@10: av_log(s->avctx, AV_LOG_WARNING, "Invalid GeoTIFF key %d\n", s->geotags[i].key); yading@10: } else { yading@10: char *ap = doubles2str(&dp[s->geotags[i].offset], s->geotags[i].count, ", "); yading@10: if (!ap) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); yading@10: av_freep(&dp); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: s->geotags[i].val = ap; yading@10: } yading@10: } yading@10: } yading@10: av_freep(&dp); yading@10: break; yading@10: case TIFF_GEO_ASCII_PARAMS: yading@10: pos = bytestream2_tell(&s->gb); yading@10: for (i = 0; i < s->geotag_count; i++) { yading@10: if (s->geotags[i].type == TIFF_GEO_ASCII_PARAMS) { yading@10: if (s->geotags[i].count == 0 yading@10: || s->geotags[i].offset + s->geotags[i].count > count) { yading@10: av_log(s->avctx, AV_LOG_WARNING, "Invalid GeoTIFF key %d\n", s->geotags[i].key); yading@10: } else { yading@10: char *ap; yading@10: yading@10: bytestream2_seek(&s->gb, pos + s->geotags[i].offset, SEEK_SET); yading@10: if (bytestream2_get_bytes_left(&s->gb) < s->geotags[i].count) yading@10: return AVERROR_INVALIDDATA; yading@10: ap = av_malloc(s->geotags[i].count); yading@10: if (!ap) { yading@10: av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: bytestream2_get_bufferu(&s->gb, ap, s->geotags[i].count); yading@10: ap[s->geotags[i].count - 1] = '\0'; //replace the "|" delimiter with a 0 byte yading@10: s->geotags[i].val = ap; yading@10: } yading@10: } yading@10: } yading@10: break; yading@10: case TIFF_ARTIST: yading@10: ADD_METADATA(count, "artist", NULL); yading@10: break; yading@10: case TIFF_COPYRIGHT: yading@10: ADD_METADATA(count, "copyright", NULL); yading@10: break; yading@10: case TIFF_DATE: yading@10: ADD_METADATA(count, "date", NULL); yading@10: break; yading@10: case TIFF_DOCUMENT_NAME: yading@10: ADD_METADATA(count, "document_name", NULL); yading@10: break; yading@10: case TIFF_HOST_COMPUTER: yading@10: ADD_METADATA(count, "computer", NULL); yading@10: break; yading@10: case TIFF_IMAGE_DESCRIPTION: yading@10: ADD_METADATA(count, "description", NULL); yading@10: break; yading@10: case TIFF_MAKE: yading@10: ADD_METADATA(count, "make", NULL); yading@10: break; yading@10: case TIFF_MODEL: yading@10: ADD_METADATA(count, "model", NULL); yading@10: break; yading@10: case TIFF_PAGE_NAME: yading@10: ADD_METADATA(count, "page_name", NULL); yading@10: break; yading@10: case TIFF_PAGE_NUMBER: yading@10: ADD_METADATA(count, "page_number", " / "); yading@10: break; yading@10: case TIFF_SOFTWARE_NAME: yading@10: ADD_METADATA(count, "software", NULL); yading@10: break; yading@10: default: yading@10: av_log(s->avctx, AV_LOG_DEBUG, "Unknown or unsupported tag %d/0X%0X\n", yading@10: tag, tag); yading@10: } yading@10: bytestream2_seek(&s->gb, start, SEEK_SET); yading@10: return 0; yading@10: } yading@10: yading@10: static int decode_frame(AVCodecContext *avctx, yading@10: void *data, int *got_frame, AVPacket *avpkt) yading@10: { yading@10: TiffContext *const s = avctx->priv_data; yading@10: AVFrame *const p = data; yading@10: unsigned off; yading@10: int id, le, ret; yading@10: int i, j, entries; yading@10: int stride; yading@10: unsigned soff, ssize; yading@10: uint8_t *dst; yading@10: GetByteContext stripsizes; yading@10: GetByteContext stripdata; yading@10: yading@10: bytestream2_init(&s->gb, avpkt->data, avpkt->size); yading@10: yading@10: //parse image header yading@10: if (avpkt->size < 8) yading@10: return AVERROR_INVALIDDATA; yading@10: id = bytestream2_get_le16u(&s->gb); yading@10: if (id == 0x4949) yading@10: le = 1; yading@10: else if (id == 0x4D4D) yading@10: le = 0; yading@10: else { yading@10: av_log(avctx, AV_LOG_ERROR, "TIFF header not found\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: s->le = le; yading@10: // TIFF_BPP is not a required tag and defaults to 1 yading@10: s->bppcount = s->bpp = 1; yading@10: s->invert = 0; yading@10: s->compr = TIFF_RAW; yading@10: s->fill_order = 0; yading@10: free_geotags(s); yading@10: yading@10: // As TIFF 6.0 specification puts it "An arbitrary but carefully chosen number yading@10: // that further identifies the file as a TIFF file" yading@10: if (tget_short(&s->gb, le) != 42) { yading@10: av_log(avctx, AV_LOG_ERROR, yading@10: "The answer to life, universe and everything is not correct!\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: // Reset these offsets so we can tell if they were set this frame yading@10: s->stripsizesoff = s->strippos = 0; yading@10: /* parse image file directory */ yading@10: off = tget_long(&s->gb, le); yading@10: if (off >= UINT_MAX - 14 || avpkt->size < off + 14) { yading@10: av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: bytestream2_seek(&s->gb, off, SEEK_SET); yading@10: entries = tget_short(&s->gb, le); yading@10: if (bytestream2_get_bytes_left(&s->gb) < entries * 12) yading@10: return AVERROR_INVALIDDATA; yading@10: for (i = 0; i < entries; i++) { yading@10: if ((ret = tiff_decode_tag(s, p)) < 0) yading@10: return ret; yading@10: } yading@10: yading@10: for (i = 0; igeotag_count; i++) { yading@10: const char *keyname = get_geokey_name(s->geotags[i].key); yading@10: if (!keyname) { yading@10: av_log(avctx, AV_LOG_WARNING, "Unknown or unsupported GeoTIFF key %d\n", s->geotags[i].key); yading@10: continue; yading@10: } yading@10: if (get_geokey_type(s->geotags[i].key) != s->geotags[i].type) { yading@10: av_log(avctx, AV_LOG_WARNING, "Type of GeoTIFF key %d is wrong\n", s->geotags[i].key); yading@10: continue; yading@10: } yading@10: ret = av_dict_set(avpriv_frame_get_metadatap(p), keyname, s->geotags[i].val, 0); yading@10: if (ret<0) { yading@10: av_log(avctx, AV_LOG_ERROR, "Writing metadata with key '%s' failed\n", keyname); yading@10: return ret; yading@10: } yading@10: } yading@10: yading@10: if (!s->strippos && !s->stripoff) { yading@10: av_log(avctx, AV_LOG_ERROR, "Image data is missing\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: /* now we have the data and may start decoding */ yading@10: if ((ret = init_image(s, p)) < 0) yading@10: return ret; yading@10: yading@10: if (s->strips == 1 && !s->stripsize) { yading@10: av_log(avctx, AV_LOG_WARNING, "Image data size missing\n"); yading@10: s->stripsize = avpkt->size - s->stripoff; yading@10: } yading@10: stride = p->linesize[0]; yading@10: dst = p->data[0]; yading@10: yading@10: if (s->stripsizesoff) { yading@10: if (s->stripsizesoff >= (unsigned)avpkt->size) yading@10: return AVERROR_INVALIDDATA; yading@10: bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff, avpkt->size - s->stripsizesoff); yading@10: } yading@10: if (s->strippos) { yading@10: if (s->strippos >= (unsigned)avpkt->size) yading@10: return AVERROR_INVALIDDATA; yading@10: bytestream2_init(&stripdata, avpkt->data + s->strippos, avpkt->size - s->strippos); yading@10: } yading@10: yading@10: if (s->rps <= 0) { yading@10: av_log(avctx, AV_LOG_ERROR, "rps %d invalid\n", s->rps); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: for (i = 0; i < s->height; i += s->rps) { yading@10: if (s->stripsizesoff) yading@10: ssize = tget(&stripsizes, s->sstype, s->le); yading@10: else yading@10: ssize = s->stripsize; yading@10: yading@10: if (s->strippos) yading@10: soff = tget(&stripdata, s->sot, s->le); yading@10: else yading@10: soff = s->stripoff; yading@10: yading@10: if (soff > avpkt->size || ssize > avpkt->size - soff) { yading@10: av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (tiff_unpack_strip(s, dst, stride, avpkt->data + soff, ssize, yading@10: FFMIN(s->rps, s->height - i)) < 0) yading@10: break; yading@10: dst += s->rps * stride; yading@10: } yading@10: if (s->predictor == 2) { yading@10: dst = p->data[0]; yading@10: soff = s->bpp >> 3; yading@10: ssize = s->width * soff; yading@10: if (s->avctx->pix_fmt == AV_PIX_FMT_RGB48LE || yading@10: s->avctx->pix_fmt == AV_PIX_FMT_RGBA64LE) { yading@10: for (i = 0; i < s->height; i++) { yading@10: for (j = soff; j < ssize; j += 2) yading@10: AV_WL16(dst + j, AV_RL16(dst + j) + AV_RL16(dst + j - soff)); yading@10: dst += stride; yading@10: } yading@10: } else if (s->avctx->pix_fmt == AV_PIX_FMT_RGB48BE || yading@10: s->avctx->pix_fmt == AV_PIX_FMT_RGBA64BE) { yading@10: for (i = 0; i < s->height; i++) { yading@10: for (j = soff; j < ssize; j += 2) yading@10: AV_WB16(dst + j, AV_RB16(dst + j) + AV_RB16(dst + j - soff)); yading@10: dst += stride; yading@10: } yading@10: } else { yading@10: for (i = 0; i < s->height; i++) { yading@10: for (j = soff; j < ssize; j++) yading@10: dst[j] += dst[j - soff]; yading@10: dst += stride; yading@10: } yading@10: } yading@10: } yading@10: yading@10: if (s->invert) { yading@10: dst = p->data[0]; yading@10: for (i = 0; i < s->height; i++) { yading@10: for (j = 0; j < p->linesize[0]; j++) yading@10: dst[j] = (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 ? (1<bpp) - 1 : 255) - dst[j]; yading@10: dst += p->linesize[0]; yading@10: } yading@10: } yading@10: *got_frame = 1; yading@10: yading@10: return avpkt->size; yading@10: } yading@10: yading@10: static av_cold int tiff_init(AVCodecContext *avctx) yading@10: { yading@10: TiffContext *s = avctx->priv_data; yading@10: yading@10: s->width = 0; yading@10: s->height = 0; yading@10: s->avctx = avctx; yading@10: ff_lzw_decode_open(&s->lzw); yading@10: ff_ccitt_unpack_init(); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static av_cold int tiff_end(AVCodecContext *avctx) yading@10: { yading@10: TiffContext *const s = avctx->priv_data; yading@10: yading@10: free_geotags(s); yading@10: yading@10: ff_lzw_decode_close(&s->lzw); yading@10: av_freep(&s->deinvert_buf); yading@10: return 0; yading@10: } yading@10: yading@10: AVCodec ff_tiff_decoder = { yading@10: .name = "tiff", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_TIFF, yading@10: .priv_data_size = sizeof(TiffContext), yading@10: .init = tiff_init, yading@10: .close = tiff_end, yading@10: .decode = decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("TIFF image"), yading@10: };