From f76e3669bb350ca6df150244f3d28d7dc5599f01 Mon Sep 17 00:00:00 2001 From: Dirk Ausserhaus Date: Thu, 29 May 2014 13:30:37 +0200 Subject: [PATCH] Decode both parts of Indeo4 IP frames Signed-off-by: Kostya Shishkov --- libavcodec/indeo4.c | 4 ++++ libavcodec/ivi_common.c | 48 ++++++++++++++++++++++++++++++----------- libavcodec/ivi_common.h | 3 +++ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/libavcodec/indeo4.c b/libavcodec/indeo4.c index ca81d62c57..3e97221229 100644 --- a/libavcodec/indeo4.c +++ b/libavcodec/indeo4.c @@ -620,6 +620,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; } diff --git a/libavcodec/ivi_common.c b/libavcodec/ivi_common.c index cf4df18737..6eb5b6cdf4 100644 --- a/libavcodec/ivi_common.c +++ b/libavcodec/ivi_common.c @@ -968,6 +968,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; @@ -1005,19 +1017,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) { - 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; @@ -1041,6 +1040,27 @@ 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; + + 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; } @@ -1073,6 +1093,8 @@ av_cold int ff_ivi_decode_close(AVCodecContext *avctx) } #endif + av_frame_free(&ctx->p_frame); + return 0; } diff --git a/libavcodec/ivi_common.h b/libavcodec/ivi_common.h index 584bf07279..604b54958b 100644 --- a/libavcodec/ivi_common.h +++ b/libavcodec/ivi_common.h @@ -260,6 +260,9 @@ typedef struct IVI45DecContext { int (*is_nonnull_frame)(struct IVI45DecContext *ctx); int gop_invalid; + + AVFrame *p_frame; + int got_p_frame; } IVI45DecContext; /** compare some properties of two pictures */