static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { GetByteContext gb; AVFrame * const p = data; int compressed, xmin, ymin, xmax, ymax, ret; unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x, bytes_per_scanline; uint8_t *ptr, *scanline; if (avpkt->size < 128) return AVERROR_INVALIDDATA; bytestream2_init(&gb, avpkt->data, avpkt->size); if (bytestream2_get_byteu(&gb) != 0x0a || bytestream2_get_byteu(&gb) > 5) { av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n"); return AVERROR_INVALIDDATA; } compressed = bytestream2_get_byteu(&gb); bits_per_pixel = bytestream2_get_byteu(&gb); xmin = bytestream2_get_le16u(&gb); ymin = bytestream2_get_le16u(&gb); xmax = bytestream2_get_le16u(&gb); ymax = bytestream2_get_le16u(&gb); avctx->sample_aspect_ratio.num = bytestream2_get_le16u(&gb); avctx->sample_aspect_ratio.den = bytestream2_get_le16u(&gb); if (xmax < xmin || ymax < ymin) { av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n"); return AVERROR_INVALIDDATA; } w = xmax - xmin + 1; h = ymax - ymin + 1; bytestream2_skipu(&gb, 49); nplanes = bytestream2_get_byteu(&gb); bytes_per_line = bytestream2_get_le16u(&gb); bytes_per_scanline = nplanes * bytes_per_line; if (bytes_per_scanline < (w * bits_per_pixel * nplanes + 7) / 8) { av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n"); return AVERROR_INVALIDDATA; } switch ((nplanes<<8) + bits_per_pixel) { case 0x0308: avctx->pix_fmt = AV_PIX_FMT_RGB24; break; case 0x0108: case 0x0104: case 0x0102: case 0x0101: case 0x0401: case 0x0301: case 0x0201: avctx->pix_fmt = AV_PIX_FMT_PAL8; break; default: av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n"); return AVERROR_INVALIDDATA; } bytestream2_skipu(&gb, 60); if ((ret = av_image_check_size(w, h, 0, avctx)) < 0) return ret; if (w != avctx->width || h != avctx->height) avcodec_set_dimensions(avctx, w, h); if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; p->pict_type = AV_PICTURE_TYPE_I; ptr = p->data[0]; stride = p->linesize[0]; scanline = av_malloc(bytes_per_scanline + FF_INPUT_BUFFER_PADDING_SIZE); if (!scanline) return AVERROR(ENOMEM); if (nplanes == 3 && bits_per_pixel == 8) { for (y=0; y<h; y++) { pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); for (x=0; x<w; x++) { ptr[3*x ] = scanline[x ]; ptr[3*x+1] = scanline[x+ bytes_per_line ]; ptr[3*x+2] = scanline[x+(bytes_per_line<<1)]; } ptr += stride; } } else if (nplanes == 1 && bits_per_pixel == 8) { int palstart = avpkt->size - 769; for (y=0; y<h; y++, ptr+=stride) { pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); memcpy(ptr, scanline, w); } if (bytestream2_tell(&gb) != palstart) { av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n"); bytestream2_seek(&gb, palstart, SEEK_SET); } if (bytestream2_get_byte(&gb) != 12) { av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n"); ret = AVERROR_INVALIDDATA; goto end; } } else if (nplanes == 1) { /* all packed formats, max. 16 colors */ GetBitContext s; for (y=0; y<h; y++) { init_get_bits8(&s, scanline, bytes_per_scanline); pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); for (x=0; x<w; x++) ptr[x] = get_bits(&s, bits_per_pixel); ptr += stride; } } else { /* planar, 4, 8 or 16 colors */ int i; for (y=0; y<h; y++) { pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); for (x=0; x<w; x++) { int m = 0x80 >> (x&7), v = 0; for (i=nplanes - 1; i>=0; i--) { v <<= 1; v += !!(scanline[i*bytes_per_line + (x>>3)] & m); } ptr[x] = v; } ptr += stride; } } ret = bytestream2_tell(&gb); if (nplanes == 1 && bits_per_pixel == 8) { pcx_palette(&gb, (uint32_t *) p->data[1], 256); ret += 256 * 3; } else if (bits_per_pixel * nplanes == 1) { AV_WN32A(p->data[1] , 0xFF000000); AV_WN32A(p->data[1]+4, 0xFFFFFFFF); } else if (bits_per_pixel < 8) { bytestream2_seek(&gb, 16, SEEK_SET); pcx_palette(&gb, (uint32_t *) p->data[1], 16); } *got_frame = 1; end: av_free(scanline); return ret; }
/* Decodes delta frames */ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst, int stride, int width, int height, int delta, const uint8_t *ctable, uint8_t *refdata) { int i, j; int code; int filled = 0; int orig_height; if(!refdata) refdata= dst; /* copy prev frame */ for(i = 0; i < height; i++) memcpy(dst + (i * stride), refdata + (i * stride), width); orig_height = height; height--; dst = dst + height * stride; while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (height >= 0)) { code = bytestream2_get_byte(&qctx->buffer); if(delta) { /* motion compensation */ while(bytestream2_get_bytes_left(&qctx->buffer) > 0 && (code & 0xF0) == 0xF0) { if(delta == 1) { int me_idx; int me_w, me_h, me_x, me_y; uint8_t *me_plane; int corr, val; /* get block size by index */ me_idx = code & 0xF; me_w = qpeg_table_w[me_idx]; me_h = qpeg_table_h[me_idx]; /* extract motion vector */ corr = bytestream2_get_byte(&qctx->buffer); val = corr >> 4; if(val > 7) val -= 16; me_x = val; val = corr & 0xF; if(val > 7) val -= 16; me_y = val; /* check motion vector */ if ((me_x + filled < 0) || (me_x + me_w + filled > width) || (height - me_y - me_h < 0) || (height - me_y > orig_height) || (filled + me_w > width) || (height - me_h < 0)) av_log(NULL, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n", me_x, me_y, me_w, me_h, filled, height); else { /* do motion compensation */ me_plane = refdata + (filled + me_x) + (height - me_y) * stride; for(j = 0; j < me_h; j++) { for(i = 0; i < me_w; i++) dst[filled + i - (j * stride)] = me_plane[i - (j * stride)]; } } } code = bytestream2_get_byte(&qctx->buffer); } } if(code == 0xE0) /* end-of-picture code */ break; if(code > 0xE0) { /* run code: 0xE1..0xFF */ int p; code &= 0x1F; p = bytestream2_get_byte(&qctx->buffer); for(i = 0; i <= code; i++) { dst[filled++] = p; if(filled >= width) { filled = 0; dst -= stride; height--; if(height < 0) break; } } } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */ code &= 0x1F; if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer)) break; for(i = 0; i <= code; i++) { dst[filled++] = bytestream2_get_byte(&qctx->buffer); if(filled >= width) { filled = 0; dst -= stride; height--; if(height < 0) break; } } } else if(code >= 0x80) { /* skip code: 0x80..0xBF */ int skip; code &= 0x3F; /* codes 0x80 and 0x81 are actually escape codes, skip value minus constant is in the next byte */ if(!code) skip = bytestream2_get_byte(&qctx->buffer) + 64; else if(code == 1) skip = bytestream2_get_byte(&qctx->buffer) + 320; else skip = code; filled += skip; while( filled >= width) { filled -= width; dst -= stride; height--; if(height < 0) break; } } else { /* zero code treated as one-pixel skip */ if(code) { dst[filled++] = ctable[code & 0x7F]; } else filled++; if(filled >= width) { filled = 0; dst -= stride; height--; } } }
static void qpeg_decode_intra(QpegContext *qctx, uint8_t *dst, int stride, int width, int height) { int i; int code; int c0, c1; int run, copy; int filled = 0; int rows_to_go; rows_to_go = height; height--; dst = dst + height * stride; while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (rows_to_go > 0)) { code = bytestream2_get_byte(&qctx->buffer); run = copy = 0; if(code == 0xFC) /* end-of-picture code */ break; if(code >= 0xF8) { /* very long run */ c0 = bytestream2_get_byte(&qctx->buffer); c1 = bytestream2_get_byte(&qctx->buffer); run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2; } else if (code >= 0xF0) { /* long run */ c0 = bytestream2_get_byte(&qctx->buffer); run = ((code & 0xF) << 8) + c0 + 2; } else if (code >= 0xE0) { /* short run */ run = (code & 0x1F) + 2; } else if (code >= 0xC0) { /* very long copy */ c0 = bytestream2_get_byte(&qctx->buffer); c1 = bytestream2_get_byte(&qctx->buffer); copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1; } else if (code >= 0x80) { /* long copy */ c0 = bytestream2_get_byte(&qctx->buffer); copy = ((code & 0x7F) << 8) + c0 + 1; } else { /* short copy */ copy = code + 1; } /* perform actual run or copy */ if(run) { int p; p = bytestream2_get_byte(&qctx->buffer); for(i = 0; i < run; i++) { dst[filled++] = p; if (filled >= width) { filled = 0; dst -= stride; rows_to_go--; if(rows_to_go <= 0) break; } } } else { for(i = 0; i < copy; i++) { dst[filled++] = bytestream2_get_byte(&qctx->buffer); if (filled >= width) { filled = 0; dst -= stride; rows_to_go--; if(rows_to_go <= 0) break; } } } } }
int ff_amf_read_null(GetByteContext *bc) { if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NULL) return AVERROR_INVALIDDATA; return 0; }
static void j2k_flush(J2kDecoderContext *s) { if (bytestream2_get_byte(&s->g) == 0xff) bytestream2_skip(&s->g, 1); s->bit_index = 8; }
static int bethsoftvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { BethsoftvidContext * vid = avctx->priv_data; char block_type; uint8_t * dst; uint8_t * frame_end; int remaining = avctx->width; // number of bytes remaining on a line int wrap_to_next_line; int code, ret; int yoffset; if ((ret = avctx->reget_buffer(avctx, &vid->frame)) < 0) { av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); return ret; } wrap_to_next_line = vid->frame.linesize[0] - avctx->width; if (avpkt->side_data_elems > 0 && avpkt->side_data[0].type == AV_PKT_DATA_PALETTE) { bytestream2_init(&vid->g, avpkt->side_data[0].data, avpkt->side_data[0].size); if ((ret = set_palette(vid)) < 0) return ret; } bytestream2_init(&vid->g, avpkt->data, avpkt->size); dst = vid->frame.data[0]; frame_end = vid->frame.data[0] + vid->frame.linesize[0] * avctx->height; switch(block_type = bytestream2_get_byte(&vid->g)){ case PALETTE_BLOCK: { *got_frame = 0; if ((ret = set_palette(vid)) < 0) { av_log(avctx, AV_LOG_ERROR, "error reading palette\n"); return ret; } return bytestream2_tell(&vid->g); } case VIDEO_YOFF_P_FRAME: yoffset = bytestream2_get_le16(&vid->g); if(yoffset >= avctx->height) return AVERROR_INVALIDDATA; dst += vid->frame.linesize[0] * yoffset; } // main code while((code = bytestream2_get_byte(&vid->g))){ int length = code & 0x7f; // copy any bytes starting at the current position, and ending at the frame width while(length > remaining){ if(code < 0x80) bytestream2_get_buffer(&vid->g, dst, remaining); else if(block_type == VIDEO_I_FRAME) memset(dst, bytestream2_peek_byte(&vid->g), remaining); length -= remaining; // decrement the number of bytes to be copied dst += remaining + wrap_to_next_line; // skip over extra bytes at end of frame remaining = avctx->width; if(dst == frame_end) goto end; } // copy any remaining bytes after / if line overflows if(code < 0x80) bytestream2_get_buffer(&vid->g, dst, length); else if(block_type == VIDEO_I_FRAME) memset(dst, bytestream2_get_byte(&vid->g), length); remaining -= length; dst += length; } end: *got_frame = 1; *(AVFrame*)data = vid->frame; return avpkt->size; }
static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size) { /* Note, the only difference between the 15Bpp and 16Bpp */ /* Format is the pixel format, the packets are processed the same. */ 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); s->frame.reference = 3; s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; if ((ret = avctx->reget_buffer(avctx, &s->frame)) < 0) { av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 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; frame_size -= 16; /* iterate through the chunks */ while ((frame_size > 0) && (num_chunks > 0)) { 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. */ av_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; line_packets = bytestream2_get_le16(&g2); if (line_packets < 0) { line_packets = -line_packets; 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*2); /* Pixel is 2 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_le16(&g2); CHECK_PIXEL_PTR(2 * byte_run); for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { *((signed short*)(&pixels[pixel_ptr])) = pixel; pixel_ptr += 2; } } 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--) { *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); pixel_ptr += 2; } } } y_ptr += s->frame.linesize[0]; } } break; case FLI_LC: av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-paletised FLC\n"); bytestream2_skip(&g2, chunk_size - 6); break; case FLI_BLACK: /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */ memset(pixels, 0x0000, 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 * 2); 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); } } } /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed. * This does not give us any good oportunity to perform word endian conversion * during decompression. So if it is required (i.e., this is not a LE target, we do * a second pass over the line here, swapping the bytes. */ #if HAVE_BIGENDIAN pixel_ptr = y_ptr; pixel_countdown = s->avctx->width; while (pixel_countdown > 0) { *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]); pixel_ptr += 2; } #endif 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_le16(&g2); CHECK_PIXEL_PTR(2 * byte_run); for (j = 0; j < byte_run; j++) { *((signed short*)(&pixels[pixel_ptr])) = pixel; pixel_ptr += 2; 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) + 2 * byte_run > stream_ptr_after_chunk) break; CHECK_PIXEL_PTR(2 * byte_run); for (j = 0; j < byte_run; j++) { *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); pixel_ptr += 2; 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)(s->avctx->width * s->avctx->height)*2) { 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) { *((signed short*)(&pixels[y_ptr + pixel_ptr])) = bytestream2_get_le16(&g2); pixel_ptr += 2; pixel_countdown--; } } } 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)); *data_size=sizeof(AVFrame); *(AVFrame*)data = s->frame; return buf_size; }
static int dxv_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { DXVContext *ctx = avctx->priv_data; ThreadFrame tframe; GetByteContext *gbc = &ctx->gbc; int (*decompress_tex)(AVCodecContext *avctx); const char *msgcomp, *msgtext; uint32_t tag; int version_major, version_minor = 0; int size = 0, old_type = 0; int ret; bytestream2_init(gbc, avpkt->data, avpkt->size); tag = bytestream2_get_le32(gbc); switch (tag) { case MKBETAG('D', 'X', 'T', '1'): decompress_tex = dxv_decompress_dxt1; ctx->tex_funct = ctx->texdsp.dxt1_block; ctx->tex_rat = 8; ctx->tex_step = 8; msgcomp = "DXTR1"; msgtext = "DXT1"; break; case MKBETAG('D', 'X', 'T', '5'): decompress_tex = dxv_decompress_dxt5; ctx->tex_funct = ctx->texdsp.dxt5_block; ctx->tex_rat = 4; ctx->tex_step = 16; msgcomp = "DXTR5"; msgtext = "DXT5"; break; case MKBETAG('Y', 'C', 'G', '6'): case MKBETAG('Y', 'G', '1', '0'): avpriv_report_missing_feature(avctx, "Tag 0x%08X", tag); return AVERROR_PATCHWELCOME; default: /* Old version does not have a real header, just size and type. */ size = tag & 0x00FFFFFF; old_type = tag >> 24; version_major = (old_type & 0x0F) - 1; if (old_type & 0x80) { msgcomp = "RAW"; decompress_tex = dxv_decompress_raw; } else { msgcomp = "LZF"; decompress_tex = dxv_decompress_lzf; } if (old_type & 0x40) { msgtext = "DXT5"; ctx->tex_funct = ctx->texdsp.dxt5_block; ctx->tex_step = 16; } else if (old_type & 0x20 || version_major == 1) { msgtext = "DXT1"; ctx->tex_funct = ctx->texdsp.dxt1_block; ctx->tex_step = 8; } else { av_log(avctx, AV_LOG_ERROR, "Unsupported header (0x%08X)\n.", tag); return AVERROR_INVALIDDATA; } ctx->tex_rat = 1; break; } /* New header is 12 bytes long. */ if (!old_type) { version_major = bytestream2_get_byte(gbc) - 1; version_minor = bytestream2_get_byte(gbc); /* Encoder copies texture data when compression is not advantageous. */ if (bytestream2_get_byte(gbc)) { msgcomp = "RAW"; ctx->tex_rat = 1; decompress_tex = dxv_decompress_raw; } bytestream2_skip(gbc, 1); // unknown size = bytestream2_get_le32(gbc); } av_log(avctx, AV_LOG_DEBUG, "%s compression with %s texture (version %d.%d)\n", msgcomp, msgtext, version_major, version_minor); if (size != bytestream2_get_bytes_left(gbc)) { av_log(avctx, AV_LOG_ERROR, "Incomplete or invalid file (header %d, left %d).\n", size, bytestream2_get_bytes_left(gbc)); return AVERROR_INVALIDDATA; } ctx->tex_size = avctx->coded_width * avctx->coded_height * 4 / ctx->tex_rat; ret = av_reallocp(&ctx->tex_data, ctx->tex_size); if (ret < 0) return ret; /* Decompress texture out of the intermediate compression. */ ret = decompress_tex(avctx); if (ret < 0) return ret; tframe.f = data; ret = ff_thread_get_buffer(avctx, &tframe, 0); if (ret < 0) return ret; /* Now decompress the texture with the standard functions. */ avctx->execute2(avctx, decompress_texture_thread, tframe.f, NULL, ctx->slice_count); /* Frame is ready to be output. */ tframe.f->pict_type = AV_PICTURE_TYPE_I; tframe.f->key_frame = 1; *got_frame = 1; return avpkt->size; }
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) { AnmContext *s = avctx->priv_data; const int buf_size = avpkt->size; uint8_t *dst, *dst_end; int count; if(avctx->reget_buffer(avctx, &s->frame) < 0){ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return -1; } dst = s->frame.data[0]; dst_end = s->frame.data[0] + s->frame.linesize[0]*avctx->height; bytestream2_init(&s->gb, avpkt->data, buf_size); if (bytestream2_get_byte(&s->gb) != 0x42) { av_log_ask_for_sample(avctx, "unknown record type\n"); return buf_size; } if (bytestream2_get_byte(&s->gb)) { av_log_ask_for_sample(avctx, "padding bytes not supported\n"); return buf_size; } bytestream2_skip(&s->gb, 2); s->x = 0; do { /* if statements are ordered by probability */ #define OP(gb, pixel, count) \ op(&dst, dst_end, (gb), (pixel), (count), &s->x, avctx->width, s->frame.linesize[0]) int type = bytestream2_get_byte(&s->gb); count = type & 0x7F; type >>= 7; if (count) { if (OP(type ? NULL : &s->gb, -1, count)) break; } else if (!type) { int pixel; count = bytestream2_get_byte(&s->gb); /* count==0 gives nop */ pixel = bytestream2_get_byte(&s->gb); if (OP(NULL, pixel, count)) break; } else { int pixel; type = bytestream2_get_le16(&s->gb); count = type & 0x3FFF; type >>= 14; if (!count) { if (type == 0) break; // stop if (type == 2) { av_log_ask_for_sample(avctx, "unknown opcode"); return AVERROR_INVALIDDATA; } continue; } pixel = type == 3 ? bytestream2_get_byte(&s->gb) : -1; if (type == 1) count += 0x4000; if (OP(type == 2 ? &s->gb : NULL, pixel, count)) break; } } while (bytestream2_get_bytes_left(&s->gb) > 0); memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); *data_size = sizeof(AVFrame); *(AVFrame*)data = s->frame; return buf_size; }
static int dxv_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { DXVContext *ctx = avctx->priv_data; ThreadFrame tframe; GetByteContext *gbc = &ctx->gbc; int (*decompress_tex)(AVCodecContext *avctx); uint32_t tag; int channels, size = 0, old_type = 0; int ret; bytestream2_init(gbc, avpkt->data, avpkt->size); tag = bytestream2_get_le32(gbc); switch (tag) { case MKBETAG('D', 'X', 'T', '1'): decompress_tex = dxv_decompress_dxt1; ctx->tex_funct = ctx->texdsp.dxt1_block; ctx->tex_rat = 8; ctx->tex_step = 8; av_log(avctx, AV_LOG_DEBUG, "DXTR1 compression and DXT1 texture "); break; case MKBETAG('D', 'X', 'T', '5'): decompress_tex = dxv_decompress_dxt5; ctx->tex_funct = ctx->texdsp.dxt5_block; ctx->tex_rat = 4; ctx->tex_step = 16; av_log(avctx, AV_LOG_DEBUG, "DXTR5 compression and DXT5 texture "); break; case MKBETAG('Y', 'C', 'G', '6'): case MKBETAG('Y', 'G', '1', '0'): avpriv_report_missing_feature(avctx, "Tag 0x%08X", tag); return AVERROR_PATCHWELCOME; default: /* Old version does not have a real header, just size and type. */ size = tag & 0x00FFFFFF; old_type = tag >> 24; channels = old_type & 0x0F; if (old_type & 0x40) { av_log(avctx, AV_LOG_DEBUG, "LZF compression and DXT5 texture "); ctx->tex_funct = ctx->texdsp.dxt5_block; ctx->tex_step = 16; } else if (old_type & 0x20) { av_log(avctx, AV_LOG_DEBUG, "LZF compression and DXT1 texture "); ctx->tex_funct = ctx->texdsp.dxt1_block; ctx->tex_step = 8; } else { av_log(avctx, AV_LOG_ERROR, "Unsupported header (0x%08X)\n.", tag); return AVERROR_INVALIDDATA; } decompress_tex = dxv_decompress_lzf; ctx->tex_rat = 1; break; } /* New header is 12 bytes long. */ if (!old_type) { channels = bytestream2_get_byte(gbc); bytestream2_skip(gbc, 3); // unknown size = bytestream2_get_le32(gbc); } av_log(avctx, AV_LOG_DEBUG, "(%d channels)\n", channels); if (size != bytestream2_get_bytes_left(gbc)) { av_log(avctx, AV_LOG_ERROR, "Incomplete or invalid file (%u > %u)\n.", size, bytestream2_get_bytes_left(gbc)); return AVERROR_INVALIDDATA; } ctx->tex_size = avctx->coded_width * avctx->coded_height * 4 / ctx->tex_rat; ret = av_reallocp(&ctx->tex_data, ctx->tex_size); if (ret < 0) return ret; /* Decompress texture out of the intermediate compression. */ ret = decompress_tex(avctx); if (ret < 0) return ret; tframe.f = data; ret = ff_thread_get_buffer(avctx, &tframe, 0); if (ret < 0) return ret; ff_thread_finish_setup(avctx); /* Now decompress the texture with the standard functions. */ avctx->execute2(avctx, decompress_texture_thread, tframe.f, NULL, ctx->slice_count); /* Frame is ready to be output. */ tframe.f->pict_type = AV_PICTURE_TYPE_I; tframe.f->key_frame = 1; *got_frame = 1; return avpkt->size; }
static int dxv_decompress_dxt5(AVCodecContext *avctx) { DXVContext *ctx = avctx->priv_data; GetByteContext *gbc = &ctx->gbc; uint32_t value, op; int idx, prev, state = 0; int pos = 4; int run = 0; int probe, check; /* Copy the first four elements */ AV_WL32(ctx->tex_data + 0, bytestream2_get_le32(gbc)); AV_WL32(ctx->tex_data + 4, bytestream2_get_le32(gbc)); AV_WL32(ctx->tex_data + 8, bytestream2_get_le32(gbc)); AV_WL32(ctx->tex_data + 12, bytestream2_get_le32(gbc)); /* Process input until the whole texture has been filled */ while (pos < ctx->tex_size / 4) { if (run) { run--; prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; } else { if (state == 0) { value = bytestream2_get_le32(gbc); state = 16; } op = value & 0x3; value >>= 2; state--; switch (op) { case 0: /* Long copy */ check = bytestream2_get_byte(gbc) + 1; if (check == 256) { do { probe = bytestream2_get_le16(gbc); check += probe; } while (probe == 0xFFFF); } while (check && pos < ctx->tex_size / 4) { prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; check--; } /* Restart (or exit) the loop */ continue; break; case 1: /* Load new run value */ run = bytestream2_get_byte(gbc); if (run == 255) { do { probe = bytestream2_get_le16(gbc); run += probe; } while (probe == 0xFFFF); } /* Copy two dwords from previous data */ prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; break; case 2: /* Copy two dwords from a previous index */ idx = 8 + bytestream2_get_le16(gbc); if (idx > pos) { av_log(avctx, AV_LOG_ERROR, "idx %d > %d\n", idx, pos); return AVERROR_INVALIDDATA; } prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; break; case 3: /* Copy two dwords from input */ prev = bytestream2_get_le32(gbc); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = bytestream2_get_le32(gbc); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; break; } } CHECKPOINT(4); /* Copy two elements from a previous offset or from the input buffer */ if (op) { prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; } else { CHECKPOINT(4); if (op) prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); else prev = bytestream2_get_le32(gbc); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; CHECKPOINT(4); if (op) prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); else prev = bytestream2_get_le32(gbc); AV_WL32(ctx->tex_data + 4 * pos, prev); pos++; } } return 0; }
static int gif_read_image(GifState *s, AVFrame *frame) { 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 = bytestream2_get_le16(&s->gb); top = bytestream2_get_le16(&s->gb); width = bytestream2_get_le16(&s->gb); height = bytestream2_get_le16(&s->gb); flags = bytestream2_get_byte(&s->gb); is_interleaved = flags & 0x40; has_local_palette = flags & 0x80; bits_per_pixel = (flags & 0x07) + 1; av_dlog(s->avctx, "gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height); if (has_local_palette) { bytestream2_get_buffer(&s->gb, 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 || !width || !height) { av_log(s->avctx, AV_LOG_ERROR, "Invalid image dimensions.\n"); return AVERROR_INVALIDDATA; } /* build the palette */ n = (1 << bits_per_pixel); spal = palette; for(i = 0; i < n; i++) { s->image_palette[i] = (0xffu << 24) | AV_RB24(spal); spal += 3; } for(; i < 256; i++) s->image_palette[i] = (0xffu << 24); /* handle transparency */ if (s->transparent_color_index >= 0) s->image_palette[s->transparent_color_index] = 0; /* now get the image data */ code_size = bytestream2_get_byte(&s->gb); ff_lzw_decode_init(s->lzw, code_size, s->gb.buffer, bytestream2_get_bytes_left(&s->gb), FF_LZW_GIF); /* read all the image */ linesize = frame->linesize[0]; ptr1 = frame->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); bytestream2_skip(&s->gb, ff_lzw_size_read(s->lzw)); return 0; }
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { AVFrame *f = data; GetByteContext gb; int width, height, ret, bits_pixel, pixel; uint8_t *out_buf; uint8_t count; int x, y; bytestream2_init(&gb, avpkt->data, avpkt->size); if (bytestream2_get_bytes_left(&gb) < ALIAS_HEADER_SIZE) { av_log(avctx, AV_LOG_ERROR, "Header too small %d.\n", avpkt->size); return AVERROR_INVALIDDATA; } width = bytestream2_get_be16u(&gb); height = bytestream2_get_be16u(&gb); bytestream2_skipu(&gb, 4); // obsolete X, Y offset bits_pixel = bytestream2_get_be16u(&gb); if (bits_pixel == 24) avctx->pix_fmt = AV_PIX_FMT_BGR24; else if (bits_pixel == 8) avctx->pix_fmt = AV_PIX_FMT_GRAY8; else { av_log(avctx, AV_LOG_ERROR, "Invalid pixel format.\n"); return AVERROR_INVALIDDATA; } ret = ff_set_dimensions(avctx, width, height); if (ret < 0) return ret; ret = ff_get_buffer(avctx, f, 0); if (ret < 0) return ret; f->pict_type = AV_PICTURE_TYPE_I; f->key_frame = 1; x = 0; y = 1; out_buf = f->data[0]; while (bytestream2_get_bytes_left(&gb) > 0) { int i; /* set buffer at the right position at every new line */ if (x == avctx->width) { x = 0; out_buf = f->data[0] + f->linesize[0] * y++; if (y > avctx->height) { av_log(avctx, AV_LOG_ERROR, "Ended frame decoding with %d bytes left.\n", bytestream2_get_bytes_left(&gb)); return AVERROR_INVALIDDATA; } } /* read packet and copy data */ count = bytestream2_get_byteu(&gb); if (!count || x + count > avctx->width) { av_log(avctx, AV_LOG_ERROR, "Invalid run length %d.\n", count); return AVERROR_INVALIDDATA; } if (avctx->pix_fmt == AV_PIX_FMT_BGR24) { pixel = bytestream2_get_be24(&gb); for (i = 0; i < count; i++) { AV_WB24(out_buf, pixel); out_buf += 3; } } else { // AV_PIX_FMT_GRAY8 pixel = bytestream2_get_byte(&gb); for (i = 0; i < count; i++) *out_buf++ = pixel; } x += i; } if (x != width || y != height) { av_log(avctx, AV_LOG_ERROR, "Picture stopped at %d,%d.\n", x, y); return AVERROR_INVALIDDATA; } *got_frame = 1; return avpkt->size; }
static int hap_parse_decode_instructions(HapContext *ctx, int size) { GetByteContext *gbc = &ctx->gbc; int section_size; enum HapSectionType section_type; int is_first_table = 1, had_offsets = 0, had_compressors = 0, had_sizes = 0; int i, ret; while (size > 0) { int stream_remaining = bytestream2_get_bytes_left(gbc); ret = parse_section_header(gbc, §ion_size, §ion_type); if (ret != 0) return ret; size -= stream_remaining - bytestream2_get_bytes_left(gbc); switch (section_type) { case HAP_ST_COMPRESSOR_TABLE: ret = ff_hap_set_chunk_count(ctx, section_size, is_first_table); if (ret != 0) return ret; for (i = 0; i < section_size; i++) { ctx->chunks[i].compressor = bytestream2_get_byte(gbc) << 4; } had_compressors = 1; is_first_table = 0; break; case HAP_ST_SIZE_TABLE: ret = ff_hap_set_chunk_count(ctx, section_size / 4, is_first_table); if (ret != 0) return ret; for (i = 0; i < section_size / 4; i++) { ctx->chunks[i].compressed_size = bytestream2_get_le32(gbc); } had_sizes = 1; is_first_table = 0; break; case HAP_ST_OFFSET_TABLE: ret = ff_hap_set_chunk_count(ctx, section_size / 4, is_first_table); if (ret != 0) return ret; for (i = 0; i < section_size / 4; i++) { ctx->chunks[i].compressed_offset = bytestream2_get_le32(gbc); } had_offsets = 1; is_first_table = 0; break; default: break; } size -= section_size; } if (!had_sizes || !had_compressors) return AVERROR_INVALIDDATA; /* The offsets table is optional. If not present than calculate offsets by * summing the sizes of preceding chunks. */ if (!had_offsets) { size_t running_size = 0; for (i = 0; i < ctx->chunk_count; i++) { ctx->chunks[i].compressed_offset = running_size; running_size += ctx->chunks[i].compressed_size; } } return 0; }
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { AnmContext *s = avctx->priv_data; const int buf_size = avpkt->size; uint8_t *dst, *dst_end; int count, ret; if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) return ret; dst = s->frame->data[0]; dst_end = s->frame->data[0] + s->frame->linesize[0]*avctx->height; bytestream2_init(&s->gb, avpkt->data, buf_size); if (bytestream2_get_byte(&s->gb) != 0x42) { avpriv_request_sample(avctx, "Unknown record type"); return AVERROR_INVALIDDATA; } if (bytestream2_get_byte(&s->gb)) { avpriv_request_sample(avctx, "Padding bytes"); return AVERROR_PATCHWELCOME; } bytestream2_skip(&s->gb, 2); s->x = 0; do { /* if statements are ordered by probability */ #define OP(gb, pixel, count) \ op(&dst, dst_end, (gb), (pixel), (count), &s->x, avctx->width, s->frame->linesize[0]) int type = bytestream2_get_byte(&s->gb); count = type & 0x7F; type >>= 7; if (count) { if (OP(type ? NULL : &s->gb, -1, count)) break; } else if (!type) { int pixel; count = bytestream2_get_byte(&s->gb); /* count==0 gives nop */ pixel = bytestream2_get_byte(&s->gb); if (OP(NULL, pixel, count)) break; } else { int pixel; type = bytestream2_get_le16(&s->gb); count = type & 0x3FFF; type >>= 14; if (!count) { if (type == 0) break; // stop if (type == 2) { avpriv_request_sample(avctx, "Unknown opcode"); return AVERROR_PATCHWELCOME; } continue; } pixel = type == 3 ? bytestream2_get_byte(&s->gb) : -1; if (type == 1) count += 0x4000; if (OP(type == 2 ? &s->gb : NULL, pixel, count)) break; } } while (bytestream2_get_bytes_left(&s->gb) > 0); memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); *got_frame = 1; if ((ret = av_frame_ref(data, s->frame)) < 0) return ret; return buf_size; }
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; }
static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic, GetByteContext *gb) { unsigned char rle_code; unsigned char extra_byte, odd_pixel; unsigned char stream_byte; unsigned int pixel_ptr = 0; int row_dec = pic->linesize[0]; int row_ptr = (avctx->height - 1) * row_dec; int frame_size = row_dec * avctx->height; int i; while (row_ptr >= 0) { if (bytestream2_get_bytes_left(gb) <= 0) { av_log(avctx, AV_LOG_ERROR, "MS RLE: bytestream overrun, %d rows left\n", row_ptr); return AVERROR_INVALIDDATA; } rle_code = stream_byte = bytestream2_get_byteu(gb); if (rle_code == 0) { /* fetch the next byte to see how to handle escape code */ stream_byte = bytestream2_get_byte(gb); if (stream_byte == 0) { /* line is done, goto the next one */ row_ptr -= row_dec; pixel_ptr = 0; } else if (stream_byte == 1) { /* decode is done */ return 0; } else if (stream_byte == 2) { /* reposition frame decode coordinates */ stream_byte = bytestream2_get_byte(gb); pixel_ptr += stream_byte; stream_byte = bytestream2_get_byte(gb); row_ptr -= stream_byte * row_dec; } else { // copy pixels from encoded stream odd_pixel = stream_byte & 1; rle_code = (stream_byte + 1) / 2; extra_byte = rle_code & 0x01; if (row_ptr + pixel_ptr + stream_byte > frame_size || bytestream2_get_bytes_left(gb) < rle_code) { av_log(avctx, AV_LOG_ERROR, "MS RLE: frame/stream ptr just went out of bounds (copy)\n"); return AVERROR_INVALIDDATA; } for (i = 0; i < rle_code; i++) { if (pixel_ptr >= avctx->width) break; stream_byte = bytestream2_get_byteu(gb); pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4; pixel_ptr++; if (i + 1 == rle_code && odd_pixel) break; if (pixel_ptr >= avctx->width) break; pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F; pixel_ptr++; } // if the RLE code is odd, skip a byte in the stream if (extra_byte) bytestream2_skip(gb, 1); } } else { // decode a run of data if (row_ptr + pixel_ptr + stream_byte > frame_size) {
static int dds_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { DDSContext *ctx = avctx->priv_data; GetByteContext *gbc = &ctx->gbc; AVFrame *frame = data; int mipmap; int ret; ff_texturedsp_init(&ctx->texdsp); bytestream2_init(gbc, avpkt->data, avpkt->size); if (bytestream2_get_bytes_left(gbc) < 128) { av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).", bytestream2_get_bytes_left(gbc)); return AVERROR_INVALIDDATA; } if (bytestream2_get_le32(gbc) != MKTAG('D', 'D', 'S', ' ') || bytestream2_get_le32(gbc) != 124) { // header size av_log(avctx, AV_LOG_ERROR, "Invalid DDS header."); return AVERROR_INVALIDDATA; } bytestream2_skip(gbc, 4); // flags avctx->height = bytestream2_get_le32(gbc); avctx->width = bytestream2_get_le32(gbc); ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n", avctx->width, avctx->height); return ret; } /* Since codec is based on 4x4 blocks, size is aligned to 4. */ avctx->coded_width = FFALIGN(avctx->width, TEXTURE_BLOCK_W); avctx->coded_height = FFALIGN(avctx->height, TEXTURE_BLOCK_H); bytestream2_skip(gbc, 4); // pitch bytestream2_skip(gbc, 4); // depth mipmap = bytestream2_get_le32(gbc); if (mipmap != 0) av_log(avctx, AV_LOG_VERBOSE, "Found %d mipmaps (ignored).\n", mipmap); /* Extract pixel format information, considering additional elements * in reserved1 and reserved2. */ ret = parse_pixel_format(avctx); if (ret < 0) return ret; ret = ff_get_buffer(avctx, frame, 0); if (ret < 0) return ret; if (ctx->compressed) { ctx->slice_count = av_clip(avctx->thread_count, 1, avctx->coded_height / TEXTURE_BLOCK_H); /* Use the decompress function on the texture, one block per thread. */ ctx->tex_data = gbc->buffer; avctx->execute2(avctx, decompress_texture_thread, frame, NULL, ctx->slice_count); } else { int linesize = av_image_get_linesize(avctx->pix_fmt, frame->width, 0); if (ctx->paletted) { int i; uint32_t *p = (uint32_t*) frame->data[1]; /* Use the first 1024 bytes as palette, then copy the rest. */ for (i = 0; i < 256; i++) { uint32_t rgba = 0; rgba |= bytestream2_get_byte(gbc) << 16; rgba |= bytestream2_get_byte(gbc) << 8; rgba |= bytestream2_get_byte(gbc) << 0; rgba |= bytestream2_get_byte(gbc) << 24; p[i] = rgba; } frame->palette_has_changed = 1; } av_image_copy_plane(frame->data[0], frame->linesize[0], gbc->buffer, linesize, linesize, frame->height); } /* Run any post processing here if needed. */ if (avctx->pix_fmt == AV_PIX_FMT_BGRA || avctx->pix_fmt == AV_PIX_FMT_RGBA || avctx->pix_fmt == AV_PIX_FMT_YA8) run_postproc(avctx, frame); /* Frame is ready to be output. */ frame->pict_type = AV_PICTURE_TYPE_I; frame->key_frame = 1; *got_frame = 1; return avpkt->size; }
static int flic_decode_frame_8BPP(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size) { FlicDecodeContext *s = avctx->priv_data; GetByteContext g2; int pixel_ptr; int palette_ptr; unsigned char palette_idx1; unsigned char palette_idx2; unsigned int frame_size; int num_chunks; unsigned int chunk_size; int chunk_type; int i, j, ret; int color_packets; int color_changes; int color_shift; unsigned char r, g, b; int lines; int compressed_lines; int starting_line; signed short line_packets; int y_ptr; int byte_run; int pixel_skip; int pixel_countdown; unsigned char *pixels; unsigned int pixel_limit; bytestream2_init(&g2, buf, buf_size); s->frame.reference = 3; s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; if ((ret = avctx->reget_buffer(avctx, &s->frame)) < 0) { av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); return ret; } pixels = s->frame.data[0]; pixel_limit = s->avctx->height * s->frame.linesize[0]; if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + FF_INPUT_BUFFER_PADDING_SIZE)) return AVERROR_INVALIDDATA; frame_size = bytestream2_get_le32(&g2); if (frame_size > buf_size) frame_size = buf_size; bytestream2_skip(&g2, 2); /* skip the magic number */ num_chunks = bytestream2_get_le16(&g2); bytestream2_skip(&g2, 8); /* skip padding */ frame_size -= 16; /* iterate through the chunks */ while ((frame_size >= 6) && (num_chunks > 0)) { 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: /* check special case: If this file is from the Magic Carpet * game and uses 6-bit colors even though it reports 256-color * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during * initialization) */ if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE)) color_shift = 0; else color_shift = 2; /* set up the palette */ color_packets = bytestream2_get_le16(&g2); palette_ptr = 0; for (i = 0; i < color_packets; i++) { /* first byte is how many colors to skip */ palette_ptr += bytestream2_get_byte(&g2); /* next byte indicates how many entries to change */ color_changes = bytestream2_get_byte(&g2); /* if there are 0 color changes, there are actually 256 */ if (color_changes == 0) color_changes = 256; if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk) break; for (j = 0; j < color_changes; j++) { unsigned int entry; /* wrap around, for good measure */ if ((unsigned)palette_ptr >= 256) palette_ptr = 0; r = bytestream2_get_byte(&g2) << color_shift; g = bytestream2_get_byte(&g2) << color_shift; b = bytestream2_get_byte(&g2) << color_shift; entry = 0xFFU << 24 | r << 16 | g << 8 | b; if (color_shift == 2) entry |= entry >> 6 & 0x30303; if (s->palette[palette_ptr] != entry) s->new_palette = 1; s->palette[palette_ptr++] = entry; } } break; case FLI_DELTA: y_ptr = 0; compressed_lines = bytestream2_get_le16(&g2); while (compressed_lines > 0) { if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) break; line_packets = bytestream2_get_le16(&g2); if ((line_packets & 0xC000) == 0xC000) { // line skip opcode line_packets = -line_packets; y_ptr += line_packets * s->frame.linesize[0]; } else if ((line_packets & 0xC000) == 0x4000) { av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets); } else if ((line_packets & 0xC000) == 0x8000) { // "last byte" opcode pixel_ptr= y_ptr + s->frame.linesize[0] - 1; CHECK_PIXEL_PTR(0); pixels[pixel_ptr] = line_packets & 0xff; } else { compressed_lines--; pixel_ptr = y_ptr; CHECK_PIXEL_PTR(0); pixel_countdown = s->avctx->width; for (i = 0; i < line_packets; i++) { if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) break; /* account for the skip bytes */ pixel_skip = bytestream2_get_byte(&g2); pixel_ptr += pixel_skip; pixel_countdown -= pixel_skip; byte_run = sign_extend(bytestream2_get_byte(&g2), 8); if (byte_run < 0) { byte_run = -byte_run; palette_idx1 = bytestream2_get_byte(&g2); palette_idx2 = bytestream2_get_byte(&g2); CHECK_PIXEL_PTR(byte_run * 2); for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { pixels[pixel_ptr++] = palette_idx1; pixels[pixel_ptr++] = palette_idx2; } } else { CHECK_PIXEL_PTR(byte_run * 2); if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk) break; for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { pixels[pixel_ptr++] = bytestream2_get_byte(&g2); } } } y_ptr += s->frame.linesize[0]; } } break; case FLI_LC: /* line compressed */ starting_line = bytestream2_get_le16(&g2); y_ptr = 0; y_ptr += starting_line * s->frame.linesize[0]; compressed_lines = bytestream2_get_le16(&g2); while (compressed_lines > 0) { pixel_ptr = y_ptr; CHECK_PIXEL_PTR(0); pixel_countdown = s->avctx->width; if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) break; line_packets = bytestream2_get_byte(&g2); if (line_packets > 0) { for (i = 0; i < line_packets; i++) { /* account for the skip bytes */ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) break; pixel_skip = bytestream2_get_byte(&g2); pixel_ptr += pixel_skip; pixel_countdown -= pixel_skip; byte_run = sign_extend(bytestream2_get_byte(&g2),8); if (byte_run > 0) { CHECK_PIXEL_PTR(byte_run); if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) break; for (j = 0; j < byte_run; j++, pixel_countdown--) { pixels[pixel_ptr++] = bytestream2_get_byte(&g2); } } else if (byte_run < 0) { byte_run = -byte_run; palette_idx1 = bytestream2_get_byte(&g2); CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++, pixel_countdown--) { pixels[pixel_ptr++] = palette_idx1; } } } } y_ptr += s->frame.linesize[0]; compressed_lines--; } break; case FLI_BLACK: /* set the whole frame to color 0 (which is usually black) */ memset(pixels, 0, s->frame.linesize[0] * s->avctx->height); break; case FLI_BRUN: /* Byte run compression: This chunk type only occurs in the first * FLI frame and it will update the entire frame. */ 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; 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) at line %d\n", pixel_countdown, lines); } } else { /* copy bytes if byte_run < 0 */ byte_run = -byte_run; CHECK_PIXEL_PTR(byte_run); if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) break; for (j = 0; j < byte_run; j++) { pixels[pixel_ptr++] = bytestream2_get_byte(&g2); 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_COPY: /* copy the chunk (uncompressed frame) */ if (chunk_size - 6 != s->avctx->width * s->avctx->height) { av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ "has incorrect size, 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]) { bytestream2_get_buffer(&g2, &pixels[y_ptr], s->avctx->width); } } break; case FLI_MINI: /* some sort of a thumbnail? disregard this chunk... */ break; default: av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); break; } if (stream_ptr_after_chunk - bytestream2_tell(&g2) > 0) bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); frame_size -= chunk_size; num_chunks--; } /* by the end of the chunk, the stream ptr should equal the frame * size (minus 1 or 2, possibly); if it doesn't, issue a warning */ if (bytestream2_get_bytes_left(&g2) > 2) av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ "and final chunk ptr = %d\n", buf_size, buf_size - bytestream2_get_bytes_left(&g2)); /* make the palette available on the way out */ memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); if (s->new_palette) { s->frame.palette_has_changed = 1; s->new_palette = 0; } *data_size=sizeof(AVFrame); *(AVFrame*)data = s->frame; return buf_size; }
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { SgiState *s = avctx->priv_data; AVFrame *p = data; unsigned int dimension, rle; int ret = 0; uint8_t *out_buf, *out_end; bytestream2_init(&s->g, avpkt->data, avpkt->size); if (bytestream2_get_bytes_left(&s->g) < SGI_HEADER_SIZE) { av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", avpkt->size); return AVERROR_INVALIDDATA; } /* Test for SGI magic. */ if (bytestream2_get_be16(&s->g) != SGI_MAGIC) { av_log(avctx, AV_LOG_ERROR, "bad magic number\n"); return AVERROR_INVALIDDATA; } rle = bytestream2_get_byte(&s->g); s->bytes_per_channel = bytestream2_get_byte(&s->g); dimension = bytestream2_get_be16(&s->g); s->width = bytestream2_get_be16(&s->g); s->height = bytestream2_get_be16(&s->g); s->depth = bytestream2_get_be16(&s->g); if (s->bytes_per_channel != 1 && (s->bytes_per_channel != 2 || rle)) { av_log(avctx, AV_LOG_ERROR, "wrong channel number\n"); return -1; } /* Check for supported image dimensions. */ if (dimension != 2 && dimension != 3) { av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n"); return -1; } if (s->depth == SGI_GRAYSCALE) { avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_GRAY16BE : AV_PIX_FMT_GRAY8; } else if (s->depth == SGI_RGB) { avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_RGB48BE : AV_PIX_FMT_RGB24; } else if (s->depth == SGI_RGBA && s->bytes_per_channel == 1) { avctx->pix_fmt = AV_PIX_FMT_RGBA; } else { av_log(avctx, AV_LOG_ERROR, "wrong picture format\n"); return -1; } if (av_image_check_size(s->width, s->height, 0, avctx)) return -1; avcodec_set_dimensions(avctx, s->width, s->height); if (ff_get_buffer(avctx, p, 0) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n"); return -1; } p->pict_type = AV_PICTURE_TYPE_I; p->key_frame = 1; out_buf = p->data[0]; out_end = out_buf + p->linesize[0] * s->height; s->linesize = p->linesize[0]; /* Skip header. */ bytestream2_seek(&s->g, SGI_HEADER_SIZE, SEEK_SET); if (rle) { ret = read_rle_sgi(out_end, s); } else { ret = read_uncompressed_sgi(out_buf, out_end, s); } if (ret == 0) { *got_frame = 1; return avpkt->size; } else { return ret; } }
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; C93DecoderContext * const c93 = avctx->priv_data; AVFrame * const newpic = &c93->pictures[c93->currentpic]; AVFrame * const oldpic = &c93->pictures[c93->currentpic^1]; GetByteContext gb; uint8_t *out; int stride, ret, i, x, y, b, bt = 0; c93->currentpic ^= 1; if ((ret = ff_reget_buffer(avctx, newpic)) < 0) return ret; stride = newpic->linesize[0]; bytestream2_init(&gb, buf, buf_size); b = bytestream2_get_byte(&gb); if (b & C93_FIRST_FRAME) { newpic->pict_type = AV_PICTURE_TYPE_I; newpic->key_frame = 1; } else { newpic->pict_type = AV_PICTURE_TYPE_P; newpic->key_frame = 0; } for (y = 0; y < HEIGHT; y += 8) { out = newpic->data[0] + y * stride; for (x = 0; x < WIDTH; x += 8) { uint8_t *copy_from = oldpic->data[0]; unsigned int offset, j; uint8_t cols[4], grps[4]; C93BlockType block_type; if (!bt) bt = bytestream2_get_byte(&gb); block_type= bt & 0x0F; switch (block_type) { case C93_8X8_FROM_PREV: offset = bytestream2_get_le16(&gb); if ((ret = copy_block(avctx, out, copy_from, offset, 8, stride)) < 0) return ret; break; case C93_4X4_FROM_CURR: copy_from = newpic->data[0]; case C93_4X4_FROM_PREV: for (j = 0; j < 8; j += 4) { for (i = 0; i < 8; i += 4) { offset = bytestream2_get_le16(&gb); if ((ret = copy_block(avctx, &out[j*stride+i], copy_from, offset, 4, stride)) < 0) return ret; } } break; case C93_8X8_2COLOR: bytestream2_get_buffer(&gb, cols, 2); for (i = 0; i < 8; i++) { draw_n_color(out + i*stride, stride, 8, 1, 1, cols, NULL, bytestream2_get_byte(&gb)); } break; case C93_4X4_2COLOR: case C93_4X4_4COLOR: case C93_4X4_4COLOR_GRP: for (j = 0; j < 8; j += 4) { for (i = 0; i < 8; i += 4) { if (block_type == C93_4X4_2COLOR) { bytestream2_get_buffer(&gb, cols, 2); draw_n_color(out + i + j*stride, stride, 4, 4, 1, cols, NULL, bytestream2_get_le16(&gb)); } else if (block_type == C93_4X4_4COLOR) { bytestream2_get_buffer(&gb, cols, 4); draw_n_color(out + i + j*stride, stride, 4, 4, 2, cols, NULL, bytestream2_get_le32(&gb)); } else { bytestream2_get_buffer(&gb, grps, 4); draw_n_color(out + i + j*stride, stride, 4, 4, 1, cols, grps, bytestream2_get_le16(&gb)); } } } break; case C93_NOOP: break; case C93_8X8_INTRA: for (j = 0; j < 8; j++) bytestream2_get_buffer(&gb, out + j*stride, 8); break; default: av_log(avctx, AV_LOG_ERROR, "unexpected type %x at %dx%d\n", block_type, x, y); return AVERROR_INVALIDDATA; } bt >>= 4; out += 8; } } if (b & C93_HAS_PALETTE) { uint32_t *palette = (uint32_t *) newpic->data[1]; for (i = 0; i < 256; i++) { palette[i] = 0xFFU << 24 | bytestream2_get_be24(&gb); } newpic->palette_has_changed = 1; } else { if (oldpic->data[1]) memcpy(newpic->data[1], oldpic->data[1], 256 * 4); } if ((ret = av_frame_ref(data, newpic)) < 0) return ret; *got_frame = 1; return buf_size; }
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 * 4; 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); /* Get pixels buffer, it may be deflated or just raw */ if (pixel_size == packed_size) { pixels = gbc->buffer; } else { uLongf len = ctx->inflated_size; 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 * 4; av_image_copy_plane(dst, -1 * ctx->reference->linesize[0], raw, ctx->tiles[i].w * 4, ctx->tiles[i].w * 4, ctx->tiles[i].h); raw += ctx->tiles[i].w * 4 * 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; }