/* Gstreamer
 * Copyright (C) <2011> Intel
 * Copyright (C) <2011> Collabora Ltd.
 * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
/**
 * SECTION:gstvc1parser
 * @short_description: Convenience library for parsing vc1 video
 * bitstream.
 *
 * For more details about the structures, look at the
 * smpte specifications (S421m-2006.pdf).
 *
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "gstvc1parser.h"
#include "parserutils.h"
#include <gst/base/gstbytereader.h>
#include <gst/base/gstbitreader.h>
#include <string.h>

#ifndef GST_DISABLE_GST_DEBUG

#define GST_CAT_DEFAULT ensure_debug_category()

static GstDebugCategory *
ensure_debug_category (void)
{
  static gsize cat_gonce = 0;

  if (g_once_init_enter (&cat_gonce)) {
    gsize cat_done;

    cat_done = (gsize) _gst_debug_category_new ("codecparsers_vc1", 0,
        "VC1 codec parsing library");

    g_once_init_leave (&cat_gonce, cat_done);
  }

  return (GstDebugCategory *) cat_gonce;
}

#else

#define ensure_debug_category() /* NOOP */

#endif /* GST_DISABLE_GST_DEBUG */

static const guint8 vc1_pquant_table[3][32] = {
  {                             /* Implicit quantizer */
        0, 1, 2, 3, 4, 5, 6, 7, 8, 6, 7, 8, 9, 10, 11, 12,
      13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 29, 31},
  {                             /* Explicit quantizer, pquantizer uniform */
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
      16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
  {                             /* Explicit quantizer, pquantizer non-uniform */
        0, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
      14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 31}
};

static const guint8 vc1_mvmode_table[2][5] = {
  /* Table 47: P Picture High rate (PQUANT <= 12) MVMODE code table */
  {
        GST_VC1_MVMODE_1MV,
        GST_VC1_MVMODE_MIXED_MV,
        GST_VC1_MVMODE_1MV_HPEL,
        GST_VC1_MVMODE_INTENSITY_COMP,
      GST_VC1_MVMODE_1MV_HPEL_BILINEAR},
  /* Table 46: P Picture Low rate (PQUANT > 12) MVMODE code table */
  {
        GST_VC1_MVMODE_1MV_HPEL_BILINEAR,
        GST_VC1_MVMODE_1MV,
        GST_VC1_MVMODE_1MV_HPEL,
        GST_VC1_MVMODE_INTENSITY_COMP,
      GST_VC1_MVMODE_MIXED_MV}
};

static const guint8 vc1_mvmode2_table[2][4] = {
  /* Table 50: P Picture High rate (PQUANT <= 12) MVMODE2 code table */
  {
        GST_VC1_MVMODE_1MV,
        GST_VC1_MVMODE_MIXED_MV,
        GST_VC1_MVMODE_1MV_HPEL,
      GST_VC1_MVMODE_1MV_HPEL_BILINEAR},
  /* Table 49: P Picture Low rate (PQUANT > 12) MVMODE2 code table */
  {
        GST_VC1_MVMODE_1MV_HPEL_BILINEAR,
        GST_VC1_MVMODE_1MV,
        GST_VC1_MVMODE_1MV_HPEL,
      GST_VC1_MVMODE_MIXED_MV}
};

/* Table 40: BFRACTION VLC Table */
static const VLCTable vc1_bfraction_vlc_table[] = {
  {GST_VC1_BFRACTION_BASIS / 2, 0x00, 3},
  {GST_VC1_BFRACTION_BASIS / 3, 0x01, 3},
  {(GST_VC1_BFRACTION_BASIS * 2) / 3, 0x02, 3},
  {GST_VC1_BFRACTION_BASIS / 4, 0x02, 3},
  {(GST_VC1_BFRACTION_BASIS * 3) / 4, 0x04, 3},
  {GST_VC1_BFRACTION_BASIS / 5, 0x05, 3},
  {(GST_VC1_BFRACTION_BASIS * 2) / 5, 0x06, 3},
  {(GST_VC1_BFRACTION_BASIS * 3) / 5, 0x70, 7},
  {(GST_VC1_BFRACTION_BASIS * 4) / 5, 0x71, 7},
  {GST_VC1_BFRACTION_BASIS / 6, 0x72, 7},
  {(GST_VC1_BFRACTION_BASIS * 5) / 6, 0x73, 7},
  {GST_VC1_BFRACTION_BASIS / 7, 0x74, 7},
  {(GST_VC1_BFRACTION_BASIS * 2) / 7, 0x75, 7},
  {(GST_VC1_BFRACTION_BASIS * 3) / 7, 0x76, 7},
  {(GST_VC1_BFRACTION_BASIS * 4) / 7, 0x77, 7},
  {(GST_VC1_BFRACTION_BASIS * 5) / 7, 0x78, 7},
  {(GST_VC1_BFRACTION_BASIS * 6) / 7, 0x79, 7},
  {GST_VC1_BFRACTION_BASIS / 8, 0x7a, 7},
  {(GST_VC1_BFRACTION_BASIS * 3) / 8, 0x7b, 7},
  {(GST_VC1_BFRACTION_BASIS * 5) / 8, 0x7c, 7},
  {(GST_VC1_BFRACTION_BASIS * 7) / 8, 0x7d, 7},
  {GST_VC1_BFRACTION_RESERVED, 0x7e, 7},
  {GST_VC1_BFRACTION_PTYPE_BI, 0x7f, 7}
};

/* Imode types */
enum
{
  IMODE_RAW,
  IMODE_NORM2,
  IMODE_DIFF2,
  IMODE_NORM6,
  IMODE_DIFF6,
  IMODE_ROWSKIP,
  IMODE_COLSKIP
};

/* Table 69: IMODE VLC Codetable */
static const VLCTable vc1_imode_vlc_table[] = {
  {IMODE_NORM2, 0x02, 2},
  {IMODE_NORM6, 0x03, 2},
  {IMODE_ROWSKIP, 0x02, 3},
  {IMODE_COLSKIP, 0x03, 3},
  {IMODE_DIFF2, 0x01, 3},
  {IMODE_DIFF6, 0x01, 4},
  {IMODE_RAW, 0x00, 4}
};

/* Table 80: Norm-2/Diff-2 Code Table */
static const VLCTable vc1_norm2_vlc_table[4] = {
  {0, 0, 1},
  {2, 4, 3},
  {1, 5, 3},
  {3, 3, 2}
};

/* Table 81: Code table for 3x2 and 2x3 tiles */
static const VLCTable vc1_norm6_vlc_table[64] = {
  {0, 1, 1},
  {1, 2, 4},
  {2, 3, 4},
  {3, 0, 8},
  {4, 4, 4},
  {5, 1, 8},
  {6, 2, 8},
  {7, (2 << 5) | 7, 10},
  {8, 5, 4},
  {9, 3, 8},
  {10, 4, 8},
  {11, (2 << 5) | 11, 10},
  {12, 5, 8},
  {13, (2 << 5) | 13, 10},
  {14, (2 << 5) | 14, 10},
  {15, (3 << 8) | 14, 13},
  {16, 6, 4},
  {17, 6, 8},
  {18, 7, 8},
  {19, (2 << 5) | 19, 10},
  {20, 8, 8},
  {21, (2 << 5) | 21, 10},
  {22, (2 << 5) | 22, 10},
  {23, (3 << 8) | 13, 13},
  {24, 9, 8},
  {25, (2 << 5) | 25, 10},
  {26, (2 << 5) | 26, 10},
  {27, (3 << 8) | 12, 13},
  {28, (2 << 5) | 28, 10},
  {29, (3 << 8) | 11, 13},
  {30, (3 << 8) | 10, 13},
  {31, (3 << 4) | 7, 9},
  {32, 7, 4},
  {33, 10, 8},
  {34, 11, 8},
  {35, (2 << 5) | 3, 10},
  {36, 12, 8},
  {37, (2 << 5) | 5, 10},
  {38, (2 << 5) | 6, 10},
  {39, (3 << 8) | 9, 13},
  {40, 13, 8},
  {41, (2 << 5) | 9, 10},
  {42, (2 << 5) | 10, 10},
  {43, (3 << 8) | 8, 13},
  {44, (2 << 5) | 12, 10},
  {45, (3 << 8) | 7, 13},
  {46, (3 << 8) | 6, 13},
  {47, (3 << 4) | 6, 9},
  {48, 14, 8},
  {49, (2 << 5) | 17, 10},
  {50, (2 << 5) | 18, 10},
  {51, (3 << 8) | 5, 13},
  {52, (2 << 5) | 20, 10},
  {53, (3 << 8) | 4, 13},
  {54, (3 << 8) | 3, 13},
  {55, (3 << 4) | 5, 9},
  {56, (2 << 5) | 24, 10},
  {57, (3 << 8) | 2, 13},
  {58, (3 << 8) | 1, 13},
  {59, (3 << 4) | 4, 9},
  {60, (3 << 8) | 0, 13},
  {61, (3 << 4) | 3, 9},
  {62, (3 << 4) | 2, 9},
  {63, (3 << 1) | 1, 6}
};

/* SMPTE 421M Table 7 */
typedef struct
{
  gint par_n, par_d;
} PAR;

static PAR aspect_ratios[] = {
  {0, 0},
  {1, 1},
  {12, 11},
  {10, 11},
  {16, 11},
  {40, 33},
  {24, 11},
  {20, 11},
  {32, 11},
  {80, 33},
  {18, 11},
  {15, 11},
  {64, 33},
  {160, 99},
  {0, 0},
  {0, 0}
};

/* SMPTE 421M Table 8 */
static const guint framerates_n[] = {
  0,
  24 * 1000,
  25 * 1000,
  30 * 1000,
  50 * 1000,
  60 * 1000,
  48 * 1000,
  72 * 1000
};

/* SMPTE 421M Table 9 */
static const guint framerates_d[] = {
  0,
  1000,
  1001
};


static inline gboolean
decode_colskip (GstBitReader * br, guint8 * data, guint width, guint height,
    guint stride, guint invert)
{
  guint x, y;
  guint8 colskip, v;

  GST_DEBUG ("Parsing colskip");

  invert &= 1;
  for (x = 0; x < width; x++) {
    READ_UINT8 (br, colskip, 1);

    if (data) {
      if (colskip) {
        for (y = 0; y < height; y++) {
          READ_UINT8 (br, v, 1);
          data[y * stride] = v ^ invert;
        }
      } else {
        for (y = 0; y < height; y++)
          data[y * stride] = invert;
      }
      data++;
    } else if (colskip)
      SKIP (br, height);
  }

  return TRUE;

failed:
  GST_WARNING ("Failed to parse colskip");

  return FALSE;
}

static inline gboolean
decode_rowskip (GstBitReader * br, guint8 * data, guint width, guint height,
    guint stride, guint invert)
{
  guint x, y;
  guint8 rowskip, v;

  GST_DEBUG ("Parsing rowskip");

  invert &= 1;
  for (y = 0; y < height; y++) {
    READ_UINT8 (br, rowskip, 1);

    if (data) {
      if (!rowskip)
        memset (data, invert, width);
      else {
        for (x = 0; x < width; x++) {
          READ_UINT8 (br, v, 1);
          data[x] = v ^ invert;
        }
      }
      data += stride;
    } else if (rowskip)
      SKIP (br, width);
  }

  return TRUE;

failed:
  GST_WARNING ("Failed to parse rowskip");

  return FALSE;
}

static inline gint8
decode012 (GstBitReader * br)
{
  guint8 n;

  READ_UINT8 (br, n, 1);

  if (n == 0)
    return 0;

  READ_UINT8 (br, n, 1);

  return n + 1;

failed:
  GST_WARNING ("Could not decode 0 1 2 returning -1");

  return -1;
}

static inline guint
calculate_nb_pan_scan_win (GstVC1AdvancedSeqHdr * advseqhdr,
    GstVC1PicAdvanced * pic)
{
  if (advseqhdr->interlace && !advseqhdr->psf) {
    if (advseqhdr->pulldown)
      return pic->rff + 2;

    return 2;

  } else {
    if (advseqhdr->pulldown)
      return pic->rptfrm + 1;

    return 1;
  }
}

static gboolean
decode_refdist (GstBitReader * br, guint16 * value)
{
  guint16 tmp;
  gint i = 2;

  if (!gst_bit_reader_peek_bits_uint16 (br, &tmp, i))
    goto failed;

  if (tmp < 0x03) {
    READ_UINT16 (br, *value, i);

    return TRUE;
  }

  do {
    i++;

    if (!gst_bit_reader_peek_bits_uint16 (br, &tmp, i))
      goto failed;

    if (!(tmp >> i)) {
      READ_UINT16 (br, *value, i);

      return TRUE;
    }
  } while (i < 16);


failed:
  {
    GST_WARNING ("Could not decode end 0 returning");

    return FALSE;
  }
}

/*** bitplanes decoding ***/
static gboolean
bitplane_decoding (GstBitReader * br, guint8 * data,
    GstVC1SeqHdr * seqhdr, guint8 * is_raw)
{
  const guint width = seqhdr->mb_width;
  const guint height = seqhdr->mb_height;
  const guint stride = seqhdr->mb_stride;
  guint imode, invert, invert_mask;
  guint x, y, v;
  guint8 *pdata = data;

  *is_raw = FALSE;

  GET_BITS (br, 1, &invert);
  invert_mask = -invert;

  if (!decode_vlc (br, &imode, vc1_imode_vlc_table,
          G_N_ELEMENTS (vc1_imode_vlc_table)))
    goto failed;

  switch (imode) {
    case IMODE_RAW:

      GST_DEBUG ("Parsing IMODE_RAW");

      *is_raw = TRUE;
      return TRUE;

    case IMODE_DIFF2:
      invert_mask = 0;
      /* fall-through */
    case IMODE_NORM2:
      invert_mask &= 3;

      GST_DEBUG ("Parsing IMODE_DIFF2 or IMODE_NORM2 biplane");

      x = 0;
      if ((height * width) & 1) {
        GET_BITS (br, 1, &v);
        if (pdata) {
          *pdata++ = (v ^ invert_mask) & 1;
          if (++x == width) {
            x = 0;
            pdata += stride - width;
          }
        }
      }

      for (y = 0; y < height * width; y += 2) {
        if (!decode_vlc (br, &v, vc1_norm2_vlc_table,
                G_N_ELEMENTS (vc1_norm2_vlc_table)))
          goto failed;
        if (pdata) {
          v ^= invert_mask;
          *pdata++ = v >> 1;
          if (++x == width) {
            x = 0;
            pdata += stride - width;
          }
          *pdata++ = v & 1;
          if (++x == width) {
            x = 0;
            pdata += stride - width;
          }
        }
      }
      break;

    case IMODE_DIFF6:
      invert_mask = 0;
      /* fall-through */
    case IMODE_NORM6:

      GST_DEBUG ("Parsing IMODE_DIFF6 or IMODE_NORM6 biplane");

      if (!(height % 3) && (width % 3)) {       /* decode 2x3 "vertical" tiles */
        for (y = 0; y < height; y += 3) {
          for (x = width & 1; x < width; x += 2) {
            if (!decode_vlc (br, &v, vc1_norm6_vlc_table,
                    G_N_ELEMENTS (vc1_norm6_vlc_table)))
              goto failed;

            if (pdata) {
              v ^= invert_mask;
              pdata[x + 0] = v & 1;
              pdata[x + 1] = (v >> 1) & 1;
              pdata[x + 0 + stride] = (v >> 2) & 1;
              pdata[x + 1 + stride] = (v >> 3) & 1;
              pdata[x + 0 + stride * 2] = (v >> 4) & 1;
              pdata[x + 1 + stride * 2] = (v >> 5) & 1;
            }
          }
          if (pdata)
            pdata += 3 * stride;
        }

        x = width & 1;
        y = 0;
      } else {                  /* decode 3x2 "horizontal" tiles */

        if (pdata)
          pdata += (height & 1) * width;
        for (y = height & 1; y < height; y += 2) {
          for (x = width % 3; x < width; x += 3) {
            if (!decode_vlc (br, &v, vc1_norm6_vlc_table,
                    G_N_ELEMENTS (vc1_norm6_vlc_table)))
              goto failed;

            if (pdata) {
              v ^= invert_mask;
              pdata[x + 0] = v & 1;
              pdata[x + 1] = (v >> 1) & 1;
              pdata[x + 2] = (v >> 2) & 1;
              pdata[x + 0 + stride] = (v >> 3) & 1;
              pdata[x + 1 + stride] = (v >> 4) & 1;
              pdata[x + 2 + stride] = (v >> 5) & 1;
            }
          }
          if (pdata)
            pdata += 2 * stride;
        }

        x = width % 3;
        y = height & 1;
      }

      if (x) {
        if (data)
          pdata = data + y * stride;
        if (!decode_colskip (br, pdata, x, height, stride, invert_mask))
          goto failed;
      }

      if (y) {
        if (data)
          pdata = data + x;
        if (!decode_rowskip (br, pdata, width, y, stride, invert_mask))
          goto failed;
      }
      break;
    case IMODE_ROWSKIP:

      GST_DEBUG ("Parsing IMODE_ROWSKIP biplane");

      if (!decode_rowskip (br, data, width, height, stride, invert_mask))
        goto failed;
      break;
    case IMODE_COLSKIP:

      GST_DEBUG ("Parsing IMODE_COLSKIP biplane");

      if (!decode_colskip (br, data, width, height, stride, invert_mask))
        goto failed;
      break;
  }

  if (!data)
    return TRUE;

  /* Applying diff operator */
  if (imode == IMODE_DIFF2 || imode == IMODE_DIFF6) {
    pdata = data;
    pdata[0] ^= invert;

    for (x = 1; x < width; x++)
      pdata[x] ^= pdata[x - 1];

    for (y = 1; y < height; y++) {
      pdata[stride] ^= pdata[0];

      for (x = 1; x < width; x++) {
        if (pdata[stride + x - 1] != pdata[x])
          pdata[stride + x] ^= invert;
        else
          pdata[stride + x] ^= pdata[stride + x - 1];
      }
      pdata += stride;
    }
  }

  return TRUE;

failed:
  GST_WARNING ("Failed to decode bitplane");

  return FALSE;
}

static gboolean
parse_vopdquant (GstBitReader * br, GstVC1FrameHdr * framehdr, guint8 dquant)
{
  GstVC1VopDquant *vopdquant = &framehdr->vopdquant;

  GST_DEBUG ("Parsing vopdquant");

  vopdquant->dqbilevel = 0;

  if (dquant == 2) {
    READ_UINT8 (br, vopdquant->dquantfrm, 1);

    READ_UINT8 (br, vopdquant->pqdiff, 3);

    if (vopdquant->pqdiff != 7)
      vopdquant->altpquant = framehdr->pquant + vopdquant->pqdiff + 1;
    else {
      READ_UINT8 (br, vopdquant->abspq, 5);
      vopdquant->altpquant = vopdquant->abspq;
    }
  } else {
    READ_UINT8 (br, vopdquant->dquantfrm, 1);
    GST_DEBUG (" %u DquantFrm %u", gst_bit_reader_get_pos (br),
        vopdquant->dquantfrm);

    if (vopdquant->dquantfrm) {
      READ_UINT8 (br, vopdquant->dqprofile, 1);

      switch (vopdquant->dqprofile) {
        case GST_VC1_DQPROFILE_SINGLE_EDGE:
        case GST_VC1_DQPROFILE_DOUBLE_EDGES:
          READ_UINT8 (br, vopdquant->dqsbedge, 2);
          break;

        case GST_VC1_DQPROFILE_ALL_MBS:
          READ_UINT8 (br, vopdquant->dqbilevel, 1);
          break;
      }

      if (vopdquant->dqbilevel
          || vopdquant->dqprofile != GST_VC1_DQPROFILE_ALL_MBS) {
        {
          READ_UINT8 (br, vopdquant->pqdiff, 3);

          if (vopdquant->pqdiff == 7)
            READ_UINT8 (br, vopdquant->abspq, 5);
        }
      }
    }
  }

  return TRUE;

failed:
  GST_WARNING ("Failed to parse vopdquant");

  return FALSE;
}

static inline gint
scan_for_start_codes (const guint8 * data, guint size)
{
  GstByteReader br;
  gst_byte_reader_init (&br, data, size);

  /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */
  return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
      0, size);
}

