static gboolean
gst_ac3_parse_frame_header_eac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
    gint skip, guint * frame_size, guint * rate, guint * chans, guint * blks,
    guint * sid)
{
  GstBitReader bits = GST_BIT_READER_INIT_FROM_BUFFER (buf);
  guint16 frmsiz, sample_rate, blocks;
  guint8 strmtyp, fscod, fscod2, acmod, lfe_on, strmid, numblkscod;

  GST_LOG_OBJECT (ac3parse, "parsing e-ac3");

  gst_bit_reader_skip_unchecked (&bits, skip * 8);

  gst_bit_reader_skip_unchecked (&bits, 16);
  strmtyp = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* strmtyp     */
  if (G_UNLIKELY (strmtyp == 3)) {
    GST_DEBUG_OBJECT (ac3parse, "bad strmtyp %d", strmtyp);
    return FALSE;
  }

  strmid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);  /* substreamid */
  frmsiz = gst_bit_reader_get_bits_uint16_unchecked (&bits, 11);        /* frmsiz      */
  fscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);   /* fscod       */
  if (fscod == 3) {
    fscod2 = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);        /* fscod2      */
    if (G_UNLIKELY (fscod2 == 3)) {
      GST_DEBUG_OBJECT (ac3parse, "invalid fscod2");
      return FALSE;
    }
    sample_rate = fscod_rates[fscod2] / 2;
    blocks = 6;
  } else {
    numblkscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);    /* numblkscod  */
    sample_rate = fscod_rates[fscod];
    blocks = numblks[numblkscod];
  }

  acmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);   /* acmod       */
  lfe_on = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1);  /* lfeon       */

  gst_bit_reader_skip_unchecked (&bits, 5);     /* bsid        */

  if (frame_size)
    *frame_size = (frmsiz + 1) * 2;
  if (rate)
    *rate = sample_rate;
  if (chans)
    *chans = acmod_chans[acmod] + lfe_on;
  if (blks)
    *blks = blocks;
  if (sid)
    *sid = (strmtyp & 0x1) << 3 | strmid;

  return TRUE;
}
Example #2
0
static gboolean
gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, gint skip,
    guint * framesize, guint * rate, guint * chans, guint * blocks,
    guint * sid, gboolean * eac)
{
  GstBitReader bits;
  guint16 sync;
  guint8 bsid;
  GstMapInfo map;
  gboolean ret = FALSE;

  gst_buffer_map (buf, &map, GST_MAP_READ);
  gst_bit_reader_init (&bits, map.data, map.size);

  GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", map.data, MIN (map.size, 16));

  gst_bit_reader_skip_unchecked (&bits, skip * 8);

  sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
  gst_bit_reader_skip_unchecked (&bits, 16 + 8);
  bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5);

  if (G_UNLIKELY (sync != 0x0b77))
    goto cleanup;

  GST_LOG_OBJECT (parse, "bsid = %d", bsid);

  if (bsid <= 10) {
    if (eac)
      *eac = FALSE;
    ret = gst_ac3_parse_frame_header_ac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
    goto cleanup;
  } else if (bsid <= 16) {
    if (eac)
      *eac = TRUE;
    ret = gst_ac3_parse_frame_header_eac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
    goto cleanup;
  } else {
    GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
    ret = FALSE;
    goto cleanup;
  }

  GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);

