X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fxxan.c;h=5495bec757788085072308d250a62062db6321bc;hb=b7f98659f21dce438c33b512e25fd64b8d07c347;hp=9e874540b59f6f9bcd0ed6764fd2b9ff038ac3c9;hpb=df9b9567518f2840d79a4a96b447ebe1aa326408;p=ffmpeg diff --git a/libavcodec/xxan.c b/libavcodec/xxan.c index 9e874540b59..5495bec7577 100644 --- a/libavcodec/xxan.c +++ b/libavcodec/xxan.c @@ -20,16 +20,16 @@ * 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; @@ -37,6 +37,18 @@ typedef struct XanContext { 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; @@ -45,6 +57,15 @@ static av_cold int xan_decode_init(AVCodecContext *avctx) 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) @@ -55,6 +76,12 @@ static av_cold int xan_decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } + s->pic = av_frame_alloc(); + if (!s->pic) { + xan_decode_end(avctx); + return AVERROR(ENOMEM); + } + return 0; } @@ -133,7 +160,7 @@ static int xan_unpack(XanContext *s, } 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); @@ -143,7 +170,7 @@ static int xan_unpack(XanContext *s, 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) @@ -167,7 +194,7 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off) 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); @@ -178,7 +205,7 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off) 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); @@ -186,11 +213,11 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off) 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) { @@ -207,12 +234,16 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off) 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) { @@ -225,10 +256,16 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off) 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]); } } @@ -292,7 +329,7 @@ static int xan_decode_frame_type0(AVCodecContext *avctx) 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++) @@ -300,12 +337,12 @@ static int xan_decode_frame_type0(AVCodecContext *avctx) } 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; @@ -345,12 +382,12 @@ static int xan_decode_frame_type1(AVCodecContext *avctx) } 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; @@ -364,11 +401,7 @@ static int xan_decode_frame(AVCodecContext *avctx, 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; } @@ -384,38 +417,27 @@ static int xan_decode_frame(AVCodecContext *avctx, 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, };