]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/ivi_common.c
v210enc: Add SIMD optimised 8-bit and 10-bit encoders
[ffmpeg] / libavcodec / ivi_common.c
index d4eae9712610547cfe0182fe837414d2d04a29fb..7c4d53ecec686d911d6d03638bf6861523685603 100644 (file)
  * Indeo5 decoders.
  */
 
+#include <inttypes.h>
+
 #define BITSTREAM_READER_LE
 #include "libavutil/attributes.h"
+#include "libavutil/timer.h"
 #include "avcodec.h"
 #include "get_bits.h"
 #include "internal.h"
 #include "ivi_common.h"
 #include "ivi_dsp.h"
 
-extern const IVIHuffDesc ff_ivi_mb_huff_desc[8];  ///< static macroblock huffman tables
-extern const IVIHuffDesc ff_ivi_blk_huff_desc[8]; ///< static block huffman tables
+/**
+ * These are 2x8 predefined Huffman codebooks for coding macroblock/block
+ * signals. They are specified using "huffman descriptors" in order to
+ * avoid huge static tables. The decoding tables will be generated at
+ * startup from these descriptors.
+ */
+/** static macroblock huffman tables */
+static const IVIHuffDesc ivi_mb_huff_desc[8] = {
+    {8,  {0, 4, 5, 4, 4, 4, 6, 6}},
+    {12, {0, 2, 2, 3, 3, 3, 3, 5, 3, 2, 2, 2}},
+    {12, {0, 2, 3, 4, 3, 3, 3, 3, 4, 3, 2, 2}},
+    {12, {0, 3, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2}},
+    {13, {0, 4, 4, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1}},
+    {9,  {0, 4, 4, 4, 4, 3, 3, 3, 2}},
+    {10, {0, 4, 4, 4, 4, 3, 3, 2, 2, 2}},
+    {12, {0, 4, 4, 4, 3, 3, 2, 3, 2, 2, 2, 2}}
+};
+
+/** static block huffman tables */
+static const IVIHuffDesc ivi_blk_huff_desc[8] = {
+    {10, {1, 2, 3, 4, 4, 7, 5, 5, 4, 1}},
+    {11, {2, 3, 4, 4, 4, 7, 5, 4, 3, 3, 2}},
+    {12, {2, 4, 5, 5, 5, 5, 6, 4, 4, 3, 1, 1}},
+    {13, {3, 3, 4, 4, 5, 6, 6, 4, 4, 3, 2, 1, 1}},
+    {11, {3, 4, 4, 5, 5, 5, 6, 5, 4, 2, 2}},
+    {13, {3, 4, 5, 5, 5, 5, 6, 4, 3, 3, 2, 1, 1}},
+    {13, {3, 4, 5, 5, 5, 6, 5, 4, 3, 3, 2, 1, 1}},
+    {9,  {3, 4, 4, 5, 5, 5, 6, 5, 5}}
+};
 
 static VLC ivi_mb_vlc_tabs [8]; ///< static macroblock Huffman tables
 static VLC ivi_blk_vlc_tabs[8]; ///< static block Huffman tables
 
 typedef void (*ivi_mc_func) (int16_t *buf, const int16_t *ref_buf,
                              uint32_t pitch, int mc_type);
