summaryrefslogtreecommitdiff
path: root/libavcodec/interplayvideo.c
diff options
context:
space:
mode:
authorHein-Pieter van Braam <hp@tmm.cx>2017-06-25 21:59:02 +0200
committerPaul B Mahol <onemda@gmail.com>2017-06-27 15:08:39 +0200
commit19f6fd199e46c5a56f09a768ece4246b48bd86dd (patch)
tree4b57dcf33224e9ee574e2bd7fb4a308588cbc055 /libavcodec/interplayvideo.c
parent8f87bfb4b7ddeb27c318aa45144d7fc45930039b (diff)
Interplay MVE: Implement frame format 0x06
This implements the 0x06 frame format for Interplay MVE movies. The format is relatively simple. The video data consists of two parts: 16 bits per 8x8 block movement data a number of 8x8 blocks of pixel data For each 8x8 block of pixel data the movement data is consulted. There are 3 possible meanings of the movement data: * zero : copy the 8x8 block from the pixel data * negative : copy the 8x8 block from the previous frame from an offset determined by the actual value of the entry -0xC000. * positive : copy the 8x8 block from the current frame from an offset determined by the actual value of the entry -0x4000 Decoding happens in two passes, in the fist pass only new pixeldata is copied, during the second pass data is copied from the previous and current frames. The codec expects that the current frame being decoded to still has the data from 2 frames ago on it when decoding starts. Signed-off-by: Hein-Pieter van Braam <hp@tmm.cx>
Diffstat (limited to 'libavcodec/interplayvideo.c')
-rw-r--r--libavcodec/interplayvideo.c125
1 files changed, 114 insertions, 11 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;