diff mbox

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

Message ID 1497708796.3919.14.camel@tmm.cx
State Superseded
Headers show

Commit Message

Hein-Pieter van Braam June 17, 2017, 2:13 p.m. UTC
Hi all,

I seemed to have done something wrong when fixing the patchcheck
problems originally. Apparently I didn't build between making my
'fixes' and creating the patch. The previous patch doesn't compile.

I fixed this in this version, my apologies for the noise.

I've also fixed reading garbage data from the 'last frame' on the very
first frame.

- HP

On Sat, 2017-06-17 at 15:08 +0200, Hein-Pieter van Braam wrote:
> Hi all,
> 
> This patch implements support for 3 previously unknown Interplay MVE
> opcodes. These opcodes together implement support for 2 additional
> video frame formats.
> 
> This is my first time trying to contribute to ffmpeg so I expect this
> code to not be entirely up to snuff, I'm interested in getting this
> merged so any comments are welcome and I'll make any necessary
> changes.
> I have ran patchcheck over it and fix most of the issues it found.
> 
> I'm working with Multimedia Mike to get these opcodes documented on
> the
> multimedia.cx wiki.
> 
> You may notice something strange going on with decoding opcode 10
> movies, the reason for that is that the codec appears to need access
> to
> a block since before the last time it was changed, this is not
> necessarily the last displayed frame. To implement this I decode to
> two
> extra AVFrame's, swapping them after each decode, and copying only
> changed blocks from the current decoding frame to the final display
> frame. I think that my implementation is probably more convoluted
> than
> it needs to be, any suggestions on that front would be most welcome
> also.
> 
> There's a bug in FFmpeg master currently that prevents the MVE
> decoder
> from signaling that the end of the file has been reached. I've made
> no
> attempt to fix that in this patch. I'll create a separate patch to
> fix
> this issue.
> 
> - HP
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Comments

Paul B Mahol June 17, 2017, 4:45 p.m. UTC | #1
On 6/17/17, Hein-Pieter van Braam <hp@tmm.cx> wrote:
> Hi all,
>
> I seemed to have done something wrong when fixing the patchcheck
> problems originally. Apparently I didn't build between making my
> 'fixes' and creating the patch. The previous patch doesn't compile.
>
> I fixed this in this version, my apologies for the noise.
>
> I've also fixed reading garbage data from the 'last frame' on the very
> first frame.

Have you made sure that new code does not cause overreads?

Use bytestream2* for that.

>
> - HP
>
> On Sat, 2017-06-17 at 15:08 +0200, Hein-Pieter van Braam wrote:
>> Hi all,
>>
>> This patch implements support for 3 previously unknown Interplay MVE
>> opcodes. These opcodes together implement support for 2 additional
>> video frame formats.
>>
>> This is my first time trying to contribute to ffmpeg so I expect this
>> code to not be entirely up to snuff, I'm interested in getting this
>> merged so any comments are welcome and I'll make any necessary
>> changes.
>> I have ran patchcheck over it and fix most of the issues it found.
>>
>> I'm working with Multimedia Mike to get these opcodes documented on
>> the
>> multimedia.cx wiki.
>>
>> You may notice something strange going on with decoding opcode 10
>> movies, the reason for that is that the codec appears to need access
>> to
>> a block since before the last time it was changed, this is not
>> necessarily the last displayed frame. To implement this I decode to
>> two
>> extra AVFrame's, swapping them after each decode, and copying only
>> changed blocks from the current decoding frame to the final display
>> frame. I think that my implementation is probably more convoluted
>> than
>> it needs to be, any suggestions on that front would be most welcome
>> also.
>>
>> There's a bug in FFmpeg master currently that prevents the MVE
>> decoder
>> from signaling that the end of the file has been reached. I've made
>> no
>> attempt to fix that in this patch. I'll create a separate patch to
>> fix
>> this issue.
>>
>> - HP
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
diff mbox

Patch

From 1e1cde69e5728f937d79815bea8b9661fb69a8dd 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 | 281 +++++++++++++++++++++++++++++++++++++++++---
 libavformat/ipmovie.c       | 101 ++++++++++++----
 2 files changed, 343 insertions(+), 39 deletions(-)

diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c
index df3314d..9542e5f 100644
--- a/libavcodec/interplayvideo.c
+++ b/libavcodec/interplayvideo.c
@@ -55,8 +55,17 @@  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;
@@ -903,7 +912,191 @@  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;
+    const unsigned char* decode_map_p;
+    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);
+
+    decode_map_p = s->decoding_map;
+    for (y = 0; y < s->avctx->height; y += 8) {
+        for (x = 0; x < s->avctx->width; x += 8) {
+            opcode = AV_RL16(decode_map_p);
+
+            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 {
+                copy_from(s, s->second_last_frame, frame, 0, 0);
+            }
+            decode_map_p += 2;
+        }
+    }
+
+    decode_map_p = s->decoding_map;
+    for (y = 0; y < s->avctx->height; y += 8) {
+        for (x = 0; x < s->avctx->width; x += 8) {
+            opcode = AV_RL16(decode_map_p);
+
+            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);
+            }
+            decode_map_p += 2;
+        }
+    }
+
+    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;
+    const unsigned char* decode_map_p;
+    const unsigned char* skip_map_p;
+    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);
+
+    decode_map_p = s->decoding_map;
+    skip_map_p = s->skip_map;
+    skip = AV_RL16(skip_map_p);
+    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 = AV_RL16(decode_map_p);
+                    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;
+                        }
+                    }
+                    decode_map_p += 2;
+                    break;
+                }
+                skip_map_p += 2;
+                skip = AV_RL16(skip_map_p);
+            }
+            skip *= 2;
+        }
+    }
+
+    decode_map_p = s->decoding_map;
+    skip_map_p = s->skip_map;
+    skip = AV_RL16(skip_map_p);
+    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 = AV_RL16(decode_map_p);
+                    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);
+                    }
+                    decode_map_p += 2;
+                    break;
+                }
+                skip_map_p += 2;
+                skip = AV_RL16(skip_map_p);
+            }
+            skip *= 2;
+        }
+    }
+
+    skip_map_p = s->skip_map;
+    skip = AV_RL16(skip_map_p);
+    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_map_p += 2;
+                skip = AV_RL16(skip_map_p);
+            }
+            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 +1165,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 +1206,53 @@  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);
+
+            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;
+
+            /* 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;
+            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 +1268,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 +1295,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