+typedef void (*ivi_mc_avg_func) (int16_t *buf, const int16_t *ref_buf1,
+                                 const int16_t *ref_buf2,
+                                 uint32_t pitch, int mc_type, int mc_type2);
+
+static int ivi_mc(IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg,
+                  int offs, int mv_x, int mv_y, int mv_x2, int mv_y2,
+                  int mc_type, int mc_type2)
+{
+    int ref_offs = offs + mv_y * band->pitch + mv_x;
+    int buf_size = band->pitch * band->aheight;
+    int min_size = band->pitch * (band->blk_size - 1) + band->blk_size;
+    int ref_size = (mc_type > 1) * band->pitch + (mc_type & 1);
+
+    if (mc_type != -1) {
+        if (offs < 0 || ref_offs < 0 || !band->ref_buf)
+            return AVERROR_INVALIDDATA;
+        if (buf_size - min_size < offs)
+            return AVERROR_INVALIDDATA;
+        if (buf_size - min_size - ref_size < ref_offs)
+            return AVERROR_INVALIDDATA;
+    }
+
+    if (mc_type2 == -1) {
+        mc(band->buf + offs, band->ref_buf + ref_offs, band->pitch, mc_type);
+    } else {
+        int ref_offs2 = offs + mv_y2 * band->pitch + mv_x2;
+        int ref_size2 = (mc_type2 > 1) * band->pitch + (mc_type2 & 1);
+        if (offs < 0 || ref_offs2 < 0 || !band->b_ref_buf)
+            return AVERROR_INVALIDDATA;
+        if (buf_size - min_size - ref_size2 < ref_offs2)
+            return AVERROR_INVALIDDATA;
+
+        if (mc_type == -1)
+            mc(band->buf + offs, band->b_ref_buf + ref_offs2,
+               band->pitch, mc_type2);
+        else
+            mc_avg(band->buf + offs, band->ref_buf + ref_offs,
+                   band->b_ref_buf + ref_offs2, band->pitch,
+                   mc_type, mc_type2);
+    }
+
+    return 0;
+}
 
 /**
  *  Reverse "nbits" bits of the value "val" and return the result
@@ -115,11 +188,11 @@ av_cold void ff_ivi_init_static_vlc(void)
     for (i = 0; i < 8; i++) {
         ivi_mb_vlc_tabs[i].table = table_data + i * 2 * 8192;
         ivi_mb_vlc_tabs[i].table_allocated = 8192;
-        ivi_create_huff_from_desc(&ff_ivi_mb_huff_desc[i],
+        ivi_create_huff_from_desc(&ivi_mb_huff_desc[i],
                                   &ivi_mb_vlc_tabs[i], 1);
         ivi_blk_vlc_tabs[i].table = table_data + (i * 2 + 1) * 8192;
         ivi_blk_vlc_tabs[i].table_allocated = 8192;
-        ivi_create_huff_from_desc(&ff_ivi_blk_huff_desc[i],
+        ivi_create_huff_from_desc(&ivi_blk_huff_desc[i],
                                   &ivi_blk_vlc_tabs[i], 1);
     }
     initialized_vlcs = 1;
@@ -216,6 +289,7 @@ static av_cold void ivi_free_buffers(IVIPlaneDesc *planes)
             av_freep(&planes[p].bands[b].bufs[0]);
             av_freep(&planes[p].bands[b].bufs[1]);
             av_freep(&planes[p].bands[b].bufs[2]);
+            av_freep(&planes[p].bands[b].bufs[3]);
 
             if (planes[p].bands[b].blk_vlc.cust_tab.table)
                 ff_free_vlc(&planes[p].bands[b].blk_vlc.cust_tab);
@@ -224,10 +298,12 @@ static av_cold void ivi_free_buffers(IVIPlaneDesc *planes)
             av_freep(&planes[p].bands[b].tiles);
         }
         av_freep(&planes[p].bands);
+        planes[p].num_bands = 0;
     }
 }
 
-av_cold int ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg)
+av_cold int ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg,
+                               int is_indeo4)
 {
     int p, b;
     uint32_t b_width, b_height, align_fac, width_aligned,
@@ -236,6 +312,10 @@ av_cold int ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg)
 
     ivi_free_buffers(planes);
 
+    if (cfg->pic_width < 1 || cfg->pic_height < 1 ||
+        cfg->luma_bands < 1 || cfg->chroma_bands < 1)
+        return AVERROR_INVALIDDATA;
+
     /* fill in the descriptor of the luminance plane */
     planes[0].width     = cfg->pic_width;
     planes[0].height    = cfg->pic_height;
@@ -285,6 +365,11 @@ av_cold int ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg)
                 if (!band->bufs[2])
                     return AVERROR(ENOMEM);
             }
