diff options
-rw-r--r-- | libavcodec/interplayvideo.c | 125 | ||||
-rw-r--r-- | libavformat/ipmovie.c | 15 |
2 files changed, 126 insertions, 14 deletions
diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c index 5dfb0d6bff..431eeb12c7 100644 --- a/libavcodec/interplayvideo.c +++ b/libavcodec/interplayvideo.c @@ -903,7 +903,81 @@ 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, short 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, short opcode) +{ + int off_x, off_y; + + if (opcode < 0) { + off_x = ((unsigned short)opcode - 0xC000) % frame->linesize[0]; + off_y = ((unsigned short)opcode - 0xC000) / frame->linesize[0]; + copy_from(s, s->last_frame, frame, off_x, off_y); + } else if (opcode > 0) { + off_x = ((unsigned short)opcode - 0x4000) % frame->linesize[0]; + off_y = ((unsigned short)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, short op) = { + ipvideo_format_06_firstpass, ipvideo_format_06_secondpass, +}; + +static void ipvideo_decode_format_06_opcodes(IpvideoContext *s, AVFrame *frame) +{ + int pass, x, y; + short 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_decode_format_11_opcodes(IpvideoContext *s, AVFrame *frame) { int x, y; unsigned char opcode; @@ -1007,18 +1081,40 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, video_data_size = AV_RL16(buf + 2); s->decoding_map_size = AV_RL16(buf + 4); - if (frame_format != 0x11) - av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", frame_format); + 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; + } - if (! s->decoding_map_size) { - av_log(avctx, AV_LOG_ERROR, "Empty decoding map\n"); - return AVERROR_INVALIDDATA; - } + 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 + 6 + 14; /* 14 bits of op data */ + video_data_size -= s->decoding_map_size + 14; + bytestream2_init(&s->stream_ptr, buf + 6 + s->decoding_map_size + 14, video_data_size); - bytestream2_init(&s->stream_ptr, buf + 6, video_data_size); + break; - /* decoding map contains 4 bits of information per 8x8 block */ - s->decoding_map = buf + 6 + video_data_size; + case 0x11: + if (! s->decoding_map_size) { + av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x11\n"); + return AVERROR_INVALIDDATA; + } + + bytestream2_init(&s->stream_ptr, buf + 6, video_data_size); + s->decoding_map = buf + 6 + 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 < 6 + s->decoding_map_size + video_data_size) { @@ -1040,7 +1136,14 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, } } - ipvideo_decode_opcodes(s, frame); + switch(frame_format) { + case 0x06: + ipvideo_decode_format_06_opcodes(s, frame); + break; + case 0x11: + ipvideo_decode_format_11_opcodes(s, frame); + break; + } *got_frame = send_buffer; diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c index a9ffca4872..7f2454b0f0 100644 --- a/libavformat/ipmovie.c +++ b/libavformat/ipmovie.c @@ -58,7 +58,7 @@ #define OPCODE_INIT_AUDIO_BUFFERS 0x03 #define OPCODE_START_STOP_AUDIO 0x04 #define OPCODE_INIT_VIDEO_BUFFERS 0x05 -#define OPCODE_UNKNOWN_06 0x06 +#define OPCODE_VIDEO_DATA_06 0x06 #define OPCODE_SEND_BUFFER 0x07 #define OPCODE_AUDIO_FRAME 0x08 #define OPCODE_SILENCE_FRAME 0x09 @@ -444,7 +444,6 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, s->video_width, s->video_height); break; - case OPCODE_UNKNOWN_06: case OPCODE_UNKNOWN_0E: case OPCODE_UNKNOWN_10: case OPCODE_UNKNOWN_12: @@ -537,8 +536,18 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, avio_skip(pb, opcode_size); break; + case OPCODE_VIDEO_DATA_06: + av_log(s->avf, AV_LOG_TRACE, "set video data format 0x06\n"); + s->frame_format = 0x06; + + /* log position and move on for now */ + s->video_chunk_offset = avio_tell(pb); + s->video_chunk_size = opcode_size; + avio_skip(pb, opcode_size); + break; + case OPCODE_VIDEO_DATA_11: - av_log(s->avf, AV_LOG_TRACE, "set video data\n"); + av_log(s->avf, AV_LOG_TRACE, "set video data format 0x11\n"); s->frame_format = 0x11; /* log position and move on for now */ |