root/modules/xvid_dec/xvid_wce/bitstream.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ByteSwap
  2. Init
  3. ShowBits
  4. Skip
  5. ShowBitsFromByteAlign
  6. GetBits
  7. get_matrix
  8. read_video_packet_header
  9. read_vol_complexity_estimation_header
  10. read_vop_complexity_estimation_header
  11. BitstreamReadHeaders

/*****************************************************************************
 *
 *  XVID MPEG-4 VIDEO CODEC
 *  - Bitstream reader/writer -
 *
 *  Copyright (C) 2001-2003 Peter Ross <pross@xvid.org>
 *                     2003 Cristoph Lampert <gruel@web.de>
 *
 *  This program is free software ; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation ; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program ; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * $Id: bitstream.cpp,v 1.1.1.1 2005-07-13 14:36:12 jeanlf Exp $
 *
 ****************************************************************************/

#include "bitstream.h"
#include "quant_matrix.h"

#ifdef WIN32
#include <stdio.h>
#endif

//----------------------------

inline dword ByteSwap(dword a) {
        return (a<<24) | ((a&0xff00) << 8) | ((a&0xff0000) >> 8) | (a>>24);
}

//----------------------------

void Bitstream::Init(const void *bitstream, dword _length) {

        dword adjbitstream = (dword)bitstream;

        /*
         * Start the stream on a dword boundary, by rounding down to the
         * previous dword and skipping the intervening bytes.
         */
        long bitpos = ((sizeof(dword)-1) & (long)bitstream);
        adjbitstream = adjbitstream - bitpos;
        start = tail = (dword *) adjbitstream;

        if(_length) {
                dword tmp = *start;
#ifndef ARCH_IS_BIG_ENDIAN
                tmp = ByteSwap(tmp);
#endif
                bufa = tmp;
                if(_length>4) {
                        tmp = *(start + 1);
#ifndef ARCH_IS_BIG_ENDIAN
                        tmp = ByteSwap(tmp);
#endif
                        bufb = tmp;
                } else
                        bufb = 0;
        } else
                bufa = bufb = 0;

        buf = 0;
        pos = initpos = bitpos*8;
        length = _length;
}

//---------------------------

/* reads n bits from bitstream without changing the stream pos */

dword Bitstream::ShowBits(dword bits) {

        int nbit = (bits + pos) - 32;
        if(nbit > 0)
                return ((bufa & (0xffffffff >> pos)) << nbit) | (bufb >> (32 - nbit));
        return (bufa & (0xffffffff >> pos)) >> (32 - pos - bits);
}

//---------------------------
// skip n bits forward in bitstream
void Bitstream::Skip(dword bits) {

        pos += bits;
        if(pos >= 32) {
                dword tmp;

                bufa = bufb;
                tmp = *((dword *) tail + 2);
#ifndef ARCH_IS_BIG_ENDIAN
                tmp = ByteSwap(tmp);
#endif
                bufb = tmp;
                tail++;
                pos -= 32;
        }
}

//---------------------------
/* show nbits from next byte alignment */
dword Bitstream::ShowBitsFromByteAlign(int bits) {

        int bspos = pos + NumBitsToByteAlign();
        int nbit = (bits + bspos) - 32;

        if (bspos >= 32) {
                return bufb >> (32 - nbit);
        } else   if (nbit > 0) {
                return ((bufa & (0xffffffff >> bspos)) << nbit) | (bufb >> (32 - nbit));
        } else {
                return (bufa & (0xffffffff >> bspos)) >> (32 - bspos - bits);
        }

}

//---------------------------
/* read n bits from bitstream */
dword Bitstream::GetBits(dword n) {
        dword ret = ShowBits(n);
        Skip(n);
        return ret;
}

//---------------------------

static const dword intra_dc_threshold_table[] = {
        32,                     /* never use */
        13,
        15,
        17,
        19,
        21,
        23,
        1,
};

//----------------------------

void Bitstream::get_matrix(byte * matrix) {

        int i = 0;
        int last, value = 0;

        do {
                last = value;
                value = GetBits(8);
                matrix[scan_tables[0][i++]] = value;
        }
        while (value != 0 && i < 64);
        i--;    /* fix little bug at coeff not full */

        while (i < 64) {
                matrix[scan_tables[0][i++]] = last;
        }
}

//----------------------------
/*
 * for PVOP addbits == fcode - 1
 * for BVOP addbits == max(fcode,bcode) - 1
 * returns mbpos
 */
