+#if CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER
+
+typedef struct {
+ /**
+ * Transform coefficients for both sprites in 16.16 fixed point format,
+ * in the order they appear in the bitstream:
+ * x scale
+ * rotation 1 (unused)
+ * x offset
+ * rotation 2 (unused)
+ * y scale
+ * y offset
+ * alpha
+ */
+ int coefs[2][7];
+
+ int effect_type, effect_flag;
+ int effect_pcount1, effect_pcount2; ///< amount of effect parameters stored in effect_params
+ int effect_params1[15], effect_params2[10]; ///< effect parameters in 16.16 fixed point format
+} SpriteData;
+
+static inline int get_fp_val(GetBitContext* gb)
+{
+ return (get_bits_long(gb, 30) - (1 << 29)) << 1;
+}
+
+static void vc1_sprite_parse_transform(GetBitContext* gb, int c[7])
+{
+ c[1] = c[3] = 0;
+
+ switch (get_bits(gb, 2)) {
+ case 0:
+ c[0] = 1 << 16;
+ c[2] = get_fp_val(gb);
+ c[4] = 1 << 16;
+ break;
+ case 1:
+ c[0] = c[4] = get_fp_val(gb);
+ c[2] = get_fp_val(gb);
+ break;
+ case 2:
+ c[0] = get_fp_val(gb);
+ c[2] = get_fp_val(gb);
+ c[4] = get_fp_val(gb);
+ break;
+ case 3:
+ c[0] = get_fp_val(gb);
+ c[1] = get_fp_val(gb);
+ c[2] = get_fp_val(gb);
+ c[3] = get_fp_val(gb);
+ c[4] = get_fp_val(gb);
+ break;
+ }
+ c[5] = get_fp_val(gb);
+ if (get_bits1(gb))
+ c[6] = get_fp_val(gb);
+ else
+ c[6] = 1 << 16;
+}
+
+static void vc1_parse_sprites(VC1Context *v, GetBitContext* gb, SpriteData* sd)
+{
+ AVCodecContext *avctx = v->s.avctx;
+ int sprite, i;
+
+ for (sprite = 0; sprite <= v->two_sprites; sprite++) {
+ vc1_sprite_parse_transform(gb, sd->coefs[sprite]);
+ if (sd->coefs[sprite][1] || sd->coefs[sprite][3])
+ av_log_ask_for_sample(avctx, "Rotation coefficients are not zero");
+ av_log(avctx, AV_LOG_DEBUG, sprite ? "S2:" : "S1:");
+ for (i = 0; i < 7; i++)
+ av_log(avctx, AV_LOG_DEBUG, " %d.%.3d",
+ sd->coefs[sprite][i] / (1<<16),
+ (abs(sd->coefs[sprite][i]) & 0xFFFF) * 1000 / (1 << 16));
+ av_log(avctx, AV_LOG_DEBUG, "\n");
+ }
+
+ skip_bits(gb, 2);
+ if (sd->effect_type = get_bits_long(gb, 30)) {
+ switch (sd->effect_pcount1 = get_bits(gb, 4)) {
+ case 7:
+ vc1_sprite_parse_transform(gb, sd->effect_params1);
+ break;
+ case 14:
+ vc1_sprite_parse_transform(gb, sd->effect_params1);
+ vc1_sprite_parse_transform(gb, sd->effect_params1 + 7);
+ break;
+ default:
+ for (i = 0; i < sd->effect_pcount1; i++)
+ sd->effect_params1[i] = get_fp_val(gb);
+ }
+ if (sd->effect_type != 13 || sd->effect_params1[0] != sd->coefs[0][6]) {
+ // effect 13 is simple alpha blending and matches the opacity above
+ av_log(avctx, AV_LOG_DEBUG, "Effect: %d; params: ", sd->effect_type);
+ for (i = 0; i < sd->effect_pcount1; i++)
+ av_log(avctx, AV_LOG_DEBUG, " %d.%.2d",
+ sd->effect_params1[i] / (1 << 16),
+ (abs(sd->effect_params1[i]) & 0xFFFF) * 1000 / (1 << 16));
+ av_log(avctx, AV_LOG_DEBUG, "\n");
+ }
+
+ sd->effect_pcount2 = get_bits(gb, 16);
+ if (sd->effect_pcount2 > 10) {
+ av_log(avctx, AV_LOG_ERROR, "Too many effect parameters\n");
+ return;
+ } else if (sd->effect_pcount2) {
+ i = -1;
+ av_log(avctx, AV_LOG_DEBUG, "Effect params 2: ");
+ while (++i < sd->effect_pcount2) {
+ sd->effect_params2[i] = get_fp_val(gb);
+ av_log(avctx, AV_LOG_DEBUG, " %d.%.2d",
+ sd->effect_params2[i] / (1 << 16),
+ (abs(sd->effect_params2[i]) & 0xFFFF) * 1000 / (1 << 16));
+ }
+ av_log(avctx, AV_LOG_DEBUG, "\n");
+ }
+ }
+ if (sd->effect_flag = get_bits1(gb))
+ av_log(avctx, AV_LOG_DEBUG, "Effect flag set\n");
+
+ if (get_bits_count(gb) >= gb->size_in_bits +
+ (avctx->codec_id == CODEC_ID_WMV3IMAGE ? 64 : 0))
+ av_log(avctx, AV_LOG_ERROR, "Buffer overrun\n");
+ if (get_bits_count(gb) < gb->size_in_bits - 8)
+ av_log(avctx, AV_LOG_WARNING, "Buffer not fully read\n");
+}
+
+static void vc1_draw_sprites(VC1Context *v, SpriteData* sd)
+{
+ int i, plane, row, sprite;
+ int sr_cache[2][2] = { { -1, -1 }, { -1, -1 } };
+ uint8_t* src_h[2][2];
+ int xoff[2], xadv[2], yoff[2], yadv[2], alpha;
+ int ysub[2];
+ MpegEncContext *s = &v->s;
+
+ for (i = 0; i < 2; i++) {
+ xoff[i] = av_clip(sd->coefs[i][2], 0, v->sprite_width-1 << 16);
+ xadv[i] = sd->coefs[i][0];
+ if (xadv[i] != 1<<16 || (v->sprite_width << 16) - (v->output_width << 16) - xoff[i])
+ xadv[i] = av_clip(xadv[i], 0, ((v->sprite_width<<16) - xoff[i] - 1) / v->output_width);
+
+ yoff[i] = av_clip(sd->coefs[i][5], 0, v->sprite_height-1 << 16);
+ yadv[i] = av_clip(sd->coefs[i][4], 0, ((v->sprite_height << 16) - yoff[i]) / v->output_height);
+ }
+ alpha = av_clip(sd->coefs[1][6], 0, (1<<16) - 1);
+
+ for (plane = 0; plane < (s->flags&CODEC_FLAG_GRAY ? 1 : 3); plane++) {
+ int width = v->output_width>>!!plane;
+
+ for (row = 0; row < v->output_height>>!!plane; row++) {
+ uint8_t *dst = v->sprite_output_frame.data[plane] +
+ v->sprite_output_frame.linesize[plane] * row;
+
+ for (sprite = 0; sprite <= v->two_sprites; sprite++) {
+ uint8_t *iplane = s->current_picture.f.data[plane];
+ int iline = s->current_picture.f.linesize[plane];
+ int ycoord = yoff[sprite] + yadv[sprite] * row;
+ int yline = ycoord >> 16;
+ ysub[sprite] = ycoord & 0xFFFF;
+ if (sprite) {
+ iplane = s->last_picture.f.data[plane];
+ iline = s->last_picture.f.linesize[plane];
+ }
+ if (!(xoff[sprite] & 0xFFFF) && xadv[sprite] == 1 << 16) {
+ src_h[sprite][0] = iplane + (xoff[sprite] >> 16) + yline * iline;
+ if (ysub[sprite])
+ src_h[sprite][1] = iplane + (xoff[sprite] >> 16) + (yline + 1) * iline;
+ } else {
+ if (sr_cache[sprite][0] != yline) {
+ if (sr_cache[sprite][1] == yline) {
+ FFSWAP(uint8_t*, v->sr_rows[sprite][0], v->sr_rows[sprite][1]);
+ FFSWAP(int, sr_cache[sprite][0], sr_cache[sprite][1]);
+ } else {
+ v->vc1dsp.sprite_h(v->sr_rows[sprite][0], iplane + yline * iline, xoff[sprite], xadv[sprite], width);
+ sr_cache[sprite][0] = yline;
+ }
+ }
+ if (ysub[sprite] && sr_cache[sprite][1] != yline + 1) {
+ v->vc1dsp.sprite_h(v->sr_rows[sprite][1], iplane + (yline + 1) * iline, xoff[sprite], xadv[sprite], width);
+ sr_cache[sprite][1] = yline + 1;
+ }
+ src_h[sprite][0] = v->sr_rows[sprite][0];
+ src_h[sprite][1] = v->sr_rows[sprite][1];
+ }
+ }
+
+ if (!v->two_sprites) {
+ if (ysub[0]) {
+ v->vc1dsp.sprite_v_single(dst, src_h[0][0], src_h[0][1], ysub[0], width);
+ } else {
+ memcpy(dst, src_h[0][0], width);
+ }
+ } else {
+ if (ysub[0] && ysub[1]) {
+ v->vc1dsp.sprite_v_double_twoscale(dst, src_h[0][0], src_h[0][1], ysub[0],
+ src_h[1][0], src_h[1][1], ysub[1], alpha, width);
+ } else if (ysub[0]) {
+ v->vc1dsp.sprite_v_double_onescale(dst, src_h[0][0], src_h[0][1], ysub[0],
+ src_h[1][0], alpha, width);
+ } else if (ysub[1]) {
+ v->vc1dsp.sprite_v_double_onescale(dst, src_h[1][0], src_h[1][1], ysub[1],
+ src_h[0][0], (1<<16)-1-alpha, width);
+ } else {
+ v->vc1dsp.sprite_v_double_noscale(dst, src_h[0][0], src_h[1][0], alpha, width);
+ }
+ }
+ }
+
+ if (!plane) {
+ for (i = 0; i < 2; i++) {
+ xoff[i] >>= 1;
+ yoff[i] >>= 1;
+ }
+ }
+
+ }
+}
+
+
+static int vc1_decode_sprites(VC1Context *v, GetBitContext* gb)
+{
+ MpegEncContext *s = &v->s;
+ AVCodecContext *avctx = s->avctx;
+ SpriteData sd;
+
+ vc1_parse_sprites(v, gb, &sd);
+
+ if (!s->current_picture.f.data[0]) {
+ av_log(avctx, AV_LOG_ERROR, "Got no sprites\n");
+ return -1;
+ }
+
+ if (v->two_sprites && (!s->last_picture_ptr || !s->last_picture.f.data[0])) {
+ av_log(avctx, AV_LOG_WARNING, "Need two sprites, only got one\n");
+ v->two_sprites = 0;
+ }
+
+ if (v->sprite_output_frame.data[0])
+ avctx->release_buffer(avctx, &v->sprite_output_frame);
+
+ v->sprite_output_frame.buffer_hints = FF_BUFFER_HINTS_VALID;
+ v->sprite_output_frame.reference = 0;
+ if (avctx->get_buffer(avctx, &v->sprite_output_frame) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ return -1;
+ }
+
+ vc1_draw_sprites(v, &sd);
+
+ return 0;
+}
+
+static void vc1_sprite_flush(AVCodecContext *avctx)
+{
+ VC1Context *v = avctx->priv_data;
+ MpegEncContext *s = &v->s;
+ AVFrame *f = &s->current_picture.f;
+ int plane, i;
+
+ /* Windows Media Image codecs have a convergence interval of two keyframes.
+ Since we can't enforce it, clear to black the missing sprite. This is
+ wrong but it looks better than doing nothing. */
+
+ if (f->data[0])
+ for (plane = 0; plane < (s->flags&CODEC_FLAG_GRAY ? 1 : 3); plane++)
+ for (i = 0; i < v->sprite_height>>!!plane; i++)
+ memset(f->data[plane] + i * f->linesize[plane],
+ plane ? 128 : 0, f->linesize[plane]);
+}
+
+#endif
+
+static av_cold int vc1_decode_init_alloc_tables(VC1Context *v)
+{
+ MpegEncContext *s = &v->s;
+ int i;
+
+ /* Allocate mb bitplanes */
+ v->mv_type_mb_plane = av_malloc (s->mb_stride * s->mb_height);
+ v->direct_mb_plane = av_malloc (s->mb_stride * s->mb_height);
+ v->forward_mb_plane = av_malloc (s->mb_stride * s->mb_height);
+ v->fieldtx_plane = av_mallocz(s->mb_stride * s->mb_height);
+ v->acpred_plane = av_malloc (s->mb_stride * s->mb_height);
+ v->over_flags_plane = av_malloc (s->mb_stride * s->mb_height);
+
+ v->n_allocated_blks = s->mb_width + 2;
+ v->block = av_malloc(sizeof(*v->block) * v->n_allocated_blks);
+ v->cbp_base = av_malloc(sizeof(v->cbp_base[0]) * 2 * s->mb_stride);
+ v->cbp = v->cbp_base + s->mb_stride;
+ v->ttblk_base = av_malloc(sizeof(v->ttblk_base[0]) * 2 * s->mb_stride);
+ v->ttblk = v->ttblk_base + s->mb_stride;
+ v->is_intra_base = av_mallocz(sizeof(v->is_intra_base[0]) * 2 * s->mb_stride);
+ v->is_intra = v->is_intra_base + s->mb_stride;
+ v->luma_mv_base = av_malloc(sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride);
+ v->luma_mv = v->luma_mv_base + s->mb_stride;
+
+ /* allocate block type info in that way so it could be used with s->block_index[] */
+ v->mb_type_base = av_malloc(s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
+ v->mb_type[0] = v->mb_type_base + s->b8_stride + 1;
+ v->mb_type[1] = v->mb_type_base + s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride + 1;
+ v->mb_type[2] = v->mb_type[1] + s->mb_stride * (s->mb_height + 1);
+
+ /* allocate memory to store block level MV info */
+ v->blk_mv_type_base = av_mallocz( s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
+ v->blk_mv_type = v->blk_mv_type_base + s->b8_stride + 1;
+ v->mv_f_base = av_mallocz(2 * (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2));
+ v->mv_f[0] = v->mv_f_base + s->b8_stride + 1;
+ v->mv_f[1] = v->mv_f[0] + (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
+ v->mv_f_last_base = av_mallocz(2 * (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2));
+ v->mv_f_last[0] = v->mv_f_last_base + s->b8_stride + 1;
+ v->mv_f_last[1] = v->mv_f_last[0] + (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
+ v->mv_f_next_base = av_mallocz(2 * (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2));
+ v->mv_f_next[0] = v->mv_f_next_base + s->b8_stride + 1;
+ v->mv_f_next[1] = v->mv_f_next[0] + (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
+
+ /* Init coded blocks info */
+ if (v->profile == PROFILE_ADVANCED) {
+// if (alloc_bitplane(&v->over_flags_plane, s->mb_width, s->mb_height) < 0)
+// return -1;
+// if (alloc_bitplane(&v->ac_pred_plane, s->mb_width, s->mb_height) < 0)
+// return -1;
+ }
+
+ ff_intrax8_common_init(&v->x8,s);
+
+ if (s->avctx->codec_id == CODEC_ID_WMV3IMAGE || s->avctx->codec_id == CODEC_ID_VC1IMAGE) {
+ for (i = 0; i < 4; i++)
+ if (!(v->sr_rows[i >> 1][i & 1] = av_malloc(v->output_width))) return -1;
+ }
+
+ if (!v->mv_type_mb_plane || !v->direct_mb_plane || !v->acpred_plane || !v->over_flags_plane ||
+ !v->block || !v->cbp_base || !v->ttblk_base || !v->is_intra_base || !v->luma_mv_base ||
+ !v->mb_type_base)
+ return -1;
+
+ return 0;
+}
+