avcodec/indeo4: Decode both parts of IP frames
authorDirk Ausserhaus <dausserhaus@gmail.com>
Thu, 29 May 2014 11:30:37 +0000 (13:30 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 30 May 2014 11:49:42 +0000 (13:49 +0200)
Fixes part of Ticket845

av_frame_move_ref() idea by Anton Khirnov

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavcodec/indeo4.c
libavcodec/ivi_common.c
libavcodec/ivi_common.h

index cee9bad..ada44af 100644 (file)
@@ -663,6 +663,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
     ctx->switch_buffers   = switch_buffers;
     ctx->is_nonnull_frame = is_nonnull_frame;
 
+    ctx->p_frame = av_frame_alloc();
+    if (!ctx->p_frame)
+        return AVERROR(ENOMEM);
+
     return 0;
 }
 
index 55843ef..53f71c7 100644 (file)
@@ -997,6 +997,18 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
     if (ctx->gop_invalid)
         return AVERROR_INVALIDDATA;
 
+    if (avctx->codec_id == AV_CODEC_ID_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;
@@ -1038,24 +1050,6 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
 
     //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 == IVI4_FRAMETYPE_INTRA) {
-            // skip version string
-        while (get_bits(&ctx->gb, 8)) {
-            if (get_bits_left(&ctx->gb) < 8)
-                return AVERROR_INVALIDDATA;
-        }
-
-        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");
-    }
-
     if (!ctx->is_nonnull_frame(ctx))
         return buf_size;
 
@@ -1080,6 +1074,31 @@ 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 (avctx->codec_id == AV_CODEC_ID_INDEO4 &&
+        ctx->frame_type == IVI4_FRAMETYPE_INTRA) {
+        int left;
+
+            // skip version string
+        while (get_bits(&ctx->gb, 8)) {
+            if (get_bits_left(&ctx->gb) < 8)
+                return AVERROR_INVALIDDATA;
+        }
+        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;
 }
 
@@ -1112,6 +1131,8 @@ av_cold int ff_ivi_decode_close(AVCodecContext *avctx)
     }
 #endif
 
+    av_frame_free(&ctx->p_frame);
+
     return 0;
 }
 
index 76d1b61..b0bdfe5 100644 (file)
@@ -262,6 +262,9 @@ typedef struct IVI45DecContext {
 
     int gop_invalid;
     int buf_invalid[3];
+
+    AVFrame         *p_frame;
+    int             got_p_frame;
 } IVI45DecContext;
 
 /** compare some properties of two pictures */