cleanup:
  gst_buffer_unmap (buf, &map);

  return ret;
}
static gboolean
gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, gint skip,
    guint * framesize, guint * rate, guint * chans, guint * blocks,
    guint * sid, gboolean * eac)
{
  GstBitReader bits = GST_BIT_READER_INIT_FROM_BUFFER (buf);
  guint16 sync;
  guint8 bsid;

  GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", GST_BUFFER_DATA (buf), 16);

  gst_bit_reader_skip_unchecked (&bits, skip * 8);

  sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
  gst_bit_reader_skip_unchecked (&bits, 16 + 8);
  bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5);

  if (G_UNLIKELY (sync != 0x0b77))
    return FALSE;

  GST_LOG_OBJECT (parse, "bsid = %d", bsid);

  if (bsid <= 10) {
    if (eac)
      *eac = FALSE;
    return gst_ac3_parse_frame_header_ac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
  } else if (bsid <= 16) {
    if (eac)
      *eac = TRUE;
    return gst_ac3_parse_frame_header_eac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
  } else {
    GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
    return FALSE;
  }
}
Example #4
0
static GstFlowReturn
gst_vdp_h264_dec_parse_data (GstBaseVideoDecoder * base_video_decoder,
    GstBuffer * buf, gboolean at_eos, GstVideoFrame * frame)
{
  GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
  GstBitReader reader;
  GstNalUnit nal_unit;
  guint8 forbidden_zero_bit;

  guint8 *data;
  guint size;
  gint i;

  GstFlowReturn ret = GST_FLOW_OK;

  GST_MEMDUMP ("data", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));

  gst_bit_reader_init_from_buffer (&reader, buf);

  if (gst_bit_reader_get_remaining (&reader) <
      h264_dec->nal_length_size * 8 + 7)
    goto invalid_packet;

  /* skip nal_length or sync code */
  gst_bit_reader_skip_unchecked (&reader, h264_dec->nal_length_size * 8);

  forbidden_zero_bit = gst_bit_reader_get_bits_uint8_unchecked (&reader, 1);

  if (forbidden_zero_bit != 0) {
    GST_WARNING ("forbidden_zero_bit != 0");
    return GST_FLOW_ERROR;
  }

  nal_unit.ref_idc = gst_bit_reader_get_bits_uint16_unchecked (&reader, 2);
  GST_DEBUG ("nal_ref_idc: %u", nal_unit.ref_idc);

  /* read nal_unit_type */
  nal_unit.type = gst_bit_reader_get_bits_uint16_unchecked (&reader, 5);

  GST_DEBUG ("nal_unit_type: %u", nal_unit.type);
  if (nal_unit.type == 14 || nal_unit.type == 20) {
    if (!gst_bit_reader_skip (&reader, 24))
      goto invalid_packet;
  }
  nal_unit.IdrPicFlag = (nal_unit.type == 5 ? 1 : 0);

  data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
  size = gst_bit_reader_get_remaining (&reader) / 8;

  i = size - 1;
  while ((gint) size > 0 && data[i] == 0x00) {
    size--;
    i--;
  }

  if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_H264_FRAME_GOT_PRIMARY)) {
    if (nal_unit.type == GST_NAL_SPS || nal_unit.type == GST_NAL_PPS ||
        nal_unit.type == GST_NAL_SEI || nal_unit.type == GST_NAL_AU_DELIMITER ||
        (nal_unit.type >= 14 && nal_unit.type <= 18))
      ret =
          gst_base_video_decoder_have_frame (base_video_decoder, FALSE, &frame);
  }

  if (nal_unit.type >= GST_NAL_SLICE && nal_unit.type <= GST_NAL_SLICE_IDR) {
    GstH264Slice slice;

    if (!gst_h264_parser_parse_slice_header (h264_dec->parser, &slice, data,
            size, nal_unit))
      goto invalid_packet;

    if (slice.redundant_pic_cnt == 0) {
      if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_H264_FRAME_GOT_PRIMARY)) {
        GstH264Slice *p_slice;
        guint8 pic_order_cnt_type, p_pic_order_cnt_type;
        gboolean finish_frame = FALSE;

        p_slice = &(GST_H264_FRAME_CAST (frame)->slice_hdr);
        pic_order_cnt_type = slice.picture->sequence->pic_order_cnt_type;
        p_pic_order_cnt_type = p_slice->picture->sequence->pic_order_cnt_type;

        if (slice.frame_num != p_slice->frame_num)
          finish_frame = TRUE;

        else if (slice.picture != p_slice->picture)
          finish_frame = TRUE;

        else if (slice.bottom_field_flag != p_slice->bottom_field_flag)
          finish_frame = TRUE;

        else if (nal_unit.ref_idc != p_slice->nal_unit.ref_idc &&
            (nal_unit.ref_idc == 0 || p_slice->nal_unit.ref_idc == 0))
          finish_frame = TRUE;

        else if ((pic_order_cnt_type == 0 && p_pic_order_cnt_type == 0) &&
            (slice.pic_order_cnt_lsb != p_slice->pic_order_cnt_lsb ||
                slice.delta_pic_order_cnt_bottom !=
                p_slice->delta_pic_order_cnt_bottom))
          finish_frame = TRUE;

        else if ((p_pic_order_cnt_type == 1 && p_pic_order_cnt_type == 1) &&
            (slice.delta_pic_order_cnt[0] != p_slice->delta_pic_order_cnt[0] ||
                slice.delta_pic_order_cnt[1] !=
                p_slice->delta_pic_order_cnt[1]))
          finish_frame = TRUE;

        if (finish_frame)
          ret =
              gst_base_video_decoder_have_frame (base_video_decoder, FALSE,
              &frame);

      }

      if (!GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_H264_FRAME_GOT_PRIMARY)) {
        if (GST_H264_IS_I_SLICE (slice.type)
            || GST_H264_IS_SI_SLICE (slice.type))
          GST_VIDEO_FRAME_FLAG_SET (frame, GST_VIDEO_FRAME_FLAG_KEYFRAME);

        GST_H264_FRAME_CAST (frame)->slice_hdr = slice;
        GST_VIDEO_FRAME_FLAG_SET (frame, GST_H264_FRAME_GOT_PRIMARY);
      }
    }
    gst_h264_frame_add_slice ((GstH264Frame *) frame, buf);
  }

  if (nal_unit.type == GST_NAL_SPS) {
    if (!gst_h264_parser_parse_sequence (h264_dec->parser, data, size))
      goto invalid_packet;
  }

  if (nal_unit.type == GST_NAL_PPS) {
    if (!gst_h264_parser_parse_picture (h264_dec->parser, data, size))
      goto invalid_packet;
  }

  gst_buffer_unref (buf);
  return ret;

