aboutsummaryrefslogblamecommitdiffstats
path: root/libavcodec/vc1dec.c
blob: da6724ca398c4613b80a1608cdb7326d7506059e (plain) (tree)
1
2
3
                        
                                             



















                                                                                  
        
                        
   
 
                    

                     
                    
                      
                        
                    
                           
                               
 
 




















                                                                                                  
 
                                                    
 
                                                                   
 
                    

                              
                       
                              
                       
              
                                     
              

                              
              



                              
              
                          
                      
                              
        
                       
 
                                                                              
 




                                                          
                                                                           
                                                            
                               
                                                   
                                                                            
                                          
     
 
                     
                                                       
               
                                                               
                  
                                                                   
                  
                                                       
         
                                                                                
                                                                               

                                                                                 
                                                                                 
                                              
         

                                                                        
                                       

                                                             
                                              
                                                       
                                                                                 
             
                                              
         
                                                         
                                                
                                                             
                                                        
                                   
                                                  
                                                                 
             









                                                           
                                           
                                                                       
                                                                                            

                                                                                                   
                                                                                                       





                                                                          
                                                                         
                                                                  
                                                                        
                                                                    
                                   
                                               
                             
                                                                
                 
                                                                                        
                                                                                               
                                     
                                                                                     




                                                                                           
                                                                                                                                 


                                                                           

                                                                            




























                                                                                                        
                                                   









                                                               
            
                                  

                                     
                               

                                        
 
                                                                  


                                                        
                                                                                  


                                                                          
                                           
                                                                    
                   






                                                   
                                         
                              
                                      




                                                                               
                        
                                                                            
                                                               
                                                            
 
      
                                                          

                              
                                             
                               




                                                               
                                          





                                                                                     
                                                                                    
                                                         
                                                                                        
                                                                                                         
                                                         
                                                                                              
 
                                                      
                                                                                                                   
                                                                 
                                                                                                                    
                                                          
                                                                                                                    
                                                               
                                                                                                                      
 
                                
                                         






                                                                                  
                                                                                                    
                               
                                                                          


                                                                                                  











                                       


             


                                                             
                                                    








                                                                     







                                                         
            
 


                                                    
                                                    
                                          
                                                                      
        
                                          
                       
 
                                          
                                               


                                                       


                                                        
 
                                      
                                          
                              
 
                                                                                          







                                                                        
                                                                     
                                                              
                        
                                                                               
                               
                                                                             
                             





                                                                
                                         


                                                                                                 
                                                                                 
                                                                                                              
                                          
                                                    
                          
                                                                   
                                     
                                 
                                                                               
                                  
                               


                                     
                                                                           
                                  
                               




                                   
                                                  

                                                                  
                                                                  
     
 


                                              


                                       
                                                
 





                                                                          
                                                   
 
                                                          
                                             
            
                                                   


                           
                                                                                              





                                                               


                                                  
                                                          
                                                                
                                        
     

             

                                                     
                                                    


                                     
                                           
 
                           
                                             
                             
                             
                                   
                                   

                                   
                                   
                                 







                                                          


                                                  
                                                              
                                                            
                                     
                                                     


                                     
                                                                   
                                


                         
                           
 
                        

                                       
                                  
                                                                                
                                           
                                                       
                                                                       
                           
                                       
 
                           
         
                        
     





                                                                
                                                                 
                                                                                        
                                                                   
                                   
 
                                                                                            


                                              
                                                                               
                                                        
                                         
                                    
                                                                              

                                                                           
                                      

                                                                              
                                                                                  
                             
                                 
                                 
                                                                                               
                                              




                                                                             
                                                                       
                                                                                           
                          
                                                                              
                                                               
                                                                
                          
                                      
                                                                                  
                             
                                 
                                 
                                                                                               
                                              






                                                                                   
                 
                                                                                                                          
                                   
                          
                                                            
                                                                                      
                                                                                
                         
                                                                 

                                                                          
                                                                              







                                                                                                                 
                                                                   
                                         
             
                                                                      
                



                                                                 
                        
                                            
                                                                                  

                                                                                   
                                                                                                  






                                                                           
     

                                             
                                 

                                  
                                              
                     
                                                     
                                 
                     


                                                             
                                                               



                                                
                            
                           
                                 
                                        
                                                       
                     
            
                                                           
                     
         
                                 
 

                                                                                                    
                                                                                             
                                               
                                                                               
     



                                                              
                             
                                                                        
                                                         
                                                                                      
                                                                                        
                 
     

                                                                                       
                 
     
 
                                              
                     
            
                                        
     
                                           
                 
     
                                                            
                                                                            
 
                             
                                               


                                                                   
                                                   
                           
                                                               
     
                                                 
 







                                                                                                              

















                                                                                                       
                                                                    














                                                                                                                           
            
                           
                                  
                               
                                  
                            

                                                    
                                                   
                                                  
 
                                   
 
                                         
                                                                 


                                                                              
                             
                                    
                                                    
                                                                   






                                                                   
                                                          
                                                                                      
                                                                                   
                                                                   

                                               
                                           
                                                                                      
                                                                                   
                                                                   
                                 
                 
                               

                                                                                                                   



                                                                                            
                                                                                                                   
             


                                                                                                         


                                                                                            
                                    


                                     
                                

                                                    
                                                   
                                                                                              
                                                               
             
         
                                                            
                                              
                  
                                                                     
                     
                           
                                    
     
                        
 
                                                                                              

                                                               
                                                  
                                                       
                                          
      
                                                                   
                     
                       
            
                                                                
                                                                          
                         
                                                                 
                           
                                         
                                                                       
                         
                                                              
                           
         
     
    
                  

                                  
                    

                  

                                  
              

 





                                            
 
                                                                 
                            
                         
                            
                         
                            




                       
                          
                            
                                                         
                                         
                                      
                                         
                                        
                                       
                                    
                                                      
                                                  
                                                    
  
                       
                           
                             
                                                                    
                                         
                                       
                                         
                                        
                                       
                                    
                                                      
                                                  
                                                    
  
      
 

                                   
                                                                          





                                                                                






                                                                                             
                                                               





                                                                                



                                                                                            

                                  
                                                                          
                                         
                                            
                                         
                                        

                                       


                                                    




                                 
                                                                             
                                         
                                           
                                         
                                        

                                       


                                                    
      
