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 is_yuv = s->photometric == TIFF_PHOTOMETRIC_YCBCR; if (s->planar) width /= s->bppcount; 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 av_log(s->avctx, AV_LOG_ERROR, "zlib support not enabled, " "deflate compression not supported\n"); return AVERROR(ENOSYS); #endif } if (s->compr == TIFF_LZW) { if (s->fill_order) { if ((ret = deinvert_buffer(s, src, size)) < 0) return ret; ssrc = src = s->deinvert_buf; } if (size > 1 && !src[0] && (src[1]&1)) { av_log(s->avctx, AV_LOG_ERROR, "Old style LZW is unsupported\n"); } if ((ret = ff_lzw_decode_init(s->lzw, 8, src, size, FF_LZW_TIFF)) < 0) { 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); } else { int i; for (i = 0; i < width; i++) dst[i] = ff_reverse[src[i]]; } src += width; break; case TIFF_PACKBITS: for (pixels = 0; pixels < width;) { if (ssrc + size - src < 2) { av_log(s->avctx, AV_LOG_ERROR, "Read went out of bounds\n"); return AVERROR_INVALIDDATA; } code = s->fill_order ? (int8_t) ff_reverse[*src++]: (int8_t) *src++; if (code >= 0) { code++; if (pixels + code > width || ssrc + size - src < code) { av_log(s->avctx, AV_LOG_ERROR, "Copy went out of bounds\n"); return AVERROR_INVALIDDATA; } horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), dst, 1, src, 0, code, pixels); src += code; pixels += code; } else if (code != -128) { // -127..-1 code = (-code) + 1; if (pixels + code > width) { av_log(s->avctx, AV_LOG_ERROR, "Run went out of bounds\n"); return AVERROR_INVALIDDATA; } c = *src++; horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), dst, 0, NULL, c, code, pixels); pixels += code; } } if (s->fill_order) { int i; for (i = 0; i < width; i++) dst[i] = ff_reverse[dst[i]]; } break; } if (is_yuv) { unpack_yuv(s, p, dst, strip_start + line); line += s->subsampling[1] - 1; } dst += stride; } return 0; }
static int gif_read_image(GifState *s, AVFrame *frame) { int left, top, width, height, bits_per_pixel, code_size, flags, pw; int is_interleaved, has_local_palette, y, pass, y1, linesize, pal_size; uint32_t *ptr, *pal, *px, *pr, *ptr1; int ret; uint8_t *idx; /* At least 9 bytes of Image Descriptor. */ if (bytestream2_get_bytes_left(&s->gb) < 9) return AVERROR_INVALIDDATA; left = bytestream2_get_le16u(&s->gb); top = bytestream2_get_le16u(&s->gb); width = bytestream2_get_le16u(&s->gb); height = bytestream2_get_le16u(&s->gb); flags = bytestream2_get_byteu(&s->gb); is_interleaved = flags & 0x40; has_local_palette = flags & 0x80; bits_per_pixel = (flags & 0x07) + 1; av_dlog(s->avctx, "image x=%d y=%d w=%d h=%d\n", left, top, width, height); if (has_local_palette) { pal_size = 1 << bits_per_pixel; if (bytestream2_get_bytes_left(&s->gb) < pal_size * 3) return AVERROR_INVALIDDATA; gif_read_palette(s, s->local_palette, pal_size); pal = s->local_palette; } else { if (!s->has_global_palette) { av_log(s->avctx, AV_LOG_ERROR, "picture doesn't have either global or local palette.\n"); return AVERROR_INVALIDDATA; } pal = s->global_palette; } if (s->keyframe) { if (s->transparent_color_index == -1 && s->has_global_palette) { /* transparency wasn't set before the first frame, fill with background color */ gif_fill(frame, s->bg_color); } else { /* otherwise fill with transparent color. * this is necessary since by default picture filled with 0x80808080. */ gif_fill(frame, s->trans_color); } } /* verify that all the image is inside the screen dimensions */ if (!width || width > s->screen_width || left >= s->screen_width) { av_log(s->avctx, AV_LOG_ERROR, "Invalid image width.\n"); return AVERROR_INVALIDDATA; } if (!height || height > s->screen_height || top >= s->screen_height) { av_log(s->avctx, AV_LOG_ERROR, "Invalid image height.\n"); return AVERROR_INVALIDDATA; } if (left + width > s->screen_width) { /* width must be kept around to avoid lzw vs line desync */ pw = s->screen_width - left; av_log(s->avctx, AV_LOG_WARNING, "Image too wide by %d, truncating.\n", left + width - s->screen_width); } else { pw = width; } if (top + height > s->screen_height) { /* we don't care about the extra invisible lines */ av_log(s->avctx, AV_LOG_WARNING, "Image too high by %d, truncating.\n", top + height - s->screen_height); height = s->screen_height - top; } /* process disposal method */ if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) { gif_fill_rect(frame, s->stored_bg_color, s->gce_l, s->gce_t, s->gce_w, s->gce_h); } else if (s->gce_prev_disposal == GCE_DISPOSAL_RESTORE) { gif_copy_img_rect(s->stored_img, (uint32_t *)frame->data[0], frame->linesize[0] / sizeof(uint32_t), s->gce_l, s->gce_t, s->gce_w, s->gce_h); } s->gce_prev_disposal = s->gce_disposal; if (s->gce_disposal != GCE_DISPOSAL_NONE) { s->gce_l = left; s->gce_t = top; s->gce_w = pw; s->gce_h = height; if (s->gce_disposal == GCE_DISPOSAL_BACKGROUND) { if (s->transparent_color_index >= 0) s->stored_bg_color = s->trans_color; else s->stored_bg_color = s->bg_color; } else if (s->gce_disposal == GCE_DISPOSAL_RESTORE) { av_fast_malloc(&s->stored_img, &s->stored_img_size, frame->linesize[0] * frame->height); if (!s->stored_img) return AVERROR(ENOMEM); gif_copy_img_rect((uint32_t *)frame->data[0], s->stored_img, frame->linesize[0] / sizeof(uint32_t), left, top, pw, height); } } /* Expect at least 2 bytes: 1 for lzw code size and 1 for block size. */ if (bytestream2_get_bytes_left(&s->gb) < 2) return AVERROR_INVALIDDATA; /* now get the image data */ code_size = bytestream2_get_byteu(&s->gb); if ((ret = ff_lzw_decode_init(s->lzw, code_size, s->gb.buffer, bytestream2_get_bytes_left(&s->gb), FF_LZW_GIF)) < 0) { av_log(s->avctx, AV_LOG_ERROR, "LZW init failed\n"); return ret; } /* read all the image */ linesize = frame->linesize[0] / sizeof(uint32_t); ptr1 = (uint32_t *)frame->data[0] + top * linesize + left; ptr = ptr1; pass = 0; y1 = 0; for (y = 0; y < height; y++) { int count = ff_lzw_decode(s->lzw, s->idx_line, width); if (count != width) { if (count) av_log(s->avctx, AV_LOG_ERROR, "LZW decode failed\n"); goto decode_tail; } pr = ptr + pw; for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) { if (*idx != s->transparent_color_index) *px = pal[*idx]; } if (is_interleaved) { switch(pass) { default: case 0: case 1: y1 += 8; ptr += linesize * 8; if (y1 >= height) { y1 = pass ? 2 : 4; ptr = ptr1 + linesize * y1; pass++; } break; case 2: y1 += 4; ptr += linesize * 4; if (y1 >= height) { y1 = 1; ptr = ptr1 + linesize; pass++; } break; case 3: y1 += 2; ptr += linesize * 2; break; } } else { ptr += linesize; } } decode_tail: /* read the garbage data until end marker is found */ ff_lzw_decode_tail(s->lzw); /* Graphic Control Extension's scope is single frame. * Remove its influence. */ s->transparent_color_index = -1; s->gce_disposal = GCE_DISPOSAL_NONE; return 0; }
static int gif_read_image(GifState *s) { int left, top, width, height, bits_per_pixel, code_size, flags; int is_interleaved, has_local_palette, y, pass, y1, linesize, n, i; uint8_t *ptr, *spal, *palette, *ptr1; left = bytestream_get_le16(&s->bytestream); top = bytestream_get_le16(&s->bytestream); width = bytestream_get_le16(&s->bytestream); height = bytestream_get_le16(&s->bytestream); flags = bytestream_get_byte(&s->bytestream); is_interleaved = flags & 0x40; has_local_palette = flags & 0x80; bits_per_pixel = (flags & 0x07) + 1; #ifdef DEBUG dprintf(s->avctx, "gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height); #endif if (has_local_palette) { bytestream_get_buffer(&s->bytestream, s->local_palette, 3 * (1 << bits_per_pixel)); palette = s->local_palette; } else { palette = s->global_palette; bits_per_pixel = s->bits_per_pixel; } /* verify that all the image is inside the screen dimensions */ if (left + width > s->screen_width || top + height > s->screen_height) return AVERROR(EINVAL); /* build the palette */ n = (1 << bits_per_pixel); spal = palette; for(i = 0; i < n; i++) { s->image_palette[i] = (0xff << 24) | AV_RB24(spal); spal += 3; } for(; i < 256; i++) s->image_palette[i] = (0xff << 24); /* handle transparency */ if (s->transparent_color_index >= 0) s->image_palette[s->transparent_color_index] = 0; /* now get the image data */ code_size = bytestream_get_byte(&s->bytestream); ff_lzw_decode_init(s->lzw, code_size, s->bytestream, s->bytestream_end - s->bytestream, FF_LZW_GIF); /* read all the image */ linesize = s->picture.linesize[0]; ptr1 = s->picture.data[0] + top * linesize + left; ptr = ptr1; pass = 0; y1 = 0; for (y = 0; y < height; y++) { ff_lzw_decode(s->lzw, ptr, width); if (is_interleaved) { switch(pass) { default: case 0: case 1: y1 += 8; ptr += linesize * 8; if (y1 >= height) { y1 = pass ? 2 : 4; ptr = ptr1 + linesize * y1; pass++; } break; case 2: y1 += 4; ptr += linesize * 4; if (y1 >= height) { y1 = 1; ptr = ptr1 + linesize; pass++; } break; case 3: y1 += 2; ptr += linesize * 2; break; } } else { ptr += linesize; } } /* read the garbage data until end marker is found */ ff_lzw_decode_tail(s->lzw); s->bytestream = ff_lzw_cur_ptr(s->lzw); return 0; }
static int gif_read_image(GifState *s) { int left, top, width, height, bits_per_pixel, code_size, flags; int is_interleaved, has_local_palette, y, pass, y1, linesize, pal_size; uint32_t *ptr, *pal, *px, *pr, *ptr1; int ret; uint8_t *idx; /* At least 9 bytes of Image Descriptor. */ if (s->bytestream_end < s->bytestream + 9) return AVERROR_INVALIDDATA; left = bytestream_get_le16(&s->bytestream); top = bytestream_get_le16(&s->bytestream); width = bytestream_get_le16(&s->bytestream); height = bytestream_get_le16(&s->bytestream); flags = bytestream_get_byte(&s->bytestream); is_interleaved = flags & 0x40; has_local_palette = flags & 0x80; bits_per_pixel = (flags & 0x07) + 1; av_dlog(s->avctx, "image x=%d y=%d w=%d h=%d\n", left, top, width, height); if (has_local_palette) { pal_size = 1 << bits_per_pixel; if (s->bytestream_end < s->bytestream + pal_size * 3) return AVERROR_INVALIDDATA; gif_read_palette(&s->bytestream, s->local_palette, pal_size); pal = s->local_palette; } else { if (!s->has_global_palette) { av_log(s->avctx, AV_LOG_FATAL, "picture doesn't have either global or local palette.\n"); return AVERROR_INVALIDDATA; } pal = s->global_palette; } if (s->keyframe) { if (s->transparent_color_index == -1 && s->has_global_palette) { /* transparency wasn't set before the first frame, fill with background color */ gif_fill(&s->picture, s->bg_color); } else { /* otherwise fill with transparent color. * this is necessary since by default picture filled with 0x80808080. */ gif_fill(&s->picture, s->trans_color); } } /* verify that all the image is inside the screen dimensions */ if (left + width > s->screen_width || top + height > s->screen_height) return AVERROR(EINVAL); /* process disposal method */ if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) { gif_fill_rect(&s->picture, s->stored_bg_color, s->gce_l, s->gce_t, s->gce_w, s->gce_h); } else if (s->gce_prev_disposal == GCE_DISPOSAL_RESTORE) { gif_copy_img_rect(s->stored_img, (uint32_t *)s->picture.data[0], s->picture.linesize[0] / sizeof(uint32_t), s->gce_l, s->gce_t, s->gce_w, s->gce_h); } s->gce_prev_disposal = s->gce_disposal; if (s->gce_disposal != GCE_DISPOSAL_NONE) { s->gce_l = left; s->gce_t = top; s->gce_w = width; s->gce_h = height; if (s->gce_disposal == GCE_DISPOSAL_BACKGROUND) { if (s->background_color_index == s->transparent_color_index) s->stored_bg_color = s->trans_color; else s->stored_bg_color = s->bg_color; } else if (s->gce_disposal == GCE_DISPOSAL_RESTORE) { av_fast_malloc(&s->stored_img, &s->stored_img_size, s->picture.linesize[0] * s->picture.height); if (!s->stored_img) return AVERROR(ENOMEM); gif_copy_img_rect((uint32_t *)s->picture.data[0], s->stored_img, s->picture.linesize[0] / sizeof(uint32_t), left, top, width, height); } } /* Expect at least 2 bytes: 1 for lzw code size and 1 for block size. */ if (s->bytestream_end < s->bytestream + 2) return AVERROR_INVALIDDATA; /* now get the image data */ code_size = bytestream_get_byte(&s->bytestream); if ((ret = ff_lzw_decode_init(s->lzw, code_size, s->bytestream, s->bytestream_end - s->bytestream, FF_LZW_GIF)) < 0) { av_log(s->avctx, AV_LOG_ERROR, "LZW init failed\n"); return ret; } /* read all the image */ linesize = s->picture.linesize[0] / sizeof(uint32_t); ptr1 = (uint32_t *)s->picture.data[0] + top * linesize + left; ptr = ptr1; pass = 0; y1 = 0; for (y = 0; y < height; y++) { if (ff_lzw_decode(s->lzw, s->idx_line, width) == 0) goto decode_tail; pr = ptr + width; for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) { if (*idx != s->transparent_color_index) *px = pal[*idx]; } if (is_interleaved) { switch(pass) { default: case 0: case 1: y1 += 8; ptr += linesize * 8; if (y1 >= height) { y1 = pass ? 2 : 4; ptr = ptr1 + linesize * y1; pass++; } break; case 2: y1 += 4; ptr += linesize * 4; if (y1 >= height) { y1 = 1; ptr = ptr1 + linesize; pass++; } break; case 3: y1 += 2; ptr += linesize * 2; break; } } else { ptr += linesize; } } decode_tail: /* read the garbage data until end marker is found */ ff_lzw_decode_tail(s->lzw); s->bytestream = ff_lzw_cur_ptr(s->lzw); /* Graphic Control Extension's scope is single frame. * Remove its influence. */ s->transparent_color_index = -1; s->gce_disposal = GCE_DISPOSAL_NONE; return 0; }