static inline gint
get_unary (GstBitReader * br, gint stop, gint len)
{
  int i;
  guint8 current = 0xff;

  for (i = 0; i < len; i++) {
    current = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
    if (current == stop)
      return i;
  }

  return i;
}

static inline void
calculate_framerate_bitrate (guint8 frmrtq_postproc, guint8 bitrtq_postproc,
    guint * framerate, guint * bitrate)
{
  if (frmrtq_postproc == 0 && bitrtq_postproc == 31) {
    *framerate = 0;
    *bitrate = 0;
  } else if (frmrtq_postproc == 0 && bitrtq_postproc == 30) {
    *framerate = 2;
    *bitrate = 1952;
  } else if (frmrtq_postproc == 1 && bitrtq_postproc == 31) {
    *framerate = 6;
    *bitrate = 2016;
  } else {
    if (frmrtq_postproc == 7) {
      *framerate = 30;
    } else {
      *framerate = 2 + (frmrtq_postproc * 4);
    }
    if (bitrtq_postproc == 31) {
      *bitrate = 2016;
    } else {
      *bitrate = 32 + (bitrtq_postproc * 64);
    }
  }
}

static inline void
calculate_mb_size (GstVC1SeqHdr * seqhdr, guint width, guint height)
{
  seqhdr->mb_width = (width + 15) >> 4;
  seqhdr->mb_height = (height + 15) >> 4;
  seqhdr->mb_stride = seqhdr->mb_width + 1;
}

