/*
* Wing Commander/Xan Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (C) 2003 The FFmpeg project
*
* This file is part of Libav.
*
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
+
+#define BITSTREAM_READER_LE
#include "avcodec.h"
#include "bytestream.h"
-#define BITSTREAM_READER_LE
#include "get_bits.h"
#include "internal.h"
typedef struct XanContext {
AVCodecContext *avctx;
- AVFrame last_frame;
- AVFrame current_frame;
+ AVFrame *last_frame;
const unsigned char *buf;
int size;
} XanContext;
+static av_cold int xan_decode_end(AVCodecContext *avctx)
+{
+ XanContext *s = avctx->priv_data;
+
+ av_frame_free(&s->last_frame);
+
+ av_freep(&s->buffer1);
+ av_freep(&s->buffer2);
+ av_freep(&s->palettes);
+
+ return 0;
+}
+
static av_cold int xan_decode_init(AVCodecContext *avctx)
{
XanContext *s = avctx->priv_data;
return AVERROR(ENOMEM);
}
+ s->last_frame = av_frame_alloc();
+ if (!s->last_frame) {
+ xan_decode_end(avctx);
+ return AVERROR(ENOMEM);
+ }
+
return 0;
}
int ptr_len = src_len - 1 - byte*2;
unsigned char val = ival;
unsigned char *dest_end = dest + dest_len;
+ unsigned char *dest_start = dest;
GetBitContext gb;
if (ptr_len < 0)
if (val < 0x16) {
if (dest >= dest_end)
- return 0;
+ return dest_len;
*dest++ = val;
val = ival;
}
}
- return 0;
+ return dest - dest_start;
}
/**
int size;
unsigned char *dest_org = dest;
unsigned char *dest_end = dest + dest_len;
- const unsigned char *src_end = src + src_len;
+ GetByteContext ctx;
- while (dest < dest_end && src < src_end) {
- opcode = *src++;
+ bytestream2_init(&ctx, src, src_len);
+ while (dest < dest_end && bytestream2_get_bytes_left(&ctx)) {
+ opcode = bytestream2_get_byte(&ctx);
if (opcode < 0xe0) {
int size2, back;
if ((opcode & 0x80) == 0) {
size = opcode & 3;
- back = ((opcode & 0x60) << 3) + *src++ + 1;
+ back = ((opcode & 0x60) << 3) + bytestream2_get_byte(&ctx) + 1;
size2 = ((opcode & 0x1c) >> 2) + 3;
} else if ((opcode & 0x40) == 0) {
- size = *src >> 6;
+ size = bytestream2_peek_byte(&ctx) >> 6;
- back = (bytestream_get_be16(&src) & 0x3fff) + 1;
+ back = (bytestream2_get_be16(&ctx) & 0x3fff) + 1;
size2 = (opcode & 0x3f) + 4;
} else {
size = opcode & 3;
- back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
- size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
+ back = ((opcode & 0x10) << 12) + bytestream2_get_be16(&ctx) + 1;
+ size2 = ((opcode & 0x0c) << 6) + bytestream2_get_byte(&ctx) + 5;
}
if (dest_end - dest < size + size2 ||
dest + size - dest_org < back ||
- src_end - src < size)
+ bytestream2_get_bytes_left(&ctx) < size)
return;
- memcpy(dest, src, size); dest += size; src += size;
+ bytestream2_get_buffer(&ctx, dest, size);
+ dest += size;
av_memcpy_backptr(dest, back, size2);
dest += size2;
} else {
int finish = opcode >= 0xfc;
size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
- if (dest_end - dest < size || src_end - src < size)
+ if (dest_end - dest < size || bytestream2_get_bytes_left(&ctx) < size)
return;
- memcpy(dest, src, size); dest += size; src += size;
+ bytestream2_get_buffer(&ctx, dest, size);
+ dest += size;
if (finish)
return;
}
}
}
-static inline void xan_wc3_output_pixel_run(XanContext *s,
+static inline void xan_wc3_output_pixel_run(XanContext *s, AVFrame *frame,
const unsigned char *pixel_buffer, int x, int y, int pixel_count)
{
int stride;
int width = s->avctx->width;
unsigned char *palette_plane;
- palette_plane = s->current_frame.data[0];
- stride = s->current_frame.linesize[0];
+ palette_plane = frame->data[0];
+ stride = frame->linesize[0];
line_inc = stride - width;
index = y * stride + x;
current_x = x;
}
}
-static inline void xan_wc3_copy_pixel_run(XanContext *s, int x, int y,
+static inline void xan_wc3_copy_pixel_run(XanContext *s, AVFrame *frame,
+ int x, int y,
int pixel_count, int motion_x,
int motion_y)
{
x + motion_x < 0 || x + motion_x >= s->avctx->width)
return;
- palette_plane = s->current_frame.data[0];
- prev_palette_plane = s->last_frame.data[0];
+ palette_plane = frame->data[0];
+ prev_palette_plane = s->last_frame->data[0];
if (!prev_palette_plane)
prev_palette_plane = palette_plane;
- stride = s->current_frame.linesize[0];
+ stride = frame->linesize[0];
line_inc = stride - width;
curframe_index = y * stride + x;
curframe_x = x;
}
}
-static int xan_wc3_decode_frame(XanContext *s) {
+static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
+{
int width = s->avctx->width;
int height = s->avctx->height;
unsigned char flag = 0;
int size = 0;
int motion_x, motion_y;
- int x, y;
+ int x, y, ret;
unsigned char *opcode_buffer = s->buffer1;
unsigned char *opcode_buffer_end = s->buffer1 + s->buffer1_size;
/* pointers to segments inside the compressed chunk */
const unsigned char *huffman_segment;
- const unsigned char *size_segment;
- const unsigned char *vector_segment;
+ GetByteContext size_segment;
+ GetByteContext vector_segment;
const unsigned char *imagedata_segment;
int huffman_offset, size_offset, vector_offset, imagedata_offset,
imagedata_size;
return AVERROR_INVALIDDATA;
huffman_segment = s->buf + huffman_offset;
- size_segment = s->buf + size_offset;
- vector_segment = s->buf + vector_offset;
+ bytestream2_init(&size_segment, s->buf + size_offset, s->size - size_offset);
+ bytestream2_init(&vector_segment, s->buf + vector_offset, s->size - vector_offset);
imagedata_segment = s->buf + imagedata_offset;
- if (xan_huffman_decode(opcode_buffer, opcode_buffer_size,
- huffman_segment, s->size - huffman_offset) < 0)
+ if ((ret = xan_huffman_decode(opcode_buffer, opcode_buffer_size,
+ huffman_segment, s->size - huffman_offset)) < 0)
return AVERROR_INVALIDDATA;
+ opcode_buffer_end = opcode_buffer + ret;
if (imagedata_segment[0] == 2) {
xan_unpack(s->buffer2, s->buffer2_size,
case 9:
case 19:
- size = *size_segment++;
+ size = bytestream2_get_byte(&size_segment);
break;
case 10:
case 20:
- size = AV_RB16(&size_segment[0]);
- size_segment += 2;
+ size = bytestream2_get_be16(&size_segment);
break;
case 11:
case 21:
- size = AV_RB24(size_segment);
- size_segment += 3;
+ size = bytestream2_get_be24(&size_segment);
break;
}
flag ^= 1;
if (flag) {
/* run of (size) pixels is unchanged from last frame */
- xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
+ xan_wc3_copy_pixel_run(s, frame, x, y, size, 0, 0);
} else {
/* output a run of pixels from imagedata_buffer */
if (imagedata_size < size)
break;
- xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
+ xan_wc3_output_pixel_run(s, frame, imagedata_buffer, x, y, size);
imagedata_buffer += size;
imagedata_size -= size;
}
} else {
/* run-based motion compensation from last frame */
- motion_x = sign_extend(*vector_segment >> 4, 4);
- motion_y = sign_extend(*vector_segment & 0xF, 4);
- vector_segment++;
+ uint8_t vector = bytestream2_get_byte(&vector_segment);
+ motion_x = sign_extend(vector >> 4, 4);
+ motion_y = sign_extend(vector & 0xF, 4);
/* copy a run of pixels from the previous frame */
- xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
+ xan_wc3_copy_pixel_run(s, frame, x, y, size, motion_x, motion_y);
flag = 0;
}
void *data, int *got_frame,
AVPacket *avpkt)
{
+ AVFrame *frame = data;
const uint8_t *buf = avpkt->data;
int ret, buf_size = avpkt->size;
XanContext *s = avctx->priv_data;
- const uint8_t *buf_end = buf + buf_size;
+ GetByteContext ctx;
int tag = 0;
- while (buf_end - buf > 8 && tag != VGA__TAG) {
+ bytestream2_init(&ctx, buf, buf_size);
+ while (bytestream2_get_bytes_left(&ctx) > 8 && tag != VGA__TAG) {
unsigned *tmpptr;
uint32_t new_pal;
int size;
int i;
- tag = bytestream_get_le32(&buf);
- size = bytestream_get_be32(&buf);
- size = FFMIN(size, buf_end - buf);
+ tag = bytestream2_get_le32(&ctx);
+ size = bytestream2_get_be32(&ctx);
+ size = FFMIN(size, bytestream2_get_bytes_left(&ctx));
switch (tag) {
case PALT_TAG:
if (size < PALETTE_SIZE)
tmpptr += s->palettes_count * AVPALETTE_COUNT;
for (i = 0; i < PALETTE_COUNT; i++) {
#if RUNTIME_GAMMA
- int r = gamma_corr(*buf++);
- int g = gamma_corr(*buf++);
- int b = gamma_corr(*buf++);
+ int r = gamma_corr(bytestream2_get_byteu(&ctx));
+ int g = gamma_corr(bytestream2_get_byteu(&ctx));
+ int b = gamma_corr(bytestream2_get_byteu(&ctx));
#else
- int r = gamma_lookup[*buf++];
- int g = gamma_lookup[*buf++];
- int b = gamma_lookup[*buf++];
+ int r = gamma_lookup[bytestream2_get_byteu(&ctx)];
+ int g = gamma_lookup[bytestream2_get_byteu(&ctx)];
+ int b = gamma_lookup[bytestream2_get_byteu(&ctx)];
#endif
*tmpptr++ = (r << 16) | (g << 8) | b;
}
case SHOT_TAG:
if (size < 4)
return AVERROR_INVALIDDATA;
- new_pal = bytestream_get_le32(&buf);
+ new_pal = bytestream2_get_le32(&ctx);
if (new_pal < s->palettes_count) {
s->cur_palette = new_pal;
} else
case VGA__TAG:
break;
default:
- buf += size;
+ bytestream2_skip(&ctx, size);
break;
}
}
- buf_size = buf_end - buf;
+ buf_size = bytestream2_get_bytes_left(&ctx);
if (s->palettes_count <= 0) {
av_log(s->avctx, AV_LOG_ERROR, "No palette found\n");
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, &s->current_frame))) {
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF))) {
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return ret;
}
- s->current_frame.reference = 3;
if (!s->frame_size)
- s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
+ s->frame_size = frame->linesize[0] * s->avctx->height;
- memcpy(s->current_frame.data[1],
+ memcpy(frame->data[1],
s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
- s->buf = buf;
+ s->buf = ctx.buffer;
s->size = buf_size;
- if (xan_wc3_decode_frame(s) < 0)
+ if (xan_wc3_decode_frame(s, frame) < 0)
return AVERROR_INVALIDDATA;
- /* release the last frame if it is allocated */
- if (s->last_frame.data[0])
- avctx->release_buffer(avctx, &s->last_frame);
+ av_frame_unref(s->last_frame);
+ if ((ret = av_frame_ref(s->last_frame, frame)) < 0)
+ return ret;
*got_frame = 1;
- *(AVFrame*)data = s->current_frame;
-
- /* shuffle frames */
- FFSWAP(AVFrame, s->current_frame, s->last_frame);
/* always report that the buffer was completely consumed */
return buf_size;
}
-static av_cold int xan_decode_end(AVCodecContext *avctx)
-{
- XanContext *s = avctx->priv_data;
-
- /* release the frames */
- if (s->last_frame.data[0])
- avctx->release_buffer(avctx, &s->last_frame);
- if (s->current_frame.data[0])
- avctx->release_buffer(avctx, &s->current_frame);
-
- av_freep(&s->buffer1);
- av_freep(&s->buffer2);
- av_freep(&s->palettes);
-
- return 0;
-}
-
AVCodec ff_xan_wc3_decoder = {
.name = "xan_wc3",
+ .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_XAN_WC3,
.priv_data_size = sizeof(XanContext),
.init = xan_decode_init,
.close = xan_decode_end,
.decode = xan_decode_frame,
- .capabilities = CODEC_CAP_DR1,
- .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
+ .capabilities = AV_CODEC_CAP_DR1,
};