int S_decoder::read_video_packet_header(Bitstream *bs, const int addbits, int *quant, int *fcode_forward, int *fcode_backward, int *intra_dc_threshold) {

        int startcode_bits = NUMBITS_VP_RESYNC_MARKER + addbits;
        int mbnum_bits = log2bin(mb_width *  mb_height - 1);
        int mbnum;
        int hec = 0;

        bs->Skip(bs->NumBitsToByteAlign());
        bs->Skip(startcode_bits);

        DPRINTF(XVID_DEBUG_STARTCODE, "<video_packet_header>\n");

        if (shape != VIDOBJLAY_SHAPE_RECTANGULAR)
        {
                hec = bs->GetBit();     /* header_extension_code */
                if (hec && !(sprite_enable == SPRITE_STATIC /* && current_coding_type = I_VOP */))
                {
                        bs->Skip(13);        /* vop_width */
                        READ_MARKER();
                        bs->Skip(13);        /* vop_height */
                        READ_MARKER();
                        bs->Skip(13);        /* vop_horizontal_mc_spatial_ref */
                        READ_MARKER();
                        bs->Skip(13);        /* vop_vertical_mc_spatial_ref */
                        READ_MARKER();
                }
        }

        mbnum = bs->GetBits(mbnum_bits);    /* macroblock_number */
        DPRINTF(XVID_DEBUG_HEADER, "mbnum %i\n", mbnum);

        if (shape != VIDOBJLAY_SHAPE_BINARY_ONLY)
        {
                *quant = bs->GetBits(quant_bits);   /* quant_scale */
                DPRINTF(XVID_DEBUG_HEADER, "quant %i\n", *quant);
        }

        if (shape == VIDOBJLAY_SHAPE_RECTANGULAR)
                hec = bs->GetBit();     /* header_extension_code */


        DPRINTF(XVID_DEBUG_HEADER, "header_extension_code %i\n", hec);
        if (hec)
        {
                int time_base;
                int time_increment = 0;
                int coding_type;

                for (time_base=0; bs->GetBit()!=0; time_base++);      /* modulo_time_base */
                READ_MARKER();
                if (time_inc_bits)
                        time_increment = (bs->GetBits(time_inc_bits));  /* vop_time_increment */
                READ_MARKER();
                //DPRINTF(XVID_DEBUG_HEADER,"time %i:%i\n", time_base, time_increment);

                coding_type = bs->GetBits(2);
                DPRINTF(XVID_DEBUG_HEADER,"coding_type %i\n", coding_type);

                if (shape != VIDOBJLAY_SHAPE_RECTANGULAR)
                {
                        bs->Skip(1);   /* change_conv_ratio_disable */
                        if (coding_type != I_VOP)
                                bs->Skip(1);   /* vop_shape_coding_type */
                }

                if (shape != VIDOBJLAY_SHAPE_BINARY_ONLY)
                {
                        *intra_dc_threshold = intra_dc_threshold_table[bs->GetBits(3)];

                        if (sprite_enable == SPRITE_GMC && coding_type == S_VOP &&
                                sprite_warping_points > 0)
                        {
                                /* TODO: sprite trajectory */
                        }
                        if(reduced_resolution_enable && shape == VIDOBJLAY_SHAPE_RECTANGULAR && (coding_type == P_VOP || coding_type == I_VOP)) {
                                bs->Skip(1); /* XXX: vop_reduced_resolution */
                        }

                        if (coding_type != I_VOP && fcode_forward)
                        {
                                *fcode_forward = bs->GetBits(3);
                                DPRINTF(XVID_DEBUG_HEADER,"fcode_forward %i\n", *fcode_forward);
                        }

                        if (coding_type == B_VOP && fcode_backward)
                        {
                                *fcode_backward = bs->GetBits(3);
                                DPRINTF(XVID_DEBUG_HEADER,"fcode_backward %i\n", *fcode_backward);
                        }
                }

        }

        if (newpred_enable) {
                int vop_id;
                int vop_id_for_prediction;

                vop_id = bs->GetBits(MIN(time_inc_bits + 3, 15));
                DPRINTF(XVID_DEBUG_HEADER, "vop_id %i\n", vop_id);
                if (bs->GetBit()) /* vop_id_for_prediction_indication */
                {
                        vop_id_for_prediction = bs->GetBits(MIN(time_inc_bits + 3, 15));
                        DPRINTF(XVID_DEBUG_HEADER, "vop_id_for_prediction %i\n", vop_id_for_prediction);
                }
                READ_MARKER();
        }

        return mbnum;
}

//----------------------------
/* vol estimation header */
void S_decoder::read_vol_complexity_estimation_header(Bitstream * bs) {

        ESTIMATION * e = &estimation;

        e->method = bs->GetBits(2);   /* estimation_method */
        DPRINTF(XVID_DEBUG_HEADER,"+ complexity_estimation_header; method=%i\n", e->method);

        if (e->method == 0 || e->method == 1) {
                if(!bs->GetBit()) {
                        //shape_complexity_estimation_disable
                        e->opaque = bs->GetBit();     /* opaque */
                        e->transparent = bs->GetBit();      /* transparent */
                        e->intra_cae = bs->GetBit();     /* intra_cae */
                        e->inter_cae = bs->GetBit();     /* inter_cae */
                        e->no_update = bs->GetBit();     /* no_update */
                        e->upsampling = bs->GetBit();    /* upsampling */
                }

                if (!bs->GetBit())   /* texture_complexity_estimation_set_1_disable */
                {
                        e->intra_blocks = bs->GetBit();     /* intra_blocks */
                        e->inter_blocks = bs->GetBit();     /* inter_blocks */
                        e->inter4v_blocks = bs->GetBit();      /* inter4v_blocks */
                        e->not_coded_blocks = bs->GetBit();    /* not_coded_blocks */
                }
        }

        READ_MARKER();

        if (!bs->GetBit()) {
                //texture_complexity_estimation_set_2_disable
                e->dct_coefs = bs->GetBit();     /* dct_coefs */
                e->dct_lines = bs->GetBit();     /* dct_lines */
                e->vlc_symbols = bs->GetBit();      /* vlc_symbols */
                e->vlc_bits = bs->GetBit();      /* vlc_bits */
        }

        if (!bs->GetBit()) {
                //motion_compensation_complexity_disable
                e->apm = bs->GetBit();     /* apm */
                e->npm = bs->GetBit();     /* npm */
                e->interpolate_mc_q = bs->GetBit();    /* interpolate_mc_q */
                e->forw_back_mc_q = bs->GetBit();      /* forw_back_mc_q */
                e->halfpel2 = bs->GetBit();      /* halfpel2 */
                e->halfpel4 = bs->GetBit();      /* halfpel4 */
        }

        READ_MARKER();

        if (e->method == 1) {
                if (!bs->GetBit()) {
                        //version2_complexity_estimation_disable
                        e->sadct = bs->GetBit();      /* sadct */
                        e->quarterpel = bs->GetBit();    /* quarterpel */
                }
        }
}