static GstVC1ParserResult
parse_hrd_param_flag (GstBitReader * br, GstVC1HrdParam * hrd_param)
{
  guint i;

  GST_DEBUG ("Parsing Hrd param flag");


  if (gst_bit_reader_get_remaining (br) < 13)
    goto failed;

  hrd_param->hrd_num_leaky_buckets =
      gst_bit_reader_get_bits_uint8_unchecked (br, 5);
  hrd_param->bit_rate_exponent =
      gst_bit_reader_get_bits_uint8_unchecked (br, 4);
  hrd_param->buffer_size_exponent =
      gst_bit_reader_get_bits_uint8_unchecked (br, 4);

  if (gst_bit_reader_get_remaining (br) <
      (32 * hrd_param->hrd_num_leaky_buckets))
    goto failed;

  for (i = 0; i < hrd_param->hrd_num_leaky_buckets; i++) {
    hrd_param->hrd_rate[i] = gst_bit_reader_get_bits_uint16_unchecked (br, 16);
    hrd_param->hrd_buffer[i] =
        gst_bit_reader_get_bits_uint16_unchecked (br, 16);
  }

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to parse hrd param flag");

  return GST_VC1_PARSER_ERROR;
}

static GstVC1ParserResult
parse_sequence_header_advanced (GstVC1SeqHdr * seqhdr, GstBitReader * br)
{
  GstVC1AdvancedSeqHdr *advanced = &seqhdr->advanced;
  guint8 tmp;

  GST_DEBUG ("Parsing sequence header in advanced mode");

  READ_UINT8 (br, tmp, 3);
  advanced->level = tmp;
  advanced->par_n = 0;
  advanced->par_d = 0;
  advanced->fps_n = 0;
  advanced->fps_d = 0;

  READ_UINT8 (br, advanced->colordiff_format, 2);
  READ_UINT8 (br, advanced->frmrtq_postproc, 3);
  READ_UINT8 (br, advanced->bitrtq_postproc, 5);

  calculate_framerate_bitrate (advanced->frmrtq_postproc,
      advanced->bitrtq_postproc, &advanced->framerate, &advanced->bitrate);

  GST_DEBUG ("level %u, colordiff_format %u , frmrtq_postproc %u,"
      " bitrtq_postproc %u", advanced->level, advanced->colordiff_format,
      advanced->frmrtq_postproc, advanced->bitrtq_postproc);

  if (gst_bit_reader_get_remaining (br) < 32)
    goto failed;

  advanced->postprocflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  advanced->max_coded_width = gst_bit_reader_get_bits_uint16_unchecked (br, 12);
  advanced->max_coded_height =
      gst_bit_reader_get_bits_uint16_unchecked (br, 12);
  advanced->max_coded_width = (advanced->max_coded_width + 1) << 1;
  advanced->max_coded_height = (advanced->max_coded_height + 1) << 1;
  calculate_mb_size (seqhdr, advanced->max_coded_width,
      advanced->max_coded_height);
  advanced->pulldown = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  advanced->interlace = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  advanced->tfcntrflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  advanced->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);

  GST_DEBUG ("postprocflag %u, max_coded_width %u, max_coded_height %u,"
      "pulldown %u, interlace %u, tfcntrflag %u, finterpflag %u",
      advanced->postprocflag, advanced->max_coded_width,
      advanced->max_coded_height, advanced->pulldown,
      advanced->interlace, advanced->tfcntrflag, advanced->finterpflag);

  /* Skipping reserved bit */
  gst_bit_reader_skip_unchecked (br, 1);

  advanced->psf = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  advanced->display_ext = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  if (advanced->display_ext) {
    READ_UINT16 (br, advanced->disp_horiz_size, 14);
    READ_UINT16 (br, advanced->disp_vert_size, 14);

    advanced->disp_horiz_size++;
    advanced->disp_vert_size++;

    READ_UINT8 (br, advanced->aspect_ratio_flag, 1);

    if (advanced->aspect_ratio_flag) {
      READ_UINT8 (br, advanced->aspect_ratio, 4);

      if (advanced->aspect_ratio == 15) {
        READ_UINT8 (br, advanced->aspect_horiz_size, 8);
        READ_UINT8 (br, advanced->aspect_vert_size, 8);
        advanced->par_n = advanced->aspect_horiz_size;
        advanced->par_d = advanced->aspect_vert_size;
      } else {
        advanced->par_n = aspect_ratios[advanced->aspect_ratio].par_n;
        advanced->par_d = aspect_ratios[advanced->aspect_ratio].par_d;
      }
    }
    READ_UINT8 (br, advanced->framerate_flag, 1);
    if (advanced->framerate_flag) {
      READ_UINT8 (br, advanced->framerateind, 1);

      if (!advanced->framerateind) {
        READ_UINT8 (br, advanced->frameratenr, 8);
        READ_UINT8 (br, advanced->frameratedr, 4);
      } else {
        READ_UINT16 (br, advanced->framerateexp, 16);
      }
      if (advanced->frameratenr > 0 &&
          advanced->frameratenr < 8 &&
          advanced->frameratedr > 0 && advanced->frameratedr < 3) {
        advanced->fps_n = framerates_n[advanced->frameratenr];
        advanced->fps_d = framerates_d[advanced->frameratedr];
      } else {
        advanced->fps_n = advanced->framerateexp + 1;
        advanced->fps_d = 32;
      }
    }
    READ_UINT8 (br, advanced->color_format_flag, 1);

    if (advanced->color_format_flag) {
      if (gst_bit_reader_get_remaining (br) < 24)
        goto failed;

      advanced->color_prim = gst_bit_reader_get_bits_uint8_unchecked (br, 8);
      advanced->transfer_char = gst_bit_reader_get_bits_uint8_unchecked (br, 8);
      advanced->matrix_coef = gst_bit_reader_get_bits_uint8_unchecked (br, 8);
    }
  }
  READ_UINT8 (br, advanced->hrd_param_flag, 1);
  if (advanced->hrd_param_flag)
    return parse_hrd_param_flag (br, &advanced->hrd_param);

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to parse advanced headers");

  return GST_VC1_PARSER_ERROR;
}

