mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-03 16:09:39 +00:00
1754 lines
49 KiB
C
1754 lines
49 KiB
C
/* 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
|
|
* @title: 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 complete 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 information */
|
|
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 information
|
|
* 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 information found during the parsing
|
|
* @vop: The last parsed #GstMpeg4VideoObjectPlane, will be updated
|
|
* with the information found during the parsing
|
|
* @sprite_trajectory: A #GstMpeg4SpriteTrajectory to fill or %NULL
|
|
* with the information 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;
|
|
}
|