+            if (is_indeo4) {
+                band->bufs[3]  = av_mallocz(buf_size);
+                if (!band->bufs[3])
+                    return AVERROR(ENOMEM);
+            }
             /* reset custom vlc */
             planes[p].bands[0].blk_vlc.cust_desc.num_rows = 0;
         }
@@ -318,6 +403,8 @@ static int ivi_init_tiles(IVIBandDesc *band, IVITile *ref_tile,
 
             tile->ref_mbs = 0;
             if (p || b) {
+                if (tile->num_MBs != ref_tile->num_MBs)
+                    return AVERROR_INVALIDDATA;
                 tile->ref_mbs = ref_tile->mbs;
                 ref_tile++;
             }
@@ -393,10 +480,31 @@ static int ivi_dec_tile_data_size(GetBitContext *gb)
     return len;
 }
 
+static int ivi_dc_transform(IVIBandDesc *band, int *prev_dc, int buf_offs,
+                            int blk_size)
+{
+    int buf_size = band->pitch * band->aheight - buf_offs;
+    int min_size = (blk_size - 1) * band->pitch + blk_size;
+
+    if (!band->dc_transform)
+        return 0;
+
+
+    if (min_size > buf_size)
+        return AVERROR_INVALIDDATA;
+
+    band->dc_transform(prev_dc, band->buf + buf_offs,
+                       band->pitch, blk_size);
+
+    return 0;
+}
 
 static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
-                                   ivi_mc_func mc, int mv_x, int mv_y,
-                                   int *prev_dc, int is_intra, int mc_type,
+                                   ivi_mc_func mc, ivi_mc_avg_func mc_avg,
+                                   int mv_x, int mv_y,
+                                   int mv_x2, int mv_y2,
+                                   int *prev_dc, int is_intra,
+                                   int mc_type, int mc_type2,
                                    uint32_t quant, int offs,
                                    AVCodecContext *avctx)
 {
@@ -410,6 +518,12 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
     int num_coeffs = blk_size * blk_size;
     int col_mask   = blk_size - 1;
     int scan_pos   = -1;
+    int min_size   = band->pitch * (band->transform_size - 1) +
+                     band->transform_size;
+    int buf_size   = band->pitch * band->aheight - offs;
+
+    if (min_size > buf_size)
+        return AVERROR_INVALIDDATA;
 
     if (!band->scan) {
         av_log(avctx, AV_LOG_ERROR, "Scan pattern is not set.\n");
@@ -435,7 +549,7 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
             val = IVI_TOSIGNED((hi << 6) | lo);
         } else {
             if (sym >= 256U) {
-                av_log(avctx, AV_LOG_ERROR, "Invalid sym encountered: %d.\n", sym);
+                av_log(avctx, AV_LOG_ERROR, "Invalid sym encountered: %"PRIu32".\n", sym);
                 return AVERROR_INVALIDDATA;
             }
             run = rvmap->runtab[sym];
@@ -444,7 +558,7 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
 
         /* de-zigzag and dequantize */
         scan_pos += run;
-        if (scan_pos >= num_coeffs)
+        if (scan_pos >= num_coeffs || scan_pos < 0)
             break;
         pos = band->scan[scan_pos];
 
@@ -459,7 +573,7 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
         col_flags[pos & col_mask] |= !!val;
     }
 
-    if (scan_pos >= num_coeffs && sym != rvmap->eob_sym)
+    if (scan_pos < 0 || scan_pos >= num_coeffs && sym != rvmap->eob_sym)
         return AVERROR_INVALIDDATA; /* corrupt block data */
 
     /* undoing DC coeff prediction for intra-blocks */
@@ -475,9 +589,8 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
 
     /* apply motion compensation */
     if (!is_intra)
-        mc(band->buf + offs,
-           band->ref_buf + offs + mv_y * band->pitch + mv_x,
-           band->pitch, mc_type);
+        return ivi_mc(band, mc, mc_avg, offs, mv_x, mv_y, mv_x2, mv_y2,
+                      mc_type, mc_type2);
 
     return 0;
 }