static GstVC1ParserResult
parse_frame_header_advanced (GstBitReader * br, GstVC1FrameHdr * framehdr,
    GstVC1SeqHdr * seqhdr, GstVC1BitPlanes * bitplanes, gboolean field2)
{
  GstVC1AdvancedSeqHdr *advhdr = &seqhdr->advanced;
  GstVC1PicAdvanced *pic = &framehdr->pic.advanced;
  GstVC1EntryPointHdr *entrypthdr = &advhdr->entrypoint;
  guint8 mvmodeidx;

  GST_DEBUG ("Parsing Frame header advanced %u", advhdr->interlace);

  /* Set the conveninence fields */
  framehdr->profile = seqhdr->profile;
  framehdr->dquant = entrypthdr->dquant;

  if (advhdr->interlace) {
    gint8 fcm = decode012 (br);

    if (fcm < 0)
      goto failed;

    pic->fcm = (guint8) fcm;
  } else
    pic->fcm = GST_VC1_FRAME_PROGRESSIVE;

  if (pic->fcm == GST_VC1_FIELD_INTERLACE) {
    READ_UINT8 (br, pic->fptype, 3);
    if (field2) {
      switch (pic->fptype) {
        case 0x00:
        case 0x02:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
        case 0x01:
        case 0x03:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_P;
        case 0x04:
        case 0x06:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_B;
        case 0x05:
        case 0x07:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
      }
    } else {
      switch (pic->fptype) {
        case 0x00:
        case 0x01:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
        case 0x02:
        case 0x03:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_P;
        case 0x04:
        case 0x05:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_B;
        case 0x06:
        case 0x07:
          framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
      }
    }
  } else
    framehdr->ptype = (guint8) get_unary (br, 0, 4);

  if (advhdr->tfcntrflag) {
    READ_UINT8 (br, pic->tfcntr, 8);
    GST_DEBUG ("tfcntr %u", pic->tfcntr);
  }

  if (advhdr->pulldown) {
    if (!advhdr->interlace || advhdr->psf) {

      READ_UINT8 (br, pic->rptfrm, 2);
      GST_DEBUG ("rptfrm %u", pic->rptfrm);

    } else {

      READ_UINT8 (br, pic->tff, 1);
      READ_UINT8 (br, pic->rff, 1);
      GST_DEBUG ("tff %u, rff %u", pic->tff, pic->rff);
    }
  }

  if (entrypthdr->panscan_flag) {
    READ_UINT8 (br, pic->ps_present, 1);

    if (pic->ps_present) {
      guint i, nb_pan_scan_win = calculate_nb_pan_scan_win (advhdr, pic);

      if (gst_bit_reader_get_remaining (br) < 64 * nb_pan_scan_win)
        goto failed;

      for (i = 0; i < nb_pan_scan_win; i++) {
        pic->ps_hoffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18);
        pic->ps_voffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18);
        pic->ps_width = gst_bit_reader_get_bits_uint16_unchecked (br, 14);
        pic->ps_height = gst_bit_reader_get_bits_uint16_unchecked (br, 14);
      }
    }
  }

  if (framehdr->ptype == GST_VC1_PICTURE_TYPE_SKIPPED)
    return GST_VC1_PARSER_OK;

  READ_UINT8 (br, pic->rndctrl, 1);

  if (advhdr->interlace) {
    READ_UINT8 (br, pic->uvsamp, 1);
    GST_DEBUG ("uvsamp %u", pic->uvsamp);
    if (pic->fcm == GST_VC1_FIELD_INTERLACE && entrypthdr->refdist_flag &&
        pic->fptype < 4)
      decode_refdist (br, &pic->refdist);
    else
      pic->refdist = 0;
  }

  if (advhdr->finterpflag) {
    READ_UINT8 (br, framehdr->interpfrm, 1);
    GST_DEBUG ("interpfrm %u", framehdr->interpfrm);
  }

  if ((pic->fcm != GST_VC1_FIELD_INTERLACE &&
          framehdr->ptype == GST_VC1_PICTURE_TYPE_B) ||
      (pic->fcm == GST_VC1_FIELD_INTERLACE && (pic->fptype > 4))) {

    guint bfraction;

    if (!decode_vlc (br, &bfraction, vc1_bfraction_vlc_table,
            G_N_ELEMENTS (vc1_bfraction_vlc_table)))
      goto failed;

    pic->bfraction = bfraction;
    GST_DEBUG ("bfraction %u", pic->bfraction);

    if (pic->bfraction == GST_VC1_BFRACTION_PTYPE_BI) {
      framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
    }

  }

  READ_UINT8 (br, framehdr->pqindex, 5);
  if (!framehdr->pqindex)
    goto failed;

  /* compute pquant */
  if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
    framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex];
  else
    framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex];

  framehdr->pquantizer = 1;
  if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
    framehdr->pquantizer = framehdr->pqindex < 9;
  if (entrypthdr->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM)
    framehdr->pquantizer = 0;

  if (framehdr->pqindex <= 8)
    READ_UINT8 (br, framehdr->halfqp, 1);
  else
    framehdr->halfqp = 0;

  if (entrypthdr->quantizer == GST_VC1_QUANTIZER_EXPLICITLY) {
    READ_UINT8 (br, framehdr->pquantizer, 1);
  }

  if (advhdr->postprocflag)
    READ_UINT8 (br, pic->postproc, 2);

  GST_DEBUG ("Parsing %u picture, pqindex %u, pquant %u pquantizer %u"
      "halfqp %u", framehdr->ptype, framehdr->pqindex, framehdr->pquant,
      framehdr->pquantizer, framehdr->halfqp);

  switch (framehdr->ptype) {
    case GST_VC1_PICTURE_TYPE_I:
    case GST_VC1_PICTURE_TYPE_BI:
      if (pic->fcm == GST_VC1_FRAME_INTERLACE) {
        if (!bitplane_decoding (br, bitplanes ? bitplanes->fieldtx : NULL,
                seqhdr, &pic->fieldtx))
          goto failed;
      }

      if (!bitplane_decoding (br, bitplanes ? bitplanes->acpred : NULL,
              seqhdr, &pic->acpred))
        goto failed;

      if (entrypthdr->overlap && framehdr->pquant <= 8) {
        pic->condover = decode012 (br);

        if (pic->condover == (guint8) - 1)
          goto failed;

        else if (pic->condover == GST_VC1_CONDOVER_SELECT) {
          if (!bitplane_decoding (br, bitplanes ? bitplanes->overflags : NULL,
                  seqhdr, &pic->overflags))
            goto failed;

          GST_DEBUG ("overflags %u", pic->overflags);
        }
      }

      framehdr->transacfrm = get_unary (br, 0, 2);
      pic->transacfrm2 = get_unary (br, 0, 2);
      READ_UINT8 (br, framehdr->transdctab, 1);

      if (framehdr->dquant)
        parse_vopdquant (br, framehdr, framehdr->dquant);

      GST_DEBUG
          ("acpred %u, condover %u, transacfrm %u, transacfrm2 %u, transdctab %u",
          pic->acpred, pic->condover, framehdr->transacfrm, pic->transacfrm2,
          framehdr->transdctab);
      break;

    case GST_VC1_PICTURE_TYPE_B:
      if (entrypthdr->extended_mv)
        pic->mvrange = get_unary (br, 0, 3);
      else
        pic->mvrange = 0;

      if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
        if (entrypthdr->extended_dmv)
          pic->dmvrange = get_unary (br, 0, 3);
      }

      if (pic->fcm == GST_VC1_FRAME_INTERLACE)
        READ_UINT8 (br, pic->intcomp, 1);
      else
        READ_UINT8 (br, pic->mvmode, 1);

      if (pic->fcm == GST_VC1_FIELD_INTERLACE) {

        if (!bitplane_decoding (br, bitplanes ? bitplanes->forwardmb : NULL,
                seqhdr, &pic->forwardmb))
          goto failed;

      } else {
        if (!bitplane_decoding (br, bitplanes ? bitplanes->directmb : NULL,
                seqhdr, &pic->directmb))
          goto failed;

        if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
                seqhdr, &pic->skipmb))
          goto failed;
      }

      if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
        if (gst_bit_reader_get_remaining (br) < 7)
          goto failed;

        pic->mbmodetab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
        pic->imvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
        pic->icbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 3);

        if (pic->fcm == GST_VC1_FRAME_INTERLACE)
          READ_UINT8 (br, pic->mvbptab2, 2);

        if (pic->fcm == GST_VC1_FRAME_INTERLACE ||
            (pic->fcm == GST_VC1_FIELD_INTERLACE
                && pic->mvmode == GST_VC1_MVMODE_MIXED_MV))
          READ_UINT8 (br, pic->mvbptab4, 2);

      } else {
        READ_UINT8 (br, pic->mvtab, 2);
        READ_UINT8 (br, pic->cbptab, 2);
      }

      if (framehdr->dquant) {
        parse_vopdquant (br, framehdr, framehdr->dquant);
      }

      if (entrypthdr->vstransform) {
        READ_UINT8 (br, pic->ttmbf, 1);

        if (pic->ttmbf) {
          READ_UINT8 (br, pic->ttfrm, 2);
        }
      }

      framehdr->transacfrm = get_unary (br, 0, 2);
      READ_UINT8 (br, framehdr->transdctab, 1);

      GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
          "cbptab %u directmb %u skipmb %u", framehdr->transacfrm,
          framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab,
          pic->directmb, pic->skipmb);

      break;
    case GST_VC1_PICTURE_TYPE_P:
      if (pic->fcm == GST_VC1_FIELD_INTERLACE) {
        READ_UINT8 (br, pic->numref, 1);

        if (pic->numref)
          READ_UINT8 (br, pic->reffield, 1);
      }

      if (entrypthdr->extended_mv)
        pic->mvrange = get_unary (br, 0, 3);
      else
        pic->mvrange = 0;

      if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
        if (entrypthdr->extended_dmv)
          pic->dmvrange = get_unary (br, 0, 3);
      }

      if (pic->fcm == GST_VC1_FRAME_INTERLACE) {
        READ_UINT8 (br, pic->mvswitch4, 1);
        READ_UINT8 (br, pic->intcomp, 1);

        if (pic->intcomp) {
          READ_UINT8 (br, pic->lumscale, 6);
          READ_UINT8 (br, pic->lumshift, 6);
        }
      } else {

        mvmodeidx = framehdr->pquant > 12;
        pic->mvmode = vc1_mvmode_table[mvmodeidx][get_unary (br, 1, 4)];

        if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) {
          pic->mvmode2 = vc1_mvmode2_table[mvmodeidx][get_unary (br, 1, 3)];

          if (pic->fcm == GST_VC1_FIELD_INTERLACE)
            pic->intcompfield = decode012 (br);

          READ_UINT8 (br, pic->lumscale, 6);
          READ_UINT8 (br, pic->lumshift, 6);
          GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift);

          if (pic->fcm == GST_VC1_FIELD_INTERLACE && pic->intcompfield) {
            READ_UINT8 (br, pic->lumscale2, 6);
            READ_UINT8 (br, pic->lumshift2, 6);
          }
        }

        if (pic->fcm == GST_VC1_FRAME_PROGRESSIVE) {
          if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV ||
              (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP &&
                  pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) {

            if (!bitplane_decoding (br, bitplanes ? bitplanes->mvtypemb : NULL,
                    seqhdr, &pic->mvtypemb))
              goto failed;

            GST_DEBUG ("mvtypemb %u", pic->mvtypemb);
          }
        }
      }

      if (pic->fcm != GST_VC1_FIELD_INTERLACE) {
        if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
                seqhdr, &pic->skipmb))
          goto failed;
      }

      if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
        if (gst_bit_reader_get_remaining (br) < 7)
          goto failed;

        pic->mbmodetab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
        pic->imvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
        pic->icbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 3);

        if (pic->fcm != GST_VC1_FIELD_INTERLACE) {
          READ_UINT8 (br, pic->mvbptab2, 2);

          if (pic->mvswitch4)
            READ_UINT8 (br, pic->mvbptab4, 2);

        } else if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV)
          READ_UINT8 (br, pic->mvbptab4, 2);

      } else {
        if (gst_bit_reader_get_remaining (br) < 4)
          goto failed;
        pic->mvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
        pic->cbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
      }

      if (framehdr->dquant) {
        parse_vopdquant (br, framehdr, framehdr->dquant);
      }

      if (entrypthdr->vstransform) {
        READ_UINT8 (br, pic->ttmbf, 1);

        if (pic->ttmbf) {
          READ_UINT8 (br, pic->ttfrm, 2);
        }
      }

      framehdr->transacfrm = get_unary (br, 0, 2);
      READ_UINT8 (br, framehdr->transdctab, 1);

      GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
          "cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab,
          pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb);

      break;

    default:
      goto failed;
      break;
  }

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to parse frame header");

  return GST_VC1_PARSER_ERROR;
}