invalid_packet:
  GST_WARNING ("Invalid packet size!");
  gst_buffer_unref (buf);

  return GST_FLOW_OK;
}
/**
 * gst_mpeg4_parse_video_object_layer:
 * @vol: The #GstMpeg4VideoObjectLayer structure to fill
 * @vo: The #GstMpeg4VisualObject currently being parsed or %NULL
 * @data: The data to parse
 * @size: The size of the @data to parse
 *
 * Parses @data containing the video object layer packet, and fills
 * the @vol structure.
 *
 * Returns: a #GstMpeg4ParseResult
 */
GstMpeg4ParseResult
gst_mpeg4_parse_video_object_layer (GstMpeg4VideoObjectLayer * vol,
    GstMpeg4VisualObject * vo, const guint8 * data, gsize size)
{
  guint8 video_object_layer_start_code;

  /* Used for enums types */
  guint8 tmp;
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (vol != NULL, GST_MPEG4_PARSER_ERROR);

  GST_DEBUG ("Parsing video object layer");

  READ_UINT8 (&br, video_object_layer_start_code, 8);
  if (!(video_object_layer_start_code >= GST_MPEG4_VIDEO_LAYER_FIRST &&
          video_object_layer_start_code <= GST_MPEG4_VIDEO_LAYER_LAST))
    goto wrong_start_code;

  /* set default values */
  if (vo) {
    vol->verid = vo->verid;
    vol->priority = vo->priority;
  } else {
    vol->verid = 1;
    vol->priority = 0;
  }

  vol->low_delay = FALSE;
  vol->chroma_format = 1;
  vol->vbv_parameters = FALSE;
  vol->quant_precision = 5;
  vol->bits_per_pixel = 8;
  vol->quarter_sample = FALSE;
  vol->newpred_enable = FALSE;
  vol->interlaced = 0;
  vol->width = 0;
  vol->height = 0;

  READ_UINT8 (&br, vol->random_accessible_vol, 1);
  READ_UINT8 (&br, vol->video_object_type_indication, 8);

  READ_UINT8 (&br, vol->is_object_layer_identifier, 1);
  if (vol->is_object_layer_identifier) {
    READ_UINT8 (&br, vol->verid, 4);
    READ_UINT8 (&br, vol->priority, 3);
  }

  READ_UINT8 (&br, tmp, 4);
  vol->aspect_ratio_info = tmp;
  if (vol->aspect_ratio_info != GST_MPEG4_EXTENDED_PAR) {
    mpeg4_util_par_from_info (vol->aspect_ratio_info, &vol->par_width,
        &vol->par_height);

  } else {
    gint v;

    READ_UINT8 (&br, vol->par_width, 8);
    v = vol->par_width;
    CHECK_ALLOWED (v, 1, 255);

    READ_UINT8 (&br, vol->par_height, 8);
    v = vol->par_height;
    CHECK_ALLOWED (v, 1, 255);
  }
  GST_DEBUG ("Pixel aspect ratio %d/%d", vol->par_width, vol->par_width);

  READ_UINT8 (&br, vol->control_parameters, 1);
  if (vol->control_parameters) {
    guint8 chroma_format;

    READ_UINT8 (&br, chroma_format, 2);
    vol->chroma_format = chroma_format;
    READ_UINT8 (&br, vol->low_delay, 1);

    READ_UINT8 (&br, vol->vbv_parameters, 1);
    if (vol->vbv_parameters) {
      CHECK_REMAINING (&br, 79);

      vol->first_half_bitrate =
          gst_bit_reader_get_bits_uint16_unchecked (&br, 15);
      MARKER_UNCHECKED (&br);

      vol->latter_half_bitrate =
          gst_bit_reader_get_bits_uint16_unchecked (&br, 15);
      MARKER_UNCHECKED (&br);

      vol->bit_rate =
          (vol->first_half_bitrate << 15) | vol->latter_half_bitrate;

      vol->first_half_vbv_buffer_size =
          gst_bit_reader_get_bits_uint16_unchecked (&br, 15);
      MARKER_UNCHECKED (&br);

      vol->latter_half_vbv_buffer_size =
          gst_bit_reader_get_bits_uint8_unchecked (&br, 3);

      vol->vbv_buffer_size = (vol->first_half_vbv_buffer_size << 15) |
          vol->latter_half_vbv_buffer_size;

      vol->first_half_vbv_occupancy =
          gst_bit_reader_get_bits_uint16_unchecked (&br, 11);
      MARKER_UNCHECKED (&br);

      vol->latter_half_vbv_occupancy =
          gst_bit_reader_get_bits_uint16_unchecked (&br, 15);
      MARKER_UNCHECKED (&br);
    }
  }

  READ_UINT8 (&br, tmp, 2);
  vol->shape = tmp;

  if (vol->shape == GST_MPEG4_GRAYSCALE) {
    /* TODO support grayscale shapes, for now we just pass */

    /* Something the standard starts to define... */
    GST_WARNING ("Grayscale shaped not supported");
    goto failed;
  }

  if (vol->shape == GST_MPEG4_GRAYSCALE && vol->verid != 0x01)
    READ_UINT8 (&br, vol->shape_extension, 4);

  CHECK_REMAINING (&br, 19);

  MARKER_UNCHECKED (&br);
  vol->vop_time_increment_resolution =
      gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
  if (vol->vop_time_increment_resolution < 1) {
    GST_WARNING ("value not in allowed range. value: %d, range %d-%d",
        vol->vop_time_increment_resolution, 1, G_MAXUINT16);
    goto failed;
  }
  vol->vop_time_increment_bits =
      g_bit_storage (vol->vop_time_increment_resolution);

  MARKER_UNCHECKED (&br);
  vol->fixed_vop_rate = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  if (vol->fixed_vop_rate)
    READ_UINT16 (&br, vol->fixed_vop_time_increment,
        vol->vop_time_increment_bits);

  if (vol->shape != GST_MPEG4_BINARY_ONLY) {
    if (vol->shape == GST_MPEG4_RECTANGULAR) {
      CHECK_REMAINING (&br, 29);

      MARKER_UNCHECKED (&br);
      vol->width = gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
      MARKER_UNCHECKED (&br);
      vol->height = gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
      MARKER_UNCHECKED (&br);
    }

    READ_UINT8 (&br, vol->interlaced, 1);
    READ_UINT8 (&br, vol->obmc_disable, 1);

    if (vol->verid == 0x1)
      READ_UINT8 (&br, tmp, 1);
    else
      READ_UINT8 (&br, tmp, 2);
    vol->sprite_enable = tmp;

    if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC ||
        vol->sprite_enable == GST_MPEG4_SPRITE_GMG) {

      if (vol->sprite_enable == GST_MPEG4_SPRITE_GMG)
        CHECK_REMAINING (&br, 9);
      else {
        CHECK_REMAINING (&br, 65);

        vol->sprite_width = gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
        MARKER_UNCHECKED (&br);

        vol->sprite_height = gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
        MARKER_UNCHECKED (&br);

        vol->sprite_left_coordinate =
            gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
        MARKER_UNCHECKED (&br);

        vol->sprite_top_coordinate =
            gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
        MARKER_UNCHECKED (&br);
      }
      vol->no_of_sprite_warping_points =
          gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
      vol->sprite_warping_accuracy =
          gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
      vol->sprite_brightness_change =
          gst_bit_reader_get_bits_uint8_unchecked (&br, 1);

      if (vol->sprite_enable != GST_MPEG4_SPRITE_GMG)
        vol->low_latency_sprite_enable =
            gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
    }

    if (vol->verid != 0x1 && vol->shape != GST_MPEG4_RECTANGULAR)
      READ_UINT8 (&br, vol->sadct_disable, 1);

    READ_UINT8 (&br, vol->not_8_bit, 1);
    if (vol->not_8_bit) {
      READ_UINT8 (&br, vol->quant_precision, 4);
      CHECK_ALLOWED (vol->quant_precision, 3, 9);

      READ_UINT8 (&br, vol->bits_per_pixel, 4);
      CHECK_ALLOWED (vol->bits_per_pixel, 4, 12);
    }

    if (vol->shape == GST_MPEG4_GRAYSCALE) {
      /* We don't actually support it */
      READ_UINT8 (&br, vol->no_gray_quant_update, 1);
      READ_UINT8 (&br, vol->composition_method, 1);
      READ_UINT8 (&br, vol->linear_composition, 1);
    }

    READ_UINT8 (&br, vol->quant_type, 1);
    if (vol->quant_type) {
      if (!parse_quant (&br, vol->intra_quant_mat, default_intra_quant_mat,
              &vol->load_intra_quant_mat))
        goto failed;

      if (!parse_quant (&br, vol->non_intra_quant_mat,
              default_non_intra_quant_mat, &vol->load_non_intra_quant_mat))
        goto failed;

      if (vol->shape == GST_MPEG4_GRAYSCALE) {
        /* Something the standard starts to define... */
        GST_WARNING ("Grayscale shaped not supported");
        goto failed;
      }

    } else {
      memset (&vol->intra_quant_mat, 0, 64);
      memset (&vol->non_intra_quant_mat, 0, 64);
    }

    if (vol->verid != 0x1)
      READ_UINT8 (&br, vol->quarter_sample, 1);

    READ_UINT8 (&br, vol->complexity_estimation_disable, 1);
    if (!vol->complexity_estimation_disable) {
      guint8 estimation_method;
      guint8 estimation_disable;

      /* skip unneeded properties */
      READ_UINT8 (&br, estimation_method, 2);
      if (estimation_method < 2) {
        READ_UINT8 (&br, estimation_disable, 1);
        if (!estimation_disable)
          SKIP (&br, 6);
        READ_UINT8 (&br, estimation_disable, 1);
        if (!estimation_disable)
          SKIP (&br, 4);
        CHECK_MARKER (&br);
        READ_UINT8 (&br, estimation_disable, 1);
        if (!estimation_disable)
          SKIP (&br, 4);
        READ_UINT8 (&br, estimation_disable, 1);
        if (!estimation_disable)
          SKIP (&br, 6);
        CHECK_MARKER (&br);

        if (estimation_method == 1) {
          READ_UINT8 (&br, estimation_disable, 1);
          if (!estimation_disable)
            SKIP (&br, 2);
        }
      }
    }

    READ_UINT8 (&br, vol->resync_marker_disable, 1);
    READ_UINT8 (&br, vol->data_partitioned, 1);

    if (vol->data_partitioned)
      READ_UINT8 (&br, vol->reversible_vlc, 1);

    if (vol->verid != 0x01) {
      READ_UINT8 (&br, vol->newpred_enable, 1);
      if (vol->newpred_enable)
        /* requested_upstream_message_type and newpred_segment_type */
        SKIP (&br, 3);

      READ_UINT8 (&br, vol->reduced_resolution_vop_enable, 1);
    }

    READ_UINT8 (&br, vol->scalability, 1);
    if (vol->scalability) {
      SKIP (&br, 26);           /* Few not needed props */
      READ_UINT8 (&br, vol->enhancement_type, 1);
    }

    /* More unused infos */
  } else if (vol->verid != 0x01) {
    GST_WARNING ("Binary only shapes not fully supported");
    goto failed;
  }
  /* ... */

  return GST_MPEG4_PARSER_OK;