/*
 * VC-1 and WMV3 decoder
 * Copyright (c) 2011 Mashiat Sarker Shakkhar
 * Copyright (c) 2006-2007 Konstantin Shishkov
 * Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * VC-1 and WMV3 decoder
 */

#include "avcodec.h"
#include "blockdsp.h"
#include "get_bits.h"
#include "internal.h"
#include "mpeg_er.h"
#include "mpegvideo.h"
#include "msmpeg4data.h"
#include "vc1.h"
#include "vc1data.h"
#include "vdpau_internal.h"
#include "libavutil/avassert.h"


#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 int 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])
            avpriv_request_sample(avctx, "Non-zero rotation coefficients");
        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 AVERROR_INVALIDDATA;
        } 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 == AV_CODEC_ID_WMV3IMAGE ? 64 : 0)) {
        av_log(avctx, AV_LOG_ERROR, "Buffer overrun\n");
        return AVERROR_INVALIDDATA;
    }
    if (get_bits_count(gb) < gb->size_in_bits - 8)
        av_log(avctx, AV_LOG_WARNING, "Buffer not fully read\n");

    return 0;
}

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 <= v->two_sprites; 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;
                int      next_line;
                ysub[sprite] = ycoord & 0xFFFF;
                if (sprite) {
                    iplane = s->last_picture.f->data[plane];
                    iline  = s->last_picture.f->linesize[plane];
                }
                next_line = FFMIN(yline + 1, (v->sprite_height >> !!plane) - 1) * iline;
                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) + next_line;
                } 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 + next_line, 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 <= v->two_sprites; i++) {
                xoff[i] >>= 1;
                yoff[i] >>= 1;
            }
        }

    }
}


