[FFmpeg-devel,RFC] Implement support for interplay MVE 0x06, 0x0F and 0x10

Submitted by Hein-Pieter van Braam on June 17, 2017, 5:13 p.m.

Details

Message ID 1497719632.3919.15.camel@tmm.cx
State New
Headers show

Commit Message

Hein-Pieter van Braam June 17, 2017, 5:13 p.m.
On Sat, 2017-06-17 at 18:45 +0200, Paul B Mahol wrote:
> Have you made sure that new code does not cause overreads?
> 
> Use bytestream2* for that.
> 

I have made that change, thanks, the code actually looks better now
too!

Attached is a new version of the patch.

Thanks!

- HP

Comments

Moritz Barsnick June 19, 2017, 12:22 p.m.
On Sat, Jun 17, 2017 at 19:13:52 +0200, Hein-Pieter van Braam wrote:
> +            s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0];

Style: You might want to add spaces around '*'.

> +            if (! opcode) {

Style: You should drop the space.

> +            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);
> +            }
> +            if (opcode > 0) {

else if?

> +                    if (opcode < 0) {
> +                        off_x = ((unsigned short)opcode - 0xC000) % s->cur_decode_frame->linesize[0];
> +                        off_y = ((unsigned short)opcode - 0xC000) / s->cur_decode_frame->linesize[0];
> +                        copy_from(s, s->prev_decode_frame, s->cur_decode_frame, off_x, off_y);
> +                    }
> +                    if (opcode > 0) {

Same here.

> +    if (s->frame_format == 0x06)
> +        ipvideo_decode_format_06_opcodes(s, frame);
> +
> +    if (s->frame_format == 0x10)
> +        ipvideo_decode_format_10_opcodes(s, frame);
> +
> +    if (s->frame_format == 0x11)
> +        ipvideo_decode_format_11_opcodes(s, frame);

Unless ipvideo_decode_format_NN_opcodes() modifies s->frame_format,
which doesn't seem to be the case, this is either if/else if/else if,
or switch/case.

Cheers,
Moritz
Hein-Pieter van Braam June 19, 2017, 12:32 p.m.
I've resubmitted the patch in a more reviewable format here:
http://ffmpeg.org/pipermail/ffmpeg-devel/2017-June/212532.html

having said that:

On Mon, 2017-06-19 at 14:22 +0200, Moritz Barsnick wrote:
> On Sat, Jun 17, 2017 at 19:13:52 +0200, Hein-Pieter van Braam wrote:
> > +            s->pixel_ptr = frame->data[0] + x + y*frame-
> > >linesize[0];

I'll fix this, I copy/pasted this from elsewhere in the file, kind of
sloppy.

> Style: You might want to add spaces around '*'.
> 
> > +            if (! opcode) {
> 
> Style: You should drop the space.

You mean the space between the ! and opcode? The space between if and
opening parenthesis should stay, right?

> 
> > +            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);
> > +            }
> > +            if (opcode > 0) {
> 
> else if?
> 
> > +                    if (opcode < 0) {
> > +                        off_x = ((unsigned short)opcode - 0xC000)
> > % s->cur_decode_frame->linesize[0];
> > +                        off_y = ((unsigned short)opcode - 0xC000)
> > / s->cur_decode_frame->linesize[0];
> > +                        copy_from(s, s->prev_decode_frame, s-
> > >cur_decode_frame, off_x, off_y);
> > +                    }
> > +                    if (opcode > 0) {

I'll fix both of these

> Same here.
> 
> > +    if (s->frame_format == 0x06)
> > +        ipvideo_decode_format_06_opcodes(s, frame);
> > +
> > +    if (s->frame_format == 0x10)
> > +        ipvideo_decode_format_10_opcodes(s, frame);
> > +
> > +    if (s->frame_format == 0x11)
> > +        ipvideo_decode_format_11_opcodes(s, frame);
> 
> Unless ipvideo_decode_format_NN_opcodes() modifies s->frame_format,
> which doesn't seem to be the case, this is either if/else if/else if,
> or switch/case.

This got replaced with a switch case in the new patchset

> Cheers,
> Moritz

Thanks for the review!
Moritz Barsnick June 19, 2017, 12:49 p.m.
On Mon, Jun 19, 2017 at 14:32:38 +0200, Hein-Pieter van Braam wrote:
> > > +            if (! opcode) {
> > 
> > Style: You should drop the space.
> 
> You mean the space between the ! and opcode? The space between if and
> opening parenthesis should stay, right?

Correct. The handling of parantheses is described in the "Contributing"
docs, the lack of space for the '!' operator is ... by looking at other
code (including other sections in your patch).

> This got replaced with a switch case in the new patchset

Yes, I had missed that - I go through the emails thread by thread and
didn't see the one I answered to closed. My bad.

Moritz

Patch hide | download patch | download mbox

From e8a45ce4748e395e829c664c61b57e3c2e9d9fc8 Mon Sep 17 00:00:00 2001
From: Hein-Pieter van Braam <hp@tmm.cx>
Date: Fri, 16 Jun 2017 22:02:43 +0200
Subject: [PATCH] Implement support for interplay MVE 0x06 and 0x10

---
 libavcodec/interplayvideo.c | 276 +++++++++++++++++++++++++++++++++++++++++---
 libavformat/ipmovie.c       | 101 ++++++++++++----
 2 files changed, 338 insertions(+), 39 deletions(-)

diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c
index df3314d..d8c6543 100644
--- a/libavcodec/interplayvideo.c
+++ b/libavcodec/interplayvideo.c
@@ -55,11 +55,21 @@  typedef struct IpvideoContext {
     HpelDSPContext hdsp;
     AVFrame *second_last_frame;
     AVFrame *last_frame;
+
+    /* For format 0x10 */
+    AVFrame *cur_decode_frame;
+    AVFrame *prev_decode_frame;
+
+    uint8_t frame_format;
+    const unsigned char *skip_map;
+    int skip_map_size;
     const unsigned char *decoding_map;
     int decoding_map_size;
+    int video_data_size;
 
     int is_16bpp;
     GetByteContext stream_ptr, mv_ptr;
+    GetByteContext decoding_map_ptr, skip_map_ptr;
     unsigned char *pixel_ptr;
     int line_inc;
     int stride;
@@ -903,7 +913,182 @@  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_decode_format_06_opcodes(IpvideoContext *s, AVFrame *frame)
+{
+    int x, y, off_x, off_y;
+    short opcode;
+
+    if (!s->is_16bpp) {
+        /* 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);
+
+    for (y = 0; y < s->avctx->height; y += 8) {
+        for (x = 0; x < s->avctx->width; x += 8) {
+            opcode = bytestream2_get_le16(&s->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];
+            if (! opcode) {
+                int k;
+                for (k = 0; k < 8; k++) {
+                    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 frame */
+                if (s->avctx->frame_number > 2)
+                    copy_from(s, s->second_last_frame, frame, 0, 0);
+            }
+        }
+    }
+
+    bytestream2_seek(&s->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(&s->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];
+            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);
+            }
+            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);
+            }
+        }
+    }
+
+    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_10_opcodes(IpvideoContext *s, AVFrame *frame)
+{
+    int x, y, off_x, off_y;
+    short opcode, skip;
+    int changed_block = 0;
+
+    if (!s->is_16bpp) {
+        /* this is PAL8, so make the palette available */
+        memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
+
+        s->stride = frame->linesize[0];
+    }
+
+    bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */
+
+    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);
+
+    skip = bytestream2_get_le16(&s->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(&s->decoding_map_ptr);
+                    if (! opcode) {
+                        int k;
+                        for (k = 0; k < 8; k++) {
+                            bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8);
+                            s->pixel_ptr += s->stride;
+                        }
+                    }
+                    break;
+                }
+                skip = bytestream2_get_le16(&s->skip_map_ptr);
+            }
+            skip *= 2;
+        }
+    }
+
+    bytestream2_seek(&s->decoding_map_ptr, 0, SEEK_SET);
+    bytestream2_seek(&s->skip_map_ptr, 0, SEEK_SET);
+    skip = bytestream2_get_le16(&s->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(&s->decoding_map_ptr);
+                    if (opcode < 0) {
+                        off_x = ((unsigned short)opcode - 0xC000) % s->cur_decode_frame->linesize[0];
+                        off_y = ((unsigned short)opcode - 0xC000) / s->cur_decode_frame->linesize[0];
+                        copy_from(s, s->prev_decode_frame, s->cur_decode_frame, off_x, off_y);
+                    }
+                    if (opcode > 0) {
+                        off_x = ((unsigned short)opcode - 0x4000) % s->cur_decode_frame->linesize[0];
+                        off_y = ((unsigned short)opcode - 0x4000) / s->cur_decode_frame->linesize[0];
+                        copy_from(s, s->cur_decode_frame, s->cur_decode_frame, off_x, off_y);
+                    }
+                    break;
+                }
+                skip = bytestream2_get_le16(&s->skip_map_ptr);
+            }
+            skip *= 2;
+        }
+    }
+
+    bytestream2_seek(&s->skip_map_ptr, 0, SEEK_SET);
+    skip = bytestream2_get_le16(&s->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;
+                }
+                skip = bytestream2_get_le16(&s->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;
@@ -972,12 +1157,26 @@  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) {
+    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) {
         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 AVERROR(ENOMEM);
     }
 
