示例#1
0
static gboolean
gst_vdp_h264_dec_set_sink_caps (GstBaseVideoDecoder * base_video_decoder,
    GstCaps * caps)
{
  GstVdpH264Dec *h264_dec;
  GstStructure *structure;
  const GValue *value;

  h264_dec = GST_VDP_H264_DEC (base_video_decoder);

  structure = gst_caps_get_structure (caps, 0);
  /* packetized video has a codec_data */
  if ((value = gst_structure_get_value (structure, "codec_data"))) {
    GstBuffer *buf;
    GstBitReader reader;
    guint8 version;
    guint8 n_sps, n_pps;
    gint i;

    GST_DEBUG_OBJECT (h264_dec, "have packetized h264");
    h264_dec->packetized = TRUE;

    buf = gst_value_get_buffer (value);
    GST_MEMDUMP ("avcC:", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));

    /* parse the avcC data */
    if (GST_BUFFER_SIZE (buf) < 7) {
      GST_ERROR_OBJECT (h264_dec, "avcC size %u < 7", GST_BUFFER_SIZE (buf));
      return FALSE;
    }

    gst_bit_reader_init_from_buffer (&reader, buf);

    READ_UINT8 (&reader, version, 8);
    if (version != 1)
      return FALSE;

    SKIP (&reader, 30);

    READ_UINT8 (&reader, h264_dec->nal_length_size, 2);
    h264_dec->nal_length_size += 1;
    GST_DEBUG_OBJECT (h264_dec, "nal length %u", h264_dec->nal_length_size);

    SKIP (&reader, 3);

    READ_UINT8 (&reader, n_sps, 5);
    for (i = 0; i < n_sps; i++) {
      guint16 sps_length;
      guint8 *data;

      READ_UINT16 (&reader, sps_length, 16);
      sps_length -= 1;
      SKIP (&reader, 8);

      data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
      if (!gst_h264_parser_parse_sequence (h264_dec->parser, data, sps_length))
        return FALSE;

      SKIP (&reader, sps_length * 8);
    }

    READ_UINT8 (&reader, n_pps, 8);
    for (i = 0; i < n_pps; i++) {
      guint16 pps_length;
      guint8 *data;

      READ_UINT16 (&reader, pps_length, 16);
      pps_length -= 1;
      SKIP (&reader, 8);

      data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
      if (!gst_h264_parser_parse_picture (h264_dec->parser, data, pps_length))
        return FALSE;

      SKIP (&reader, pps_length * 8);
    }
  }

  return TRUE;
}
示例#2
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_plane_with_short_header:
 * @shorthdr: The #GstMpeg4VideoPlaneShortHdr to parse
 * @data: The data to parse
 * @size: The size of the @data to parse
 */
GstMpeg4ParseResult
gst_mpeg4_parse_video_plane_short_header (GstMpeg4VideoPlaneShortHdr *
    shorthdr, const guint8 * data, gsize size)
{
  guint8 zero_bits;

  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (shorthdr != NULL, GST_MPEG4_PARSER_ERROR);

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

  if (gst_bit_reader_get_bits_uint32_unchecked (&br, 22) != 0x20)
    goto failed;

  shorthdr->temporal_reference =
      gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
  CHECK_MARKER (&br);
  zero_bits = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  if (zero_bits != 0x00)
    goto failed;

  shorthdr->split_screen_indicator =
      gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  shorthdr->document_camera_indicator =
      gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  shorthdr->full_picture_freeze_release =
      gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  shorthdr->source_format = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);

  /* Set parameters/Table 6-25 */
  switch (shorthdr->source_format) {
    case 0x01:
      shorthdr->vop_width = 128;
      shorthdr->vop_height = 96;
      shorthdr->num_macroblocks_in_gob = 8;
      shorthdr->num_gobs_in_vop = 6;
      break;
    case 0x02:
      shorthdr->vop_width = 176;
      shorthdr->vop_height = 144;
      shorthdr->num_macroblocks_in_gob = 11;
      shorthdr->num_gobs_in_vop = 9;
      break;
    case 0x03:
      shorthdr->vop_width = 352;
      shorthdr->vop_height = 288;
      shorthdr->num_macroblocks_in_gob = 22;
      shorthdr->num_gobs_in_vop = 18;
      break;
    case 0x04:
      shorthdr->vop_width = 704;
      shorthdr->vop_height = 576;
      shorthdr->num_macroblocks_in_gob = 88;
      shorthdr->num_gobs_in_vop = 18;
      break;
    case 0x05:
      shorthdr->vop_width = 1408;
      shorthdr->vop_height = 1152;
      shorthdr->num_macroblocks_in_gob = 352;
      shorthdr->num_gobs_in_vop = 18;
      break;
    default:
      shorthdr->vop_width = 0;
      shorthdr->vop_height = 0;
      shorthdr->num_macroblocks_in_gob = 0;
      shorthdr->num_gobs_in_vop = 0;
  }

  shorthdr->picture_coding_type =
      gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
  zero_bits = gst_bit_reader_get_bits_uint8_unchecked (&br, 4);

  if (zero_bits != 0x00)
    goto failed;

  shorthdr->vop_quant = gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
  zero_bits = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);

  if (zero_bits != 0x00)
    goto failed;

  do {
    READ_UINT8 (&br, shorthdr->pei, 1);

    if (shorthdr->pei == 1)
      READ_UINT8 (&br, shorthdr->psupp, 8);

  } while (shorthdr->pei == 1);

  shorthdr->size = gst_bit_reader_get_pos (&br);

  return GST_MPEG4_PARSER_OK;

