blob: b4557647b4023bcb047803fba9d11bdd6f9bd88b [file] [log] [blame]
/* 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., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:gstmpeg4parser
* @short_description: Convenience library for parsing mpeg4 part 2 video
* bitstream.
*
* For more details about the structures, you can refer to the
* specifications: ISO-IEC-14496-2_2004_MPEG4_VISUAL.pdf
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/base/gstbitreader.h>
#include <gst/base/gstbytereader.h>
#include "gstmpeg4parser.h"
#include "parserutils.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_mpeg4", 0,
"GstMpeg4 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 */
#define CHECK_MARKER(br) G_STMT_START { \
guint8 marker;\
if (!gst_bit_reader_get_bits_uint8 (br, &marker, 1)) { \
GST_WARNING ("failed to read marker bit"); \
goto failed; \
} else if (!marker) {\
GST_WARNING ("Wrong marker bit"); \
goto failed;\
}\
} G_STMT_END
#define MARKER_UNCHECKED(br) G_STMT_START { \
if (!gst_bit_reader_get_bits_uint8_unchecked (br, 1)) { \
GST_WARNING ("Wrong marker bit"); \
goto failed; \
} \
} G_STMT_END
#define CHECK_REMAINING(br, needed) G_STMT_START { \
if (gst_bit_reader_get_remaining (br) < needed) \
goto failed; \
} G_STMT_END
static const guint8 default_intra_quant_mat[64] = {
8, 17, 18, 19, 21, 23, 25, 27,
17, 18, 19, 21, 23, 25, 27, 28,
20, 21, 22, 23, 24, 26, 28, 30,
21, 22, 23, 24, 26, 28, 30, 32,
22, 23, 24, 26, 28, 30, 32, 35,
23, 24, 26, 28, 30, 32, 35, 38,
25, 26, 28, 30, 32, 35, 38, 41,
27, 28, 30, 32, 35, 38, 41, 45
};
static const guint8 default_non_intra_quant_mat[64] = {
16, 17, 18, 19, 20, 21, 22, 23,
17, 18, 19, 20, 21, 22, 23, 24,
18, 19, 20, 21, 22, 23, 24, 25,
19, 20, 21, 22, 23, 24, 26, 27,
20, 21, 22, 23, 25, 26, 27, 28,
21, 22, 23, 24, 26, 27, 28, 30,
22, 23, 24, 26, 27, 28, 30, 31,
23, 24, 25, 27, 28, 30, 31, 33,
};
static const guint8 mpeg4_zigzag_8x8[64] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
static const VLCTable mpeg4_dmv_size_vlc_table[] = {
{0, 0x00, 2},
{1, 0x02, 3},
{2, 0x03, 3},
{3, 0x04, 3},
{4, 0x05, 3},
{5, 0x06, 3},
{6, 0x0e, 4},
{7, 0x1e, 5},
{8, 0x3e, 6},
{9, 0x7e, 7},
{10, 0xfe, 8},
{11, 0x1fe, 9},
{12, 0x3fe, 10},
{13, 0x7fe, 11},
{14, 0xffe, 12}
};
static void
mpeg4_util_par_from_info (guint8 aspect_ratio_info, guint8 * par_width,
guint8 * par_height)
{
switch (aspect_ratio_info) {
case 0x02:
*par_width = 12;
*par_height = 11;
break;
case 0x03:
*par_width = 10;
*par_height = 11;
break;
case 0x04:
*par_width = 16;
*par_height = 11;
break;
case 0x05:
*par_width = 40;
*par_height = 33;
break;
case 0x01:
default:
*par_width = 1;
*par_height = 1;
}
}
static gboolean
parse_quant (GstBitReader * br, guint8 quant_mat[64],
const guint8 default_quant_mat[64], guint8 * load_quant_mat)
{
READ_UINT8 (br, *load_quant_mat, 1);
if (*load_quant_mat) {
guint i;
guint8 val;
val = 1;
for (i = 0; i < 64; i++) {
if (val != 0)
READ_UINT8 (br, val, 8);
if (val == 0) {
if (i == 0)
goto invalid_quant_mat;
quant_mat[mpeg4_zigzag_8x8[i]] = quant_mat[mpeg4_zigzag_8x8[i - 1]];
} else
quant_mat[mpeg4_zigzag_8x8[i]] = val;
}
} else
memcpy (quant_mat, default_quant_mat, 64);
return TRUE;
failed:
GST_WARNING ("failed parsing quant matrix");
return FALSE;
invalid_quant_mat:
GST_WARNING ("the first value should be non zero");
goto failed;
}
static gboolean
parse_signal_type (GstBitReader * br, GstMpeg4VideoSignalType * signal_type)
{
READ_UINT8 (br, signal_type->type, 1);
if (signal_type->type) {
READ_UINT8 (br, signal_type->format, 3);
READ_UINT8 (br, signal_type->range, 1);
READ_UINT8 (br, signal_type->color_description, 1);
if (signal_type->color_description) {
READ_UINT8 (br, signal_type->color_primaries, 8);
READ_UINT8 (br, signal_type->transfer_characteristics, 8);
READ_UINT8 (br, signal_type->matrix_coefficients, 8);
}
}
return TRUE;
failed:
GST_WARNING ("failed parsing \"Video Signal Type\"");
return FALSE;
}
static gboolean
parse_sprite_trajectory (GstBitReader * br,
GstMpeg4SpriteTrajectory * sprite_traj, guint no_of_sprite_warping_points)
{
guint i, length;
for (i = 0; i < no_of_sprite_warping_points; i++) {
if (!decode_vlc (br, &length, mpeg4_dmv_size_vlc_table,
G_N_ELEMENTS (mpeg4_dmv_size_vlc_table)))
goto failed;
if (length)
READ_UINT16 (br, sprite_traj->vop_ref_points[i], length);
CHECK_MARKER (br);
if (!decode_vlc (br, &length, mpeg4_dmv_size_vlc_table,
G_N_ELEMENTS (mpeg4_dmv_size_vlc_table)))
goto failed;
if (length)
READ_UINT16 (br, sprite_traj->sprite_ref_points[i], length);
CHECK_MARKER (br);
}
return TRUE;
failed:
GST_WARNING ("Could not parse the sprite trajectory");
return FALSE;
}
static guint
find_psc (GstByteReader * br)
{
guint psc_pos = -1, psc;
if (!gst_byte_reader_peek_uint24_be (br, &psc))
goto failed;
/* Scan for the picture start code (22 bits - 0x0020) */
while ((gst_byte_reader_get_remaining (br) >= 3)) {
if (gst_byte_reader_peek_uint24_be (br, &psc) &&
((psc & 0xfffffc) == 0x000080)) {
psc_pos = gst_byte_reader_get_pos (br);
break;
} else
gst_byte_reader_skip_unchecked (br, 1);
}
failed:
return psc_pos;
}
static inline guint8
compute_resync_marker_size (const GstMpeg4VideoObjectPlane * vop,
guint32 * pattern, guint32 * mask)
{
guint8 off;
/* FIXME handle the binary only shape case */
switch (vop->coding_type) {
case (GST_MPEG4_I_VOP):
off = 16;
break;
case (GST_MPEG4_S_VOP):
case (GST_MPEG4_P_VOP):
off = 15 + vop->fcode_forward;
break;
case (GST_MPEG4_B_VOP):
off = MAX (15 + MAX (vop->fcode_forward, vop->fcode_backward), 17);
break;
default:
return -1;
}
if (mask && pattern) {
switch (off) {
case 16:
*pattern = 0x00008000;
*mask = 0xffff8000;
break;
case 17:
*pattern = 0x00004000;
*mask = 0xffffc000;
break;
case 18:
*pattern = 0x00002000;
*mask = 0xffffe000;
break;
case 19:
*pattern = 0x00001000;
*mask = 0xfffff000;
break;
case 20:
*pattern = 0x00000800;
*mask = 0xfffff800;
break;
case 21:
*pattern = 0x00000400;
*mask = 0xfffffc00;
break;
case 22:
*pattern = 0x00000200;
*mask = 0xfffffe00;
break;
case 23:
*pattern = 0x00000100;
*mask = 0xffffff00;
break;
}
}
return off + 1; /* Take the following 1 into account */
}
/**
* gst_mpeg4_next_resync:
* @packet: The #GstMpeg4Packet to fill
* @vop: The previously parsed #GstMpeg4VideoObjectPlane
* @offset: offset from which to start the parsing
* @data: The data to parse
* @size: The size of the @data to parse
*
* Parses @data and fills @packet with the information of the next resync packet
* found.
*
* Returns: a #GstMpeg4ParseResult
*/
static GstMpeg4ParseResult
gst_mpeg4_next_resync (GstMpeg4Packet * packet,
const GstMpeg4VideoObjectPlane * vop, const guint8 * data, gsize size,
gboolean first_resync_marker)
{
guint markersize = 0, off1, off2;
guint32 mask = 0xff, pattern = 0xff;
GstByteReader br;
gst_byte_reader_init (&br, data, size);
g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR);
g_return_val_if_fail (vop != NULL, GST_MPEG4_PARSER_ERROR);
markersize = compute_resync_marker_size (vop, &pattern, &mask);
if (first_resync_marker) {
off1 = 0;
} else {
off1 = gst_byte_reader_masked_scan_uint32 (&br, mask, pattern, 0, size);
}
if (off1 == -1)
return GST_MPEG4_PARSER_NO_PACKET;
GST_DEBUG ("Resync code found at %i", off1);
packet->offset = off1;
packet->type = GST_MPEG4_RESYNC;
packet->marker_size = markersize;
off2 = gst_byte_reader_masked_scan_uint32 (&br, mask, pattern,
off1 + 2, size - off1 - 2);
if (off2 == -1)
return GST_MPEG4_PARSER_NO_PACKET_END;
packet->size = off2 - off1;
return GST_MPEG4_PARSER_OK;
}
/********** API **********/
/**
* gst_mpeg4_parse:
* @packet: The #GstMpeg4Packet to fill
* @skip_user_data: %TRUE to skip user data packet %FALSE otherwise
* @vop: The last parsed #GstMpeg4VideoObjectPlane or %NULL if you do
* not need to detect the resync codes.
* @offset: offset from which to start the parsing
* @data: The data to parse
* @size: The size of the @data to parse
*
* Parses @data and fills @packet with the information of the next packet
* found.
*
* Returns: a #GstMpeg4ParseResult
*/
GstMpeg4ParseResult
gst_mpeg4_parse (GstMpeg4Packet * packet, gboolean skip_user_data,
GstMpeg4VideoObjectPlane * vop, const guint8 * data, guint offset,
gsize size)
{
gint off1, off2;
GstByteReader br;
GstMpeg4ParseResult resync_res;
static guint first_resync_marker = TRUE;
gst_byte_reader_init (&br, data, size);
g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR);
if (size - offset <= 4) {
GST_DEBUG ("Can't parse, buffer is to small size %" G_GSIZE_FORMAT
" at offset %d", size, offset);
return GST_MPEG4_PARSER_ERROR;
}
if (vop) {
resync_res =
gst_mpeg4_next_resync (packet, vop, data + offset, size - offset,
first_resync_marker);
first_resync_marker = FALSE;
/* We found a complet slice */
if (resync_res == GST_MPEG4_PARSER_OK)
return resync_res;
else if (resync_res == GST_MPEG4_PARSER_NO_PACKET_END) {
/* It doesn't mean there is no standard packet end, look for it */
off1 = packet->offset;
goto find_end;
} else if (resync_res == GST_MPEG4_PARSER_NO_PACKET)
return resync_res;
} else {
first_resync_marker = TRUE;
}
off1 = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
offset, size - offset);
if (off1 == -1) {
GST_DEBUG ("No start code prefix in this buffer");
return GST_MPEG4_PARSER_NO_PACKET;
}
/* Recursively skip user data if needed */
if (skip_user_data && data[off1 + 3] == GST_MPEG4_USER_DATA)
/* If we are here, we know no resync code has been found the first time, so we
* don't look for it this time */
return gst_mpeg4_parse (packet, skip_user_data, NULL, data, off1 + 3, size);
packet->offset = off1 + 3;
packet->data = data;
packet->type = (GstMpeg4StartCode) (data[off1 + 3]);
find_end:
if (off1 < size - 4)
off2 = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
off1 + 4, size - off1 - 4);
else
off2 = -1;
if (off2 == -1) {
GST_DEBUG ("Packet start %d, No end found", off1 + 4);
packet->size = G_MAXUINT;
return GST_MPEG4_PARSER_NO_PACKET_END;
}
if (packet->type == GST_MPEG4_RESYNC) {
packet->size = (gsize) off2 - off1;
} else {
packet->size = (gsize) off2 - off1 - 3;
}
GST_DEBUG ("Complete packet of type %x found at: %d, Size: %" G_GSIZE_FORMAT,
packet->type, packet->offset, packet->size);
return GST_MPEG4_PARSER_OK;
}
/**
* gst_h263_parse:
* @packet: The #GstMpeg4Packet to fill
* @offset: offset from which to start the parsing
* @data: The data to parse
* @size: The size of the @data to parse
*
* Parses @data and fills @packet with the information of the next packet
* found.
*
* Note that the type of the packet is meaningless in this case.
*
* Returns: a #GstMpeg4ParseResult
*/
GstMpeg4ParseResult
gst_h263_parse (GstMpeg4Packet * packet,
const guint8 * data, guint offset, gsize size)
{
gint off1, off2;
GstByteReader br;
gst_byte_reader_init (&br, data + offset, size - offset);
g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR);
if (size - offset < 3) {
GST_DEBUG ("Can't parse, buffer is to small size %" G_GSIZE_FORMAT
" at offset %d", size, offset);
return GST_MPEG4_PARSER_ERROR;
}
off1 = find_psc (&br);
if (off1 == -1) {
GST_DEBUG ("No start code prefix in this buffer");
return GST_MPEG4_PARSER_NO_PACKET;
}
packet->offset = off1 + offset;
packet->data = data;
gst_byte_reader_skip_unchecked (&br, 3);
off2 = find_psc (&br);
if (off2 == -1) {
GST_DEBUG ("Packet start %d, No end found", off1);
packet->size = G_MAXUINT;
return GST_MPEG4_PARSER_NO_PACKET_END;
}
packet->size = (gsize) off2 - off1;
GST_DEBUG ("Complete packet found at: %d, Size: %" G_GSIZE_FORMAT,
packet->offset, packet->size);
return GST_MPEG4_PARSER_OK;
}
/**
* gst_mpeg4_parse_visual_object_sequence:
* @vos: The #GstMpeg4VisualObjectSequence structure to fill
* @data: The data to parse, should contain the visual_object_sequence_start_code
* but not the start code prefix
* @size: The size of the @data to parse
*
* Parses @data containing the visual object sequence packet, and fills
* the @vos structure.
*
* Returns: a #GstMpeg4ParseResult
*/
GstMpeg4ParseResult
gst_mpeg4_parse_visual_object_sequence (GstMpeg4VisualObjectSequence * vos,
const guint8 * data, gsize size)
{
guint8 vos_start_code;
GstBitReader br = GST_BIT_READER_INIT (data, size);
g_return_val_if_fail (vos != NULL, GST_MPEG4_PARSER_ERROR);
READ_UINT8 (&br, vos_start_code, 8);
if (vos_start_code != GST_MPEG4_VISUAL_OBJ_SEQ_START)
goto wrong_start_code;
READ_UINT8 (&br, vos->profile_and_level_indication, 8);
switch (vos->profile_and_level_indication) {
case 0x01:
vos->profile = GST_MPEG4_PROFILE_SIMPLE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x02:
vos->profile = GST_MPEG4_PROFILE_SIMPLE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x03:
vos->profile = GST_MPEG4_PROFILE_SIMPLE;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0x08:
vos->profile = GST_MPEG4_PROFILE_SIMPLE;
vos->level = GST_MPEG4_LEVEL0;
break;
case 0x10:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_SCALABLE;
vos->level = GST_MPEG4_LEVEL0;
break;
case 0x11:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_SCALABLE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x12:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_SCALABLE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x21:
vos->profile = GST_MPEG4_PROFILE_CORE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x22:
vos->profile = GST_MPEG4_PROFILE_CORE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x32:
vos->profile = GST_MPEG4_PROFILE_MAIN;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x33:
vos->profile = GST_MPEG4_PROFILE_MAIN;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0x34:
vos->profile = GST_MPEG4_PROFILE_MAIN;
vos->level = GST_MPEG4_LEVEL4;
break;
case 0x42:
vos->profile = GST_MPEG4_PROFILE_N_BIT;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x51:
vos->profile = GST_MPEG4_PROFILE_SCALABLE_TEXTURE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x61:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_FACE_ANIMATION;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x62:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_FACE_ANIMATION;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x63:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_FBA;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x64:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_FBA;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x71:
vos->profile = GST_MPEG4_PROFILE_BASIC_ANIMATED_TEXTURE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x72:
vos->profile = GST_MPEG4_PROFILE_BASIC_ANIMATED_TEXTURE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x81:
vos->profile = GST_MPEG4_PROFILE_HYBRID;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x82:
vos->profile = GST_MPEG4_PROFILE_HYBRID;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x91:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0x92:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0x93:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0x94:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE;
vos->level = GST_MPEG4_LEVEL4;
break;
case 0xa1:
vos->profile = GST_MPEG4_PROFILE_CORE_SCALABLE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xa2:
vos->profile = GST_MPEG4_PROFILE_CORE_SCALABLE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xa3:
vos->profile = GST_MPEG4_PROFILE_CORE_SCALABLE;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xb1:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xb2:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xb3:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xb4:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY;
vos->level = GST_MPEG4_LEVEL4;
break;
case 0xc1:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_CORE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xc2:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_CORE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xc3:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_CORE;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xd1:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xd2:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xd3:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xe1:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xe2:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xe3:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xe4:
vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO;
vos->level = GST_MPEG4_LEVEL4;
break;
case 0xe5:
vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xe6:
vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xe7:
vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xe8:
vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO;
vos->level = GST_MPEG4_LEVEL4;
break;
case 0xf0:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE;
vos->level = GST_MPEG4_LEVEL0;
break;
case 0xf1:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xf2:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xf3:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xf4:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE;
vos->level = GST_MPEG4_LEVEL4;
break;
case 0xf5:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE;
vos->level = GST_MPEG4_LEVEL5;
break;
case 0xf7:
vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE;
vos->level = GST_MPEG4_LEVEL3b;
break;
case 0xf8:
vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE;
vos->level = GST_MPEG4_LEVEL0;
break;
case 0xf9:
vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE;
vos->level = GST_MPEG4_LEVEL1;
break;
case 0xfa:
vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE;
vos->level = GST_MPEG4_LEVEL2;
break;
case 0xfb:
vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE;
vos->level = GST_MPEG4_LEVEL3;
break;
case 0xfc:
vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE;
vos->level = GST_MPEG4_LEVEL4;
break;
case 0xfd:
vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE;
vos->level = GST_MPEG4_LEVEL5;
break;
default:
vos->profile = GST_MPEG4_PROFILE_RESERVED;
vos->level = GST_MPEG4_LEVEL_RESERVED;
break;
}
return GST_MPEG4_PARSER_OK;
wrong_start_code:
GST_WARNING ("got buffer with wrong start code");
return GST_MPEG4_PARSER_ERROR;
failed:
GST_WARNING ("failed parsing \"Visual Object\"");
return GST_MPEG4_PARSER_ERROR;
}
/**
* gst_mpeg4_parse_visual_object:
* @vo: The #GstMpeg4VisualObject structure to fill
* @signal_type: The #GstMpeg4VideoSignalType to fill or %NULL
* @data: The data to parse, should contain the vo_start_code
* but not the start code prefix
* @size: The size of the @data to parse
*
* Parses @data containing the visual object packet, and fills
* the @vo structure.
*
* Returns: a #GstMpeg4ParseResult
*/
GstMpeg4ParseResult
gst_mpeg4_parse_visual_object (GstMpeg4VisualObject * vo,
GstMpeg4VideoSignalType * signal_type, const guint8 * data, gsize size)
{
guint8 vo_start_code, type;
GstBitReader br = GST_BIT_READER_INIT (data, size);
g_return_val_if_fail (vo != NULL, GST_MPEG4_PARSER_ERROR);
GST_DEBUG ("Parsing visual object");
READ_UINT8 (&br, vo_start_code, 8);
if (vo_start_code != GST_MPEG4_VISUAL_OBJ)
goto wrong_start_code;
/* set default values */
vo->verid = 0x1;
vo->priority = 1;
READ_UINT8 (&br, vo->is_identifier, 1);
if (vo->is_identifier) {
READ_UINT8 (&br, vo->verid, 4);
READ_UINT8 (&br, vo->priority, 3);
}
READ_UINT8 (&br, type, 4);
vo->type = type;
if ((type == GST_MPEG4_VIDEO_ID ||
type == GST_MPEG4_STILL_TEXTURE_ID) && signal_type) {
if (!parse_signal_type (&br, signal_type))
goto failed;
} else if (signal_type) {
signal_type->type = 0;
}
return GST_MPEG4_PARSER_OK;
wrong_start_code:
GST_WARNING ("got buffer with wrong start code");
return GST_MPEG4_PARSER_ERROR;
failed:
GST_WARNING ("failed parsing \"Visual Object\"");
return GST_MPEG4_PARSER_ERROR;
}
/**
* 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_group_of_vop:
* @gov: The #GstMpeg4GroupOfVOP structure to fill
* @data: The data to parse
* @size: The size of the @data to parse
*
* Parses @data containing the group of video object plane packet, and fills
* the @gov structure.
*
* Returns: a #GstMpeg4ParseResult
*/
GstMpeg4ParseResult
gst_mpeg4_parse_group_of_vop (GstMpeg4GroupOfVOP *
gov, const guint8 * data, gsize size)
{
guint8 gov_start_code;
GstBitReader br = GST_BIT_READER_INIT (data, size);
g_return_val_if_fail (gov != NULL, GST_MPEG4_PARSER_ERROR);
READ_UINT8 (&br, gov_start_code, 8);
if (gov_start_code != GST_MPEG4_GROUP_OF_VOP)
goto wrong_start_code;
CHECK_REMAINING (&br, 65);
gov->hours = gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
gov->minutes = gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
/* marker bit */
MARKER_UNCHECKED (&br);
gov->seconds = gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
gov->closed = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
gov->broken_link = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
return GST_MPEG4_PARSER_OK;
failed:
GST_WARNING ("failed parsing \"Group of Video Object Plane\"");
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;
}
/**
* 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;
}