+    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;
+
+    ff_get_buffer(avctx, s->cur_decode_frame, 0);
+    ff_get_buffer(avctx, s->prev_decode_frame, 0);
     return 0;
 }
 
@@ -999,18 +1198,56 @@  static int ipvideo_decode_frame(AVCodecContext *avctx,
     if (buf_size < 2)
         return AVERROR_INVALIDDATA;
 
-    /* decoding map contains 4 bits of information per 8x8 block */
-    s->decoding_map_size = AV_RL16(avpkt->data);
-
-    /* compressed buffer needs to be large enough to at least hold an entire
-     * decoding map */
-    if (buf_size < s->decoding_map_size + 2)
-        return buf_size;
-
-
-    s->decoding_map = buf + 2;
-    bytestream2_init(&s->stream_ptr, buf + 2 + s->decoding_map_size,
-                     buf_size - s->decoding_map_size);
+    s->frame_format = AV_RB8(avpkt->data);
+    switch (s->frame_format) {
+        case 0x06:
+            /* Format 0x06 has decoding map appended to the top of pixel data */
+            /* decoding map contains 16 bits of information per 8x8 block */
+            s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2;
+            s->decoding_map = buf + 3 + 14; /* 14 bits of op data */
+
+            s->video_data_size = AV_RL16(avpkt->data + 1) - s->decoding_map_size - 14;
+            bytestream2_init(&s->stream_ptr, buf + 3 + s->decoding_map_size + 14, s->video_data_size);
+            bytestream2_init(&s->decoding_map_ptr, s->decoding_map, s->decoding_map_size);
+
+            if (buf_size < s->decoding_map_size + 2)
+                return buf_size;
+            break;
+
+        case 0x10:
+            /* Format 0x10 has a decoding map, pixel data, and a skip map */
+            s->video_data_size = AV_RL16(avpkt->data + 1);
+            bytestream2_init(&s->stream_ptr, buf + 3, s->video_data_size);
+
+            /* decoding map contains 16 bits of information per 8x8 block */
+            s->decoding_map_size = AV_RL16(avpkt->data + 3 + s->video_data_size);
+            s->decoding_map = buf + 3 + s->video_data_size + 2;
+            bytestream2_init(&s->decoding_map_ptr, s->decoding_map, s->decoding_map_size);
+
+            /* skip map contains 16 bits of information per 15 blocks, ish */
+            s->skip_map_size = AV_RL16(avpkt->data + 3 + s->video_data_size + 2 + s->decoding_map_size);
+            s->skip_map = buf + 3 + s->video_data_size + 2 + s->decoding_map_size + 2;
+            bytestream2_init(&s->skip_map_ptr, s->skip_map, s->skip_map_size);
+            break;
+
+        case 0x11:
+            /* Format 0x11 has a decoding map and pixel data */
+            s->video_data_size = AV_RL16(avpkt->data + 1);
+            bytestream2_init(&s->stream_ptr, buf + 3, s->video_data_size);
+
+            /* decoding map contains 4 bits of information per 8x8 block */
+            s->decoding_map_size = AV_RL16(avpkt->data + 3 + s->video_data_size);
+            s->decoding_map = buf + 3 + s->video_data_size + 2;
+
+            /* compressed buffer needs to be large enough to at least hold an entire
+             * decoding map */
+            if (buf_size < s->decoding_map_size + 2)
+                return buf_size;
+            break;
+
+        default:
+            av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", s->frame_format);
+    }
 
     if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
         return ret;
@@ -1026,7 +1263,14 @@  static int ipvideo_decode_frame(AVCodecContext *avctx,
         }
     }
 