//----------------------------
/* vop estimation header */
void S_decoder::read_vop_complexity_estimation_header(Bitstream * bs, int coding_type) {

        ESTIMATION * e = &estimation;

        if (e->method == 0 || e->method == 1)
        {
                if (coding_type == I_VOP) {
                        if (e->opaque)    bs->Skip(8);   /* dcecs_opaque */
                        if (e->transparent) bs->Skip(8); /* */
                        if (e->intra_cae) bs->Skip(8);   /* */
                        if (e->inter_cae) bs->Skip(8);   /* */
                        if (e->no_update) bs->Skip(8);   /* */
                        if (e->upsampling)   bs->Skip(8);   /* */
                        if (e->intra_blocks) bs->Skip(8);   /* */
                        if (e->not_coded_blocks) bs->Skip(8);  /* */
                        if (e->dct_coefs) bs->Skip(8);   /* */
                        if (e->dct_lines) bs->Skip(8);   /* */
                        if (e->vlc_symbols) bs->Skip(8); /* */
                        if (e->vlc_bits)  bs->Skip(8);   /* */
                        if (e->sadct)     bs->Skip(8);   /* */
                }

                if (coding_type == P_VOP) {
                        if (e->opaque) bs->Skip(8);      /* */
                        if (e->transparent) bs->Skip(8); /* */
                        if (e->intra_cae) bs->Skip(8);   /* */
                        if (e->inter_cae) bs->Skip(8);   /* */
                        if (e->no_update) bs->Skip(8);   /* */
                        if (e->upsampling) bs->Skip(8);  /* */
                        if (e->intra_blocks) bs->Skip(8);   /* */
                        if (e->not_coded_blocks)   bs->Skip(8);   /* */
                        if (e->dct_coefs) bs->Skip(8);   /* */
                        if (e->dct_lines) bs->Skip(8);   /* */
                        if (e->vlc_symbols) bs->Skip(8); /* */
                        if (e->vlc_bits)  bs->Skip(8);   /* */
                        if (e->inter_blocks) bs->Skip(8);   /* */
                        if (e->inter4v_blocks) bs->Skip(8); /* */
                        if (e->apm)       bs->Skip(8);   /* */
                        if (e->npm)       bs->Skip(8);   /* */
                        if (e->forw_back_mc_q) bs->Skip(8); /* */
                        if (e->halfpel2)  bs->Skip(8);   /* */
                        if (e->halfpel4)  bs->Skip(8);   /* */
                        if (e->sadct)     bs->Skip(8);   /* */
                        if (e->quarterpel)   bs->Skip(8);   /* */
                }
                if (coding_type == B_VOP) {
                        if (e->opaque)    bs->Skip(8);   /* */
                        if (e->transparent)  bs->Skip(8);   /* */
                        if (e->intra_cae) bs->Skip(8);   /* */
                        if (e->inter_cae) bs->Skip(8);   /* */
                        if (e->no_update) bs->Skip(8);   /* */
                        if (e->upsampling)   bs->Skip(8);   /* */
                        if (e->intra_blocks) bs->Skip(8);   /* */
                        if (e->not_coded_blocks) bs->Skip(8);  /* */
                        if (e->dct_coefs) bs->Skip(8);   /* */
                        if (e->dct_lines) bs->Skip(8);   /* */
                        if (e->vlc_symbols)  bs->Skip(8);   /* */
                        if (e->vlc_bits)  bs->Skip(8);   /* */
                        if (e->inter_blocks) bs->Skip(8);   /* */
                        if (e->inter4v_blocks) bs->Skip(8); /* */
                        if (e->apm)       bs->Skip(8);   /* */
                        if (e->npm)       bs->Skip(8);   /* */
                        if (e->forw_back_mc_q) bs->Skip(8); /* */
                        if (e->halfpel2)  bs->Skip(8);   /* */
                        if (e->halfpel4)  bs->Skip(8);   /* */
                        if (e->interpolate_mc_q) bs->Skip(8);  /* */
                        if (e->sadct)     bs->Skip(8);   /* */
                        if (e->quarterpel)   bs->Skip(8);   /* */
                }

                if (coding_type == S_VOP && sprite_enable == SPRITE_STATIC) {
                        if (e->intra_blocks) bs->Skip(8);   /* */
                        if (e->not_coded_blocks) bs->Skip(8);  /* */
                        if (e->dct_coefs) bs->Skip(8);   /* */
                        if (e->dct_lines) bs->Skip(8);   /* */
                        if (e->vlc_symbols)  bs->Skip(8);   /* */
                        if (e->vlc_bits)  bs->Skip(8);   /* */
                        if (e->inter_blocks) bs->Skip(8);   /* */
                        if (e->inter4v_blocks)  bs->Skip(8);   /* */
                        if (e->apm)       bs->Skip(8);   /* */
                        if (e->npm)       bs->Skip(8);   /* */
                        if (e->forw_back_mc_q)  bs->Skip(8);   /* */
                        if (e->halfpel2)  bs->Skip(8);   /* */
                        if (e->halfpel4)  bs->Skip(8);   /* */
                        if (e->interpolate_mc_q) bs->Skip(8);  /* */
                }
        }
}

