/* The first three bytes are the size of the section past the header, or zero * if the length is stored in the next long word. The fourth byte in the first * long word indicates the type of the current section. */ static int parse_section_header(GetByteContext *gbc, int *section_size, enum HapSectionType *section_type) { if (bytestream2_get_bytes_left(gbc) < 4) return AVERROR_INVALIDDATA; *section_size = bytestream2_get_le24(gbc); *section_type = bytestream2_get_byte(gbc); if (*section_size == 0) { if (bytestream2_get_bytes_left(gbc) < 4) return AVERROR_INVALIDDATA; *section_size = bytestream2_get_le32(gbc); } if (*section_size > bytestream2_get_bytes_left(gbc) || *section_size < 0) return AVERROR_INVALIDDATA; else return 0; }
/* The first three bytes are the size of the section past the header, or zero * if the length is stored in the next long word. The fourth byte in the first * long word indicates the type of the current section. */ static int parse_section_header(AVCodecContext *avctx) { HapContext *ctx = avctx->priv_data; GetByteContext *gbc = &ctx->gbc; int length; if (bytestream2_get_bytes_left(gbc) < 4) return AVERROR_INVALIDDATA; length = bytestream2_get_le24(gbc); ctx->section_type = bytestream2_get_byte(gbc); if (length == 0) { if (bytestream2_get_bytes_left(gbc) < 4) return AVERROR_INVALIDDATA; length = bytestream2_get_le32(gbc); } if (length > bytestream2_get_bytes_left(gbc) || length == 0) return AVERROR_INVALIDDATA; return length; }
static int rscc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { RsccContext *ctx = avctx->priv_data; GetByteContext *gbc = &ctx->gbc; GetByteContext tiles_gbc; AVFrame *frame = data; const uint8_t *pixels, *raw; uint8_t *inflated_tiles = NULL; int tiles_nb, packed_size, pixel_size = 0; int i, ret = 0; bytestream2_init(gbc, avpkt->data, avpkt->size); /* Size check */ if (bytestream2_get_bytes_left(gbc) < 12) { av_log(avctx, AV_LOG_ERROR, "Packet too small (%d)\n", avpkt->size); return AVERROR_INVALIDDATA; } /* Read number of tiles, and allocate the array */ tiles_nb = bytestream2_get_le16(gbc); av_fast_malloc(&ctx->tiles, &ctx->tiles_size, tiles_nb * sizeof(*ctx->tiles)); if (!ctx->tiles) { ret = AVERROR(ENOMEM); goto end; } av_log(avctx, AV_LOG_DEBUG, "Frame with %d tiles.\n", tiles_nb); /* When there are more than 5 tiles, they are packed together with * a size header. When that size does not match the number of tiles * times the tile size, it means it needs to be inflated as well */ if (tiles_nb > 5) { uLongf packed_tiles_size; if (tiles_nb < 32) packed_tiles_size = bytestream2_get_byte(gbc); else packed_tiles_size = bytestream2_get_le16(gbc); ff_dlog(avctx, "packed tiles of size %lu.\n", packed_tiles_size); /* If necessary, uncompress tiles, and hijack the bytestream reader */ if (packed_tiles_size != tiles_nb * TILE_SIZE) { uLongf length = tiles_nb * TILE_SIZE; inflated_tiles = av_malloc(length); if (!inflated_tiles) { ret = AVERROR(ENOMEM); goto end; } ret = uncompress(inflated_tiles, &length, gbc->buffer, packed_tiles_size); if (ret) { av_log(avctx, AV_LOG_ERROR, "Tile deflate error %d.\n", ret); ret = AVERROR_UNKNOWN; goto end; } /* Skip the compressed tile section in the main byte reader, * and point it to read the newly uncompressed data */ bytestream2_skip(gbc, packed_tiles_size); bytestream2_init(&tiles_gbc, inflated_tiles, length); gbc = &tiles_gbc; } } /* Fill in array of tiles, keeping track of how many pixels are updated */ for (i = 0; i < tiles_nb; i++) { ctx->tiles[i].x = bytestream2_get_le16(gbc); ctx->tiles[i].w = bytestream2_get_le16(gbc); ctx->tiles[i].y = bytestream2_get_le16(gbc); ctx->tiles[i].h = bytestream2_get_le16(gbc); pixel_size += ctx->tiles[i].w * ctx->tiles[i].h * ctx->component_size; ff_dlog(avctx, "tile %d orig(%d,%d) %dx%d.\n", i, ctx->tiles[i].x, ctx->tiles[i].y, ctx->tiles[i].w, ctx->tiles[i].h); if (ctx->tiles[i].w == 0 || ctx->tiles[i].h == 0) { av_log(avctx, AV_LOG_ERROR, "invalid tile %d at (%d.%d) with size %dx%d.\n", i, ctx->tiles[i].x, ctx->tiles[i].y, ctx->tiles[i].w, ctx->tiles[i].h); ret = AVERROR_INVALIDDATA; goto end; } else if (ctx->tiles[i].x + ctx->tiles[i].w > avctx->width || ctx->tiles[i].y + ctx->tiles[i].h > avctx->height) { av_log(avctx, AV_LOG_ERROR, "out of bounds tile %d at (%d.%d) with size %dx%d.\n", i, ctx->tiles[i].x, ctx->tiles[i].y, ctx->tiles[i].w, ctx->tiles[i].h); ret = AVERROR_INVALIDDATA; goto end; } } /* Reset the reader in case it had been modified before */ gbc = &ctx->gbc; /* Extract how much pixel data the tiles contain */ if (pixel_size < 0x100) packed_size = bytestream2_get_byte(gbc); else if (pixel_size < 0x10000) packed_size = bytestream2_get_le16(gbc); else if (pixel_size < 0x1000000) packed_size = bytestream2_get_le24(gbc); else packed_size = bytestream2_get_le32(gbc); ff_dlog(avctx, "pixel_size %d packed_size %d.\n", pixel_size, packed_size); if (packed_size < 0) { av_log(avctx, AV_LOG_ERROR, "Invalid tile size %d\n", packed_size); ret = AVERROR_INVALIDDATA; goto end; } /* Get pixels buffer, it may be deflated or just raw */ if (pixel_size == packed_size) { if (bytestream2_get_bytes_left(gbc) < pixel_size) { av_log(avctx, AV_LOG_ERROR, "Insufficient input for %d\n", pixel_size); ret = AVERROR_INVALIDDATA; goto end; } pixels = gbc->buffer; } else { uLongf len = ctx->inflated_size; if (bytestream2_get_bytes_left(gbc) < packed_size) { av_log(avctx, AV_LOG_ERROR, "Insufficient input for %d\n", packed_size); ret = AVERROR_INVALIDDATA; goto end; } ret = uncompress(ctx->inflated_buf, &len, gbc->buffer, packed_size); if (ret) { av_log(avctx, AV_LOG_ERROR, "Pixel deflate error %d.\n", ret); ret = AVERROR_UNKNOWN; goto end; } pixels = ctx->inflated_buf; } /* Allocate when needed */ ret = ff_reget_buffer(avctx, ctx->reference); if (ret < 0) goto end; /* Pointer to actual pixels, will be updated when data is consumed */ raw = pixels; for (i = 0; i < tiles_nb; i++) { uint8_t *dst = ctx->reference->data[0] + ctx->reference->linesize[0] * (avctx->height - ctx->tiles[i].y - 1) + ctx->tiles[i].x * ctx->component_size; av_image_copy_plane(dst, -1 * ctx->reference->linesize[0], raw, ctx->tiles[i].w * ctx->component_size, ctx->tiles[i].w * ctx->component_size, ctx->tiles[i].h); raw += ctx->tiles[i].w * ctx->component_size * ctx->tiles[i].h; } /* Frame is ready to be output */ ret = av_frame_ref(frame, ctx->reference); if (ret < 0) goto end; /* Keyframe when the number of pixels updated matches the whole surface */ if (pixel_size == ctx->inflated_size) { frame->pict_type = AV_PICTURE_TYPE_I; frame->key_frame = 1; } else { frame->pict_type = AV_PICTURE_TYPE_P; } *got_frame = 1; end: av_free(inflated_tiles); return ret; }
static int flic_decode_frame_24BPP(AVCodecContext *avctx, void *data, int *got_frame, const uint8_t *buf, int buf_size) { FlicDecodeContext *s = avctx->priv_data; GetByteContext g2; int pixel_ptr; unsigned char palette_idx1; unsigned int frame_size; int num_chunks; unsigned int chunk_size; int chunk_type; int i, j, ret; int lines; int compressed_lines; signed short line_packets; int y_ptr; int byte_run; int pixel_skip; int pixel_countdown; unsigned char *pixels; int pixel; unsigned int pixel_limit; bytestream2_init(&g2, buf, buf_size); if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) return ret; pixels = s->frame->data[0]; pixel_limit = s->avctx->height * s->frame->linesize[0]; frame_size = bytestream2_get_le32(&g2); bytestream2_skip(&g2, 2); /* skip the magic number */ num_chunks = bytestream2_get_le16(&g2); bytestream2_skip(&g2, 8); /* skip padding */ if (frame_size > buf_size) frame_size = buf_size; if (frame_size < 16) return AVERROR_INVALIDDATA; frame_size -= 16; /* iterate through the chunks */ while ((frame_size > 0) && (num_chunks > 0) && bytestream2_get_bytes_left(&g2) >= 4) { int stream_ptr_after_chunk; chunk_size = bytestream2_get_le32(&g2); if (chunk_size > frame_size) { av_log(avctx, AV_LOG_WARNING, "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); chunk_size = frame_size; } stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; chunk_type = bytestream2_get_le16(&g2); switch (chunk_type) { case FLI_256_COLOR: case FLI_COLOR: /* For some reason, it seems that non-palettized flics do * include one of these chunks in their first frame. * Why I do not know, it seems rather extraneous. */ ff_dlog(avctx, "Unexpected Palette chunk %d in non-palettized FLC\n", chunk_type); bytestream2_skip(&g2, chunk_size - 6); break; case FLI_DELTA: case FLI_DTA_LC: y_ptr = 0; compressed_lines = bytestream2_get_le16(&g2); while (compressed_lines > 0) { if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) break; if (y_ptr > pixel_limit) return AVERROR_INVALIDDATA; line_packets = bytestream2_get_le16(&g2); if (line_packets < 0) { line_packets = -line_packets; if (line_packets > s->avctx->height) return AVERROR_INVALIDDATA; y_ptr += line_packets * s->frame->linesize[0]; } else { compressed_lines--; pixel_ptr = y_ptr; CHECK_PIXEL_PTR(0); pixel_countdown = s->avctx->width; for (i = 0; i < line_packets; i++) { /* account for the skip bytes */ if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) break; pixel_skip = bytestream2_get_byte(&g2); pixel_ptr += (pixel_skip*3); /* Pixel is 3 bytes wide */ pixel_countdown -= pixel_skip; byte_run = sign_extend(bytestream2_get_byte(&g2), 8); if (byte_run < 0) { byte_run = -byte_run; pixel = bytestream2_get_le24(&g2); CHECK_PIXEL_PTR(3 * byte_run); for (j = 0; j < byte_run; j++, pixel_countdown -= 1) { AV_WL24(&pixels[pixel_ptr], pixel); pixel_ptr += 3; } } else { if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) break; CHECK_PIXEL_PTR(2 * byte_run); for (j = 0; j < byte_run; j++, pixel_countdown--) { pixel = bytestream2_get_le24(&g2); AV_WL24(&pixels[pixel_ptr], pixel); pixel_ptr += 3; } } } y_ptr += s->frame->linesize[0]; } } break; case FLI_LC: av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); bytestream2_skip(&g2, chunk_size - 6); break; case FLI_BLACK: /* set the whole frame to 0x00 which is black for 24 bit mode. */ memset(pixels, 0x00, s->frame->linesize[0] * s->avctx->height); break; case FLI_BRUN: y_ptr = 0; for (lines = 0; lines < s->avctx->height; lines++) { pixel_ptr = y_ptr; /* disregard the line packets; instead, iterate through all * pixels on a row */ bytestream2_skip(&g2, 1); pixel_countdown = (s->avctx->width * 3); while (pixel_countdown > 0) { if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) break; byte_run = sign_extend(bytestream2_get_byte(&g2), 8); if (byte_run > 0) { palette_idx1 = bytestream2_get_byte(&g2); CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++) { pixels[pixel_ptr++] = palette_idx1; pixel_countdown--; if (pixel_countdown < 0) av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", pixel_countdown, lines); } } else { /* copy bytes if byte_run < 0 */ byte_run = -byte_run; if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) break; CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++) { palette_idx1 = bytestream2_get_byte(&g2); pixels[pixel_ptr++] = palette_idx1; pixel_countdown--; if (pixel_countdown < 0) av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", pixel_countdown, lines); } } } y_ptr += s->frame->linesize[0]; } break; case FLI_DTA_BRUN: y_ptr = 0; for (lines = 0; lines < s->avctx->height; lines++) { pixel_ptr = y_ptr; /* disregard the line packets; instead, iterate through all * pixels on a row */ bytestream2_skip(&g2, 1); pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ while (pixel_countdown > 0) { if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) break; byte_run = sign_extend(bytestream2_get_byte(&g2), 8); if (byte_run > 0) { pixel = bytestream2_get_le24(&g2); CHECK_PIXEL_PTR(3 * byte_run); for (j = 0; j < byte_run; j++) { AV_WL24(pixels + pixel_ptr, pixel); pixel_ptr += 3; pixel_countdown--; if (pixel_countdown < 0) av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", pixel_countdown); } } else { /* copy pixels if byte_run < 0 */ byte_run = -byte_run; if (bytestream2_tell(&g2) + 3 * byte_run > stream_ptr_after_chunk) break; CHECK_PIXEL_PTR(3 * byte_run); for (j = 0; j < byte_run; j++) { pixel = bytestream2_get_le24(&g2); AV_WL24(pixels + pixel_ptr, pixel); pixel_ptr += 3; pixel_countdown--; if (pixel_countdown < 0) av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", pixel_countdown); } } } y_ptr += s->frame->linesize[0]; } break; case FLI_COPY: case FLI_DTA_COPY: /* copy the chunk (uncompressed frame) */ if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*3) { av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ "bigger than image, skipping chunk\n", chunk_size - 6); bytestream2_skip(&g2, chunk_size - 6); } else { for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; y_ptr += s->frame->linesize[0]) { pixel_countdown = s->avctx->width; pixel_ptr = 0; while (pixel_countdown > 0) { pixel = bytestream2_get_le24(&g2); AV_WL24(&pixels[y_ptr + pixel_ptr], pixel); pixel_ptr += 3; pixel_countdown--; } if (s->avctx->width & 1) bytestream2_skip(&g2, 3); } } break; case FLI_MINI: /* some sort of a thumbnail? disregard this chunk... */ bytestream2_skip(&g2, chunk_size - 6); break; default: av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); break; } frame_size -= chunk_size; num_chunks--; } /* by the end of the chunk, the stream ptr should equal the frame * size (minus 1, possibly); if it doesn't, issue a warning */ if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); if ((ret = av_frame_ref(data, s->frame)) < 0) return ret; *got_frame = 1; return buf_size; }