-    ipvideo_decode_opcodes(s, frame);
+    if (s->frame_format == 0x06)
+        ipvideo_decode_format_06_opcodes(s, frame);
+
+    if (s->frame_format == 0x10)
+        ipvideo_decode_format_10_opcodes(s, frame);
+
+    if (s->frame_format == 0x11)
+        ipvideo_decode_format_11_opcodes(s, frame);
 
     *got_frame = 1;
 
@@ -1046,6 +1290,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;
 }
diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c
index a83909f..3c4d85c 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
@@ -66,10 +66,10 @@ 
 #define OPCODE_CREATE_GRADIENT         0x0B
 #define OPCODE_SET_PALETTE             0x0C
 #define OPCODE_SET_PALETTE_COMPRESSED  0x0D
-#define OPCODE_UNKNOWN_0E              0x0E
+#define OPCODE_SET_SKIP_MAP            0x0E
 #define OPCODE_SET_DECODING_MAP        0x0F
-#define OPCODE_UNKNOWN_10              0x10
-#define OPCODE_VIDEO_DATA              0x11
+#define OPCODE_VIDEO_DATA_10           0x10
+#define OPCODE_VIDEO_DATA_11           0x11
 #define OPCODE_UNKNOWN_12              0x12
 #define OPCODE_UNKNOWN_13              0x13
 #define OPCODE_UNKNOWN_14              0x14