static int vc1_decode_sprites(VC1Context *v, GetBitContext* gb)
{
    int ret;
    MpegEncContext *s     = &v->s;
    AVCodecContext *avctx = s->avctx;
    SpriteData sd;

    memset(&sd, 0, sizeof(sd));

    ret = vc1_parse_sprites(v, gb, &sd);
    if (ret < 0)
        return ret;

    if (!s->current_picture.f || !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;
    }

    av_frame_unref(v->sprite_output_frame);
    if ((ret = ff_get_buffer(avctx, v->sprite_output_frame, 0)) < 0)
        return ret;

    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 && 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

av_cold int ff_vc1_decode_init_alloc_tables(VC1Context *v)
{
    MpegEncContext *s = &v->s;
    int i;
    int mb_height = FFALIGN(s->mb_height, 2);

    /* Allocate mb bitplanes */
    v->mv_type_mb_plane = av_malloc (s->mb_stride * mb_height);
    v->direct_mb_plane  = av_malloc (s->mb_stride * mb_height);
    v->forward_mb_plane = av_malloc (s->mb_stride * mb_height);
    v->fieldtx_plane    = av_mallocz(s->mb_stride * mb_height);
    v->acpred_plane     = av_malloc (s->mb_stride * mb_height);
    v->over_flags_plane = av_malloc (s->mb_stride * 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_mallocz(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 * (mb_height * 2 + 1) + s->mb_stride * (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 * (mb_height * 2 + 1) + s->mb_stride + 1;
    v->mb_type[2]   = v->mb_type[1] + s->mb_stride * (mb_height + 1);

    /* allocate memory to store block level MV info */
    v->blk_mv_type_base = av_mallocz(     s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (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 * (mb_height * 2 + 1) + s->mb_stride * (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 * (mb_height * 2 + 1) + s->mb_stride * (mb_height + 1) * 2);
    v->mv_f_next_base   = av_mallocz(2 * (s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (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 * (mb_height * 2 + 1) + s->mb_stride * (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 == AV_CODEC_ID_WMV3IMAGE || s->avctx->codec_id == AV_CODEC_ID_VC1IMAGE) {
        for (i = 0; i < 4; i++)
            if (!(v->sr_rows[i >> 1][i & 1] = av_malloc(v->output_width)))
                return AVERROR(ENOMEM);
    }

    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) {
        av_freep(&v->mv_type_mb_plane);
        av_freep(&v->direct_mb_plane);
        av_freep(&v->acpred_plane);
        av_freep(&v->over_flags_plane);
        av_freep(&v->block);
        av_freep(&v->cbp_base);
        av_freep(&v->ttblk_base);
        av_freep(&v->is_intra_base);
        av_freep(&v->luma_mv_base);
        av_freep(&v->mb_type_base);
        return AVERROR(ENOMEM);
    }

    return 0;
}

av_cold void ff_vc1_init_transposed_scantables(VC1Context *v)
{
    int i;
    for (i = 0; i < 64; i++) {
#define transpose(x) (((x) >> 3) | (((x) & 7) << 3))
        v->zz_8x8[0][i] = transpose(ff_wmv1_scantable[0][i]);
        v->zz_8x8[1][i] = transpose(ff_wmv1_scantable[1][i]);
        v->zz_8x8[2][i] = transpose(ff_wmv1_scantable[2][i]);
        v->zz_8x8[3][i] = transpose(ff_wmv1_scantable[3][i]);
        v->zzi_8x8[i]   = transpose(ff_vc1_adv_interlaced_8x8_zz[i]);
    }
    v->left_blk_sh = 0;
    v->top_blk_sh  = 3;
}

/** Initialize a VC1/WMV3 decoder
 * @todo TODO: Handle VC-1 IDUs (Transport level?)
 * @todo TODO: Decypher remaining bits in extra_data
 */
static av_cold int vc1_decode_init(AVCodecContext *avctx)
{
    VC1Context *v = avctx->priv_data;
    MpegEncContext *s = &v->s;
    GetBitContext gb;
    int ret;

    /* save the container output size for WMImage */
    v->output_width  = avctx->width;
    v->output_height = avctx->height;

    if (!avctx->extradata_size || !avctx->extradata)
        return -1;
    if (!(avctx->flags & CODEC_FLAG_GRAY))
        avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);
    else
        avctx->pix_fmt = AV_PIX_FMT_GRAY8;
    v->s.avctx = avctx;

    if ((ret = ff_vc1_init_common(v)) < 0)
        return ret;
    // ensure static VLC tables are initialized
    if ((ret = ff_msmpeg4_decode_init(avctx)) < 0)
        return ret;
    if ((ret = ff_vc1_decode_init_alloc_tables(v)) < 0)
        return ret;
    // Hack to ensure the above functions will be called
    // again once we know all necessary settings.
    // That this is necessary might indicate a bug.
    ff_vc1_decode_end(avctx);

    ff_blockdsp_init(&s->bdsp, avctx);
    ff_h264chroma_init(&v->h264chroma, 8);
    ff_qpeldsp_init(&s->qdsp);

    if (avctx->codec_id == AV_CODEC_ID_WMV3 || avctx->codec_id == AV_CODEC_ID_WMV3IMAGE) {
        int count = 0;

        // looks like WMV3 has a sequence header stored in the extradata
        // advanced sequence header may be before the first frame
        // the last byte of the extradata is a version number, 1 for the
        // samples we can decode

        init_get_bits(&gb, avctx->extradata, avctx->extradata_size*8);

        if ((ret = ff_vc1_decode_sequence_header(avctx, v, &gb)) < 0)
          return ret;

        count = avctx->extradata_size*8 - get_bits_count(&gb);
        if (count > 0) {
            av_log(avctx, AV_LOG_INFO, "Extra data: %i bits left, value: %X\n",
                   count, get_bits(&gb, count));
        } else if (count < 0) {
            av_log(avctx, AV_LOG_INFO, "Read %i bits in overflow\n", -count);
        }
    } else { // VC1/WVC1/WVP2
        const uint8_t *start = avctx->extradata;
        uint8_t *end = avctx->extradata + avctx->extradata_size;
        const uint8_t *next;
        int size, buf2_size;
        uint8_t *buf2 = NULL;
        int seq_initialized = 0, ep_initialized = 0;

        if (avctx->extradata_size < 16) {
            av_log(avctx, AV_LOG_ERROR, "Extradata size too small: %i\n", avctx->extradata_size);
            return -1;
        }

        buf2  = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
        start = find_next_marker(start, end); // in WVC1 extradata first byte is its size, but can be 0 in mkv
        next  = start;
        for (; next < end; start = next) {
            next = find_next_marker(start + 4, end);
            size = next - start - 4;
            if (size <= 0)
                continue;
            buf2_size = vc1_unescape_buffer(start + 4, size, buf2);
            init_get_bits(&gb, buf2, buf2_size * 8);
            switch (AV_RB32(start)) {
            case VC1_CODE_SEQHDR:
                if ((ret = ff_vc1_decode_sequence_header(avctx, v, &gb)) < 0) {
                    av_free(buf2);
                    return ret;
                }
                seq_initialized = 1;
                break;
            case VC1_CODE_ENTRYPOINT:
                if ((ret = ff_vc1_decode_entry_point(avctx, v, &gb)) < 0) {
                    av_free(buf2);
                    return ret;
                }
                ep_initialized = 1;
                break;
            }
        }
        av_free(buf2);
        if (!seq_initialized || !ep_initialized) {
            av_log(avctx, AV_LOG_ERROR, "Incomplete extradata\n");
            return -1;
        }
        v->res_sprite = (avctx->codec_id == AV_CODEC_ID_VC1IMAGE);
    }

    v->sprite_output_frame = av_frame_alloc();
    if (!v->sprite_output_frame)
        return AVERROR(ENOMEM);

    avctx->profile = v->profile;
    if (v->profile == PROFILE_ADVANCED)
        avctx->level = v->level;

    avctx->has_b_frames = !!avctx->max_b_frames;

    if (v->color_prim == 1 || v->color_prim == 5 || v->color_prim == 6)
        avctx->color_primaries = v->color_prim;
    if (v->transfer_char == 1 || v->transfer_char == 7)
        avctx->color_trc = v->transfer_char;
    if (v->matrix_coef == 1 || v->matrix_coef == 6 || v->matrix_coef == 7)
        avctx->colorspace = v->matrix_coef;

    s->mb_width  = (avctx->coded_width  + 15) >> 4;
    s->mb_height = (avctx->coded_height + 15) >> 4;

    if (v->profile == PROFILE_ADVANCED || v->res_fasttx) {
        ff_vc1_init_transposed_scantables(v);
    } else {
        memcpy(v->zz_8x8, ff_wmv1_scantable, 4*64);
        v->left_blk_sh = 3;
        v->top_blk_sh  = 0;
    }

    if (avctx->codec_id == AV_CODEC_ID_WMV3IMAGE || avctx->codec_id == AV_CODEC_ID_VC1IMAGE) {
        v->sprite_width  = avctx->coded_width;
        v->sprite_height = avctx->coded_height;

        avctx->coded_width  = avctx->width  = v->output_width;
        avctx->coded_height = avctx->height = v->output_height;

        // prevent 16.16 overflows
        if (v->sprite_width  > 1 << 14 ||
            v->sprite_height > 1 << 14 ||
            v->output_width  > 1 << 14 ||
            v->output_height > 1 << 14) return -1;

        if ((v->sprite_width&1) || (v->sprite_height&1)) {
            avpriv_request_sample(avctx, "odd sprites support");
            return AVERROR_PATCHWELCOME;
        }
    }
    return 0;
}

/** Close a VC1/WMV3 decoder
 * @warning Initial try at using MpegEncContext stuff
 */
av_cold int ff_vc1_decode_end(AVCodecContext *avctx)
{
    VC1Context *v = avctx->priv_data;
    int i;

    av_frame_free(&v->sprite_output_frame);

    for (i = 0; i < 4; i++)
        av_freep(&v->sr_rows[i >> 1][i & 1]);
    av_freep(&v->hrd_rate);
    av_freep(&v->hrd_buffer);
    ff_mpv_common_end(&v->s);
    av_freep(&v->mv_type_mb_plane);
    av_freep(&v->direct_mb_plane);
    av_freep(&v->forward_mb_plane);
    av_freep(&v->fieldtx_plane);
    av_freep(&v->acpred_plane);
    av_freep(&v->over_flags_plane);
    av_freep(&v->mb_type_base);
    av_freep(&v->blk_mv_type_base);
    av_freep(&v->mv_f_base);
    av_freep(&v->mv_f_next_base);
    av_freep(&v->block);
    av_freep(&v->cbp_base);
    av_freep(&v->ttblk_base);
    av_freep(&v->is_intra_base); // FIXME use v->mb_type[]
    av_freep(&v->luma_mv_base);
    ff_intrax8_common_end(&v->x8);
    return 0;
}


/** Decode a VC1/WMV3 frame
 * @todo TODO: Handle VC-1 IDUs (Transport level?)
 */
static int vc1_decode_frame(AVCodecContext *avctx, void *data,
                            int *got_frame, AVPacket *avpkt)
{
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size, n_slices = 0, i, ret;
    VC1Context *v = avctx->priv_data;
    MpegEncContext *s = &v->s;
    AVFrame *pict = data;
    uint8_t *buf2 = NULL;
    const uint8_t *buf_start = buf, *buf_start_second_field = NULL;
    int mb_height, n_slices1=-1;
    struct {
        uint8_t *buf;
        GetBitContext gb;
        int mby_start;
    } *slices = NULL, *tmp;

    v->second_field = 0;

    if(s->flags & CODEC_FLAG_LOW_DELAY)
        s->low_delay = 1;

    /* no supplementary picture */
    if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == VC1_CODE_ENDOFSEQ)) {
        /* special case for last picture */
        if (s->low_delay == 0 && s->next_picture_ptr) {
            if ((ret = av_frame_ref(pict, s->next_picture_ptr->f)) < 0)
                return ret;
            s->next_picture_ptr = NULL;

            *got_frame = 1;
        }

        return buf_size;
    }

    if (s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU) {
        if (v->profile < PROFILE_ADVANCED)
            avctx->pix_fmt = AV_PIX_FMT_VDPAU_WMV3;
        else
            avctx->pix_fmt = AV_PIX_FMT_VDPAU_VC1;
    }

    //for advanced profile we may need to parse and unescape data
    if (avctx->codec_id == AV_CODEC_ID_VC1 || avctx->codec_id == AV_CODEC_ID_VC1IMAGE) {
        int buf_size2 = 0;
        buf2 = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
        if (!buf2)
            return AVERROR(ENOMEM);

        if (IS_MARKER(AV_RB32(buf))) { /* frame starts with marker and needs to be parsed */
            const uint8_t *start, *end, *next;
            int size;

            next = buf;
            for (start = buf, end = buf + buf_size; next < end; start = next) {
                next = find_next_marker(start + 4, end);
                size = next - start - 4;
                if (size <= 0) continue;
                switch (AV_RB32(start)) {
                case VC1_CODE_FRAME:
                    if (avctx->hwaccel ||
                        s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
                        buf_start = start;
                    buf_size2 = vc1_unescape_buffer(start + 4, size, buf2);
                    break;
                case VC1_CODE_FIELD: {
                    int buf_size3;
                    if (avctx->hwaccel ||
                        s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
                        buf_start_second_field = start;
                    tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1));
                    if (!tmp)
                        goto err;
                    slices = tmp;
                    slices[n_slices].buf = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
                    if (!slices[n_slices].buf)
                        goto err;
                    buf_size3 = vc1_unescape_buffer(start + 4, size,
                                                    slices[n_slices].buf);
                    init_get_bits(&slices[n_slices].gb, slices[n_slices].buf,
                                  buf_size3 << 3);
                    /* assuming that the field marker is at the exact middle,
                       hope it's correct */
                    slices[n_slices].mby_start = s->mb_height + 1 >> 1;
                    n_slices1 = n_slices - 1; // index of the last slice of the first field
                    n_slices++;
                    break;
                }
                case VC1_CODE_ENTRYPOINT: /* it should be before frame data */
                    buf_size2 = vc1_unescape_buffer(start + 4, size, buf2);
                    init_get_bits(&s->gb, buf2, buf_size2 * 8);
                    ff_vc1_decode_entry_point(avctx, v, &s->gb);
                    break;
                case VC1_CODE_SLICE: {
                    int buf_size3;
                    tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1));
                    if (!tmp)
                        goto err;
                    slices = tmp;
                    slices[n_slices].buf = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
                    if (!slices[n_slices].buf)
                        goto err;
                    buf_size3 = vc1_unescape_buffer(start + 4, size,
                                                    slices[n_slices].buf);
                    init_get_bits(&slices[n_slices].gb, slices[n_slices].buf,
                                  buf_size3 << 3);
                    slices[n_slices].mby_start = get_bits(&slices[n_slices].gb, 9);
                    n_slices++;
                    break;
                }
                }
            }
        } else if (v->interlace && ((buf[0] & 0xC0) == 0xC0)) { /* WVC1 interlaced stores both fields divided by marker */
            const uint8_t *divider;
            int buf_size3;

            divider = find_next_marker(buf, buf + buf_size);
            if ((divider == (buf + buf_size)) || AV_RB32(divider) != VC1_CODE_FIELD) {
                av_log(avctx, AV_LOG_ERROR, "Error in WVC1 interlaced frame\n");
                goto err;
            } else { // found field marker, unescape second field
                if (avctx->hwaccel ||
                    s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
                    buf_start_second_field = divider;
                tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1));
                if (!tmp)
                    goto err;
                slices = tmp;
                slices[n_slices].buf = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
                if (!slices[n_slices].buf)
                    goto err;
                buf_size3 = vc1_unescape_buffer(divider + 4, buf + buf_size - divider - 4, slices[n_slices].buf);
                init_get_bits(&slices[n_slices].gb, slices[n_slices].buf,
                              buf_size3 << 3);
                slices[n_slices].mby_start = s->mb_height + 1 >> 1;
                n_slices1 = n_slices - 1;
                n_slices++;
            }
            buf_size2 = vc1_unescape_buffer(buf, divider - buf, buf2);
        } else {
            buf_size2 = vc1_unescape_buffer(buf, buf_size, buf2);
        }
        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);
        /* res_sprite means a Windows Media Image stream, AV_CODEC_ID_*IMAGE means
           we're using the sprite compositor. These are intentionally kept separate
           so you can get the raw sprites by using the wmv3 decoder for WMVP or
           the vc1 one for WVP2 */
        if (avctx->codec_id == AV_CODEC_ID_WMV3IMAGE || avctx->codec_id == AV_CODEC_ID_VC1IMAGE) {
            if (v->new_sprite) {
                // switch AVCodecContext parameters to those of the sprites
                avctx->width  = avctx->coded_width  = v->sprite_width;
                avctx->height = avctx->coded_height = v->sprite_height;
            } else {
                goto image;
            }
        }
    }

    if (s->context_initialized &&
        (s->width  != avctx->coded_width ||
         s->height != avctx->coded_height)) {
        ff_vc1_decode_end(avctx);
    }

    if (!s->context_initialized) {
        if (ff_msmpeg4_decode_init(avctx) < 0)
            goto err;
        if (ff_vc1_decode_init_alloc_tables(v) < 0) {
            ff_mpv_common_end(s);
            goto err;
        }

        s->low_delay = !avctx->has_b_frames || v->res_sprite;

        if (v->profile == PROFILE_ADVANCED) {
            if(avctx->coded_width<=1 || avctx->coded_height<=1)
                goto err;
            s->h_edge_pos = avctx->coded_width;
            s->v_edge_pos = avctx->coded_height;
        }
    }

    // do parse frame header
    v->pic_header_flag = 0;
    v->first_pic_header_flag = 1;
    if (v->profile < PROFILE_ADVANCED) {
        if (ff_vc1_parse_frame_header(v, &s->gb) < 0) {
            goto err;
        }
    } else {
        if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) {
            goto err;
        }
    }
    v->first_pic_header_flag = 0;

    if (avctx->debug & FF_DEBUG_PICT_INFO)
        av_log(v->s.avctx, AV_LOG_DEBUG, "pict_type: %c\n", av_get_picture_type_char(s->pict_type));

    if ((avctx->codec_id == AV_CODEC_ID_WMV3IMAGE || avctx->codec_id == AV_CODEC_ID_VC1IMAGE)
        && s->pict_type != AV_PICTURE_TYPE_I) {
        av_log(v->s.avctx, AV_LOG_ERROR, "Sprite decoder: expected I-frame\n");
        goto err;
    }

    if ((s->mb_height >> v->field_mode) == 0) {
        av_log(v->s.avctx, AV_LOG_ERROR, "image too short\n");
        goto err;
    }

    // for skipping the frame
    s->current_picture.f->pict_type = s->pict_type;
    s->current_picture.f->key_frame = s->pict_type == AV_PICTURE_TYPE_I;

    /* skip B-frames if we don't have reference frames */
    if (!s->last_picture_ptr && (s->pict_type == AV_PICTURE_TYPE_B || s->droppable)) {
        av_log(v->s.avctx, AV_LOG_DEBUG, "Skipping B frame without reference frames\n");
        goto end;
    }
    if ((avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) ||
        (avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) ||
         avctx->skip_frame >= AVDISCARD_ALL) {
        goto end;
    }

    if (s->next_p_frame_damaged) {
        if (s->pict_type == AV_PICTURE_TYPE_B)
            goto end;
        else
            s->next_p_frame_damaged = 0;
    }

    if (ff_mpv_frame_start(s, avctx) < 0) {
        goto err;
    }

    v->s.current_picture_ptr->field_picture = v->field_mode;
    v->s.current_picture_ptr->f->interlaced_frame = (v->fcm != PROGRESSIVE);
    v->s.current_picture_ptr->f->top_field_first  = v->tff;

    // process pulldown flags
    s->current_picture_ptr->f->repeat_pict = 0;
    // Pulldown flags are only valid when 'broadcast' has been set.
    // So ticks_per_frame will be 2
    if (v->rff) {
        // repeat field
        s->current_picture_ptr->f->repeat_pict = 1;
    } else if (v->rptfrm) {
        // repeat frames
        s->current_picture_ptr->f->repeat_pict = v->rptfrm * 2;
    }

    s->me.qpel_put = s->qdsp.put_qpel_pixels_tab;
    s->me.qpel_avg = s->qdsp.avg_qpel_pixels_tab;

    if ((CONFIG_VC1_VDPAU_DECODER)
        &&s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU) {
        if (v->field_mode && buf_start_second_field) {
            ff_vdpau_vc1_decode_picture(s, buf_start, buf_start_second_field - buf_start);
            ff_vdpau_vc1_decode_picture(s, buf_start_second_field, (buf + buf_size) - buf_start_second_field);
        } else {
            ff_vdpau_vc1_decode_picture(s, buf_start, (buf + buf_size) - buf_start);
        }
    } else if (avctx->hwaccel) {
        if (v->field_mode && buf_start_second_field) {
            // decode first field
            s->picture_structure = PICT_BOTTOM_FIELD - v->tff;
            if (avctx->hwaccel->start_frame(avctx, buf_start, buf_start_second_field - buf_start) < 0)
                goto err;
            if (avctx->hwaccel->decode_slice(avctx, buf_start, buf_start_second_field - buf_start) < 0)
                goto err;
            if (avctx->hwaccel->end_frame(avctx) < 0)
                goto err;

            // decode second field
            s->gb = slices[n_slices1 + 1].gb;
            s->picture_structure = PICT_TOP_FIELD + v->tff;
            v->second_field = 1;
            v->pic_header_flag = 0;
            if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) {
                av_log(avctx, AV_LOG_ERROR, "parsing header for second field failed");
                goto err;
            }
            v->s.current_picture_ptr->f->pict_type = v->s.pict_type;

            if (avctx->hwaccel->start_frame(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field) < 0)
                goto err;
            if (avctx->hwaccel->decode_slice(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field) < 0)
                goto err;
            if (avctx->hwaccel->end_frame(avctx) < 0)
                goto err;
        } else {
            s->picture_structure = PICT_FRAME;
            if (avctx->hwaccel->start_frame(avctx, buf_start, (buf + buf_size) - buf_start) < 0)
                goto err;
            if (avctx->hwaccel->decode_slice(avctx, buf_start, (buf + buf_size) - buf_start) < 0)
                goto err;
            if (avctx->hwaccel->end_frame(avctx) < 0)
                goto err;
        }
    } else {
        int header_ret = 0;

        ff_mpeg_er_frame_start(s);

        v->bits = buf_size * 8;
        v->end_mb_x = s->mb_width;
        if (v->field_mode) {
            s->current_picture.f->linesize[0] <<= 1;
            s->current_picture.f->linesize[1] <<= 1;
            s->current_picture.f->linesize[2] <<= 1;
            s->linesize                      <<= 1;
            s->uvlinesize                    <<= 1;
        }
        mb_height = s->mb_height >> v->field_mode;

        av_assert0 (mb_height > 0);

        for (i = 0; i <= n_slices; i++) {
            if (i > 0 &&  slices[i - 1].mby_start >= mb_height) {
                if (v->field_mode <= 0) {
                    av_log(v->s.avctx, AV_LOG_ERROR, "Slice %d starts beyond "
                           "picture boundary (%d >= %d)\n", i,
                           slices[i - 1].mby_start, mb_height);
                    continue;
                }
                v->second_field = 1;
                av_assert0((s->mb_height & 1) == 0);
                v->blocks_off   = s->b8_stride * (s->mb_height&~1);
                v->mb_off       = s->mb_stride * s->mb_height >> 1;
            } else {
                v->second_field = 0;
                v->blocks_off   = 0;
                v->mb_off       = 0;
            }
            if (i) {
                v->pic_header_flag = 0;
                if (v->field_mode && i == n_slices1 + 2) {
                    if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) {
                        av_log(v->s.avctx, AV_LOG_ERROR, "Field header damaged\n");
                        if (avctx->err_recognition & AV_EF_EXPLODE)
                            goto err;
                        continue;
                    }
                } else if (get_bits1(&s->gb)) {
                    v->pic_header_flag = 1;
                    if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) {
                        av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n");
                        if (avctx->err_recognition & AV_EF_EXPLODE)
                            goto err;
                        continue;
                    }
                }
            }
            if (header_ret < 0)
                continue;
            s->start_mb_y = (i == 0) ? 0 : FFMAX(0, slices[i-1].mby_start % mb_height);
            if (!v->field_mode || v->second_field)
                s->end_mb_y = (i == n_slices     ) ? mb_height : FFMIN(mb_height, slices[i].mby_start % mb_height);
            else {
                if (i >= n_slices) {
                    av_log(v->s.avctx, AV_LOG_ERROR, "first field slice count too large\n");
                    continue;
                }
                s->end_mb_y = (i <= n_slices1 + 1) ? mb_height : FFMIN(mb_height, slices[i].mby_start % mb_height);
            }
            if (s->end_mb_y <= s->start_mb_y) {
                av_log(v->s.avctx, AV_LOG_ERROR, "end mb y %d %d invalid\n", s->end_mb_y, s->start_mb_y);
                continue;
            }
            if (!v->p_frame_skipped && s->pict_type != AV_PICTURE_TYPE_I && !v->cbpcy_vlc) {
                av_log(v->s.avctx, AV_LOG_ERROR, "missing cbpcy_vlc\n");
                continue;
            }
            ff_vc1_decode_blocks(v);
            if (i != n_slices)
                s->gb = slices[i].gb;
        }
        if (v->field_mode) {
            v->second_field = 0;
            s->current_picture.f->linesize[0] >>= 1;
            s->current_picture.f->linesize[1] >>= 1;
            s->current_picture.f->linesize[2] >>= 1;
            s->linesize                      >>= 1;
            s->uvlinesize                    >>= 1;
            if (v->s.pict_type != AV_PICTURE_TYPE_BI && v->s.pict_type != AV_PICTURE_TYPE_B) {
                FFSWAP(uint8_t *, v->mv_f_next[0], v->mv_f[0]);
                FFSWAP(uint8_t *, v->mv_f_next[1], v->mv_f[1]);
            }
        }
        av_dlog(s->avctx, "Consumed %i/%i bits\n",
                get_bits_count(&s->gb), s->gb.size_in_bits);
