diff options
Diffstat (limited to 'libavcodec/interplayvideo.c')
-rw-r--r-- | libavcodec/interplayvideo.c | 445 |
1 files changed, 404 insertions, 41 deletions
diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c index f5593d3..deaa09c 100644 --- a/libavcodec/interplayvideo.c +++ b/libavcodec/interplayvideo.c @@ -2,20 +2,20 @@ * Interplay MVE Video Decoder * Copyright (C) 2003 The FFmpeg project * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -38,10 +38,12 @@ #include <stdlib.h> #include <string.h> +#include "libavutil/intreadwrite.h" + #define BITSTREAM_READER_LE #include "avcodec.h" -#include "bitstream.h" #include "bytestream.h" +#include "get_bits.h" #include "hpeldsp.h" #include "internal.h" @@ -53,8 +55,15 @@ typedef struct IpvideoContext { HpelDSPContext hdsp; AVFrame *second_last_frame; AVFrame *last_frame; + + /* For format 0x10 */ + AVFrame *cur_decode_frame; + AVFrame *prev_decode_frame; + const unsigned char *decoding_map; int decoding_map_size; + const unsigned char *skip_map; + int skip_map_size; int is_16bpp; GetByteContext stream_ptr, mv_ptr; @@ -72,10 +81,10 @@ static int copy_from(IpvideoContext *s, AVFrame *src, AVFrame *dst, int delta_x, int motion_offset = current_offset + delta_y * dst->linesize[0] + delta_x * (1 + s->is_16bpp); if (motion_offset < 0) { - av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); + av_log(s->avctx, AV_LOG_ERROR, "motion offset < 0 (%d)\n", motion_offset); return AVERROR_INVALIDDATA; } else if (motion_offset > s->upper_motion_limit_offset) { - av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", + av_log(s->avctx, AV_LOG_ERROR, "motion offset above limit (%d >= %d)\n", motion_offset, s->upper_motion_limit_offset); return AVERROR_INVALIDDATA; } @@ -118,7 +127,7 @@ static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s, AVFrame *frame) y = 8 + ((B - 56) / 29); } - ff_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); + ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); return copy_from(s, s->second_last_frame, frame, x, y); } @@ -144,7 +153,7 @@ static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s, AVFrame *frame) y = -( 8 + ((B - 56) / 29)); } - ff_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); + ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); return copy_from(s, frame, frame, x, y); } @@ -165,7 +174,7 @@ static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s, AVFrame *frame) x = -8 + BL; y = -8 + BH; - ff_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); + ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); return copy_from(s, s->last_frame, frame, x, y); } @@ -178,14 +187,14 @@ static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s, AVFrame *frame) x = bytestream2_get_byte(&s->stream_ptr); y = bytestream2_get_byte(&s->stream_ptr); - ff_dlog(NULL, " motion bytes = %d, %d\n", x, y); + ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y); return copy_from(s, s->last_frame, frame, x, y); } static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s, AVFrame *frame) { /* mystery opcode? skip multiple blocks? */ - av_log(s->avctx, AV_LOG_ERROR, " Interplay video: Help! Mystery opcode 0x6 seen\n"); + av_log(s->avctx, AV_LOG_ERROR, "Help! Mystery opcode 0x6 seen\n"); /* report success */ return 0; @@ -197,6 +206,11 @@ static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s, AVFrame *frame) unsigned char P[2]; unsigned int flags; + if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) { + av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x7\n"); + return AVERROR_INVALIDDATA; + } + /* 2-color encoding */ P[0] = bytestream2_get_byte(&s->stream_ptr); P[1] = bytestream2_get_byte(&s->stream_ptr); @@ -236,6 +250,11 @@ static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s, AVFrame *frame) unsigned char P[4]; unsigned int flags = 0; + if (bytestream2_get_bytes_left(&s->stream_ptr) < 12) { + av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x8\n"); + return AVERROR_INVALIDDATA; + } + /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on * either top and bottom or left and right halves */ P[0] = bytestream2_get_byte(&s->stream_ptr); @@ -308,6 +327,11 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s, AVFrame *frame) int x, y; unsigned char P[4]; + if (bytestream2_get_bytes_left(&s->stream_ptr) < 8) { + av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x9\n"); + return AVERROR_INVALIDDATA; + } + /* 4-color encoding */ bytestream2_get_buffer(&s->stream_ptr, P, 4); @@ -374,6 +398,11 @@ static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s, AVFrame *frame) unsigned char P[8]; int flags = 0; + if (bytestream2_get_bytes_left(&s->stream_ptr) < 16) { + av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xA\n"); + return AVERROR_INVALIDDATA; + } + bytestream2_get_buffer(&s->stream_ptr, P, 4); /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on @@ -467,6 +496,11 @@ static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s, AVFrame *frame) int y; unsigned char P[2]; + if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) { + av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xD\n"); + return AVERROR_INVALIDDATA; + } + /* 4-color block encoding: each 4x4 block is a different color */ for (y = 0; y < 8; y++) { if (!(y & 3)) { @@ -528,7 +562,7 @@ static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s, AVFrame *frame) x = bytestream2_get_byte(&s->stream_ptr); y = bytestream2_get_byte(&s->stream_ptr); - ff_dlog(NULL, " motion bytes = %d, %d\n", x, y); + ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y); return copy_from(s, s->second_last_frame, frame, x, y); } @@ -876,12 +910,198 @@ static int (* const ipvideo_decode_block16[])(IpvideoContext *s, AVFrame *frame) ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1, }; -static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame) +static void ipvideo_format_06_firstpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) +{ + int line; + + if (!opcode) { + for (line = 0; line < 8; ++line) { + bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8); + s->pixel_ptr += s->stride; + } + } else { + /* Don't try to copy second_last_frame data on the first frames */ + if (s->avctx->frame_number > 2) + copy_from(s, s->second_last_frame, frame, 0, 0); + } +} + +static void ipvideo_format_06_secondpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) +{ + int off_x, off_y; + + if (opcode < 0) { + off_x = ((uint16_t)opcode - 0xC000) % frame->linesize[0]; + off_y = ((uint16_t)opcode - 0xC000) / frame->linesize[0]; + copy_from(s, s->last_frame, frame, off_x, off_y); + } else if (opcode > 0) { + off_x = ((uint16_t)opcode - 0x4000) % frame->linesize[0]; + off_y = ((uint16_t)opcode - 0x4000) / frame->linesize[0]; + copy_from(s, frame, frame, off_x, off_y); + } +} + +static void (* const ipvideo_format_06_passes[])(IpvideoContext *s, AVFrame *frame, int16_t op) = { + ipvideo_format_06_firstpass, ipvideo_format_06_secondpass, +}; + +static void ipvideo_decode_format_06_opcodes(IpvideoContext *s, AVFrame *frame) +{ + int pass, x, y; + int16_t opcode; + GetByteContext decoding_map_ptr; + + /* this is PAL8, so make the palette available */ + memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); + s->stride = frame->linesize[0]; + + s->line_inc = s->stride - 8; + s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0] + + (s->avctx->width - 8) * (1 + s->is_16bpp); + + bytestream2_init(&decoding_map_ptr, s->decoding_map, s->decoding_map_size); + + for (pass = 0; pass < 2; ++pass) { + bytestream2_seek(&decoding_map_ptr, 0, SEEK_SET); + for (y = 0; y < s->avctx->height; y += 8) { + for (x = 0; x < s->avctx->width; x += 8) { + opcode = bytestream2_get_le16(&decoding_map_ptr); + + ff_tlog(s->avctx, + " block @ (%3d, %3d): opcode 0x%X, data ptr offset %d\n", + x, y, opcode, bytestream2_tell(&s->stream_ptr)); + + s->pixel_ptr = frame->data[0] + x + y * frame->linesize[0]; + ipvideo_format_06_passes[pass](s, frame, opcode); + } + } + } + + if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) { + av_log(s->avctx, AV_LOG_DEBUG, + "decode finished with %d bytes left over\n", + bytestream2_get_bytes_left(&s->stream_ptr)); + } +} + +static void ipvideo_format_10_firstpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) +{ + int line; + + if (!opcode) { + for (line = 0; line < 8; ++line) { + bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8); + s->pixel_ptr += s->stride; + } + } +} + +static void ipvideo_format_10_secondpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) +{ + int off_x, off_y; + + if (opcode < 0) { + off_x = ((uint16_t)opcode - 0xC000) % s->cur_decode_frame->linesize[0]; + off_y = ((uint16_t)opcode - 0xC000) / s->cur_decode_frame->linesize[0]; + copy_from(s, s->prev_decode_frame, s->cur_decode_frame, off_x, off_y); + } else if (opcode > 0) { + off_x = ((uint16_t)opcode - 0x4000) % s->cur_decode_frame->linesize[0]; + off_y = ((uint16_t)opcode - 0x4000) / s->cur_decode_frame->linesize[0]; + copy_from(s, s->cur_decode_frame, s->cur_decode_frame, off_x, off_y); + } +} + +static void (* const ipvideo_format_10_passes[])(IpvideoContext *s, AVFrame *frame, int16_t op) = { + ipvideo_format_10_firstpass, ipvideo_format_10_secondpass, +}; + +static void ipvideo_decode_format_10_opcodes(IpvideoContext *s, AVFrame *frame) +{ + int pass, x, y, changed_block; + int16_t opcode, skip; + GetByteContext decoding_map_ptr; + GetByteContext skip_map_ptr; + + bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */ + + /* this is PAL8, so make the palette available */ + memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); + s->stride = frame->linesize[0]; + + s->line_inc = s->stride - 8; + s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0] + + (s->avctx->width - 8) * (1 + s->is_16bpp); + + bytestream2_init(&decoding_map_ptr, s->decoding_map, s->decoding_map_size); + bytestream2_init(&skip_map_ptr, s->skip_map, s->skip_map_size); + + for (pass = 0; pass < 2; ++pass) { + bytestream2_seek(&decoding_map_ptr, 0, SEEK_SET); + bytestream2_seek(&skip_map_ptr, 0, SEEK_SET); + skip = bytestream2_get_le16(&skip_map_ptr); + + for (y = 0; y < s->avctx->height; y += 8) { + for (x = 0; x < s->avctx->width; x += 8) { + s->pixel_ptr = s->cur_decode_frame->data[0] + x + y * s->cur_decode_frame->linesize[0]; + + while (skip <= 0) { + if (skip != -0x8000 && skip) { + opcode = bytestream2_get_le16(&decoding_map_ptr); + ipvideo_format_10_passes[pass](s, frame, opcode); + break; + } + if (bytestream2_get_bytes_left(&skip_map_ptr) < 2) + return; + skip = bytestream2_get_le16(&skip_map_ptr); + } + skip *= 2; + } + } + } + + bytestream2_seek(&skip_map_ptr, 0, SEEK_SET); + skip = bytestream2_get_le16(&skip_map_ptr); + for (y = 0; y < s->avctx->height; y += 8) { + for (x = 0; x < s->avctx->width; x += 8) { + changed_block = 0; + s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0]; + + while (skip <= 0) { + if (skip != -0x8000 && skip) { + changed_block = 1; + break; + } + if (bytestream2_get_bytes_left(&skip_map_ptr) < 2) + return; + skip = bytestream2_get_le16(&skip_map_ptr); + } + + if (changed_block) { + copy_from(s, s->cur_decode_frame, frame, 0, 0); + } else { + /* Don't try to copy last_frame data on the first frame */ + if (s->avctx->frame_number) + copy_from(s, s->last_frame, frame, 0, 0); + } + skip *= 2; + } + } + + FFSWAP(AVFrame*, s->prev_decode_frame, s->cur_decode_frame); + + if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) { + av_log(s->avctx, AV_LOG_DEBUG, + "decode finished with %d bytes left over\n", + bytestream2_get_bytes_left(&s->stream_ptr)); + } +} + +static void ipvideo_decode_format_11_opcodes(IpvideoContext *s, AVFrame *frame) { int x, y; unsigned char opcode; int ret; - BitstreamContext bc; + GetBitContext gb; bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */ if (!s->is_16bpp) { @@ -898,12 +1118,14 @@ static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame) s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0] + (s->avctx->width - 8) * (1 + s->is_16bpp); - bitstream_init8(&bc, s->decoding_map, s->decoding_map_size); + init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8); for (y = 0; y < s->avctx->height; y += 8) { for (x = 0; x < s->avctx->width; x += 8) { - opcode = bitstream_read(&bc, 4); + if (get_bits_left(&gb) < 4) + return; + opcode = get_bits(&gb, 4); - ff_dlog(s->avctx, + ff_tlog(s->avctx, " block @ (%3d, %3d): encoding 0x%X, data ptr offset %d\n", x, y, opcode, bytestream2_tell(&s->stream_ptr)); @@ -917,15 +1139,15 @@ static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame) ret = ipvideo_decode_block16[opcode](s, frame); } if (ret != 0) { - av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n", + av_log(s->avctx, AV_LOG_ERROR, "decode problem on frame %d, @ block (%d, %d)\n", s->avctx->frame_number, x, y); return; } } } if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) { - av_log(s->avctx, AV_LOG_ERROR, - "Interplay video: decode finished with %d bytes left over\n", + av_log(s->avctx, AV_LOG_DEBUG, + "decode finished with %d bytes left over\n", bytestream2_get_bytes_left(&s->stream_ptr)); } } @@ -933,6 +1155,7 @@ static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame) static av_cold int ipvideo_decode_init(AVCodecContext *avctx) { IpvideoContext *s = avctx->priv_data; + int ret; s->avctx = avctx; @@ -943,13 +1166,36 @@ static av_cold int ipvideo_decode_init(AVCodecContext *avctx) s->last_frame = av_frame_alloc(); s->second_last_frame = av_frame_alloc(); - if (!s->last_frame || !s->second_last_frame) { - av_frame_free(&s->last_frame); - av_frame_free(&s->second_last_frame); - return AVERROR(ENOMEM); + s->cur_decode_frame = av_frame_alloc(); + s->prev_decode_frame = av_frame_alloc(); + if (!s->last_frame || !s->second_last_frame || + !s->cur_decode_frame || !s->prev_decode_frame) { + ret = AVERROR(ENOMEM); + goto error; } + s->cur_decode_frame->width = avctx->width; + s->prev_decode_frame->width = avctx->width; + s->cur_decode_frame->height = avctx->height; + s->prev_decode_frame->height = avctx->height; + s->cur_decode_frame->format = avctx->pix_fmt; + s->prev_decode_frame->format = avctx->pix_fmt; + + ret = ff_get_buffer(avctx, s->cur_decode_frame, 0); + if (ret < 0) + goto error; + + ret = ff_get_buffer(avctx, s->prev_decode_frame, 0); + if (ret < 0) + goto error; + return 0; +error: + av_frame_free(&s->last_frame); + av_frame_free(&s->second_last_frame); + av_frame_free(&s->cur_decode_frame); + av_frame_free(&s->prev_decode_frame); + return ret; } static int ipvideo_decode_frame(AVCodecContext *avctx, @@ -961,35 +1207,150 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, IpvideoContext *s = avctx->priv_data; AVFrame *frame = data; int ret; + int send_buffer; + int frame_format; + int video_data_size; + + if (av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, NULL)) { + av_frame_unref(s->last_frame); + av_frame_unref(s->second_last_frame); + av_frame_unref(s->cur_decode_frame); + av_frame_unref(s->prev_decode_frame); + } + + if (!s->cur_decode_frame->data[0]) { + ret = ff_get_buffer(avctx, s->cur_decode_frame, 0); + if (ret < 0) + return ret; + + ret = ff_get_buffer(avctx, s->prev_decode_frame, 0); + if (ret < 0) { + av_frame_unref(s->cur_decode_frame); + return ret; + } + } - /* decoding map contains 4 bits of information per 8x8 block */ - s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2); + if (buf_size < 8) + return AVERROR_INVALIDDATA; - /* compressed buffer needs to be large enough to at least hold an entire - * decoding map */ - if (buf_size < s->decoding_map_size) - return buf_size; + frame_format = AV_RL8(buf); + send_buffer = AV_RL8(buf + 1); + video_data_size = AV_RL16(buf + 2); + s->decoding_map_size = AV_RL16(buf + 4); + s->skip_map_size = AV_RL16(buf + 6); + + switch(frame_format) { + case 0x06: + if (s->decoding_map_size) { + av_log(avctx, AV_LOG_ERROR, "Decoding map for format 0x06\n"); + return AVERROR_INVALIDDATA; + } - s->decoding_map = buf; - bytestream2_init(&s->stream_ptr, buf + s->decoding_map_size, - buf_size - s->decoding_map_size); + if (s->skip_map_size) { + av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x06\n"); + return AVERROR_INVALIDDATA; + } - if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) { - av_log(avctx, AV_LOG_ERROR, " Interplay Video: get_buffer() failed\n"); - return ret; + if (s->is_16bpp) { + av_log(avctx, AV_LOG_ERROR, "Video format 0x06 does not support 16bpp movies\n"); + return AVERROR_INVALIDDATA; + } + + /* Decoding map for 0x06 frame format is at the top of pixeldata */ + s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2; + s->decoding_map = buf + 8 + 14; /* 14 bits of op data */ + video_data_size -= s->decoding_map_size + 14; + if (video_data_size <= 0) + return AVERROR_INVALIDDATA; + + if (buf_size < 8 + s->decoding_map_size + 14 + video_data_size) + return AVERROR_INVALIDDATA; + + bytestream2_init(&s->stream_ptr, buf + 8 + s->decoding_map_size + 14, video_data_size); + + break; + + case 0x10: + if (! s->decoding_map_size) { + av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x10\n"); + return AVERROR_INVALIDDATA; + } + + if (! s->skip_map_size) { + av_log(avctx, AV_LOG_ERROR, "Empty skip map for format 0x10\n"); + return AVERROR_INVALIDDATA; + } + + if (s->is_16bpp) { + av_log(avctx, AV_LOG_ERROR, "Video format 0x10 does not support 16bpp movies\n"); + return AVERROR_INVALIDDATA; + } + + if (buf_size < 8 + video_data_size + s->decoding_map_size + s->skip_map_size) + return AVERROR_INVALIDDATA; + + bytestream2_init(&s->stream_ptr, buf + 8, video_data_size); + s->decoding_map = buf + 8 + video_data_size; + s->skip_map = buf + 8 + video_data_size + s->decoding_map_size; + + break; + + case 0x11: + if (! s->decoding_map_size) { + av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x11\n"); + return AVERROR_INVALIDDATA; + } + + if (s->skip_map_size) { + av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x11\n"); + return AVERROR_INVALIDDATA; + } + + if (buf_size < 8 + video_data_size + s->decoding_map_size) + return AVERROR_INVALIDDATA; + + bytestream2_init(&s->stream_ptr, buf + 8, video_data_size); + s->decoding_map = buf + 8 + video_data_size; + + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", frame_format); + } + + /* ensure we can't overread the packet */ + if (buf_size < 8 + s->decoding_map_size + video_data_size + s->skip_map_size) { + av_log(avctx, AV_LOG_ERROR, "Invalid IP packet size\n"); + return AVERROR_INVALIDDATA; } + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + if (!s->is_16bpp) { - const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL); - if (pal) { + int size; + const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size); + if (pal && size == AVPALETTE_SIZE) { frame->palette_has_changed = 1; memcpy(s->pal, pal, AVPALETTE_SIZE); + } else if (pal) { + av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size); } } - ipvideo_decode_opcodes(s, frame); + switch(frame_format) { + case 0x06: + ipvideo_decode_format_06_opcodes(s, frame); + break; + case 0x10: + ipvideo_decode_format_10_opcodes(s, frame); + break; + case 0x11: + ipvideo_decode_format_11_opcodes(s, frame); + break; + } - *got_frame = 1; + *got_frame = send_buffer; /* shuffle frames */ av_frame_unref(s->second_last_frame); @@ -1007,6 +1368,8 @@ static av_cold int ipvideo_decode_end(AVCodecContext *avctx) av_frame_free(&s->last_frame); av_frame_free(&s->second_last_frame); + av_frame_free(&s->cur_decode_frame); + av_frame_free(&s->prev_decode_frame); return 0; } |