@@ -91,6 +91,7 @@  typedef struct IPMVEContext {
     uint32_t     palette[256];
     int          has_palette;
     int          changed;
+    uint8_t      frame_format;
 
     unsigned int audio_bits;
     unsigned int audio_channels;
@@ -105,6 +106,8 @@  typedef struct IPMVEContext {
     int audio_chunk_size;
     int64_t video_chunk_offset;
     int video_chunk_size;
+    int64_t skip_map_chunk_offset;
+    int skip_map_chunk_size;
     int64_t decode_map_chunk_offset;
     int decode_map_chunk_size;
 
@@ -152,11 +155,11 @@  static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb,
 
         chunk_type = CHUNK_VIDEO;
 
-    } else if (s->decode_map_chunk_offset) {
+    } else if (s->frame_format) {
+        av_log(s->avf, AV_LOG_TRACE, "frame format 0x%02X\n", s->frame_format);
 
-        /* send both the decode map and the video data together */
-
-        if (av_new_packet(pkt, 2 + s->decode_map_chunk_size + s->video_chunk_size))
+        /* send video data, skip map, and decode map together */
+        if (av_new_packet(pkt, 1 + 2 + s->video_chunk_size + 2 + s->decode_map_chunk_size + 2 + s->skip_map_chunk_size))
             return CHUNK_NOMEM;
 
         if (s->has_palette) {
@@ -174,26 +177,47 @@  static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb,
             ff_add_param_change(pkt, 0, 0, 0, s->video_width, s->video_height);
             s->changed = 0;
         }
-        pkt->pos= s->decode_map_chunk_offset;
-        avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET);
-        s->decode_map_chunk_offset = 0;
 
-        AV_WL16(pkt->data, s->decode_map_chunk_size);
-        if (avio_read(pb, pkt->data + 2, s->decode_map_chunk_size) !=
-            s->decode_map_chunk_size) {
-            av_packet_unref(pkt);
-            return CHUNK_EOF;
-        }
+        AV_WB8(pkt->data, s->frame_format);
+        s->frame_format = 0;
 
+        pkt->pos= s->video_chunk_offset;
         avio_seek(pb, s->video_chunk_offset, SEEK_SET);
         s->video_chunk_offset = 0;
 
-        if (avio_read(pb, pkt->data + 2 + s->decode_map_chunk_size,
-            s->video_chunk_size) != s->video_chunk_size) {
+        AV_WL16(pkt->data + 1, s->video_chunk_size);
+        if (avio_read(pb, pkt->data + 3, s->video_chunk_size) !=
+            s->video_chunk_size) {
             av_packet_unref(pkt);
             return CHUNK_EOF;
         }
 
+        if (s->decode_map_chunk_size) {
+            pkt->pos= s->decode_map_chunk_offset;
+            avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET);
+            s->decode_map_chunk_offset = 0;
+
+            AV_WL16(pkt->data + 3 + s->video_chunk_size, s->decode_map_chunk_size);
+            if (avio_read(pb, pkt->data + 3 + s->video_chunk_size + 2, s->decode_map_chunk_size) !=
+                s->decode_map_chunk_size) {
+                av_packet_unref(pkt);
+                return CHUNK_EOF;
+            }
+        }
+
+        if (s->skip_map_chunk_size) {
+            pkt->pos= s->skip_map_chunk_offset;
+            avio_seek(pb, s->skip_map_chunk_offset, SEEK_SET);
+            s->skip_map_chunk_offset = 0;
+
+            AV_WL16(pkt->data + 3 + s->video_chunk_size + 2 + s->decode_map_chunk_size, s->skip_map_chunk_size);
+            if (avio_read(pb, pkt->data + 3 + s->video_chunk_size + 2 + s->decode_map_chunk_size + 2, s->skip_map_chunk_size) !=
+                s->skip_map_chunk_size) {
+                av_packet_unref(pkt);
+                return CHUNK_EOF;
+            }
+        }
+
         pkt->stream_index = s->video_stream_index;
         pkt->pts = s->video_pts;
 
@@ -430,9 +454,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:
         case OPCODE_UNKNOWN_13:
         case OPCODE_UNKNOWN_14:
@@ -513,6 +534,15 @@  static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
             avio_skip(pb, opcode_size);
             break;
 
+        case OPCODE_SET_SKIP_MAP:
+            av_log(s->avf, AV_LOG_TRACE, "set skip map\n");
+
+            /* log position and move on for now */
+            s->skip_map_chunk_offset = avio_tell(pb);
+            s->skip_map_chunk_size = opcode_size;
+            avio_skip(pb, opcode_size);
+            break;
+
         case OPCODE_SET_DECODING_MAP:
             av_log(s->avf, AV_LOG_TRACE, "set decoding map\n");
 
@@ -522,8 +552,29 @@  static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
             avio_skip(pb, opcode_size);
             break;
 
-        case OPCODE_VIDEO_DATA:
-            av_log(s->avf, AV_LOG_TRACE, "set video data\n");
+        case OPCODE_VIDEO_DATA_06:
+            av_log(s->avf, AV_LOG_TRACE, "set video data type 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_10:
+            av_log(s->avf, AV_LOG_TRACE, "set video data type 0x10\n");
+            s->frame_format = 0x10;
+
+            /* 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 type 0x11\n");
+            s->frame_format = 0x11;
 
             /* log position and move on for now */
             s->video_chunk_offset = avio_tell(pb);
@@ -587,8 +638,10 @@  static int ipmovie_read_header(AVFormatContext *s)
             return AVERROR_EOF;
     }
     /* initialize private context members */
+    ipmovie->frame_format = 0;
     ipmovie->video_pts = ipmovie->audio_frame_count = 0;
     ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset =
+    ipmovie->skip_map_chunk_offset = 0;
     ipmovie->decode_map_chunk_offset = 0;
 
     /* on the first read, this will position the stream at the first chunk */
-- 
2.9.4