//  if (get_bits_count(&s->gb) > buf_size * 8)
//      return -1;
        if(s->er.error_occurred && s->pict_type == AV_PICTURE_TYPE_B)
            goto err;
        if (!v->field_mode)
            ff_er_frame_end(&s->er);
    }

    ff_mpv_frame_end(s);

    if (avctx->codec_id == AV_CODEC_ID_WMV3IMAGE || avctx->codec_id == AV_CODEC_ID_VC1IMAGE) {
image:
        avctx->width  = avctx->coded_width  = v->output_width;
        avctx->height = avctx->coded_height = v->output_height;
        if (avctx->skip_frame >= AVDISCARD_NONREF)
            goto end;
#if CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER
        if (vc1_decode_sprites(v, &s->gb))
            goto err;
#endif
        if ((ret = av_frame_ref(pict, v->sprite_output_frame)) < 0)
            goto err;
        *got_frame = 1;
    } else {
        if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
            if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0)
                goto err;
            ff_print_debug_info(s, s->current_picture_ptr, pict);
            *got_frame = 1;
        } else if (s->last_picture_ptr) {
            if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0)
                goto err;
            ff_print_debug_info(s, s->last_picture_ptr, pict);
            *got_frame = 1;
        }
    }

end:
    av_free(buf2);
    for (i = 0; i < n_slices; i++)
        av_free(slices[i].buf);
    av_free(slices);
    return buf_size;