@@ -495,12 +608,14 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
 static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band,
                              IVITile *tile, AVCodecContext *avctx)
 {
-    int mbn, blk, num_blocks, blk_size, ret, is_intra, mc_type = 0;
-    int mv_x = 0, mv_y = 0;
+    int mbn, blk, num_blocks, blk_size, ret, is_intra;
+    int mc_type = 0, mc_type2 = -1;
+    int mv_x = 0, mv_y = 0, mv_x2 = 0, mv_y2 = 0;
     int32_t prev_dc;
     uint32_t cbp, quant, buf_offs;
     IVIMbInfo *mb;
     ivi_mc_func mc_with_delta_func, mc_no_delta_func;
+    ivi_mc_avg_func mc_avg_with_delta_func, mc_avg_no_delta_func;
     const uint8_t *scale_tab;
 
     /* init intra prediction for the DC coefficient */
@@ -509,11 +624,15 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band,
     /* number of blocks per mb */
     num_blocks = (band->mb_size != blk_size) ? 4 : 1;
     if (blk_size == 8) {
-        mc_with_delta_func = ff_ivi_mc_8x8_delta;
-        mc_no_delta_func   = ff_ivi_mc_8x8_no_delta;
+        mc_with_delta_func     = ff_ivi_mc_8x8_delta;
+        mc_no_delta_func       = ff_ivi_mc_8x8_no_delta;
+        mc_avg_with_delta_func = ff_ivi_mc_avg_8x8_delta;
+        mc_avg_no_delta_func   = ff_ivi_mc_avg_8x8_no_delta;
     } else {
-        mc_with_delta_func = ff_ivi_mc_4x4_delta;
-        mc_no_delta_func   = ff_ivi_mc_4x4_no_delta;
+        mc_with_delta_func     = ff_ivi_mc_4x4_delta;
+        mc_no_delta_func       = ff_ivi_mc_4x4_no_delta;
+        mc_avg_with_delta_func = ff_ivi_mc_avg_4x4_delta;
+        mc_avg_no_delta_func   = ff_ivi_mc_avg_4x4_no_delta;
     }
 
     for (mbn = 0, mb = tile->mbs; mbn < tile->num_MBs; mb++, mbn++) {
@@ -532,13 +651,22 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band,
             quant = scale_tab[quant];
 
         if (!is_intra) {
-            mv_x = mb->mv_x;
-            mv_y = mb->mv_y;
+            mv_x  = mb->mv_x;
+            mv_y  = mb->mv_y;
+            mv_x2 = mb->b_mv_x;
+            mv_y2 = mb->b_mv_y;
             if (band->is_halfpel) {
-                mc_type = ((mv_y & 1) << 1) | (mv_x & 1);
-                mv_x >>= 1;
-                mv_y >>= 1; /* convert halfpel vectors into fullpel ones */
+                mc_type  = ((mv_y  & 1) << 1) | (mv_x  & 1);
+                mc_type2 = ((mv_y2 & 1) << 1) | (mv_x2 & 1);
+                mv_x  >>= 1;
+                mv_y  >>= 1;
+                mv_x2 >>= 1;
+                mv_y2 >>= 1; /* convert halfpel vectors into fullpel ones */
             }
+            if (mb->type == 2)
+                mc_type = -1;
+            if (mb->type != 2 && mb->type != 3)
+                mc_type2 = -1;
             if (mb->type) {
                 int dmv_x, dmv_y, cx, cy;
 
@@ -547,6 +675,21 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band,
                 cx    = mb->mv_x &  band->is_halfpel;
                 cy    = mb->mv_y &  band->is_halfpel;
 
+                if (mb->xpos + dmv_x < 0 ||
+                    mb->xpos + dmv_x + band->mb_size + cx > band->pitch ||
+                    mb->ypos + dmv_y < 0 ||
+                    mb->ypos + dmv_y + band->mb_size + cy > band->aheight) {
+                    return AVERROR_INVALIDDATA;
+                }
+            }
+            if (mb->type == 2 || mb->type == 3) {
+                int dmv_x, dmv_y, cx, cy;
+
+                dmv_x = mb->b_mv_x >> band->is_halfpel;
+                dmv_y = mb->b_mv_y >> band->is_halfpel;
+                cx    = mb->b_mv_x &  band->is_halfpel;
+                cy    = mb->b_mv_y &  band->is_halfpel;
+
                 if (mb->xpos + dmv_x < 0 ||
                     mb->xpos + dmv_x + band->mb_size + cx > band->pitch ||
                     mb->ypos + dmv_y < 0 ||
@@ -567,8 +710,11 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band,
 
             if (cbp & 1) { /* block coded ? */
                 ret = ivi_decode_coded_blocks(gb, band, mc_with_delta_func,
-                                              mv_x, mv_y, &prev_dc, is_intra,
-                                              mc_type, quant, buf_offs, avctx);
+                                              mc_avg_with_delta_func,
+                                              mv_x, mv_y, mv_x2, mv_y2,
+                                              &prev_dc, is_intra,
+                                              mc_type, mc_type2, quant,
+                                              buf_offs, avctx);
                 if (ret < 0)
                     return ret;
             } else {
@@ -576,13 +722,16 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band,
                 /* for intra blocks apply the dc slant transform */
                 /* for inter - perform the motion compensation without delta */
                 if (is_intra) {
-                    if (band->dc_transform)
-                        band->dc_transform(&prev_dc, band->buf + buf_offs,
-                                           band->pitch, blk_size);
-                } else
-                    mc_no_delta_func(band->buf + buf_offs,
-                                     band->ref_buf + buf_offs + mv_y * band->pitch + mv_x,
-                                     band->pitch, mc_type);
+                    ret = ivi_dc_transform(band, &prev_dc, buf_offs, blk_size);
+                    if (ret < 0)
+                        return ret;
+                } else {
+                    ret = ivi_mc(band, mc_no_delta_func, mc_avg_no_delta_func,
+                                 buf_offs, mv_x, mv_y, mv_x2, mv_y2,
+                                 mc_type, mc_type2);
+                    if (ret < 0)
+                        return ret;
+                }
             }
 
             cbp >>= 1;
@@ -607,7 +756,7 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band,
                                   IVITile *tile, int32_t mv_scale)
 {
     int             x, y, need_mc, mbn, blk, num_blocks, mv_x, mv_y, mc_type;
-    int             offs, mb_offset, row_offset;
+    int             offs, mb_offset, row_offset, ret;
     IVIMbInfo       *mb, *ref_mb;
     const int16_t   *src;
     int16_t         *dst;
@@ -685,9 +834,10 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band,
             for (blk = 0; blk < num_blocks; blk++) {
                 /* adjust block position in the buffer according with its number */
                 offs = mb->buf_offs + band->blk_size * ((blk & 1) + !!(blk & 2) * band->pitch);
-                mc_no_delta_func(band->buf + offs,
-                                 band->ref_buf + offs + mv_y * band->pitch + mv_x,
-                                 band->pitch, mc_type);
+                ret = ivi_mc(band, mc_no_delta_func, 0, offs,
+                             mv_x, mv_y, 0, 0, mc_type, -1);
+                if (ret < 0)
+                    return ret;
             }
         }
     } else {
@@ -767,8 +917,14 @@ static int decode_band(IVI45DecContext *ctx,
         av_log(avctx, AV_LOG_ERROR, "Band buffer points to no data!\n");
         return AVERROR_INVALIDDATA;
     }
-    band->ref_buf = band->bufs[ctx->ref_buf];
-    band->data_ptr = ctx->frame_data + (get_bits_count(&ctx->gb) >> 3);
+    if (ctx->is_indeo4 && ctx->frame_type == IVI4_FRAMETYPE_BIDIR) {
+        band->ref_buf   = band->bufs[ctx->b_ref_buf];
+        band->b_ref_buf = band->bufs[ctx->ref_buf];
+    } else {
+        band->ref_buf   = band->bufs[ctx->ref_buf];
+        band->b_ref_buf = 0;
+    }
+    band->data_ptr  = ctx->frame_data + (get_bits_count(&ctx->gb) >> 3);
 
     result = ctx->decode_band_hdr(ctx, band, avctx);
     if (result) {
@@ -853,7 +1009,7 @@ static int decode_band(IVI45DecContext *ctx,
         if (chksum != band->checksum) {
             av_log(avctx, AV_LOG_ERROR,
                    "Band checksum mismatch! Plane %d, band %d, "
-                   "received: %x, calculated: %x\n",
+                   "received: %"PRIx32", calculated: %"PRIx16"\n",
                    band->plane, band->band_num, band->checksum, chksum);
         }
     }
@@ -886,11 +1042,27 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
     if (ctx->gop_invalid)
         return AVERROR_INVALIDDATA;
 
+    if (ctx->is_indeo4 && ctx->frame_type == IVI4_FRAMETYPE_NULL_LAST) {
+        if (ctx->got_p_frame) {
+            av_frame_move_ref(data, ctx->p_frame);
+            *got_frame = 1;
+            ctx->got_p_frame = 0;
+        } else {
+            *got_frame = 0;
+        }
+        return buf_size;
+    }
+
     if (ctx->gop_flags & IVI5_IS_PROTECTED) {
         avpriv_report_missing_feature(avctx, "Password-protected clip!\n");
         return AVERROR_PATCHWELCOME;
     }
 
+    if (!ctx->planes[0].bands) {
+        av_log(avctx, AV_LOG_ERROR, "Color planes not initialized yet\n");
+        return AVERROR_INVALIDDATA;
+    }
+
     ctx->switch_buffers(ctx);
 
     //{ START_TIMER;
@@ -906,31 +1078,29 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
                 }
             }
         }