//----------------------------
// decode headers
// returns coding_type, or -1 if error

#define VIDOBJ_START_CODE_MASK      0x0000001f
#define VIDOBJLAY_START_CODE_MASK   0x0000000f

int S_decoder::BitstreamReadHeaders(Bitstream * bs, bool &rounding, bool *reduced_resolution, dword *quant, dword *fcode_forward,
                                    dword *fcode_backward, dword *intra_dc_threshold, WARPPOINTS *gmc_warp) {

        dword vol_ver_id;
        dword coding_type;
        dword start_code;
        dword time_incr = 0;
        int time_increment = 0;
        int resize = 0;

        while((bs->Pos() >> 3) < bs->length) {
                bs->ByteAlign();
                start_code = bs->ShowBits(32);

                switch(start_code) {
                case VISOBJSEQ_START_CODE:
                {
                        DPRINTF(XVID_DEBUG_STARTCODE, "<visual_object_sequence>\n");

                        bs->Skip(32);     //visual_object_sequence_start_code
                        int profile = bs->GetBits(8);  //profile_and_level_indication

                        DPRINTF(XVID_DEBUG_HEADER, "profile_and_level_indication %i\n", profile);
                }
                break;
                case VISOBJSEQ_STOP_CODE:
                {
                        //visual_object_sequence_stop_code
                        bs->Skip(32);
                        DPRINTF(XVID_DEBUG_STARTCODE, "</visual_object_sequence>\n");

                }
                break;
                case VISOBJ_START_CODE:
                {
                        DPRINTF(XVID_DEBUG_STARTCODE, "<visual_object>\n");

                        bs->Skip(32);  //visual_object_start_code

                        int visobj_ver_id;
                        //is_visual_object_identified
                        if(bs->GetBit()) {
                                visobj_ver_id = bs->GetBits(4);  /* visual_object_ver_id */
                                DPRINTF(XVID_DEBUG_HEADER,"visobj_ver_id %i\n", visobj_ver_id);
                                bs->Skip(3);   //visual_object_priority
                        } else {
                                visobj_ver_id = 1;
                        }

                        if(bs->ShowBits(4) != VISOBJ_TYPE_VIDEO) {
                                //visual_object_type
                                DPRINTF(XVID_DEBUG_ERROR, "visual_object_type != video\n");
                                return -1;
                        }
                        bs->Skip(4);
                        //video_signal_type

                        if(bs->GetBit()) {
                                DPRINTF(XVID_DEBUG_HEADER,"+ video_signal_type\n");
                                bs->Skip(3);   /* video_format */
                                bs->Skip(1);   /* video_range */
                                if (bs->GetBit()) /* color_description */
                                {
                                        DPRINTF(XVID_DEBUG_HEADER,"+ color_description");
                                        bs->Skip(8);   /* color_primaries */
                                        bs->Skip(8);   /* transfer_characteristics */
                                        bs->Skip(8);   /* matrix_coefficients */
                                }
                        }
                }
                break;
                case GRPOFVOP_START_CODE:
                {
                        DPRINTF(XVID_DEBUG_STARTCODE, "<group_of_vop>\n");

                        bs->Skip(32);
                        {
                                int hours, minutes, seconds;

                                hours = bs->GetBits(5);
                                minutes = bs->GetBits(6);
                                READ_MARKER();
                                seconds = bs->GetBits(6);
                                //DPRINTF(XVID_DEBUG_HEADER, "time %ih%im%is\n", hours,minutes,seconds);
                        }
                        bs->Skip(1);   /* closed_gov */
                        bs->Skip(1);   /* broken_link */
                }
                break;
                case VOP_START_CODE:
                {

                        DPRINTF(XVID_DEBUG_STARTCODE, "<vop>\n");

                        bs->Skip(32);  /* vop_start_code */

                        coding_type = bs->GetBits(2); /* vop_coding_type */
                        DPRINTF(XVID_DEBUG_HEADER, "coding_type %i\n", coding_type);

                        /*********************** for decode B-frame time ***********************/
                        while (bs->GetBit() != 0)  /* time_base */
                                time_incr++;

                        READ_MARKER();

                        if (time_inc_bits) {
                                time_increment = (bs->GetBits(time_inc_bits));  /* vop_time_increment */
                        }

                        DPRINTF(XVID_DEBUG_HEADER, "time_base %i\n", time_incr);
                        DPRINTF(XVID_DEBUG_HEADER, "time_increment %i\n", time_increment);

                        //DPRINTF(XVID_DEBUG_TIMECODE, "%c %i:%i\n", coding_type == I_VOP ? 'I' : coding_type == P_VOP ? 'P' : coding_type == B_VOP ? 'B' : 'S', time_incr, time_increment);
                        if (coding_type != B_VOP) {
                                last_time_base = time_base;
                                time_base += time_incr;
                                time = time_increment;

#if 0
                                time_base * time_inc_resolution +
                                time_increment;
#endif
                                time_pp = (dword)
                                          (time_inc_resolution + time - last_non_b_time)%time_inc_resolution;
                                last_non_b_time = time;
                        } else {
                                time = time_increment;
#if 0
                                (last_time_base +
                                 time_incr) * time_inc_resolution + time_increment;
#endif
                                time_bp = (dword)
                                          (time_inc_resolution + last_non_b_time - time)%time_inc_resolution;
                        }
                        DPRINTF(XVID_DEBUG_HEADER,"time_pp=%i\n", time_pp);
                        DPRINTF(XVID_DEBUG_HEADER,"time_bp=%i\n", time_bp);

                        READ_MARKER();

                        if (!bs->GetBit())   /* vop_coded */
                        {
                                DPRINTF(XVID_DEBUG_HEADER, "vop_coded==false\n");
                                return N_VOP;
                        }

                        if (newpred_enable) {
                                int vop_id;
                                int vop_id_for_prediction;

                                vop_id = bs->GetBits(MIN(time_inc_bits + 3, 15));
                                DPRINTF(XVID_DEBUG_HEADER, "vop_id %i\n", vop_id);
                                if (bs->GetBit()) /* vop_id_for_prediction_indication */
                                {
                                        vop_id_for_prediction = bs->GetBits(MIN(time_inc_bits + 3, 15));
                                        DPRINTF(XVID_DEBUG_HEADER, "vop_id_for_prediction %i\n", vop_id_for_prediction);
                                }
                                READ_MARKER();
                        }

                        //fix a little bug by MinChen <chenm002@163.com>
                        if((shape != VIDOBJLAY_SHAPE_BINARY_ONLY) &&
                                ((coding_type == P_VOP) || (coding_type == S_VOP && sprite_enable == SPRITE_GMC))) {
                                rounding = !!bs->GetBit();  //rounding_type
                                DPRINTF(XVID_DEBUG_HEADER, "rounding %i\n", rounding);
                        }

                        if(reduced_resolution_enable && shape == VIDOBJLAY_SHAPE_RECTANGULAR && (coding_type == P_VOP || coding_type == I_VOP)) {

                                *reduced_resolution = !!bs->GetBit();
                                DPRINTF(XVID_DEBUG_HEADER, "reduced_resolution %i\n", *reduced_resolution);
                        } else {
                                *reduced_resolution = false;
                        }

                        if (shape != VIDOBJLAY_SHAPE_RECTANGULAR) {
                                if(!(sprite_enable == SPRITE_STATIC && coding_type == I_VOP)) {

                                        dword width, height;
                                        dword horiz_mc_ref, vert_mc_ref;

                                        width = bs->GetBits(13);
                                        READ_MARKER();
                                        height = bs->GetBits(13);
                                        READ_MARKER();
                                        horiz_mc_ref = bs->GetBits(13);
                                        READ_MARKER();
                                        vert_mc_ref = bs->GetBits(13);
                                        READ_MARKER();

                                        DPRINTF(XVID_DEBUG_HEADER, "width %i\n", width);
                                        DPRINTF(XVID_DEBUG_HEADER, "height %i\n", height);
                                        DPRINTF(XVID_DEBUG_HEADER, "horiz_mc_ref %i\n", horiz_mc_ref);
                                        DPRINTF(XVID_DEBUG_HEADER, "vert_mc_ref %i\n", vert_mc_ref);
                                }

                                bs->Skip(1);   /* change_conv_ratio_disable */
                                if (bs->GetBit()) /* vop_constant_alpha */
                                {
                                        bs->Skip(8);   /* vop_constant_alpha_value */
                                }
                        }

                        if (shape != VIDOBJLAY_SHAPE_BINARY_ONLY) {

                                if (!complexity_estimation_disable)
                                {
                                        read_vop_complexity_estimation_header(bs, coding_type);
                                }

                                /* intra_dc_vlc_threshold */
                                *intra_dc_threshold =
                                    intra_dc_threshold_table[bs->GetBits(3)];

                                top_field_first = 0;
                                alternate_vertical_scan = 0;

                                if(interlacing) {
                                        top_field_first = bs->GetBit();
                                        DPRINTF(XVID_DEBUG_HEADER, "interlace top_field_first %i\n", top_field_first);
                                        alternate_vertical_scan = bs->GetBit();
                                        DPRINTF(XVID_DEBUG_HEADER, "interlace alternate_vertical_scan %i\n", alternate_vertical_scan);

                                }
                        }

                        if ((sprite_enable == SPRITE_STATIC || sprite_enable== SPRITE_GMC) && coding_type == S_VOP) {

                                int i;

                                for (i = 0 ; i < sprite_warping_points; i++)
                                {
                                        int length;
                                        int x = 0, y = 0;

                                        /* sprite code borowed from ffmpeg; thx Michael Niedermayer <michaelni@gmx.at> */
                                        length = bs->bs_get_spritetrajectory();
                                        if(length) {
                                                x= bs->GetBits(length);
                                                if ((x >> (length - 1)) == 0) /* if MSB not set it is negative*/
                                                        x = - (x ^ ((1 << length) - 1));
                                        }
                                        READ_MARKER();

                                        length = bs->bs_get_spritetrajectory();
                                        if(length) {
                                                y = bs->GetBits(length);
                                                if ((y >> (length - 1)) == 0) /* if MSB not set it is negative*/
                                                        y = - (y ^ ((1 << length) - 1));
                                        }
                                        READ_MARKER();

                                        gmc_warp->duv[i].x = x;
                                        gmc_warp->duv[i].y = y;

                                        //DPRINTF(XVID_DEBUG_HEADER,"sprite_warping_point[%i] xy=(%i,%i)\n", i, x, y);
                                }

                                if (sprite_brightness_change)
                                {
                                        /* XXX: brightness_change_factor() */
                                }
                                if (sprite_enable == SPRITE_STATIC)
                                {
                                        /* XXX: todo */
                                }

                        }

                        if ((*quant = bs->GetBits(quant_bits)) < 1)  /* vop_quant */
                                *quant = 1;
                        DPRINTF(XVID_DEBUG_HEADER, "quant %i\n", *quant);

                        if (coding_type != I_VOP) {
                                *fcode_forward = bs->GetBits(3); /* fcode_forward */
                                DPRINTF(XVID_DEBUG_HEADER, "fcode_forward %i\n", *fcode_forward);
                        }

                        if (coding_type == B_VOP) {
                                *fcode_backward = bs->GetBits(3);   /* fcode_backward */
                                DPRINTF(XVID_DEBUG_HEADER, "fcode_backward %i\n", *fcode_backward);
                        }
                        if(!scalability) {
                                if ((shape != VIDOBJLAY_SHAPE_RECTANGULAR) &&
                                        (coding_type != I_VOP)) {
                                        bs->Skip(1);   /* vop_shape_coding_type */
                                }
                        }
                        return coding_type;

                }
                break;
                case USERDATA_START_CODE:
                {
                        char tmp[256];
                        int i;

                        bs->Skip(32);  /* user_data_start_code */

                        tmp[0] = bs->ShowBits(8);

                        for(i = 1; i < 256; i++) {
                                tmp[i] = (bs->ShowBits(16) & 0xFF);

                                if(tmp[i] == 0)
                                        break;

                                bs->Skip(8);
                        }

                        //DPRINTF(XVID_DEBUG_STARTCODE, "<user_data>: %s\n", tmp);

                        /* read xvid bitstream version */
#ifdef WIN32
                        {
                                char packed;
                                int version, build;
                                if(MemCmp(tmp, "XviD", 4) == 0) {
                                        sscanf(tmp, "XviD%d", &bs_version);
                                        DPRINTF(XVID_DEBUG_HEADER, "xvid bitstream version=%i", bs_version);
                                }

                                /* divx detection */
                                i = sscanf(tmp, "DivX%dBuild%d%c", &version, &build, &packed);
                                if (i < 2)
                                        i = sscanf(tmp, "DivX%db%d%c", &version, &build, &packed);
                                if (i >= 2) {
                                        packed_mode = (i == 3 && packed == 'p');
                                        //DPRINTF(XVID_DEBUG_HEADER, "divx version=%i, build=%i packed=%i\n", version, build, packed_mode);
                                }
                        }
#endif
                }
                break;
                default:
                        switch(start_code & ~VIDOBJ_START_CODE_MASK) {
                        case VIDOBJ_START_CODE:
                        {

                                DPRINTF(XVID_DEBUG_STARTCODE, "<video_object>\n");
                                DPRINTF(XVID_DEBUG_HEADER, "vo id %i\n", start_code & VIDOBJ_START_CODE_MASK);
                                //video_object_start_code
                                bs->Skip(32);
                        }
                        break;
                        case VIDOBJLAY_START_CODE:
                        {

                                DPRINTF(XVID_DEBUG_STARTCODE, "<video_object_layer>\n");
                                DPRINTF(XVID_DEBUG_HEADER, "vol id %i\n", start_code & VIDOBJLAY_START_CODE_MASK);

                                bs->Skip(32);  //video_object_layer_start_code
                                bs->Skip(1);   //random_accessible_vol

                                bs->Skip(8);   //video_object_type_indication

                                if(bs->GetBit()) {
                                        //is_object_layer_identifier
                                        DPRINTF(XVID_DEBUG_HEADER, "+ is_object_layer_identifier\n");
                                        vol_ver_id = bs->GetBits(4);  /* video_object_layer_verid */
                                        DPRINTF(XVID_DEBUG_HEADER,"ver_id %i\n", vol_ver_id);
                                        bs->Skip(3);   /* video_object_layer_priority */
                                } else {
                                        vol_ver_id = 1;
                                }

                                aspect_ratio = bs->GetBits(4);

                                if(aspect_ratio == VIDOBJLAY_AR_EXTPAR) {
                                        //aspect_ratio_info
                                        DPRINTF(XVID_DEBUG_HEADER, "+ aspect_ratio_info\n");
                                        par_width = bs->GetBits(8);   /* par_width */
                                        par_height = bs->GetBits(8);  /* par_height */
                                }

                                if(bs->GetBit()) {
                                        //vol_control_parameters
                                        DPRINTF(XVID_DEBUG_HEADER, "+ vol_control_parameters\n");
                                        bs->Skip(2);   /* chroma_format */
                                        low_delay = (bs->GetBit()!=0);
                                        DPRINTF(XVID_DEBUG_HEADER, "low_delay %i\n", (int)low_delay);
                                        if (bs->GetBit()) /* vbv_parameters */
                                        {
                                                unsigned int bitrate;
                                                unsigned int buffer_size;
                                                unsigned int occupancy;

                                                DPRINTF(XVID_DEBUG_HEADER,"+ vbv_parameters\n");

                                                bitrate = bs->GetBits(15) << 15; /* first_half_bit_rate */
                                                READ_MARKER();
                                                bitrate |= bs->GetBits(15);      /* latter_half_bit_rate */
                                                READ_MARKER();

                                                buffer_size = bs->GetBits(15) << 3; /* first_half_vbv_buffer_size */
                                                READ_MARKER();
                                                buffer_size |= bs->GetBits(3);      /* latter_half_vbv_buffer_size */

                                                occupancy = bs->GetBits(11) << 15;  /* first_half_vbv_occupancy */
                                                READ_MARKER();
                                                occupancy |= bs->GetBits(15); /* latter_half_vbv_occupancy */
                                                READ_MARKER();

                                                DPRINTF(XVID_DEBUG_HEADER,"bitrate %d (unit=400 bps)\n", bitrate);
                                                DPRINTF(XVID_DEBUG_HEADER,"buffer_size %d (unit=16384 bits)\n", buffer_size);
                                                DPRINTF(XVID_DEBUG_HEADER,"occupancy %d (unit=64 bits)\n", occupancy);
                                        }
                                } else {
                                        low_delay = low_delay_default;
                                }

                                //video_object_layer_shape
                                shape = bs->GetBits(2);

                                DPRINTF(XVID_DEBUG_HEADER, "shape %i\n", shape);
                                if(shape != VIDOBJLAY_SHAPE_RECTANGULAR) {
                                        DPRINTF(XVID_DEBUG_ERROR,"non-rectangular shapes are not supported\n");
                                }

                                if(shape == VIDOBJLAY_SHAPE_GRAYSCALE && vol_ver_id != 1) {
                                        //video_object_layer_shape_extension
                                        bs->Skip(4);
                                }

                                READ_MARKER();

                                /********************** for decode B-frame time ***********************/
                                time_inc_resolution = bs->GetBits(16); /* vop_time_increment_resolution */
                                DPRINTF(XVID_DEBUG_HEADER,"vop_time_increment_resolution %i\n", time_inc_resolution);

#if 0
                                time_inc_resolution--;
#endif

                                if(time_inc_resolution > 0) {
                                        time_inc_bits = log2bin(time_inc_resolution-1);
                                } else {
#if 0
                                        time_inc_bits = 0;
#endif
                                        /* for "old" xvid compatibility, set time_inc_bits = 1 */
                                        time_inc_bits = 1;
                                }

                                READ_MARKER();

                                if(bs->GetBit()) {
                                        //fixed_vop_rate
                                        DPRINTF(XVID_DEBUG_HEADER, "+ fixed_vop_rate\n");
                                        bs->Skip(time_inc_bits);   //fixed_vop_time_increment
                                }

                                if(shape != VIDOBJLAY_SHAPE_BINARY_ONLY) {

                                        if(shape == VIDOBJLAY_SHAPE_RECTANGULAR) {
                                                dword _width, _height;

                                                READ_MARKER();
                                                _width = bs->GetBits(13);  //video_object_layer_width
                                                READ_MARKER();
                                                _height = bs->GetBits(13); //video_object_layer_height
                                                READ_MARKER();

                                                DPRINTF(XVID_DEBUG_HEADER, "width %i\n", _width);
                                                DPRINTF(XVID_DEBUG_HEADER, "height %i\n", _height);

                                                if(width != _width || height != _height) {
                                                        if(fixed_dimensions) {
                                                                DPRINTF(XVID_DEBUG_ERROR, "decoder width/height does not match bitstream\n");
                                                                return -1;
                                                        }
                                                        resize = 1;
                                                        width = _width;
                                                        height = _height;
                                                }
                                        }

                                        interlacing = !!bs->GetBit();
                                        DPRINTF(XVID_DEBUG_HEADER, "interlacing %i\n", interlacing);

                                        if(!bs->GetBit()) {
                                                //obmc_disable
                                                DPRINTF(XVID_DEBUG_ERROR, "obmc_disabled==false not supported\n");
                                                /* TODO */
                                                /* fucking divx4.02 has this enabled */
                                        }

                                        sprite_enable = bs->GetBits((vol_ver_id == 1 ? 1 : 2));

                                        if(sprite_enable == SPRITE_STATIC || sprite_enable == SPRITE_GMC) {
                                                int low_latency_sprite_enable;

                                                if(sprite_enable != SPRITE_GMC) {
                                                        int sprite_width;
                                                        int sprite_height;
                                                        int sprite_left_coord;
                                                        int sprite_top_coord;
                                                        sprite_width = bs->GetBits(13);     /* sprite_width */
                                                        READ_MARKER();
                                                        sprite_height = bs->GetBits(13); /* sprite_height */
                                                        READ_MARKER();
                                                        sprite_left_coord = bs->GetBits(13);   /* sprite_left_coordinate */
                                                        READ_MARKER();
                                                        sprite_top_coord = bs->GetBits(13); /* sprite_top_coordinate */
                                                        READ_MARKER();
                                                }
                                                sprite_warping_points = bs->GetBits(6);      /* no_of_sprite_warping_points */
                                                sprite_warping_accuracy = bs->GetBits(2);    /* sprite_warping_accuracy */
                                                sprite_brightness_change = bs->GetBits(1);      /* brightness_change */
                                                if (sprite_enable != SPRITE_GMC)
                                                {
                                                        low_latency_sprite_enable = bs->GetBits(1);     /* low_latency_sprite_enable */
                                                }
                                        }

                                        if(vol_ver_id != 1 && shape != VIDOBJLAY_SHAPE_RECTANGULAR) {
                                                //sadct_disable
                                                bs->Skip(1);
                                        }

                                        if(bs->GetBit()) {
                                                //not_8_bit
                                                DPRINTF(XVID_DEBUG_HEADER, "not_8_bit==true (ignored)\n");
                                                quant_bits = bs->GetBits(4);  /* quant_precision */
                                                bs->Skip(4);   /* bits_per_pixel */
                                        } else {
                                                quant_bits = 5;
                                        }

                                        if(shape == VIDOBJLAY_SHAPE_GRAYSCALE) {
                                                bs->Skip(1);   /* no_gray_quant_update */
                                                bs->Skip(1);   /* composition_method */
                                                bs->Skip(1);   /* linear_composition */
                                        }

                                        quant_type = bs->GetBit();
                                        DPRINTF(XVID_DEBUG_HEADER, "quant_type %i\n", quant_type);

                                        if(quant_type) {
                                                if (bs->GetBit()) //load_intra_quant_mat
                                                {
                                                        byte matrix[64];

                                                        DPRINTF(XVID_DEBUG_HEADER, "load_intra_quant_mat\n");

                                                        bs->get_matrix(matrix);
                                                        set_intra_matrix(mpeg_quant_matrices, matrix);
                                                } else
                                                        set_intra_matrix(mpeg_quant_matrices, get_default_intra_matrix());

                                                if (bs->GetBit()) /* load_inter_quant_mat */
                                                {
                                                        byte matrix[64];

                                                        DPRINTF(XVID_DEBUG_HEADER, "load_inter_quant_mat\n");

                                                        bs->get_matrix(matrix);
                                                        set_inter_matrix(mpeg_quant_matrices, matrix);
                                                } else
                                                        set_inter_matrix(mpeg_quant_matrices, get_default_inter_matrix());

                                                if (shape == VIDOBJLAY_SHAPE_GRAYSCALE) {
                                                        DPRINTF(XVID_DEBUG_ERROR, "greyscale matrix not supported\n");
                                                        return -1;
                                                }

                                        }

                                        if(vol_ver_id != 1) {
                                                quarterpel = bs->GetBit();
                                                DPRINTF(XVID_DEBUG_HEADER,"quarterpel %i\n", quarterpel);
                                        } else
                                                quarterpel = 0;


                                        complexity_estimation_disable = bs->GetBit();
                                        if(!complexity_estimation_disable) {
                                                read_vol_complexity_estimation_header(bs);
                                        }

                                        bs->Skip(1);   //resync_marker_disable

                                        if(bs->GetBit()) {
                                                //data_partitioned
                                                DPRINTF(XVID_DEBUG_ERROR, "data_partitioned not supported\n");
                                                bs->Skip(1);   /* reversible_vlc */
                                        }

                                        if(vol_ver_id != 1) {
                                                newpred_enable = !!bs->GetBit();
                                                if (newpred_enable)  /* newpred_enable */
                                                {
                                                        DPRINTF(XVID_DEBUG_HEADER, "+ newpred_enable\n");
                                                        bs->Skip(2);   /* requested_upstream_message_type */
                                                        bs->Skip(1);   /* newpred_segment_type */
                                                }
                                                reduced_resolution_enable = !!bs->GetBit(); //reduced_resolution_vop_enable
                                                DPRINTF(XVID_DEBUG_HEADER, "reduced_resolution_enable %i\n", reduced_resolution_enable);
                                        } else {
                                                newpred_enable = false;
                                                reduced_resolution_enable = false;
                                        }

                                        scalability = (bs->GetBit()!=0);
                                        if(scalability) {
                                                DPRINTF(XVID_DEBUG_ERROR, "scalability not supported\n");
                                                bs->Skip(1);   /* hierarchy_type */
                                                bs->Skip(4);   /* ref_layer_id */
                                                bs->Skip(1);   /* ref_layer_sampling_direc */
                                                bs->Skip(5);   /* hor_sampling_factor_n */
                                                bs->Skip(5);   /* hor_sampling_factor_m */
                                                bs->Skip(5);   /* vert_sampling_factor_n */
                                                bs->Skip(5);   /* vert_sampling_factor_m */
                                                bs->Skip(1);   /* enhancement_type */
                                                if(shape == VIDOBJLAY_SHAPE_BINARY /* && hierarchy_type==0 */) {
                                                        bs->Skip(1);   /* use_ref_shape */
                                                        bs->Skip(1);   /* use_ref_texture */
                                                        bs->Skip(5);   /* shape_hor_sampling_factor_n */
                                                        bs->Skip(5);   /* shape_hor_sampling_factor_m */
                                                        bs->Skip(5);   /* shape_vert_sampling_factor_n */
                                                        bs->Skip(5);   /* shape_vert_sampling_factor_m */
                                                }
                                                return -1;
                                        }
                                } else {
                                        //shape == BINARY_ONLY
                                        if(vol_ver_id != 1) {
                                                scalability = (bs->GetBit()!=0);
                                                if(scalability) {
                                                        DPRINTF(XVID_DEBUG_ERROR, "scalability not supported\n");
                                                        bs->Skip(4);   /* ref_layer_id */
                                                        bs->Skip(5);   /* hor_sampling_factor_n */
                                                        bs->Skip(5);   /* hor_sampling_factor_m */
                                                        bs->Skip(5);   /* vert_sampling_factor_n */
                                                        bs->Skip(5);   /* vert_sampling_factor_m */
                                                        return -1;
                                                }
                                        }
                                        bs->Skip(1);   /* resync_marker_disable */

                                }

                                return (resize ? -3 : -2);   //VOL

                        }
                        break;
                        default:
                        {
                                //start_code == ?
                                //if(bs->ShowBits(24) == 0x000001)
                                if((start_code&0x00ffffff) == 0x000001) {
                                        DPRINTF(XVID_DEBUG_STARTCODE, "<unknown: %x>\n", bs->ShowBits(32));
                                }
                                bs->Skip(8);
                        }
                        }
                }
        }

#if 0
        DPRINTF("*** WARNING: no vop_start_code found");
#endif
        return -1;                 //ignore it
}

//----------------------------


/* [<][>][^][v][top][bottom][index][help] */