err:
    av_free(buf2);
    for (i = 0; i < n_slices; i++)
        av_free(slices[i].buf);
    av_free(slices);
    return -1;
}


static const AVProfile profiles[] = {
    { FF_PROFILE_VC1_SIMPLE,   "Simple"   },
    { FF_PROFILE_VC1_MAIN,     "Main"     },
    { FF_PROFILE_VC1_COMPLEX,  "Complex"  },
    { FF_PROFILE_VC1_ADVANCED, "Advanced" },
    { FF_PROFILE_UNKNOWN },
};

static const enum AVPixelFormat vc1_hwaccel_pixfmt_list_420[] = {
#if CONFIG_VC1_DXVA2_HWACCEL
    AV_PIX_FMT_DXVA2_VLD,
#endif
#if CONFIG_VC1_VAAPI_HWACCEL
    AV_PIX_FMT_VAAPI_VLD,
#endif
#if CONFIG_VC1_VDPAU_HWACCEL
    AV_PIX_FMT_VDPAU,
#endif
    AV_PIX_FMT_YUV420P,
    AV_PIX_FMT_NONE
};

AVCodec ff_vc1_decoder = {
    .name           = "vc1",
    .long_name      = NULL_IF_CONFIG_SMALL("SMPTE VC-1"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_VC1,
    .priv_data_size = sizeof(VC1Context),
    .init           = vc1_decode_init,
    .close          = ff_vc1_decode_end,
    .decode         = vc1_decode_frame,
    .flush          = ff_mpeg_flush,
    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
    .pix_fmts       = vc1_hwaccel_pixfmt_list_420,
    .profiles       = NULL_IF_CONFIG_SMALL(profiles)
};

#if CONFIG_WMV3_DECODER
AVCodec ff_wmv3_decoder = {
    .name           = "wmv3",
    .long_name      = NULL_IF_CONFIG_SMALL("Windows Media Video 9"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_WMV3,
    .priv_data_size = sizeof(VC1Context),
    .init           = vc1_decode_init,
    .close          = ff_vc1_decode_end,
    .decode         = vc1_decode_frame,
    .flush          = ff_mpeg_flush,
    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
    .pix_fmts       = vc1_hwaccel_pixfmt_list_420,
    .profiles       = NULL_IF_CONFIG_SMALL(profiles)
};
#endif

#if CONFIG_WMV3_VDPAU_DECODER
AVCodec ff_wmv3_vdpau_decoder = {
    .name           = "wmv3_vdpau",
    .long_name      = NULL_IF_CONFIG_SMALL("Windows Media Video 9 VDPAU"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_WMV3,
    .priv_data_size = sizeof(VC1Context),
    .init           = vc1_decode_init,
    .close          = ff_vc1_decode_end,
    .decode         = vc1_decode_frame,
    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_HWACCEL_VDPAU,
    .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_WMV3, AV_PIX_FMT_NONE },
    .profiles       = NULL_IF_CONFIG_SMALL(profiles)
};
#endif

#if CONFIG_VC1_VDPAU_DECODER
AVCodec ff_vc1_vdpau_decoder = {
    .name           = "vc1_vdpau",
    .long_name      = NULL_IF_CONFIG_SMALL("SMPTE VC-1 VDPAU"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_VC1,
    .priv_data_size = sizeof(VC1Context),
    .init           = vc1_decode_init,
    .close          = ff_vc1_decode_end,
    .decode         = vc1_decode_frame,
    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_HWACCEL_VDPAU,
    .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_VC1, AV_PIX_FMT_NONE },
    .profiles       = NULL_IF_CONFIG_SMALL(profiles)
};
#endif

#if CONFIG_WMV3IMAGE_DECODER
AVCodec ff_wmv3image_decoder = {
    .name           = "wmv3image",
    .long_name      = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_WMV3IMAGE,
    .priv_data_size = sizeof(VC1Context),
    .init           = vc1_decode_init,
    .close          = ff_vc1_decode_end,
    .decode         = vc1_decode_frame,
    .capabilities   = CODEC_CAP_DR1,
    .flush          = vc1_sprite_flush,
    .pix_fmts       = (const enum AVPixelFormat[]) {
        AV_PIX_FMT_YUV420P,
        AV_PIX_FMT_NONE
    },
};
#endif

#if CONFIG_VC1IMAGE_DECODER
AVCodec ff_vc1image_decoder = {
    .name           = "vc1image",
    .long_name      = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image v2"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_VC1IMAGE,
    .priv_data_size = sizeof(VC1Context),
    .init           = vc1_decode_init,
    .close          = ff_vc1_decode_end,
    .decode         = vc1_decode_frame,
    .capabilities   = CODEC_CAP_DR1,
    .flush          = vc1_sprite_flush,
    .pix_fmts       = (const enum AVPixelFormat[]) {
        AV_PIX_FMT_YUV420P,
        AV_PIX_FMT_NONE
    },
};
#endif