diff options
Diffstat (limited to 'chromium/third_party/ffmpeg/libavcodec/tiff.c')
-rw-r--r-- | chromium/third_party/ffmpeg/libavcodec/tiff.c | 285 |
1 files changed, 208 insertions, 77 deletions
diff --git a/chromium/third_party/ffmpeg/libavcodec/tiff.c b/chromium/third_party/ffmpeg/libavcodec/tiff.c index cd209674ca7..1caad84845f 100644 --- a/chromium/third_party/ffmpeg/libavcodec/tiff.c +++ b/chromium/third_party/ffmpeg/libavcodec/tiff.c @@ -53,11 +53,13 @@ typedef struct TiffContext { int palette_is_set; int le; enum TiffCompr compr; - int invert; + enum TiffPhotometric photometric; int planar; + int subsampling[2]; int fax_opts; int predictor; int fill_order; + uint32_t res[4]; int strips, rps, sstype; int sot; @@ -66,6 +68,8 @@ typedef struct TiffContext { uint8_t *deinvert_buf; int deinvert_buf_size; + uint8_t *yuv_line; + unsigned int yuv_line_size; int geotag_count; TiffGeoTag *geotags; @@ -79,6 +83,7 @@ static void free_geotags(TiffContext *const s) av_freep(&s->geotags[i].val); } av_freep(&s->geotags); + s->geotag_count = 0; } #define RET_GEOKEY(TYPE, array, element)\ @@ -194,7 +199,7 @@ static char *doubles2str(double *dp, int count, const char *sep) char *ap, *ap0; uint64_t component_len; if (!sep) sep = ", "; - component_len = 15LL + strlen(sep); + component_len = 24LL + strlen(sep); if (count >= (INT_MAX - 1)/component_len) return NULL; ap = av_malloc(component_len * count + 1); @@ -203,7 +208,7 @@ static char *doubles2str(double *dp, int count, const char *sep) ap0 = ap; ap[0] = '\0'; for (i = 0; i < count; i++) { - unsigned l = snprintf(ap, component_len, "%f%s", dp[i], sep); + unsigned l = snprintf(ap, component_len, "%.15g%s", dp[i], sep); if(l >= component_len) { av_free(ap0); return NULL; @@ -219,7 +224,7 @@ static int add_metadata(int count, int type, { switch(type) { 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_SHORT : return ff_tadd_shorts_metadata(count, name, sep, &s->gb, s->le, 0, 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; }; @@ -378,12 +383,43 @@ static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride, return ret; } -static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride, - const uint8_t *src, int size, int lines) +static void unpack_yuv(TiffContext *s, AVFrame *p, + const uint8_t *src, int lnum) { + int i, j, k; + int w = (s->width - 1) / s->subsampling[0] + 1; + uint8_t *pu = &p->data[1][lnum / s->subsampling[1] * p->linesize[1]]; + uint8_t *pv = &p->data[2][lnum / s->subsampling[1] * p->linesize[2]]; + if (s->width % s->subsampling[0] || s->height % s->subsampling[1]) { + for (i = 0; i < w; i++) { + for (j = 0; j < s->subsampling[1]; j++) + for (k = 0; k < s->subsampling[0]; k++) + p->data[0][FFMIN(lnum + j, s->height-1) * p->linesize[0] + + FFMIN(i * s->subsampling[0] + k, s->width-1)] = *src++; + *pu++ = *src++; + *pv++ = *src++; + } + }else{ + for (i = 0; i < w; i++) { + for (j = 0; j < s->subsampling[1]; j++) + for (k = 0; k < s->subsampling[0]; k++) + p->data[0][(lnum + j) * p->linesize[0] + + i * s->subsampling[0] + k] = *src++; + *pu++ = *src++; + *pv++ = *src++; + } + } +} + + +static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int stride, + const uint8_t *src, int size, int strip_start, int lines) +{ + PutByteContext pb; int c, line, pixels, code, ret; const uint8_t *ssrc = src; - int width = ((s->width * s->bpp) + 7) >> 3; + int width = ((s->width * s->bpp) + 7) >> 3; + int is_yuv = s->photometric == TIFF_PHOTOMETRIC_YCBCR; if (s->planar) width /= s->bppcount; @@ -391,7 +427,26 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride, if (size <= 0) return AVERROR_INVALIDDATA; + if (is_yuv) { + int bytes_per_row = (((s->width - 1) / s->subsampling[0] + 1) * s->bpp * + s->subsampling[0] * s->subsampling[1] + 7) >> 3; + av_fast_padded_malloc(&s->yuv_line, &s->yuv_line_size, bytes_per_row); + if (s->yuv_line == NULL) { + av_log(s->avctx, AV_LOG_ERROR, "Not enough memory\n"); + return AVERROR(ENOMEM); + } + dst = s->yuv_line; + stride = 0; + width = s->width * s->subsampling[1] + 2*(s->width / s->subsampling[0]); + av_assert0(width <= bytes_per_row); + av_assert0(s->bpp == 24); + } + if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE) { + if (is_yuv) { + av_log(s->avctx, AV_LOG_ERROR, "YUV deflate is unsupported"); + return AVERROR_PATCHWELCOME; + } #if CONFIG_ZLIB return tiff_unpack_zlib(s, dst, stride, src, size, width, lines); #else @@ -414,21 +469,49 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride, av_log(s->avctx, AV_LOG_ERROR, "Error initializing LZW decoder\n"); return ret; } + for (line = 0; line < lines; line++) { + pixels = ff_lzw_decode(s->lzw, dst, width); + if (pixels < width) { + av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n", + pixels, width); + return AVERROR_INVALIDDATA; + } + if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) + horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0); + if (is_yuv) { + unpack_yuv(s, p, dst, strip_start + line); + line += s->subsampling[1] - 1; + } + dst += stride; + } + return 0; } if (s->compr == TIFF_CCITT_RLE || s->compr == TIFF_G3 || s->compr == TIFF_G4) { + if (is_yuv) + return AVERROR_INVALIDDATA; + return tiff_unpack_fax(s, dst, stride, src, size, width, lines); } + + bytestream2_init(&s->gb, src, size); + bytestream2_init_writer(&pb, dst, is_yuv ? s->yuv_line_size : (stride * lines)); + for (line = 0; line < lines; line++) { if (src - ssrc > size) { av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n"); return AVERROR_INVALIDDATA; } + + if (bytestream2_get_bytes_left(&s->gb) == 0 || bytestream2_get_eof(&pb)) + break; + bytestream2_seek_p(&pb, stride * line, SEEK_SET); switch (s->compr) { case TIFF_RAW: if (ssrc + size - src < width) return AVERROR_INVALIDDATA; + if (!s->fill_order) { horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), dst, 1, src, 0, width, 0); @@ -477,16 +560,10 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride, dst[i] = ff_reverse[dst[i]]; } break; - case TIFF_LZW: - pixels = ff_lzw_decode(s->lzw, dst, width); - if (pixels < width) { - av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n", - pixels, width); - return AVERROR_INVALIDDATA; - } - if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) - horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0); - break; + } + if (is_yuv) { + unpack_yuv(s, p, dst, strip_start + line); + line += s->subsampling[1] - 1; } dst += stride; } @@ -510,7 +587,25 @@ static int init_image(TiffContext *s, ThreadFrame *frame) s->avctx->pix_fmt = AV_PIX_FMT_PAL8; break; case 243: - s->avctx->pix_fmt = AV_PIX_FMT_RGB24; + if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) { + if (s->subsampling[0] == 1 && s->subsampling[1] == 1) { + s->avctx->pix_fmt = AV_PIX_FMT_YUV444P; + } else if (s->subsampling[0] == 2 && s->subsampling[1] == 1) { + s->avctx->pix_fmt = AV_PIX_FMT_YUV422P; + } else if (s->subsampling[0] == 4 && s->subsampling[1] == 1) { + s->avctx->pix_fmt = AV_PIX_FMT_YUV411P; + } else if (s->subsampling[0] == 1 && s->subsampling[1] == 2) { + s->avctx->pix_fmt = AV_PIX_FMT_YUV440P; + } else if (s->subsampling[0] == 2 && s->subsampling[1] == 2) { + s->avctx->pix_fmt = AV_PIX_FMT_YUV420P; + } else if (s->subsampling[0] == 4 && s->subsampling[1] == 4) { + s->avctx->pix_fmt = AV_PIX_FMT_YUV410P; + } else { + av_log(s->avctx, AV_LOG_ERROR, "Unsupported YCbCr subsampling\n"); + return AVERROR_PATCHWELCOME; + } + } else + s->avctx->pix_fmt = AV_PIX_FMT_RGB24; break; case 161: s->avctx->pix_fmt = s->le ? AV_PIX_FMT_GRAY16LE : AV_PIX_FMT_GRAY16BE; @@ -565,12 +660,22 @@ static int init_image(TiffContext *s, ThreadFrame *frame) return 0; } +static void set_sar(TiffContext *s, unsigned tag, unsigned num, unsigned den) +{ + int offset = tag == TIFF_YRES ? 2 : 0; + s->res[offset++] = num; + s->res[offset] = den; + if (s->res[0] && s->res[1] && s->res[2] && s->res[3]) + av_reduce(&s->avctx->sample_aspect_ratio.num, &s->avctx->sample_aspect_ratio.den, + s->res[2] * (uint64_t)s->res[1], s->res[0] * (uint64_t)s->res[3], INT32_MAX); +} + static int tiff_decode_tag(TiffContext *s, AVFrame *frame) { - unsigned tag, type, count, off, value = 0; - int i, j, k, pos, start; + unsigned tag, type, count, off, value = 0, value2 = 0; + int i, start; + int pos; int ret; - uint32_t *pal; double *dp; ret = ff_tread_tag(&s->gb, s->le, &tag, &type, &count, &start); @@ -586,6 +691,10 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) case TIFF_LONG: value = ff_tget(&s->gb, type, s->le); break; + case TIFF_RATIONAL: + value = ff_tget(&s->gb, TIFF_LONG, s->le); + value2 = ff_tget(&s->gb, TIFF_LONG, s->le); + break; case TIFF_STRING: if (count <= 4) { break; @@ -675,46 +784,35 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } break; case TIFF_ROWSPERSTRIP: - if (type == TIFF_LONG && value == UINT_MAX) + if (!value || (type == TIFF_LONG && value == UINT_MAX)) value = s->height; - if (value < 1) { - av_log(s->avctx, AV_LOG_ERROR, - "Incorrect value of rows per strip\n"); - return AVERROR_INVALIDDATA; - } - s->rps = value; + s->rps = FFMIN(value, s->height); break; case TIFF_STRIP_OFFS: if (count == 1) { - s->strippos = 0; - s->stripoff = value; + s->strippos = 0; + s->stripoff = value; } else s->strippos = off; s->strips = count; if (s->strips == 1) s->rps = s->height; s->sot = type; - if (s->strippos > bytestream2_size(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, - "Tag referencing position outside the image\n"); - return AVERROR_INVALIDDATA; - } break; case TIFF_STRIP_SIZE: if (count == 1) { s->stripsizesoff = 0; - s->stripsize = value; - s->strips = 1; + s->stripsize = value; + s->strips = 1; } else { s->stripsizesoff = off; } s->strips = count; s->sstype = type; - if (s->stripsizesoff > bytestream2_size(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, - "Tag referencing position outside the image\n"); - return AVERROR_INVALIDDATA; - } + break; + case TIFF_XRES: + case TIFF_YRES: + set_sar(s, tag, value, value2); break; case TIFF_TILE_BYTE_COUNTS: case TIFF_TILE_LENGTH: @@ -726,20 +824,31 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) case TIFF_PREDICTOR: s->predictor = value; break; - case TIFF_INVERT: + case TIFF_PHOTOMETRIC: switch (value) { - case 0: - s->invert = 1; - break; - case 1: - s->invert = 0; - break; - case 2: - case 3: + case TIFF_PHOTOMETRIC_WHITE_IS_ZERO: + case TIFF_PHOTOMETRIC_BLACK_IS_ZERO: + case TIFF_PHOTOMETRIC_RGB: + case TIFF_PHOTOMETRIC_PALETTE: + case TIFF_PHOTOMETRIC_YCBCR: + s->photometric = value; break; + case TIFF_PHOTOMETRIC_ALPHA_MASK: + case TIFF_PHOTOMETRIC_SEPARATED: + case TIFF_PHOTOMETRIC_CIE_LAB: + case TIFF_PHOTOMETRIC_ICC_LAB: + case TIFF_PHOTOMETRIC_ITU_LAB: + case TIFF_PHOTOMETRIC_CFA: + case TIFF_PHOTOMETRIC_LOG_L: + case TIFF_PHOTOMETRIC_LOG_LUV: + case TIFF_PHOTOMETRIC_LINEAR_RAW: + avpriv_report_missing_feature(s->avctx, + "PhotometricInterpretation 0x%04X", + value); + return AVERROR_PATCHWELCOME; default: - av_log(s->avctx, AV_LOG_ERROR, "Color mode %d is not supported\n", - value); + av_log(s->avctx, AV_LOG_ERROR, "PhotometricInterpretation %u is " + "unknown\n", value); return AVERROR_INVALIDDATA; } break; @@ -751,25 +860,39 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } s->fill_order = value - 1; break; - case TIFF_PAL: - pal = (uint32_t *) s->palette; + case TIFF_PAL: { + GetByteContext pal_gb[3]; off = type_sizes[type]; - if (count / 3 > 256 || bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3) + if (count / 3 > 256 || + bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3) return AVERROR_INVALIDDATA; + + pal_gb[0] = pal_gb[1] = pal_gb[2] = s->gb; + bytestream2_skip(&pal_gb[1], count / 3 * off); + bytestream2_skip(&pal_gb[2], count / 3 * off * 2); + off = (type_sizes[type] - 1) << 3; - for (k = 2; k >= 0; k--) { - for (i = 0; i < count / 3; i++) { - if (k == 2) - pal[i] = 0xFFU << 24; - j = (ff_tget(&s->gb, type, s->le) >> off) << (k * 8); - pal[i] |= j; - } + for (i = 0; i < count / 3; i++) { + uint32_t p = 0xFF000000; + p |= (ff_tget(&pal_gb[0], type, s->le) >> off) << 16; + p |= (ff_tget(&pal_gb[1], type, s->le) >> off) << 8; + p |= ff_tget(&pal_gb[2], type, s->le) >> off; + s->palette[i] = p; } s->palette_is_set = 1; break; + } case TIFF_PLANAR: s->planar = value == 2; break; + case TIFF_YCBCR_SUBSAMPLING: + if (count != 2) { + av_log(s->avctx, AV_LOG_ERROR, "subsample count invalid\n"); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < count; i++) + s->subsampling[i] = ff_tget(&s->gb, type, s->le); + break; case TIFF_T4OPTIONS: if (s->compr == TIFF_G3) s->fax_opts = value; @@ -804,7 +927,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) s->geotag_count = 0; return -1; } - s->geotags = av_mallocz(sizeof(TiffGeoTag) * s->geotag_count); + s->geotags = av_mallocz_array(s->geotag_count, sizeof(TiffGeoTag)); if (!s->geotags) { av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); s->geotag_count = 0; @@ -826,7 +949,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) return AVERROR_INVALIDDATA; if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t)) return AVERROR_INVALIDDATA; - dp = av_malloc(count * sizeof(double)); + dp = av_malloc_array(count, sizeof(double)); if (!dp) { av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); goto end; @@ -946,12 +1069,12 @@ static int decode_frame(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n"); return AVERROR_INVALIDDATA; } - s->le = le; + s->le = le; // TIFF_BPP is not a required tag and defaults to 1 - s->bppcount = s->bpp = 1; - s->invert = 0; - s->compr = TIFF_RAW; - s->fill_order = 0; + s->bppcount = s->bpp = 1; + s->photometric = TIFF_PHOTOMETRIC_NONE; + s->compr = TIFF_RAW; + s->fill_order = 0; free_geotags(s); // Reset these offsets so we can tell if they were set this frame @@ -999,12 +1122,14 @@ static int decode_frame(AVCodecContext *avctx, if (s->stripsizesoff) { if (s->stripsizesoff >= (unsigned)avpkt->size) return AVERROR_INVALIDDATA; - bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff, avpkt->size - s->stripsizesoff); + bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff, + avpkt->size - s->stripsizesoff); } if (s->strippos) { if (s->strippos >= (unsigned)avpkt->size) return AVERROR_INVALIDDATA; - bytestream2_init(&stripdata, avpkt->data + s->strippos, avpkt->size - s->strippos); + bytestream2_init(&stripdata, avpkt->data + s->strippos, + avpkt->size - s->strippos); } if (s->rps <= 0) { @@ -1018,12 +1143,12 @@ static int decode_frame(AVCodecContext *avctx, dst = p->data[plane]; for (i = 0; i < s->height; i += s->rps) { if (s->stripsizesoff) - ssize = ff_tget(&stripsizes, s->sstype, s->le); + ssize = ff_tget(&stripsizes, s->sstype, le); else ssize = s->stripsize; if (s->strippos) - soff = ff_tget(&stripdata, s->sot, s->le); + soff = ff_tget(&stripdata, s->sot, le); else soff = s->stripoff; @@ -1031,7 +1156,7 @@ static int decode_frame(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n"); return AVERROR_INVALIDDATA; } - if ((ret = tiff_unpack_strip(s, dst, stride, avpkt->data + soff, ssize, + if ((ret = tiff_unpack_strip(s, p, dst, stride, avpkt->data + soff, ssize, i, FFMIN(s->rps, s->height - i))) < 0) { if (avctx->err_recognition & AV_EF_EXPLODE) return ret; @@ -1040,6 +1165,10 @@ static int decode_frame(AVCodecContext *avctx, dst += s->rps * stride; } if (s->predictor == 2) { + if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) { + av_log(s->avctx, AV_LOG_ERROR, "predictor == 2 with YUV is unsupported"); + return AVERROR_PATCHWELCOME; + } dst = p->data[plane]; soff = s->bpp >> 3; if (s->planar) @@ -1072,12 +1201,12 @@ static int decode_frame(AVCodecContext *avctx, } } - if (s->invert) { + if (s->photometric == TIFF_PHOTOMETRIC_WHITE_IS_ZERO) { dst = p->data[plane]; for (i = 0; i < s->height; i++) { for (j = 0; j < p->linesize[plane]; j++) dst[j] = (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 ? (1<<s->bpp) - 1 : 255) - dst[j]; - dst += p->linesize[plane]; + dst += stride; } } } @@ -1100,6 +1229,8 @@ static av_cold int tiff_init(AVCodecContext *avctx) s->width = 0; s->height = 0; + s->subsampling[0] = + s->subsampling[1] = 1; s->avctx = avctx; ff_lzw_decode_open(&s->lzw); ff_ccitt_unpack_init(); |