+    } else {
+        if (ctx->is_scalable)
+            return AVERROR_INVALIDDATA;
+
+        for (p = 0; p < 3; p++) {
+            if (!ctx->planes[p].bands[0].buf)
+                return AVERROR_INVALIDDATA;
+        }
     }
 
     //STOP_TIMER("decode_planes"); }
 
-    /* If the bidirectional mode is enabled, next I and the following P
-     * frame will be sent together. Unfortunately the approach below seems
-     * to be the only way to handle the B-frames mode.
-     * That's exactly the same Intel decoders do.
-     */
-    if (avctx->codec_id == AV_CODEC_ID_INDEO4 &&
-        ctx->frame_type == 0/*FRAMETYPE_INTRA*/) {
-        while (get_bits(&ctx->gb, 8)); // skip version string
-        skip_bits_long(&ctx->gb, 64);  // skip padding, TODO: implement correct 8-bytes alignment
-        if (get_bits_left(&ctx->gb) > 18 && show_bits(&ctx->gb, 18) == 0x3FFF8)
-            av_log(avctx, AV_LOG_ERROR, "Buffer contains IP frames!\n");
-    }
+    result = ff_set_dimensions(avctx, ctx->planes[0].width, ctx->planes[0].height);
+    if (result < 0)
+        return result;
 