static GstVC1ParserResult
parse_frame_header (GstBitReader * br, GstVC1FrameHdr * framehdr,
    GstVC1SeqHdr * seqhdr, GstVC1BitPlanes * bitplanes)
{
  guint8 mvmodeidx, tmp;
  GstVC1PicSimpleMain *pic = &framehdr->pic.simple;
  GstVC1SeqStructC *structc = &seqhdr->struct_c;

  GST_DEBUG ("Parsing frame header in simple or main mode");

  /* Set the conveninence fields */
  framehdr->profile = seqhdr->profile;
  framehdr->dquant = structc->dquant;

  framehdr->interpfrm = 0;
  if (structc->finterpflag)
    READ_UINT8 (br, framehdr->interpfrm, 1);

  READ_UINT8 (br, pic->frmcnt, 2);

  pic->rangeredfrm = 0;
  if (structc->rangered) {
    READ_UINT8 (br, pic->rangeredfrm, 1);
  }

  /*  Figuring out the picture type */
  READ_UINT8 (br, tmp, 1);
  framehdr->ptype = tmp;

  if (structc->maxbframes) {
    if (!framehdr->ptype) {
      READ_UINT8 (br, tmp, 1);

      if (tmp)
        framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
      else
        framehdr->ptype = GST_VC1_PICTURE_TYPE_B;

    } else
      framehdr->ptype = GST_VC1_PICTURE_TYPE_P;

  } else {
    if (framehdr->ptype)
      framehdr->ptype = GST_VC1_PICTURE_TYPE_P;
    else
      framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
  }


  if (framehdr->ptype == GST_VC1_PICTURE_TYPE_B) {
    guint bfraction;
    if (!decode_vlc (br, &bfraction, vc1_bfraction_vlc_table,
            G_N_ELEMENTS (vc1_bfraction_vlc_table)))
      goto failed;

    pic->bfraction = bfraction;
    GST_DEBUG ("bfraction %d", pic->bfraction);

    if (pic->bfraction == GST_VC1_BFRACTION_PTYPE_BI) {
      framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
    }
  }

  if (framehdr->ptype == GST_VC1_PICTURE_TYPE_I ||
      framehdr->ptype == GST_VC1_PICTURE_TYPE_BI)
    READ_UINT8 (br, pic->bf, 7);

  READ_UINT8 (br, framehdr->pqindex, 5);
  if (!framehdr->pqindex)
    return GST_VC1_PARSER_ERROR;

  GST_DEBUG ("pqindex %u", framehdr->pqindex);

  /* compute pquant */
  if (structc->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
    framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex];
  else
    framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex];

  GST_DEBUG ("pquant %u", framehdr->pquant);

  if (framehdr->pqindex <= 8)
    READ_UINT8 (br, framehdr->halfqp, 1);
  else
    framehdr->halfqp = 0;

  /* Set pquantizer */
  framehdr->pquantizer = 1;
  if (structc->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
    framehdr->pquantizer = framehdr->pqindex < 9;
  else if (structc->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM)
    framehdr->pquantizer = 0;

  if (structc->quantizer == GST_VC1_QUANTIZER_EXPLICITLY)
    READ_UINT8 (br, framehdr->pquantizer, 1);

  if (structc->extended_mv == 1) {
    pic->mvrange = get_unary (br, 0, 3);
    GST_DEBUG ("mvrange %u", pic->mvrange);
  }

  if (structc->multires && (framehdr->ptype == GST_VC1_PICTURE_TYPE_P ||
          framehdr->ptype == GST_VC1_PICTURE_TYPE_I)) {
    READ_UINT8 (br, pic->respic, 2);
    GST_DEBUG ("Respic %u", pic->respic);
  }

  GST_DEBUG ("Parsing %u Frame, pquantizer %u, halfqp %u, rangeredfrm %u, "
      "interpfrm %u", framehdr->ptype, framehdr->pquantizer, framehdr->halfqp,
      pic->rangeredfrm, framehdr->interpfrm);

  switch (framehdr->ptype) {
    case GST_VC1_PICTURE_TYPE_I:
    case GST_VC1_PICTURE_TYPE_BI:
      framehdr->transacfrm = get_unary (br, 0, 2);
      pic->transacfrm2 = get_unary (br, 0, 2);
      READ_UINT8 (br, framehdr->transdctab, 1);

      GST_DEBUG ("transacfrm %u, transacfrm2 %u, transdctab %u",
          framehdr->transacfrm, pic->transacfrm2, framehdr->transdctab);
      break;

    case GST_VC1_PICTURE_TYPE_P:
      mvmodeidx = framehdr->pquant > 12;
      pic->mvmode = vc1_mvmode_table[mvmodeidx][get_unary (br, 1, 4)];

      if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) {
        pic->mvmode2 = vc1_mvmode2_table[mvmodeidx][get_unary (br, 1, 3)];
        READ_UINT8 (br, pic->lumscale, 6);
        READ_UINT8 (br, pic->lumshift, 6);
        GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift);
      }

      if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV ||
          (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP &&
              pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) {
        if (!bitplane_decoding (br, bitplanes ? bitplanes->mvtypemb : NULL,
                seqhdr, &pic->mvtypemb))
          goto failed;
        GST_DEBUG ("mvtypemb %u", pic->mvtypemb);
      }
      if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
              seqhdr, &pic->skipmb))
        goto failed;

      READ_UINT8 (br, pic->mvtab, 2);
      READ_UINT8 (br, pic->cbptab, 2);

      if (framehdr->dquant) {
        parse_vopdquant (br, framehdr, framehdr->dquant);
      }

      if (structc->vstransform) {
        READ_UINT8 (br, pic->ttmbf, 1);
        GST_DEBUG ("ttmbf %u", pic->ttmbf);

        if (pic->ttmbf) {
          READ_UINT8 (br, pic->ttfrm, 2);
          GST_DEBUG ("ttfrm %u", pic->ttfrm);
        }
      }

      framehdr->transacfrm = get_unary (br, 0, 2);
      READ_UINT8 (br, framehdr->transdctab, 1);

      GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
          "cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab,
          pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb);
      break;

    case GST_VC1_PICTURE_TYPE_B:
      READ_UINT8 (br, pic->mvmode, 1);
      if (!bitplane_decoding (br, bitplanes ? bitplanes->directmb : NULL,
              seqhdr, &pic->directmb))
        goto failed;

      if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
              seqhdr, &pic->skipmb))
        goto failed;

      READ_UINT8 (br, pic->mvtab, 2);
      READ_UINT8 (br, pic->cbptab, 2);

      if (framehdr->dquant)
        parse_vopdquant (br, framehdr, framehdr->dquant);

      if (structc->vstransform) {
        READ_UINT8 (br, pic->ttmbf, 1);

        if (pic->ttmbf) {
          READ_UINT8 (br, pic->ttfrm, 2);
        }
      }

      framehdr->transacfrm = get_unary (br, 0, 2);
      READ_UINT8 (br, framehdr->transdctab, 1);

      GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
          "cbptab %u directmb %u skipmb %u", framehdr->transacfrm,
          framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab,
          pic->directmb, pic->skipmb);

      break;

    default:
      goto failed;
      break;
  }

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to parse Simple picture header");

  return GST_VC1_PARSER_ERROR;
}