failed:
  GST_WARNING ("failed parsing \"Video Object Layer\"");
  return GST_MPEG4_PARSER_ERROR;

wrong_start_code:
  GST_WARNING ("got buffer with wrong start code");
  goto failed;
}
/**
 * gst_mpeg4_parse_video_object_plane:
 * @vop: The #GstMpeg4VideoObjectPlane currently being parsed
 * @sprite_trajectory: A #GstMpeg4SpriteTrajectory to fill or %NULL
 * @vol: The #GstMpeg4VideoObjectLayer structure to fill
 * @data: The data to parse
 * @size: The size of the @data to parse
 *
 * Parses @data containing the video object plane packet, and fills the @vol
 * structure.
 *
 * Returns: a #GstMpeg4ParseResult
 */
GstMpeg4ParseResult
gst_mpeg4_parse_video_object_plane (GstMpeg4VideoObjectPlane * vop,
    GstMpeg4SpriteTrajectory * sprite_trajectory,
    GstMpeg4VideoObjectLayer * vol, const guint8 * data, gsize size)
{
  guint8 vop_start_code, coding_type, modulo_time_base;
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (vop != NULL, GST_MPEG4_PARSER_ERROR);

  if (vol->shape == GST_MPEG4_BINARY_ONLY) {
    /* TODO: implement binary only shapes */
    GST_WARNING ("Binary only shapes not supported");
    goto failed;
  }

  READ_UINT8 (&br, vop_start_code, 8);
  if (vop_start_code != GST_MPEG4_VIDEO_OBJ_PLANE)
    goto wrong_start_code;


  /* set default values */
  vop->modulo_time_base = 0;
  vop->rounding_type = 0;
  vop->top_field_first = 1;
  vop->alternate_vertical_scan_flag = 0;
  vop->fcode_forward = 1;
  vop->fcode_backward = 1;

  /*  Compute macroblock informations */
  if (vol->interlaced)
    vop->mb_height = (2 * (vol->height + 31) / 32);
  else
    vop->mb_height = (vol->height + 15) / 16;

  vop->mb_width = (vol->width + 15) / 16;
  vop->mb_num = vop->mb_height * vop->mb_width;

  READ_UINT8 (&br, coding_type, 2);
  vop->coding_type = coding_type;

  READ_UINT8 (&br, modulo_time_base, 1);
  while (modulo_time_base) {
    vop->modulo_time_base++;

    READ_UINT8 (&br, modulo_time_base, 1);
  }

  CHECK_REMAINING (&br, vol->vop_time_increment_bits + 3);

  MARKER_UNCHECKED (&br);
  vop->time_increment =
      gst_bit_reader_get_bits_uint16_unchecked (&br,
      vol->vop_time_increment_bits);
  MARKER_UNCHECKED (&br);

  vop->coded = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  if (!vop->coded)
    return GST_MPEG4_PARSER_OK;

  if (vol->newpred_enable) {
    guint16 nbbits =
        vop->time_increment + 3 < 15 ? vop->time_increment + 3 : 15;

    READ_UINT16 (&br, vop->id, nbbits);
    READ_UINT8 (&br, vop->id_for_prediction_indication, 1);
    if (vop->id_for_prediction_indication) {
      /* Would be nice if the standard actually told us... */
      READ_UINT16 (&br, vop->id, nbbits);
      CHECK_MARKER (&br);
    }
  }

  if (vol->shape != GST_MPEG4_BINARY_ONLY &&
      (vop->coding_type == GST_MPEG4_P_VOP ||
          (vop->coding_type == GST_MPEG4_S_VOP &&
              vol->sprite_enable == GST_MPEG4_SPRITE_GMG)))
    READ_UINT8 (&br, vop->rounding_type, 1);

  if ((vol->reduced_resolution_vop_enable) &&
      (vol->shape == GST_MPEG4_RECTANGULAR ||
          (vop->coding_type = GST_MPEG4_P_VOP ||
              vop->coding_type == GST_MPEG4_I_VOP)))
    READ_UINT8 (&br, vop->reduced_resolution, 1);

  if (vol->shape != GST_MPEG4_RECTANGULAR) {
    if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC &&
        vop->coding_type == GST_MPEG4_I_VOP) {
      CHECK_REMAINING (&br, 55);

      vop->width = gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
      MARKER_UNCHECKED (&br);

      vop->height = gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
      MARKER_UNCHECKED (&br);

      vop->horizontal_mc_spatial_ref =
          gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
      MARKER_UNCHECKED (&br);

      vop->vertical_mc_spatial_ref =
          gst_bit_reader_get_bits_uint16_unchecked (&br, 13);
      MARKER_UNCHECKED (&br);

      /* Recompute the Macroblock informations
       * accordingly to the new values */
      if (vol->interlaced)
        vop->mb_height = (2 * (vol->height + 31) / 32);
      else
        vop->mb_height = (vol->height + 15) / 16;

      vop->mb_width = (vol->width + 15) / 16;
      vop->mb_num = vop->mb_height * vop->mb_width;
    }

    if ((vol->shape != GST_MPEG4_BINARY_ONLY) &&
        vol->scalability && vol->enhancement_type)
      READ_UINT8 (&br, vop->background_composition, 1);

    READ_UINT8 (&br, vop->change_conv_ratio_disable, 1);

    READ_UINT8 (&br, vop->constant_alpha, 1);
    if (vop->constant_alpha)
      READ_UINT8 (&br, vop->constant_alpha_value, 1);
  }

  if (vol->shape != GST_MPEG4_BINARY_ONLY) {
    if (!vol->complexity_estimation_disable) {
      GST_WARNING ("Complexity estimation not supported");
      goto failed;
    }

    READ_UINT8 (&br, vop->intra_dc_vlc_thr, 3);

    if (vol->interlaced) {
      READ_UINT8 (&br, vop->top_field_first, 1);
      READ_UINT8 (&br, vop->alternate_vertical_scan_flag, 1);
    }
  }

  if ((vol->sprite_enable == GST_MPEG4_SPRITE_STATIC ||
          vol->sprite_enable == GST_MPEG4_SPRITE_GMG) &&
      vop->coding_type == GST_MPEG4_S_VOP) {

    /* only if @sprite_trajectory is not NULL we parse it */
    if (sprite_trajectory && vol->no_of_sprite_warping_points)
      parse_sprite_trajectory (&br, sprite_trajectory,
          vol->no_of_sprite_warping_points);

    if (vol->sprite_brightness_change) {
      GST_WARNING ("sprite_brightness_change not supported");
      goto failed;
    }

    if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC) {
      GST_WARNING ("sprite enable static not supported");
      goto failed;
    }
  }

  if (vol->shape != GST_MPEG4_BINARY_ONLY) {
    READ_UINT16 (&br, vop->quant, vol->quant_precision);

    if (vol->shape == GST_MPEG4_GRAYSCALE) {
      /* TODO implement grayscale support */
      GST_WARNING ("Grayscale shapes no supported");

      /* TODO implement me */
      goto failed;
    }

    if (vop->coding_type != GST_MPEG4_I_VOP) {
      READ_UINT8 (&br, vop->fcode_forward, 3);
      CHECK_ALLOWED (vop->fcode_forward, 1, 7);
    }

    if (vop->coding_type == GST_MPEG4_B_VOP) {
      READ_UINT8 (&br, vop->fcode_backward, 3);
      CHECK_ALLOWED (vop->fcode_backward, 1, 7);
    }
  }

  if (!vol->scalability) {
    if (vol->shape != GST_MPEG4_RECTANGULAR)
      READ_UINT8 (&br, vop->shape_coding_type, 1);

  } else {
    if (vol->enhancement_type) {
      READ_UINT8 (&br, vop->load_backward_shape, 1);

      if (vop->load_backward_shape) {
        GST_WARNING ("Load backward shape not supported");
        goto failed;
      }

      READ_UINT8 (&br, vop->ref_select_code, 2);
    }
  }

  vop->size = gst_bit_reader_get_pos (&br);
  /* More things to possibly parse ... */

  return GST_MPEG4_PARSER_OK;

failed:
  GST_WARNING ("failed parsing \"Video Object Plane\"");
  return GST_MPEG4_PARSER_ERROR;

wrong_start_code:
  GST_WARNING ("got buffer with wrong start code");
  goto failed;
}