-    avcodec_set_dimensions(avctx, ctx->planes[0].width, ctx->planes[0].height);
     if ((result = ff_get_buffer(avctx, frame, 0)) < 0) {
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return result;
     }
 
     if (ctx->is_scalable) {
-        if (avctx->codec_id == AV_CODEC_ID_INDEO4)
+        if (ctx->is_indeo4)
             ff_ivi_recompose_haar(&ctx->planes[0], frame->data[0], frame->linesize[0]);
         else
             ff_ivi_recompose53   (&ctx->planes[0], frame->data[0], frame->linesize[0]);
@@ -943,6 +1113,26 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
 
     *got_frame = 1;
 
+    /* If the bidirectional mode is enabled, next I and the following P
+     * frame will be sent together. Unfortunately the approach below seems
+     * to be the only way to handle the B-frames mode.
+     * That's exactly the same Intel decoders do.
+     */
+    if (ctx->is_indeo4 && ctx->frame_type == IVI4_FRAMETYPE_INTRA) {
+        int left;
+
+        while (get_bits(&ctx->gb, 8)); // skip version string
+        left = get_bits_count(&ctx->gb) & 0x18;
+        skip_bits_long(&ctx->gb, 64 - left);
+        if (get_bits_left(&ctx->gb) > 18 &&
+            show_bits_long(&ctx->gb, 21) == 0xBFFF8) { // syncheader + inter type
+            AVPacket pkt;
+            pkt.data = avpkt->data + (get_bits_count(&ctx->gb) >> 3);
+            pkt.size = get_bits_left(&ctx->gb) >> 3;
+            ff_ivi_decode_frame(avctx, ctx->p_frame, &ctx->got_p_frame, &pkt);
+        }
+    }
+
     return buf_size;
 }
 
