blob: b87cefb35575d7703570cf23e140ad1bef0a95e5 [file] [log] [blame]
/*
* GStreamer
* Copyright (C) 2009 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "mpeg4util.h"
GST_DEBUG_CATEGORY_EXTERN (gst_vdp_mpeg4_dec_debug);
#define GST_CAT_DEFAULT gst_vdp_mpeg4_dec_debug
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
};
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,
};
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
};
gboolean
mpeg4_util_parse_VOP (GstBuffer * buf, Mpeg4VideoObjectLayer * vol,
Mpeg4VideoObjectPlane * vop)
{
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buf);
guint8 vop_start_code;
guint8 modulo_time_base;
/* 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;
/* start code prefix */
SKIP (&reader, 24);
READ_UINT8 (&reader, vop_start_code, 8);
if (vop_start_code != MPEG4_PACKET_VOP)
goto wrong_start_code;
READ_UINT8 (&reader, vop->coding_type, 2);
READ_UINT8 (&reader, modulo_time_base, 1);
while (modulo_time_base) {
vop->modulo_time_base++;
READ_UINT8 (&reader, modulo_time_base, 1);
}
/* marker bit */
SKIP (&reader, 1);
READ_UINT16 (&reader, vop->time_increment, vol->vop_time_increment_bits);
/* marker bit */
SKIP (&reader, 1);
READ_UINT8 (&reader, vop->coded, 1);
if (!vop->coded)
return TRUE;
if (vop->coding_type == P_VOP)
READ_UINT8 (&reader, vop->rounding_type, 1);
READ_UINT8 (&reader, vop->intra_dc_vlc_thr, 3);
if (vol->interlaced) {
READ_UINT8 (&reader, vop->top_field_first, 1);
READ_UINT8 (&reader, vop->alternate_vertical_scan_flag, 1);
}
READ_UINT16 (&reader, vop->quant, vol->quant_precision);
if (vop->coding_type != I_VOP) {
READ_UINT8 (&reader, vop->fcode_forward, 3);
CHECK_ALLOWED (vop->fcode_forward, 1, 7);
}
if (vop->coding_type == B_VOP) {
READ_UINT8 (&reader, vop->fcode_backward, 3);
CHECK_ALLOWED (vop->fcode_backward, 1, 7);
}
return TRUE;
error:
GST_WARNING ("error parsing \"Video Object Plane\"");
return FALSE;
wrong_start_code:
GST_WARNING ("got buffer with wrong start code");
goto error;
}
gboolean
mpeg4_util_parse_GOV (GstBuffer * buf, Mpeg4GroupofVideoObjectPlane * gov)
{
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buf);
guint8 gov_start_code;
/* start code prefix */
SKIP (&reader, 24);
READ_UINT8 (&reader, gov_start_code, 8);
if (gov_start_code != MPEG4_PACKET_GOV)
goto wrong_start_code;
READ_UINT8 (&reader, gov->hours, 5);
READ_UINT8 (&reader, gov->minutes, 6);
/* marker bit */
SKIP (&reader, 1);
READ_UINT8 (&reader, gov->seconds, 6);
READ_UINT8 (&reader, gov->closed, 1);
READ_UINT8 (&reader, gov->broken_link, 1);
return TRUE;
error:
GST_WARNING ("error parsing \"Group of Video Object Plane\"");
return FALSE;
wrong_start_code:
GST_WARNING ("got buffer with wrong start code");
goto error;
}
static void
mpeg4_util_par_from_info (guint8 aspect_ratio_info, guint8 * par_n,
guint8 * par_d)
{
switch (aspect_ratio_info) {
case 0x02:
*par_n = 12;
*par_d = 11;
break;
case 0x03:
*par_n = 10;
*par_d = 11;
break;
case 0x04:
*par_n = 16;
*par_d = 11;
break;
case 0x05:
*par_n = 40;
*par_d = 33;
break;
case 0x01:
default:
*par_n = 1;
*par_d = 1;
}
}
static gboolean
mpeg4_util_parse_quant (GstBitReader * reader, guint8 quant_mat[64],
const guint8 default_quant_mat[64])
{
guint8 load_quant_mat;
READ_UINT8 (reader, 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 (reader, 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;
error:
GST_WARNING ("error parsing quant matrix");
return FALSE;
invalid_quant_mat:
GST_WARNING ("the first value should be non zero");
goto error;
}
gboolean
mpeg4_util_parse_VOL (GstBuffer * buf, Mpeg4VisualObject * vo,
Mpeg4VideoObjectLayer * vol)
{
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buf);
guint8 video_object_layer_start_code;
guint8 aspect_ratio_info;
guint8 control_parameters;
guint8 not_8_bit;
/* set default values */
vol->verid = vo->verid;
vol->priority = vo->priority;
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;
/* start code prefix */
SKIP (&reader, 24);
READ_UINT8 (&reader, video_object_layer_start_code, 8);
if (!(video_object_layer_start_code >= MPEG4_PACKET_VOL_MIN &&
video_object_layer_start_code <= MPEG4_PACKET_VOL_MAX))
goto wrong_start_code;
READ_UINT8 (&reader, vol->random_accesible_vol, 1);
READ_UINT8 (&reader, vol->video_object_type_indication, 8);
READ_UINT8 (&reader, vol->is_object_layer_identifier, 1);
if (vol->is_object_layer_identifier) {
READ_UINT8 (&reader, vol->verid, 4);
READ_UINT8 (&reader, vol->priority, 3);
}
READ_UINT8 (&reader, aspect_ratio_info, 4);
if (aspect_ratio_info != 0xff)
mpeg4_util_par_from_info (aspect_ratio_info, &vol->par_n, &vol->par_d);
else {
READ_UINT8 (&reader, vol->par_n, 8);
CHECK_ALLOWED (vol->par_n, 1, 255);
READ_UINT8 (&reader, vol->par_d, 8);
CHECK_ALLOWED (vol->par_d, 1, 255);
}
READ_UINT8 (&reader, control_parameters, 1);
if (control_parameters) {
READ_UINT8 (&reader, vol->chroma_format, 2);
READ_UINT8 (&reader, vol->low_delay, 1);
READ_UINT8 (&reader, vol->vbv_parameters, 1);
if (vol->vbv_parameters) {
guint16 first_half, latter_half;
guint8 latter_part;
READ_UINT16 (&reader, first_half, 15);
SKIP (&reader, 1);
READ_UINT16 (&reader, latter_half, 15);
SKIP (&reader, 1);
vol->bit_rate = (first_half << 15) | latter_half;
READ_UINT16 (&reader, first_half, 15);
SKIP (&reader, 1);
READ_UINT8 (&reader, latter_part, 3);
SKIP (&reader, 1);
vol->vbv_buffer_size = (first_half << 15) | latter_part;
}
}
READ_UINT8 (&reader, vol->shape, 2);
if (vol->shape != 0x0)
goto invalid_shape;
/* marker_bit */
SKIP (&reader, 1);
READ_UINT16 (&reader, vol->vop_time_increment_resolution, 16);
CHECK_ALLOWED (vol->vop_time_increment_resolution, 1, G_MAXUINT16);
vol->vop_time_increment_bits =
g_bit_storage (vol->vop_time_increment_resolution);
/* marker_bit */
SKIP (&reader, 1);
READ_UINT8 (&reader, vol->fixed_vop_rate, 1);
if (vol->fixed_vop_rate)
READ_UINT16 (&reader, vol->fixed_vop_time_increment,
vol->vop_time_increment_bits);
/* marker bit */
SKIP (&reader, 1);
READ_UINT16 (&reader, vol->width, 13);
/* marker bit */
SKIP (&reader, 1);
READ_UINT16 (&reader, vol->height, 13);
/* marker bit */
SKIP (&reader, 1);
READ_UINT8 (&reader, vol->interlaced, 1);
READ_UINT8 (&reader, vol->obmc_disable, 1);
if (vol->verid == 0x1) {
READ_UINT8 (&reader, vol->sprite_enable, 1);
} else
READ_UINT8 (&reader, vol->sprite_enable, 2);
if (vol->sprite_enable != 0x0)
goto invalid_sprite_enable;
READ_UINT8 (&reader, not_8_bit, 1);
if (not_8_bit) {
READ_UINT8 (&reader, vol->quant_precision, 4);
CHECK_ALLOWED (vol->quant_precision, 3, 9);
READ_UINT8 (&reader, vol->bits_per_pixel, 4);
CHECK_ALLOWED (vol->bits_per_pixel, 4, 12);
}
READ_UINT8 (&reader, vol->quant_type, 1);
if (vol->quant_type) {
if (!mpeg4_util_parse_quant (&reader, vol->intra_quant_mat,
default_intra_quant_mat))
goto error;
if (!mpeg4_util_parse_quant (&reader, vol->non_intra_quant_mat,
default_non_intra_quant_mat))
goto error;
} else {
memset (&vol->intra_quant_mat, 0, 64);
memset (&vol->non_intra_quant_mat, 0, 64);
}
if (vol->verid != 0x1)
READ_UINT8 (&reader, vol->quarter_sample, 1);
READ_UINT8 (&reader, vol->complexity_estimation_disable, 1);
if (!vol->complexity_estimation_disable)
goto complexity_estimation_error;
READ_UINT8 (&reader, vol->resync_marker_disable, 1);
return TRUE;
error:
GST_WARNING ("error parsing \"Video Object Layer\"");
return FALSE;
wrong_start_code:
GST_WARNING ("got buffer with wrong start code");
goto error;
invalid_shape:
GST_WARNING ("we only support rectangular shape");
goto error;
invalid_sprite_enable:
GST_WARNING ("we only support sprite_enable == 0");
goto error;
complexity_estimation_error:
GST_WARNING ("don't support complexity estimation");
goto error;
}
gboolean
mpeg4_util_parse_VO (GstBuffer * buf, Mpeg4VisualObject * vo)
{
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buf);
guint8 visual_object_start_code;
guint8 is_visual_object_identifier;
/* set defualt values */
vo->verid = 0x1;
vo->priority = 1;
/* start code prefix */
SKIP (&reader, 24);
READ_UINT8 (&reader, visual_object_start_code, 8);
if (visual_object_start_code != MPEG4_PACKET_VO)
goto wrong_start_code;
READ_UINT8 (&reader, is_visual_object_identifier, 1);
if (is_visual_object_identifier) {
READ_UINT8 (&reader, vo->verid, 4);
READ_UINT8 (&reader, vo->priority, 3);
}
READ_UINT8 (&reader, vo->type, 4);
return TRUE;
wrong_start_code:
GST_WARNING ("got buffer with wrong start code");
return FALSE;
error:
GST_WARNING ("error parsing \"Visual Object\"");
return FALSE;
}
gboolean
mpeg4_util_parse_VOS (GstBuffer * buf, Mpeg4VisualObjectSequence * vos)
{
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buf);
guint8 visual_object_sequence_start_code;
/* start code prefix */
SKIP (&reader, 24);
READ_UINT8 (&reader, visual_object_sequence_start_code, 8);
if (visual_object_sequence_start_code != MPEG4_PACKET_VOS)
goto wrong_start_code;
READ_UINT8 (&reader, vos->profile_and_level_indication, 8);
return TRUE;
wrong_start_code:
GST_WARNING ("got buffer with wrong start code");
return FALSE;
error:
GST_WARNING ("error parsing \"Visual Object\"");
return FALSE;
}