static GstVC1ParserResult
parse_sequence_header_struct_a (GstBitReader * br, GstVC1SeqStructA * structa)
{
  if (gst_bit_reader_get_remaining (br) < 64) {
    GST_WARNING ("Failed to parse struct A");

    return GST_VC1_PARSER_ERROR;
  }

  structa->vert_size = gst_bit_reader_get_bits_uint32_unchecked (br, 32);
  structa->horiz_size = gst_bit_reader_get_bits_uint32_unchecked (br, 32);

  return GST_VC1_PARSER_OK;
}

static GstVC1ParserResult
parse_sequence_header_struct_b (GstBitReader * br, GstVC1SeqStructB * structb)
{
  if (gst_bit_reader_get_remaining (br) < 96) {
    GST_WARNING ("Failed to parse sequence header");

    return GST_VC1_PARSER_ERROR;
  }

  structb->level = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
  structb->cbr = gst_bit_reader_get_bits_uint8_unchecked (br, 1);

  /* res4 */
  gst_bit_reader_skip_unchecked (br, 4);

  structb->hrd_buffer = gst_bit_reader_get_bits_uint32_unchecked (br, 24);
  structb->hrd_rate = gst_bit_reader_get_bits_uint32_unchecked (br, 32);
  structb->framerate = gst_bit_reader_get_bits_uint32_unchecked (br, 32);

  return GST_VC1_PARSER_OK;
}

static GstVC1ParserResult
parse_sequence_header_struct_c (GstBitReader * br, GstVC1SeqStructC * structc)
{
  guint8 old_interlaced_mode, tmp;

  READ_UINT8 (br, tmp, 2);
  structc->profile = tmp;

  if (structc->profile == GST_VC1_PROFILE_ADVANCED)
    return GST_VC1_PARSER_OK;

  GST_DEBUG ("Parsing sequence header in simple or main mode");

  if (gst_bit_reader_get_remaining (br) < 29)
    goto failed;

  /* Reserved bits */
  old_interlaced_mode = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  if (old_interlaced_mode)
    GST_WARNING ("Old interlaced mode used");

  structc->wmvp = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  if (structc->wmvp)
    GST_DEBUG ("WMVP mode");

  structc->frmrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
  structc->bitrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (br, 5);
  structc->loop_filter = gst_bit_reader_get_bits_uint8_unchecked (br, 1);

  calculate_framerate_bitrate (structc->frmrtq_postproc,
      structc->bitrtq_postproc, &structc->framerate, &structc->bitrate);

  /* Skipping reserved3 bit */
  gst_bit_reader_skip_unchecked (br, 1);

  structc->multires = gst_bit_reader_get_bits_uint8_unchecked (br, 1);

  /* Skipping reserved4 bit */
  gst_bit_reader_skip_unchecked (br, 1);

  structc->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  structc->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  structc->dquant = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
  structc->vstransform = gst_bit_reader_get_bits_uint8_unchecked (br, 1);

  /* Skipping reserved5 bit */
  gst_bit_reader_skip_unchecked (br, 1);

  structc->overlap = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  structc->syncmarker = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  structc->rangered = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
  structc->maxbframes = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
  structc->quantizer = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
  structc->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);

  GST_DEBUG ("frmrtq_postproc %u, bitrtq_postproc %u, loop_filter %u, "
      "multires %u, fastuvmc %u, extended_mv %u, dquant %u, vstransform %u, "
      "overlap %u, syncmarker %u, rangered %u, maxbframes %u, quantizer %u, "
      "finterpflag %u", structc->frmrtq_postproc, structc->bitrtq_postproc,
      structc->loop_filter, structc->multires, structc->fastuvmc,
      structc->extended_mv, structc->dquant, structc->vstransform,
      structc->overlap, structc->syncmarker, structc->rangered,
      structc->maxbframes, structc->quantizer, structc->finterpflag);

  if (structc->wmvp) {
    if (gst_bit_reader_get_remaining (br) < 29)
      goto failed;

    structc->coded_width = gst_bit_reader_get_bits_uint16_unchecked (br, 11);
    structc->coded_height = gst_bit_reader_get_bits_uint16_unchecked (br, 11);
    structc->framerate = gst_bit_reader_get_bits_uint8_unchecked (br, 5);
    gst_bit_reader_skip_unchecked (br, 1);
    structc->slice_code = gst_bit_reader_get_bits_uint8_unchecked (br, 1);

    GST_DEBUG ("coded_width %u, coded_height %u, framerate %u slice_code %u",
        structc->coded_width, structc->coded_height, structc->framerate,
        structc->slice_code);
  }

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to struct C");

  return GST_VC1_PARSER_ERROR;
}