@@ -959,7 +1149,7 @@ av_cold int ff_ivi_decode_close(AVCodecContext *avctx)
         ff_free_vlc(&ctx->mb_vlc.cust_tab);
 
 #if IVI4_STREAM_ANALYSER
-    if (avctx->codec_id == AV_CODEC_ID_INDEO4) {
+    if (ctx->is_indeo4) {
     if (ctx->is_scalable)
         av_log(avctx, AV_LOG_ERROR, "This video uses scalability mode!\n");
     if (ctx->uses_tiling)
@@ -975,39 +1165,12 @@ av_cold int ff_ivi_decode_close(AVCodecContext *avctx)
     }
 #endif
 
+    av_frame_free(&ctx->p_frame);
+
     return 0;
 }
 
 
-/**
- * These are 2x8 predefined Huffman codebooks for coding macroblock/block
- * signals. They are specified using "huffman descriptors" in order to
- * avoid huge static tables. The decoding tables will be generated at
- * startup from these descriptors.
- */
-const IVIHuffDesc ff_ivi_mb_huff_desc[8] = {
-    {8,  {0, 4, 5, 4, 4, 4, 6, 6}},
-    {12, {0, 2, 2, 3, 3, 3, 3, 5, 3, 2, 2, 2}},
-    {12, {0, 2, 3, 4, 3, 3, 3, 3, 4, 3, 2, 2}},
-    {12, {0, 3, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2}},
-    {13, {0, 4, 4, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1}},
-    {9,  {0, 4, 4, 4, 4, 3, 3, 3, 2}},
-    {10, {0, 4, 4, 4, 4, 3, 3, 2, 2, 2}},
-    {12, {0, 4, 4, 4, 3, 3, 2, 3, 2, 2, 2, 2}}
-};
-
-const IVIHuffDesc ff_ivi_blk_huff_desc[8] = {
-    {10, {1, 2, 3, 4, 4, 7, 5, 5, 4, 1}},
-    {11, {2, 3, 4, 4, 4, 7, 5, 4, 3, 3, 2}},
-    {12, {2, 4, 5, 5, 5, 5, 6, 4, 4, 3, 1, 1}},
-    {13, {3, 3, 4, 4, 5, 6, 6, 4, 4, 3, 2, 1, 1}},
-    {11, {3, 4, 4, 5, 5, 5, 6, 5, 4, 2, 2}},
-    {13, {3, 4, 5, 5, 5, 5, 6, 4, 3, 3, 2, 1, 1}},
-    {13, {3, 4, 5, 5, 5, 6, 5, 4, 3, 3, 2, 1, 1}},
-    {9,  {3, 4, 4, 5, 5, 5, 6, 5, 5}}
-};
-
-
 /**
  *  Scan patterns shared between indeo4 and indeo5
  */