failed:
  GST_WARNING ("Could not parse the Plane short header");

  return GST_MPEG4_PARSER_ERROR;
}
/**
 * gst_mpeg4_parse_video_packet_header:
 * @videopackethdr: The #GstMpeg4VideoPacketHdr structure to fill
 * @vol: The last parsed #GstMpeg4VideoObjectLayer, will be updated
 * with the informations found during the parsing
 * @vop: The last parsed #GstMpeg4VideoObjectPlane, will be updated
 * with the informations found during the parsing
 * @sprite_trajectory: A #GstMpeg4SpriteTrajectory to fill or %NULL
 * with the informations found during the parsing
 * @data: The data to parse, should be set after the resync marker.
 * @size: The size of the data to parse
 *
 * Parsers @data containing the video packet header
 * and fills the @videopackethdr structure
 */
GstMpeg4ParseResult
gst_mpeg4_parse_video_packet_header (GstMpeg4VideoPacketHdr * videopackethdr,
    GstMpeg4VideoObjectLayer * vol, GstMpeg4VideoObjectPlane * vop,
    GstMpeg4SpriteTrajectory * sprite_trajectory, const guint8 * data,
    gsize size)
{
  guint8 markersize;
  GstBitReader br = GST_BIT_READER_INIT (data, size);

  g_return_val_if_fail (videopackethdr != NULL, GST_MPEG4_PARSER_ERROR);
  g_return_val_if_fail (vol != NULL, GST_MPEG4_PARSER_ERROR);

  markersize = compute_resync_marker_size (vop, NULL, NULL);

  CHECK_REMAINING (&br, markersize);

  if (gst_bit_reader_get_bits_uint32_unchecked (&br, markersize) != 0x01)
    goto failed;

  if (vol->shape != GST_MPEG4_RECTANGULAR) {
    READ_UINT8 (&br, videopackethdr->header_extension_code, 1);
    if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC &&
        vop->coding_type == GST_MPEG4_I_VOP) {

      CHECK_REMAINING (&br, 56);

      U_READ_UINT16 (&br, vop->width, 13);
      CHECK_MARKER (&br);
      U_READ_UINT16 (&br, vop->height, 13);
      CHECK_MARKER (&br);
      U_READ_UINT16 (&br, vop->horizontal_mc_spatial_ref, 13);
      CHECK_MARKER (&br);
      U_READ_UINT16 (&br, vop->vertical_mc_spatial_ref, 13);
      CHECK_MARKER (&br);

      /* Update macroblock infirmations */
      vop->mb_height = (vop->height + 15) / 16;
      vop->mb_width = (vop->width + 15) / 16;
      vop->mb_num = vop->mb_height * vop->mb_width;
    }
  }

  READ_UINT16 (&br, videopackethdr->macroblock_number,
      g_bit_storage (vop->mb_num - 1));

  if (vol->shape != GST_MPEG4_BINARY_ONLY)
    READ_UINT16 (&br, videopackethdr->quant_scale, vol->quant_precision);

  if (vol->shape == GST_MPEG4_RECTANGULAR)
    READ_UINT8 (&br, videopackethdr->header_extension_code, 1);

  if (videopackethdr->header_extension_code) {
    guint timeincr = 0;
    guint8 bit = 0, coding_type;

    do {
      READ_UINT8 (&br, bit, 1);
      timeincr++;
    } while (bit);

    vol->vop_time_increment_bits = timeincr;

    CHECK_MARKER (&br);
    READ_UINT16 (&br, vop->time_increment, timeincr);
    CHECK_MARKER (&br);
    READ_UINT8 (&br, coding_type, 2);
    vop->coding_type = coding_type;

    if (vol->shape != GST_MPEG4_RECTANGULAR) {
      READ_UINT8 (&br, vop->change_conv_ratio_disable, 1);
      if (vop->coding_type != GST_MPEG4_I_VOP)
        READ_UINT8 (&br, vop->shape_coding_type, 1);
    }

    if (vol->shape != GST_MPEG4_BINARY_ONLY) {
      READ_UINT8 (&br, vop->intra_dc_vlc_thr, 3);

      if (sprite_trajectory && vol->sprite_enable == GST_MPEG4_SPRITE_GMG &&
          vop->coding_type == GST_MPEG4_S_VOP &&
          vol->no_of_sprite_warping_points > 0) {

        parse_sprite_trajectory (&br, sprite_trajectory,
            vol->no_of_sprite_warping_points);
      }

      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 (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->newpred_enable) {
    guint16 nbbits =
        vol->vop_time_increment_bits + 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);
    }
  }

  videopackethdr->size = gst_bit_reader_get_pos (&br);

failed:
  GST_DEBUG ("Failed to parse video packet header");

  return GST_MPEG4_PARSER_NO_PACKET;
}
/**
 * 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;
}