* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "avcodec.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
+
+#include "avcodec.h"
#include "bytestream.h"
-#define BITSTREAM_READER_LE
-#include "get_bits.h"
+#include "internal.h"
typedef struct XanContext {
AVCodecContext *avctx;
- AVFrame pic;
+ AVFrame *pic;
uint8_t *y_buffer;
uint8_t *scratch_buffer;
GetByteContext gb;
} XanContext;
+static av_cold int xan_decode_end(AVCodecContext *avctx)
+{
+ XanContext *s = avctx->priv_data;
+
+ av_frame_free(&s->pic);
+
+ av_freep(&s->y_buffer);
+ av_freep(&s->scratch_buffer);
+
+ return 0;
+}
+
static av_cold int xan_decode_init(AVCodecContext *avctx)
{
XanContext *s = avctx->priv_data;
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ if (avctx->height < 8) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid frame height: %d.\n", avctx->height);
+ return AVERROR(EINVAL);
+ }
+ if (avctx->width & 1) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid frame width: %d.\n", avctx->width);
+ return AVERROR(EINVAL);
+ }
+
s->buffer_size = avctx->width * avctx->height;
s->y_buffer = av_malloc(s->buffer_size);
if (!s->y_buffer)
return AVERROR(ENOMEM);
}
+ s->pic = av_frame_alloc();
+ if (!s->pic) {
+ xan_decode_end(avctx);
+ return AVERROR(ENOMEM);
+ }
+
return 0;
}
}
if (dest + size + size2 > dest_end ||
dest - orig_dest + size < back)
- return -1;
+ return AVERROR_INVALIDDATA;
bytestream2_get_buffer(&s->gb, dest, size);
dest += size;
av_memcpy_backptr(dest, back, size2);
size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
if (dest_end - dest < size)
- return -1;
+ return AVERROR_INVALIDDATA;
bytestream2_get_buffer(&s->gb, dest, size);
dest += size;
if (finish)
return 0;
if (chroma_off + 4 >= bytestream2_get_bytes_left(&s->gb)) {
av_log(avctx, AV_LOG_ERROR, "Invalid chroma block position\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
bytestream2_seek(&s->gb, chroma_off + 4, SEEK_SET);
mode = bytestream2_get_le16(&s->gb);
if (offset >= bytestream2_get_bytes_left(&s->gb)) {
av_log(avctx, AV_LOG_ERROR, "Invalid chroma block offset\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
bytestream2_skip(&s->gb, offset);
dec_size = xan_unpack(s, s->scratch_buffer, s->buffer_size);
if (dec_size < 0) {
av_log(avctx, AV_LOG_ERROR, "Chroma unpacking failed\n");
- return -1;
+ return dec_size;
}
- U = s->pic.data[1];
- V = s->pic.data[2];
+ U = s->pic->data[1];
+ V = s->pic->data[2];
src = s->scratch_buffer;
src_end = src + dec_size;
if (mode) {
if (src == src_end)
return 0;
}
- U += s->pic.linesize[1];
- V += s->pic.linesize[2];
+ U += s->pic->linesize[1];
+ V += s->pic->linesize[2];
+ }
+ if (avctx->height & 1) {
+ memcpy(U, U - s->pic->linesize[1], avctx->width >> 1);
+ memcpy(V, V - s->pic->linesize[2], avctx->width >> 1);
}
} else {
- uint8_t *U2 = U + s->pic.linesize[1];
- uint8_t *V2 = V + s->pic.linesize[2];
+ uint8_t *U2 = U + s->pic->linesize[1];
+ uint8_t *V2 = V + s->pic->linesize[2];
for (j = 0; j < avctx->height >> 2; j++) {
for (i = 0; i < avctx->width >> 1; i += 2) {
V[i] = V[i+1] = V2[i] = V2[i+1] = vval | (vval >> 5);
}
}
- U += s->pic.linesize[1] * 2;
- V += s->pic.linesize[2] * 2;
- U2 += s->pic.linesize[1] * 2;
- V2 += s->pic.linesize[2] * 2;
+ U += s->pic->linesize[1] * 2;
+ V += s->pic->linesize[2] * 2;
+ U2 += s->pic->linesize[1] * 2;
+ V2 += s->pic->linesize[2] * 2;
+ }
+ if (avctx->height & 3) {
+ int lines = ((avctx->height + 1) >> 1) - (avctx->height >> 2) * 2;
+
+ memcpy(U, U - lines * s->pic->linesize[1], lines * s->pic->linesize[1]);
+ memcpy(V, V - lines * s->pic->linesize[2], lines * s->pic->linesize[2]);
}
}
int dec_size;
bytestream2_seek(&s->gb, 8 + corr_off, SEEK_SET);
- dec_size = xan_unpack(s, s->scratch_buffer, s->buffer_size);
+ dec_size = xan_unpack(s, s->scratch_buffer, s->buffer_size / 2);
if (dec_size < 0)
dec_size = 0;
for (i = 0; i < dec_size; i++)
}
src = s->y_buffer;
- ybuf = s->pic.data[0];
+ ybuf = s->pic->data[0];
for (j = 0; j < avctx->height; j++) {
for (i = 0; i < avctx->width; i++)
ybuf[i] = (src[i] << 2) | (src[i] >> 3);
src += avctx->width;
- ybuf += s->pic.linesize[0];
+ ybuf += s->pic->linesize[0];
}
return 0;
}
src = s->y_buffer;
- ybuf = s->pic.data[0];
+ ybuf = s->pic->data[0];
for (j = 0; j < avctx->height; j++) {
for (i = 0; i < avctx->width; i++)
ybuf[i] = (src[i] << 2) | (src[i] >> 3);
src += avctx->width;
- ybuf += s->pic.linesize[0];
+ ybuf += s->pic->linesize[0];
}
return 0;
int ftype;
int ret;
- s->pic.reference = 1;
- s->pic.buffer_hints = FF_BUFFER_HINTS_VALID |
- FF_BUFFER_HINTS_PRESERVE |
- FF_BUFFER_HINTS_REUSABLE;
- if ((ret = avctx->reget_buffer(avctx, &s->pic))) {
+ if ((ret = ff_reget_buffer(avctx, s->pic))) {
av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
return ret;
}
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unknown frame type %d\n", ftype);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (ret)
return ret;
+ if ((ret = av_frame_ref(data, s->pic)) < 0)
+ return ret;
+
*got_frame = 1;
- *(AVFrame*)data = s->pic;
return avpkt->size;
}
-static av_cold int xan_decode_end(AVCodecContext *avctx)
-{
- XanContext *s = avctx->priv_data;
-
- if (s->pic.data[0])
- avctx->release_buffer(avctx, &s->pic);
-
- av_freep(&s->y_buffer);
- av_freep(&s->scratch_buffer);
-
- return 0;
-}
-
AVCodec ff_xan_wc4_decoder = {
.name = "xan_wc4",
+ .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_XAN_WC4,
.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 IV / Xxan"),
+ .capabilities = AV_CODEC_CAP_DR1,
};