/**** API ****/
/**
 * gst_vc1_identify_next_bdu:
 * @data: The data to parse
 * @size: the size of @data
 * @bdu: (out): The #GstVC1BDU where to store parsed bdu headers
 *
 * Parses @data and fills @bdu fields
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_identify_next_bdu (const guint8 * data, gsize size, GstVC1BDU * bdu)
{
  gint off1, off2;

  g_return_val_if_fail (bdu != NULL, GST_VC1_PARSER_ERROR);

  if (size < 4) {
    GST_DEBUG ("Can't parse, buffer has too small size %" G_GSSIZE_FORMAT,
        size);
    return GST_VC1_PARSER_ERROR;
  }

  off1 = scan_for_start_codes (data, size);

  if (off1 < 0) {
    GST_DEBUG ("No start code prefix in this buffer");
    return GST_VC1_PARSER_NO_BDU;
  }

  bdu->sc_offset = off1;

  bdu->offset = off1 + 4;
  bdu->data = (guint8 *) data;
  bdu->type = (GstVC1StartCode) (data[bdu->offset - 1]);

  if (bdu->type == GST_VC1_END_OF_SEQ) {
    GST_DEBUG ("End-of-Seq BDU found");
    bdu->size = 0;
    return GST_VC1_PARSER_OK;
  }

  off2 = scan_for_start_codes (data + bdu->offset, size - bdu->offset);
  if (off2 < 0) {
    GST_DEBUG ("Bdu start %d, No end found", bdu->offset);

    return GST_VC1_PARSER_NO_BDU_END;
  }

  if (off2 > 0 && data[bdu->offset + off2 - 1] == 00)
    off2--;

  bdu->size = off2;

  GST_DEBUG ("Complete bdu found. Off: %d, Size: %d", bdu->offset, bdu->size);
  return GST_VC1_PARSER_OK;
}

/**
 * gst_vc1_parse_sequence_layer:
 * @data: The data to parse
 * @size: the size of @data
 * @structa: The #GstVC1SeqLayer to set.
 *
 * Parses @data, and fills @seqlayer fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_sequence_layer (const guint8 * data, gsize size,
    GstVC1SeqLayer * seqlayer)
{
  guint32 tmp;
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (seqlayer != NULL, GST_VC1_PARSER_ERROR);

  READ_UINT32 (&br, tmp, 8);
  if (tmp != 0xC5)
    goto failed;

  READ_UINT32 (&br, seqlayer->numframes, 24);

  READ_UINT32 (&br, tmp, 32);
  if (tmp != 0x04)
    goto failed;

  if (parse_sequence_header_struct_c (&br, &seqlayer->struct_c) ==
      GST_VC1_PARSER_ERROR)
    goto failed;

  if (parse_sequence_header_struct_a (&br, &seqlayer->struct_a) ==
      GST_VC1_PARSER_ERROR)
    goto failed;

  READ_UINT32 (&br, tmp, 32);
  if (tmp != 0x0C)
    goto failed;

  if (parse_sequence_header_struct_b (&br, &seqlayer->struct_b) ==
      GST_VC1_PARSER_ERROR)
    goto failed;

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to parse sequence layer");

  return GST_VC1_PARSER_ERROR;
}

/**
 * gst_vc1_parse_sequence_header_struct_a:
 * @data: The data to parse
 * @size: the size of @data
 * @structa: The #GstVC1SeqStructA to set.
 *
 * Parses @data, and fills @structa fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_sequence_header_struct_a (const guint8 * data,
    gsize size, GstVC1SeqStructA * structa)
{
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (structa != NULL, GST_VC1_PARSER_ERROR);

  return parse_sequence_header_struct_a (&br, structa);
}

/**
 * gst_vc1_parse_sequence_header_struct_b:
 * @data: The data to parse
 * @size: the size of @data
 * @structa: The #GstVC1SeqStructB to set.
 *
 * Parses @data, and fills @structb fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_sequence_header_struct_b (const guint8 * data,
    gsize size, GstVC1SeqStructB * structb)
{
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (structb != NULL, GST_VC1_PARSER_ERROR);

  return parse_sequence_header_struct_b (&br, structb);
}

/**
 * gst_vc1_parse_sequence_header_struct_c:
 * @data: The data to parse
 * @size: the size of @data
 * @structc: The #GstVC1SeqStructC to set.
 *
 * Parses @data, and fills @structc fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_sequence_header_struct_c (const guint8 * data, gsize size,
    GstVC1SeqStructC * structc)
{
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (structc != NULL, GST_VC1_PARSER_ERROR);

  return parse_sequence_header_struct_c (&br, structc);
}

/**
* gst_vc1_parse_sequence_header:
* @data: The data to parse
* @size: the size of @data
* @seqhdr: The #GstVC1SeqHdr to set.
 *
 * Parses @data, and fills @seqhdr fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_sequence_header (const guint8 * data, gsize size,
    GstVC1SeqHdr * seqhdr)
{
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (seqhdr != NULL, GST_VC1_PARSER_ERROR);

  if (parse_sequence_header_struct_c (&br, &seqhdr->struct_c) ==
      GST_VC1_PARSER_ERROR)
    goto failed;

  /*  Convenience field */
  seqhdr->profile = seqhdr->struct_c.profile;

  if (seqhdr->profile == GST_VC1_PROFILE_ADVANCED)
    return parse_sequence_header_advanced (seqhdr, &br);

  /* Compute MB height and width */
  calculate_mb_size (seqhdr, seqhdr->struct_c.coded_width,
      seqhdr->struct_c.coded_height);

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to parse sequence header");

  return GST_VC1_PARSER_ERROR;
}

/**
 * gst_vc1_parse_entry_point_header:
 * @data: The data to parse
 * @size: the size of @data
 * @entrypoint: (out): The #GstVC1EntryPointHdr to set.
 * @seqhdr: The #GstVC1SeqHdr currently being parsed
 *
 * Parses @data, and sets @entrypoint fields.
 *
 * Returns: a #GstVC1EntryPointHdr
 */
