From 768c5251141be705d64a480b641c6b17d32a4e7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alberto=20Delm=C3=A1s?= <adelmas@gmail.com>
Date: Fri, 8 Apr 2011 20:00:48 +0200
Subject: Parse sprite data for WMVP and WVP2, and decode sprites for the
 latter

Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
 libavcodec/vc1dec.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 124 insertions(+), 3 deletions(-)

(limited to 'libavcodec/vc1dec.c')

diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c
index cde284dac2..8200cde0ff 100644
--- a/libavcodec/vc1dec.c
+++ b/libavcodec/vc1dec.c
@@ -3097,6 +3097,116 @@ static void vc1_decode_blocks(VC1Context *v, int mby_start, int mby_end)
     }
 }
 
+static inline float get_float_val(GetBitContext* gb)
+{
+    return (float)get_bits_long(gb, 30) / (1<<15) - (1<<14);
+}
+
+static void vc1_sprite_parse_transform(VC1Context *v, GetBitContext* gb, float c[7])
+{
+    c[1] = c[3] = 0.0f;
+
+    switch (get_bits(gb, 2)) {
+    case 0:
+        c[0] = 1.0f;
+        c[2] = get_float_val(gb);
+        c[4] = 1.0f;
+        break;
+    case 1:
+        c[0] = c[4] = get_float_val(gb);
+        c[2] = get_float_val(gb);
+        break;
+    case 2:
+        c[0] = get_float_val(gb);
+        c[2] = get_float_val(gb);
+        c[4] = get_float_val(gb);
+        break;
+    case 3:
+        av_log_ask_for_sample(v->s.avctx, NULL);
+        c[0] = get_float_val(gb);
+        c[1] = get_float_val(gb);
+        c[2] = get_float_val(gb);
+        c[3] = get_float_val(gb);
+        c[4] = get_float_val(gb);
+        break;
+    }
+    c[5] = get_float_val(gb);
+    if (get_bits1(gb))
+        c[6] = get_float_val(gb);
+    else
+        c[6] = 1.0f;
+}
+
+static void vc1_parse_sprites(VC1Context *v, GetBitContext* gb)
+{
+    int effect_type, effect_flag, effect_pcount1, effect_pcount2, i;
+    float effect_params1[14], effect_params2[10];
+
+    float coefs[2][7];
+    vc1_sprite_parse_transform(v, gb, coefs[0]);
+    av_log(v->s.avctx, AV_LOG_DEBUG, "S1:");
+    for (i = 0; i < 7; i++)
+        av_log(v->s.avctx, AV_LOG_DEBUG, " %.3f", coefs[0][i]);
+    av_log(v->s.avctx, AV_LOG_DEBUG, "\n");
+
+    if (v->two_sprites) {
+        vc1_sprite_parse_transform(v, gb, coefs[1]);
+        av_log(v->s.avctx, AV_LOG_DEBUG, "S2:");
+        for (i = 0; i < 7; i++)
+            av_log(v->s.avctx, AV_LOG_DEBUG, " %.3f", coefs[1][i]);
+        av_log(v->s.avctx, AV_LOG_DEBUG, "\n");
+    }
+    skip_bits(gb, 2);
+    if (effect_type = get_bits_long(gb, 30)){
+        switch (effect_pcount1 = get_bits(gb, 4)) {
+        case 2:
+            effect_params1[0] = get_float_val(gb);
+            effect_params1[1] = get_float_val(gb);
+            break;
+        case 7:
+            vc1_sprite_parse_transform(v, gb, effect_params1);
+            break;
+        case 14:
+            vc1_sprite_parse_transform(v, gb, effect_params1);
+            vc1_sprite_parse_transform(v, gb, &effect_params1[7]);
+            break;
+        default:
+            av_log_ask_for_sample(v->s.avctx, NULL);
+            return;
+        }
+        if (effect_type != 13 || effect_params1[0] != coefs[0][6]) {
+            // effect 13 is simple alpha blending and matches the opacity above
+            av_log(v->s.avctx, AV_LOG_DEBUG, "Effect: %d; params: ", effect_type);
+            for (i = 0; i < effect_pcount1; i++)
+                av_log(v->s.avctx, AV_LOG_DEBUG, " %.3f", effect_params1[i]);
+            av_log(v->s.avctx, AV_LOG_DEBUG, "\n");
+        }
+
+        effect_pcount2 = get_bits(gb, 16);
+        if (effect_pcount2 > 10) {
+            av_log(v->s.avctx, AV_LOG_ERROR, "Too many effect parameters\n");
+            return;
+        } else if (effect_pcount2) {
+            i = 0;
+            av_log(v->s.avctx, AV_LOG_DEBUG, "Effect params 2: ");
+            while (i < effect_pcount2){
+                effect_params2[i] = get_float_val(gb);
+                av_log(v->s.avctx, AV_LOG_DEBUG, " %.3f", effect_params2[i]);
+                i++;
+            }
+            av_log(v->s.avctx, AV_LOG_DEBUG, "\n");
+        }
+    }
+    if (effect_flag = get_bits1(gb))
+        av_log(v->s.avctx, AV_LOG_DEBUG, "Effect flag set\n");
+
+    if (get_bits_count(gb) >= gb->size_in_bits +
+       (v->s.avctx->codec_id == CODEC_ID_WMV3 ? 64 : 0))
+        av_log(v->s.avctx, AV_LOG_ERROR, "Buffer overrun\n");
+    if (get_bits_count(gb) < gb->size_in_bits - 8)
+        av_log(v->s.avctx, AV_LOG_WARNING, "Buffer not fully read\n");
+}
+
 /** Initialize a VC1/WMV3 decoder
  * @todo TODO: Handle VC-1 IDUs (Transport level?)
  * @todo TODO: Decypher remaining bits in extra_data
@@ -3160,7 +3270,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
         {
             av_log(avctx, AV_LOG_INFO, "Read %i bits in overflow\n", -count);
         }
-    } else { // VC1/WVC1
+    } else { // VC1/WVC1/WVP2
         const uint8_t *start = avctx->extradata;
         uint8_t *end = avctx->extradata + avctx->extradata_size;
         const uint8_t *next;
@@ -3204,6 +3314,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
             av_log(avctx, AV_LOG_ERROR, "Incomplete extradata\n");
             return -1;
         }
+        v->res_sprite = (avctx->codec_tag == MKTAG('W','V','P','2'));
     }
     avctx->profile = v->profile;
     if (v->profile == PROFILE_ADVANCED)
@@ -3359,6 +3470,14 @@ static int vc1_decode_frame(AVCodecContext *avctx,
         init_get_bits(&s->gb, buf2, buf_size2*8);
     } else
         init_get_bits(&s->gb, buf, buf_size*8);
+
+    if (v->res_sprite) {
+        v->new_sprite = !get_bits1(&s->gb);
+        v->two_sprites = get_bits1(&s->gb);
+        if (!v->new_sprite)
+            goto end;
+    }
+
     // do parse frame header
     if(v->profile < PROFILE_ADVANCED) {
         if(vc1_parse_frame_header(v, &s->gb) == -1) {
@@ -3370,8 +3489,8 @@ static int vc1_decode_frame(AVCodecContext *avctx,
         }
     }
 
-    if(v->res_sprite && (s->pict_type!=FF_I_TYPE)){
-        goto err;
+    if (v->res_sprite && s->pict_type!=FF_I_TYPE) {
+        av_log(v->s.avctx, AV_LOG_WARNING, "Sprite decoder: expected I-frame\n");
     }
 
     // for skipping the frame
@@ -3455,6 +3574,8 @@ assert(s->current_picture.pict_type == s->pict_type);
     }
 
 end:
+    if (v->res_sprite)
+        vc1_parse_sprites(v, &s->gb);
     av_free(buf2);
     for (i = 0; i < n_slices; i++)
         av_free(slices[i].buf);
-- 
cgit v1.2.1