GstVC1ParserResult
gst_vc1_parse_entry_point_header (const guint8 * data, gsize size,
    GstVC1EntryPointHdr * entrypoint, GstVC1SeqHdr * seqhdr)
{
  GstBitReader br;
  guint8 i;
  GstVC1AdvancedSeqHdr *advanced = &seqhdr->advanced;

  g_return_val_if_fail (entrypoint != NULL, GST_VC1_PARSER_ERROR);

  gst_bit_reader_init (&br, data, size);

  if (gst_bit_reader_get_remaining (&br) < 13)
    goto failed;

  entrypoint->broken_link = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->closed_entry = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->panscan_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->refdist_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->loopfilter = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->dquant = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
  entrypoint->vstransform = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->overlap = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  entrypoint->quantizer = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);

  if (advanced->hrd_param_flag) {
    if (seqhdr->advanced.hrd_param.hrd_num_leaky_buckets >
        MAX_HRD_NUM_LEAKY_BUCKETS) {
      GST_WARNING
          ("hrd_num_leaky_buckets (%d) > MAX_HRD_NUM_LEAKY_BUCKETS (%d)",
          seqhdr->advanced.hrd_param.hrd_num_leaky_buckets,
          MAX_HRD_NUM_LEAKY_BUCKETS);
      goto failed;
    }
    for (i = 0; i < seqhdr->advanced.hrd_param.hrd_num_leaky_buckets; i++)
      READ_UINT8 (&br, entrypoint->hrd_full[i], 8);
  }

  READ_UINT8 (&br, entrypoint->coded_size_flag, 1);
  if (entrypoint->coded_size_flag) {
    READ_UINT16 (&br, entrypoint->coded_width, 12);
    READ_UINT16 (&br, entrypoint->coded_height, 12);
    entrypoint->coded_height = (entrypoint->coded_height + 1) << 1;
    entrypoint->coded_width = (entrypoint->coded_width + 1) << 1;
    calculate_mb_size (seqhdr, entrypoint->coded_width,
        entrypoint->coded_height);
  }

  if (entrypoint->extended_mv)
    READ_UINT8 (&br, entrypoint->extended_dmv, 1);

  READ_UINT8 (&br, entrypoint->range_mapy_flag, 1);
  if (entrypoint->range_mapy_flag)
    READ_UINT8 (&br, entrypoint->range_mapy, 3);

  READ_UINT8 (&br, entrypoint->range_mapuv_flag, 1);
  if (entrypoint->range_mapy_flag)
    READ_UINT8 (&br, entrypoint->range_mapuv, 3);

  advanced->entrypoint = *entrypoint;

  return GST_VC1_PARSER_OK;

failed:
  GST_WARNING ("Failed to parse entry point header");

  return GST_VC1_PARSER_ERROR;
}

/**
 * gst_vc1_parse_frame_layer:
 * @data: The data to parse
 * @size: the size of @data
 * @framelayer: The #GstVC1FrameLayer to fill.
 *
 * Parses @data, and fills @framelayer fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_frame_layer (const guint8 * data, gsize size,
    GstVC1FrameLayer * framelayer)
{
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  if (gst_bit_reader_get_remaining (&br) < 64) {
    GST_WARNING ("Could not parse frame layer");

    return GST_VC1_PARSER_ERROR;
  }

  /* set default values */
  framelayer->skiped_p_frame = 0;

  framelayer->key = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  gst_bit_reader_skip_unchecked (&br, 7);

  framelayer->framesize = gst_bit_reader_get_bits_uint32_unchecked (&br, 24);

  if (framelayer->framesize == 0 || framelayer->framesize == 1)
    framelayer->skiped_p_frame = 1;

  /* compute  next_framelayer_offset */
  framelayer->next_framelayer_offset = framelayer->framesize + 8;

  framelayer->timestamp = gst_bit_reader_get_bits_uint32_unchecked (&br, 32);

  return GST_VC1_PARSER_OK;
}

/**
 * gst_vc1_parse_frame_header:
 * @data: The data to parse
 * @size: the size of @data
 * @framehdr: The #GstVC1FrameHdr to fill.
 * @seqhdr: The #GstVC1SeqHdr currently being parsed
 * @bitplanes: The #GstVC1BitPlanes to store bitplanes in or %NULL
 *
 * Parses @data, and fills @entrypoint fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_frame_header (const guint8 * data, gsize size,
    GstVC1FrameHdr * framehdr, GstVC1SeqHdr * seqhdr,
    GstVC1BitPlanes * bitplanes)
{
  GstBitReader br;
  GstVC1ParserResult result;

  gst_bit_reader_init (&br, data, size);

  if (seqhdr->profile == GST_VC1_PROFILE_ADVANCED)
    result = parse_frame_header_advanced (&br, framehdr, seqhdr, bitplanes,
        FALSE);
  else
    result = parse_frame_header (&br, framehdr, seqhdr, bitplanes);

  framehdr->header_size = gst_bit_reader_get_pos (&br);
  return result;
}

/**
 * gst_vc1_parse_field_header:
 * @data: The data to parse
 * @size: the size of @data
 * @fieldhdr: The #GstVC1FrameHdr to fill.
 * @seqhdr: The #GstVC1SeqHdr currently being parsed
 * @bitplanes: The #GstVC1BitPlanes to store bitplanes in or %NULL
 *
 * Parses @data, and fills @fieldhdr fields.
 *
 * Returns: a #GstVC1ParserResult
 */
GstVC1ParserResult
gst_vc1_parse_field_header (const guint8 * data, gsize size,
    GstVC1FrameHdr * fieldhdr, GstVC1SeqHdr * seqhdr,
    GstVC1BitPlanes * bitplanes)
{
  GstBitReader br;
  GstVC1ParserResult result;

  gst_bit_reader_init (&br, data, size);

  result = parse_frame_header_advanced (&br, fieldhdr, seqhdr, bitplanes, TRUE);

  return result;
}

/**
 * gst_vc1_bitplanes_new:
 * @seqhdr: The #GstVC1SeqHdr from which to set @bitplanes
 *
 * Creates a new #GstVC1BitPlanes. It should be freed with
 * gst_vc1_bitplanes_free() after use.
 *
 * Returns: a new #GstVC1BitPlanes
 */
GstVC1BitPlanes *
gst_vc1_bitplanes_new (void)
{
  return g_slice_new0 (GstVC1BitPlanes);
}

/**
 * gst_vc1_bitplane_free:
 * @bitplanes: the #GstVC1BitPlanes to free
 *
 * Frees @bitplanes.
 */
void
gst_vc1_bitplanes_free (GstVC1BitPlanes * bitplanes)
{
  gst_vc1_bitplanes_free_1 (bitplanes);
  g_slice_free (GstVC1BitPlanes, bitplanes);
}

/**
 * gst_vc1_bitplane_free_1:
 * @bitplanes: The #GstVC1BitPlanes to free
 *
 * Frees @bitplanes fields.
 */
void
gst_vc1_bitplanes_free_1 (GstVC1BitPlanes * bitplanes)
{
  g_free (bitplanes->acpred);
  g_free (bitplanes->fieldtx);
  g_free (bitplanes->overflags);
  g_free (bitplanes->mvtypemb);
  g_free (bitplanes->skipmb);
  g_free (bitplanes->directmb);
  g_free (bitplanes->forwardmb);
}

/**
 * gst_vc1_bitplanes_ensure_size:
 * @bitplanes: The #GstVC1BitPlanes to reset
 * @seqhdr: The #GstVC1SeqHdr from which to set @bitplanes
 *
 * Fills the @bitplanes structure from @seqhdr, this function
 * should be called after #gst_vc1_parse_sequence_header if
 * in simple or main mode, or after #gst_vc1_parse_entry_point_header
 * if in advanced mode.
 *
 * Returns: %TRUE if everything went fine, %FALSE otherwize
 */
gboolean
gst_vc1_bitplanes_ensure_size (GstVC1BitPlanes * bitplanes,
    GstVC1SeqHdr * seqhdr)
{
  g_return_val_if_fail (bitplanes != NULL, FALSE);
  g_return_val_if_fail (seqhdr != NULL, FALSE);

  if (bitplanes->size) {
    bitplanes->size = seqhdr->mb_height * seqhdr->mb_stride;
    bitplanes->acpred =
        g_realloc_n (bitplanes->acpred, bitplanes->size, sizeof (guint8));
    bitplanes->fieldtx =
        g_realloc_n (bitplanes->fieldtx, bitplanes->size, sizeof (guint8));
    bitplanes->overflags =
        g_realloc_n (bitplanes->overflags, bitplanes->size, sizeof (guint8));
    bitplanes->mvtypemb =
        g_realloc_n (bitplanes->mvtypemb, bitplanes->size, sizeof (guint8));
    bitplanes->skipmb =
        g_realloc_n (bitplanes->skipmb, bitplanes->size, sizeof (guint8));
    bitplanes->directmb =
        g_realloc_n (bitplanes->directmb, bitplanes->size, sizeof (guint8));
    bitplanes->forwardmb =
        g_realloc_n (bitplanes->forwardmb, bitplanes->size, sizeof (guint8));
  } else {
    bitplanes->size = seqhdr->mb_height * seqhdr->mb_stride;
    bitplanes->acpred = g_malloc0 (bitplanes->size * sizeof (guint8));
    bitplanes->fieldtx = g_malloc0 (bitplanes->size * sizeof (guint8));
    bitplanes->overflags = g_malloc0 (bitplanes->size * sizeof (guint8));
    bitplanes->mvtypemb = g_malloc0 (bitplanes->size * sizeof (guint8));
    bitplanes->skipmb = g_malloc0 (bitplanes->size * sizeof (guint8));
    bitplanes->directmb = g_malloc0 (bitplanes->size * sizeof (guint8));
    bitplanes->forwardmb = g_malloc0 (bitplanes->size * sizeof (guint8));
  }

  return TRUE;
}
