summaryrefslogtreecommitdiff
path: root/sys/vdpau
diff options
context:
space:
mode:
authorCarl-Anton Ingmarsson <ca.ingmarsson@gmail.com>2010-06-10 12:13:50 +0200
committerCarl-Anton Ingmarsson <ca.ingmarsson@gmail.com>2010-06-23 21:51:53 +0200
commit686d2d230325465119c51a2ac451849ef290e37b (patch)
treef2d2ac1a06dd97f99f2861939e57fd18c5efc56a /sys/vdpau
parent0490cb89c67ef173ce3d68f14fbedb87e2788181 (diff)
vdpau: add beginning of h264 decoder
Diffstat (limited to 'sys/vdpau')
-rw-r--r--sys/vdpau/Makefile.am2
-rw-r--r--sys/vdpau/basevideodecoder/gstvideoframe.h7
-rw-r--r--sys/vdpau/h264/gsth264parser.c1184
-rw-r--r--sys/vdpau/h264/gsth264parser.h411
-rw-r--r--sys/vdpau/h264/gstnalreader.c503
-rw-r--r--sys/vdpau/h264/gstnalreader.h99
-rw-r--r--sys/vdpau/h264/gstvdph264dec.c533
-rw-r--r--sys/vdpau/h264/gstvdph264dec.h61
-rw-r--r--sys/vdpau/h264/gstvdph264frame.c104
-rw-r--r--sys/vdpau/h264/gstvdph264frame.h60
10 files changed, 2961 insertions, 3 deletions
diff --git a/sys/vdpau/Makefile.am b/sys/vdpau/Makefile.am
index 10e552c2f..79a58b64f 100644
--- a/sys/vdpau/Makefile.am
+++ b/sys/vdpau/Makefile.am
@@ -11,6 +11,7 @@ libgstvdpau_la_SOURCES = \
mpeg/gstvdpmpegdec.c \
h264/gstnalreader.c \
h264/gsth264parser.c \
+ h264/gstvdph264frame.c \
h264/gstvdph264dec.c
libgstvdpau_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(X11_CFLAGS) $(VDPAU_CFLAGS)
@@ -32,4 +33,5 @@ noinst_HEADERS = \
mpeg/gstvdpmpegdec.h \
h264/gstnalreader.h \
h264/gsth264parser.h \
+ h264/gstvdph264frame.h \
h264/gstvdph264dec.h \ No newline at end of file
diff --git a/sys/vdpau/basevideodecoder/gstvideoframe.h b/sys/vdpau/basevideodecoder/gstvideoframe.h
index fa6e87dc7..8c9e12c65 100644
--- a/sys/vdpau/basevideodecoder/gstvideoframe.h
+++ b/sys/vdpau/basevideodecoder/gstvideoframe.h
@@ -23,9 +23,10 @@
#include <gst/gst.h>
-#define GST_TYPE_VIDEO_FRAME (gst_video_frame_get_type())
-#define GST_IS_VIDEO_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VIDEO_FRAME))
-#define GST_VIDEO_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VIDEO_FRAME, GstVideoFrame))
+#define GST_TYPE_VIDEO_FRAME (gst_video_frame_get_type())
+#define GST_IS_VIDEO_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VIDEO_FRAME))
+#define GST_VIDEO_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VIDEO_FRAME, GstVideoFrame))
+#define GST_VIDEO_FRAME_CAST(obj) ((GstVideoFrame *)obj)
/**
* GstVideoFrameFlag:
diff --git a/sys/vdpau/h264/gsth264parser.c b/sys/vdpau/h264/gsth264parser.c
new file mode 100644
index 000000000..f08210789
--- /dev/null
+++ b/sys/vdpau/h264/gsth264parser.c
@@ -0,0 +1,1184 @@
+/* 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "gstnalreader.h"
+
+#include "gsth264parser.h"
+
+/* default scaling_lists according to Table 7-2 */
+const guint8 default_4x4_intra[16] =
+ { 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32,
+ 32, 37, 37, 42
+};
+
+const guint8 default_4x4_inter[16] =
+ { 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27,
+ 27, 30, 30, 34
+};
+
+const guint8 default_8x8_intra[64] =
+ { 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18,
+ 18, 18, 18, 23, 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27,
+ 27, 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 31, 33,
+ 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42
+};
+
+const guint8 default_8x8_inter[64] =
+ { 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19,
+ 19, 19, 19, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24,
+ 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 28,
+ 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35
+};
+
+
+#define CHECK_ALLOWED(val, min, max) { \
+ if (val < min || val > max) { \
+ GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \
+ val, min, max); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT8(reader, val, nbits) { \
+ if (!gst_nal_reader_get_bits_uint8 (reader, &val, nbits)) { \
+ GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT16(reader, val, nbits) { \
+ if (!gst_nal_reader_get_bits_uint16 (reader, &val, nbits)) { \
+ GST_WARNING ("failed to read uint16, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT32(reader, val, nbits) { \
+ if (!gst_nal_reader_get_bits_uint32 (reader, &val, nbits)) { \
+ GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT64(reader, val, nbits) { \
+ if (!gst_nal_reader_get_bits_uint64 (reader, &val, nbits)) { \
+ GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UE(reader, val) { \
+ if (!gst_nal_reader_get_ue (reader, &val)) { \
+ GST_WARNING ("failed to read UE"); \
+ goto error; \
+ } \
+}
+
+#define READ_UE_ALLOWED(reader, val, min, max) { \
+ guint32 tmp; \
+ READ_UE (reader, tmp); \
+ CHECK_ALLOWED (tmp, min, max); \
+ val = tmp; \
+}
+
+#define READ_SE(reader, val) { \
+ if (!gst_nal_reader_get_se (reader, &val)) { \
+ GST_WARNING ("failed to read SE"); \
+ goto error; \
+ } \
+}
+
+#define READ_SE_ALLOWED(reader, val, min, max) { \
+ gint32 tmp; \
+ READ_SE (reader, tmp); \
+ CHECK_ALLOWED (tmp, min, max); \
+ val = tmp; \
+}
+
+GST_DEBUG_CATEGORY_STATIC (h264parser_debug);
+#define GST_CAT_DEFAULT h264parser_debug
+
+#define _do_init \
+ GST_DEBUG_CATEGORY_INIT (h264parser_debug, "h264parser", 0, \
+ "H264 parser");
+
+G_DEFINE_TYPE_WITH_CODE (GstH264Parser, gst_h264_parser, G_TYPE_OBJECT,
+ _do_init);
+
+static void
+gst_h264_sequence_free (void *data)
+{
+ g_slice_free (GstH264Sequence, data);
+}
+
+static gboolean
+gst_h264_parse_hrd_parameters (GstH264HRDParameters * hrd,
+ GstNalReader * reader)
+{
+ guint SchedSelIdx;
+
+ GST_DEBUG ("parsing \"HRD Parameters\"");
+
+ READ_UE_ALLOWED (reader, hrd->cpb_cnt_minus1, 0, 31);
+ READ_UINT8 (reader, hrd->bit_rate_scale, 4);
+ READ_UINT8 (reader, hrd->cpb_size_scale, 4);
+
+ for (SchedSelIdx = 0; SchedSelIdx <= hrd->cpb_cnt_minus1; SchedSelIdx++) {
+ READ_UE (reader, hrd->bit_rate_value_minus1[SchedSelIdx]);
+ READ_UE (reader, hrd->cpb_size_value_minus1[SchedSelIdx]);
+ }
+
+ READ_UINT8 (reader, hrd->initial_cpb_removal_delay_length_minus1, 5);
+ READ_UINT8 (reader, hrd->cpb_removal_delay_length_minus1, 5);
+ READ_UINT8 (reader, hrd->dpb_output_delay_length_minus1, 5);
+ READ_UINT8 (reader, hrd->time_offset_length, 5);
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"HRD Parameters\"");
+ return FALSE;
+
+}
+
+static gboolean
+gst_h264_parse_vui_parameters (GstH264VUIParameters * vui,
+ GstNalReader * reader)
+{
+ guint8 aspect_ratio_info_present_flag;
+ guint8 video_signal_type_present_flag;
+ guint8 chroma_loc_info_present_flag;
+
+ GST_DEBUG ("parsing \"VUI Parameters\"");
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ vui->aspect_ratio_idc = 0;
+ vui->video_format = 5;
+ vui->video_full_range_flag = 0;
+ vui->colour_primaries = 2;
+ vui->transfer_characteristics = 2;
+ vui->matrix_coefficients = 2;
+ vui->chroma_sample_loc_type_top_field = 0;
+ vui->chroma_sample_loc_type_bottom_field = 0;
+ vui->low_delay_hrd_flag = 0;
+
+ READ_UINT8 (reader, aspect_ratio_info_present_flag, 1);
+ if (aspect_ratio_info_present_flag) {
+ READ_UINT8 (reader, vui->aspect_ratio_idc, 8);
+ if (vui->aspect_ratio_idc == 255) {
+ READ_UINT16 (reader, vui->sar_width, 16);
+ READ_UINT16 (reader, vui->sar_height, 16);
+ }
+ }
+
+ READ_UINT8 (reader, vui->overscan_info_present_flag, 1);
+ if (vui->overscan_info_present_flag)
+ READ_UINT8 (reader, vui->overscan_appropriate_flag, 1);
+
+ READ_UINT8 (reader, video_signal_type_present_flag, 1);
+ if (video_signal_type_present_flag) {
+ guint8 colour_description_present_flag;
+
+ READ_UINT8 (reader, vui->video_format, 3);
+ READ_UINT8 (reader, vui->video_full_range_flag, 1);
+ READ_UINT8 (reader, colour_description_present_flag, 1);
+ if (colour_description_present_flag) {
+ READ_UINT8 (reader, vui->colour_primaries, 8);
+ READ_UINT8 (reader, vui->transfer_characteristics, 8);
+ READ_UINT8 (reader, vui->matrix_coefficients, 8);
+ }
+ }
+
+ READ_UINT8 (reader, chroma_loc_info_present_flag, 1);
+ if (chroma_loc_info_present_flag) {
+ READ_UE_ALLOWED (reader, vui->chroma_sample_loc_type_top_field, 0, 5);
+ READ_UE_ALLOWED (reader, vui->chroma_sample_loc_type_bottom_field, 0, 5);
+ }
+
+ READ_UINT8 (reader, vui->timing_info_present_flag, 1);
+ if (vui->timing_info_present_flag) {
+ READ_UINT32 (reader, vui->num_units_in_tick, 32);
+ READ_UINT32 (reader, vui->time_scale, 32);
+ READ_UINT8 (reader, vui->fixed_frame_rate_flag, 1);
+ }
+
+ READ_UINT8 (reader, vui->nal_hrd_parameters_present_flag, 1);
+ if (vui->nal_hrd_parameters_present_flag) {
+ if (!gst_h264_parse_hrd_parameters (&vui->nal_hrd_parameters, reader))
+ goto error;
+ }
+
+ READ_UINT8 (reader, vui->vcl_hrd_parameters_present_flag, 1);
+ if (vui->vcl_hrd_parameters_present_flag) {
+ if (!gst_h264_parse_hrd_parameters (&vui->vcl_hrd_parameters, reader))
+ goto error;
+ }
+
+ if (vui->nal_hrd_parameters_present_flag ||
+ vui->vcl_hrd_parameters_present_flag)
+ READ_UINT8 (reader, vui->low_delay_hrd_flag, 1);
+
+ READ_UINT8 (reader, vui->pic_struct_present_flag, 1);
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"VUI Parameters\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_scaling_list (GstNalReader * reader,
+ guint8 scaling_lists_4x4[6][16], guint8 scaling_lists_8x8[6][64],
+ const guint8 fallback_4x4_inter[16], const guint8 fallback_4x4_intra[16],
+ const guint8 fallback_8x8_inter[64], const guint8 fallback_8x8_intra[64],
+ guint32 chroma_format_idc)
+{
+ gint i;
+ guint8 seq_scaling_list_present_flag[12] = { 0, };
+
+ GST_WARNING ("parsing scaling lists");
+
+ for (i = 0; i < ((chroma_format_idc) != 3) ? 8 : 12; i++) {
+ READ_UINT8 (reader, seq_scaling_list_present_flag[i], 1);
+ }
+
+ for (i = 0; i < 12; i++) {
+ gboolean use_default = FALSE;
+
+ if (seq_scaling_list_present_flag[i]) {
+ guint8 *scaling_list;
+ guint size;
+ guint j;
+ guint8 last_scale, next_scale;
+
+ if (i <= 5) {
+ scaling_list = scaling_lists_4x4[i];
+ size = 16;
+ } else {
+ scaling_list = scaling_lists_8x8[i];
+ size = 64;
+ }
+
+ last_scale = 8;
+ next_scale = 8;
+ for (j = 0; j < size; j++) {
+ if (next_scale != 0) {
+ gint32 delta_scale;
+
+ READ_SE (reader, delta_scale);
+ next_scale = (last_scale + delta_scale + 256) % 256;
+ use_default = (j == 0 && next_scale == 0);
+ }
+ scaling_list[j] = (next_scale == 0) ? last_scale : next_scale;
+ last_scale = scaling_list[j];
+ }
+ } else
+ use_default = TRUE;
+
+ if (use_default) {
+ switch (i) {
+ case 0:
+ memcpy (scaling_lists_4x4[0], fallback_4x4_intra, 16);
+ break;
+ case 1:
+ memcpy (scaling_lists_4x4[1], scaling_lists_4x4[0], 16);
+ break;
+ case 2:
+ memcpy (scaling_lists_4x4[2], scaling_lists_4x4[1], 16);
+ break;
+ case 3:
+ memcpy (scaling_lists_4x4[3], fallback_4x4_inter, 16);
+ break;
+ case 4:
+ memcpy (scaling_lists_4x4[4], scaling_lists_4x4[3], 16);
+ break;
+ case 5:
+ memcpy (scaling_lists_4x4[5], scaling_lists_4x4[4], 16);
+ break;
+ case 6:
+ memcpy (scaling_lists_8x8[0], fallback_8x8_intra, 64);
+ break;
+ case 7:
+ memcpy (scaling_lists_8x8[1], fallback_8x8_inter, 64);
+ break;
+ case 8:
+ memcpy (scaling_lists_8x8[2], scaling_lists_8x8[0], 64);
+ break;
+ case 9:
+ memcpy (scaling_lists_8x8[3], scaling_lists_8x8[1], 64);
+ break;
+ case 10:
+ memcpy (scaling_lists_8x8[4], scaling_lists_8x8[2], 64);
+ break;
+ case 11:
+ memcpy (scaling_lists_8x8[5], scaling_lists_8x8[3], 64);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+
+ GST_WARNING ("error parsing scaling lists");
+ return FALSE;
+}
+
+GstH264Sequence *
+gst_h264_parser_parse_sequence (GstH264Parser * parser, guint8 * data,
+ guint size)
+{
+ GstNalReader reader = GST_NAL_READER_INIT (data, size);
+ GstH264Sequence *seq;
+ guint8 frame_cropping_flag;
+
+ g_return_val_if_fail (GST_IS_H264_PARSER (parser), NULL);
+ g_return_val_if_fail (data != NULL, NULL);
+ g_return_val_if_fail (size > 0, NULL);
+
+ GST_DEBUG ("parsing \"Sequence parameter set\"");
+
+ seq = g_slice_new (GstH264Sequence);
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ seq->chroma_format_idc = 1;
+ seq->separate_colour_plane_flag = 0;
+ seq->bit_depth_luma_minus8 = 0;
+ seq->bit_depth_chroma_minus8 = 0;
+ memset (seq->scaling_lists_4x4, 16, 96);
+ memset (seq->scaling_lists_8x8, 16, 384);
+ seq->frame_crop_left_offset = 0;
+ seq->frame_crop_right_offset = 0;
+ seq->frame_crop_top_offset = 0;
+ seq->frame_crop_bottom_offset = 0;
+
+ READ_UINT8 (&reader, seq->profile_idc, 8);
+ READ_UINT8 (&reader, seq->constraint_set0_flag, 1);
+ READ_UINT8 (&reader, seq->constraint_set1_flag, 1);
+ READ_UINT8 (&reader, seq->constraint_set2_flag, 1);
+ READ_UINT8 (&reader, seq->constraint_set3_flag, 1);
+
+ /* skip reserved_zero_4bits */
+ if (!gst_nal_reader_skip (&reader, 4))
+ goto error;
+
+ READ_UINT8 (&reader, seq->level_idc, 8);
+
+ READ_UE_ALLOWED (&reader, seq->id, 0, 31);
+
+ if (seq->profile_idc == 100 || seq->profile_idc == 110 ||
+ seq->profile_idc == 122 || seq->profile_idc == 244 ||
+ seq->profile_idc == 244 || seq->profile_idc == 44 ||
+ seq->profile_idc == 83 || seq->profile_idc == 86) {
+ READ_UE_ALLOWED (&reader, seq->chroma_format_idc, 0, 3);
+ if (seq->chroma_format_idc == 3)
+ READ_UINT8 (&reader, seq->separate_colour_plane_flag, 1);
+
+ READ_UE_ALLOWED (&reader, seq->bit_depth_luma_minus8, 0, 6);
+ READ_UE_ALLOWED (&reader, seq->bit_depth_chroma_minus8, 0, 6);
+ READ_UINT8 (&reader, seq->qpprime_y_zero_transform_bypass_flag, 1);
+
+ READ_UINT8 (&reader, seq->scaling_matrix_present_flag, 1);
+ if (seq->scaling_matrix_present_flag) {
+ if (!gst_h264_parser_parse_scaling_list (&reader,
+ seq->scaling_lists_4x4, seq->scaling_lists_8x8,
+ default_4x4_inter, default_4x4_intra,
+ default_8x8_inter, default_8x8_intra, seq->chroma_format_idc))
+ goto error;
+ }
+ }
+
+ READ_UE_ALLOWED (&reader, seq->log2_max_frame_num_minus4, 0, 12);
+ /* calculate MaxFrameNum */
+ seq->MaxFrameNum = pow (2, seq->log2_max_frame_num_minus4 + 4);
+
+ READ_UE_ALLOWED (&reader, seq->pic_order_cnt_type, 0, 2);
+ if (seq->pic_order_cnt_type == 0) {
+ READ_UE_ALLOWED (&reader, seq->log2_max_pic_order_cnt_lsb_minus4, 0, 12);
+ } else if (seq->pic_order_cnt_type == 1) {
+ guint i;
+
+ READ_UINT8 (&reader, seq->delta_pic_order_always_zero_flag, 1);
+ READ_SE (&reader, seq->offset_for_non_ref_pic);
+ READ_SE (&reader, seq->offset_for_top_to_bottom_field);
+ READ_UE_ALLOWED (&reader, seq->num_ref_frames_in_pic_order_cnt_cycle, 0,
+ 255);
+ for (i = 0; i < seq->num_ref_frames_in_pic_order_cnt_cycle; i++)
+ READ_SE (&reader, seq->offset_for_ref_frame[i]);
+ }
+
+ READ_UE (&reader, seq->num_ref_frames);
+ READ_UINT8 (&reader, seq->gaps_in_frame_num_value_allowed_flag, 1);
+ READ_UE (&reader, seq->pic_width_in_mbs_minus1);
+ READ_UE (&reader, seq->pic_height_in_map_units_minus1);
+ READ_UINT8 (&reader, seq->frame_mbs_only_flag, 1);
+
+ if (!seq->frame_mbs_only_flag)
+ READ_UINT8 (&reader, seq->mb_adaptive_frame_field_flag, 1);
+
+ READ_UINT8 (&reader, seq->direct_8x8_inference_flag, 1);
+ READ_UINT8 (&reader, frame_cropping_flag, 1);
+ if (frame_cropping_flag) {
+ READ_UE (&reader, seq->frame_crop_left_offset);
+ READ_UE (&reader, seq->frame_crop_right_offset);
+ READ_UE (&reader, seq->frame_crop_top_offset);
+ READ_UE (&reader, seq->frame_crop_bottom_offset);
+ }
+
+ READ_UINT8 (&reader, seq->vui_parameters_present_flag, 1);
+ if (seq->vui_parameters_present_flag) {
+ if (!gst_h264_parse_vui_parameters (&seq->vui_parameters, &reader))
+ goto error;
+ }
+
+ GST_DEBUG ("adding sequence parameter set with id: %d to hash table",
+ seq->id);
+ g_hash_table_replace (parser->sequences, &seq->id, seq);
+ return seq;
+
+error:
+ GST_WARNING ("error parsing \"Sequence parameter set\"");
+
+ gst_h264_sequence_free (seq);
+ return NULL;
+}
+
+static void
+gst_h264_picture_free (void *data)
+{
+ GstH264Picture *pic = (GstH264Picture *) data;
+
+ if (pic->slice_group_id)
+ g_free (pic->slice_group_id);
+
+ g_slice_free (GstH264Picture, data);
+}
+
+static gboolean
+gst_h264_parser_more_data (GstNalReader * reader)
+{
+ guint remaining;
+
+ remaining = gst_nal_reader_get_remaining (reader);
+ if (remaining == 0)
+ return FALSE;
+
+ if (remaining <= 8) {
+ guint8 rbsp_stop_one_bit;
+
+ if (!gst_nal_reader_peek_bits_uint8 (reader, &rbsp_stop_one_bit, 1))
+ return FALSE;
+
+ if (rbsp_stop_one_bit == 1)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GstH264Picture *
+gst_h264_parser_parse_picture (GstH264Parser * parser, guint8 * data,
+ guint size)
+{
+ GstNalReader reader = GST_NAL_READER_INIT (data, size);
+ GstH264Picture *pic;
+ gint seq_parameter_set_id;
+ GstH264Sequence *seq;
+
+ g_return_val_if_fail (GST_IS_H264_PARSER (parser), NULL);
+ g_return_val_if_fail (data != NULL, NULL);
+ g_return_val_if_fail (size > 0, NULL);
+
+ GST_DEBUG ("parsing \"Picture parameter set\"");
+
+ pic = g_slice_new (GstH264Picture);
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ pic->slice_group_id = NULL;
+ pic->transform_8x8_mode_flag = 0;
+
+ READ_UE_ALLOWED (&reader, pic->id, 0, 255);
+ READ_UE_ALLOWED (&reader, seq_parameter_set_id, 0, 31);
+ seq = g_hash_table_lookup (parser->sequences, &seq_parameter_set_id);
+ if (!seq) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ seq_parameter_set_id);
+ goto error;
+ }
+ pic->sequence = seq;
+
+ READ_UINT8 (&reader, pic->entropy_coding_mode_flag, 1);
+ READ_UINT8 (&reader, pic->pic_order_present_flag, 1);
+ READ_UE_ALLOWED (&reader, pic->num_slice_groups_minus1, 0, 7);
+ if (pic->num_slice_groups_minus1 > 0) {
+ READ_UE_ALLOWED (&reader, pic->slice_group_map_type, 0, 6);
+ if (pic->slice_group_map_type == 0) {
+ gint i;
+
+ for (i = 0; i <= pic->num_slice_groups_minus1; i++)
+ READ_UE (&reader, pic->run_length_minus1[i]);
+ }
+ } else if (pic->slice_group_map_type == 2) {
+ gint i;
+
+ for (i = 0; i <= pic->num_slice_groups_minus1; i++) {
+ READ_UE (&reader, pic->top_left[i]);
+ READ_UE (&reader, pic->bottom_right[i]);
+ }
+ } else if (pic->slice_group_map_type >= 3 && pic->slice_group_map_type <= 5) {
+ READ_UINT8 (&reader, pic->slice_group_change_direction_flag, 1);
+ READ_UE (&reader, pic->slice_group_change_rate_minus1);
+ } else if (pic->slice_group_map_type == 6) {
+ gint bits;
+ gint i;
+
+ READ_UE (&reader, pic->pic_size_in_map_units_minus1);
+ bits = ceil (log2 (pic->num_slice_groups_minus1 + 1));
+
+ pic->slice_group_id = g_new (guint8, pic->pic_size_in_map_units_minus1 + 1);
+ for (i = 0; i <= pic->pic_size_in_map_units_minus1; i++)
+ READ_UINT8 (&reader, pic->slice_group_id[i], bits);
+ }
+
+ READ_UE_ALLOWED (&reader, pic->num_ref_idx_l0_active_minus1, 0, 31);
+ READ_UE_ALLOWED (&reader, pic->num_ref_idx_l1_active_minus1, 0, 31);
+ READ_UINT8 (&reader, pic->weighted_pred_flag, 1);
+ READ_UINT8 (&reader, pic->weighted_bipred_idc, 2);
+ READ_SE_ALLOWED (&reader, pic->pic_init_qp_minus26, -26, 25);
+ READ_SE_ALLOWED (&reader, pic->pic_init_qs_minus26, -26, 25);
+ READ_SE_ALLOWED (&reader, pic->chroma_qp_index_offset, -12, 12);
+ pic->second_chroma_qp_index_offset = pic->chroma_qp_index_offset;
+ READ_UINT8 (&reader, pic->deblocking_filter_control_present_flag, 1);
+ READ_UINT8 (&reader, pic->constrained_intra_pred_flag, 1);
+ READ_UINT8 (&reader, pic->redundant_pic_cnt_present_flag, 1);
+
+ if (!gst_h264_parser_more_data (&reader))
+ goto done;
+
+ READ_UINT8 (&reader, pic->transform_8x8_mode_flag, 1);
+
+ READ_UINT8 (&reader, pic->scaling_matrix_present_flag, 1);
+ if (pic->scaling_matrix_present_flag) {
+ if (seq->scaling_matrix_present_flag) {
+ if (!gst_h264_parser_parse_scaling_list (&reader,
+ pic->scaling_lists_4x4, pic->scaling_lists_8x8,
+ seq->scaling_lists_4x4[0], seq->scaling_lists_4x4[3],
+ seq->scaling_lists_8x8[0], seq->scaling_lists_8x8[3],
+ seq->chroma_format_idc))
+ goto error;
+ } else {
+ if (!gst_h264_parser_parse_scaling_list (&reader,
+ seq->scaling_lists_4x4, seq->scaling_lists_8x8,
+ default_4x4_inter, default_4x4_intra,
+ default_8x8_inter, default_8x8_intra, seq->chroma_format_idc))
+ goto error;
+ }
+ }
+
+ READ_SE_ALLOWED (&reader, pic->second_chroma_qp_index_offset, -12, 12);
+
+done:
+ GST_DEBUG ("adding picture parameter set with id: %d to hash table", pic->id);
+ g_hash_table_replace (parser->pictures, &pic->id, pic);
+ return pic;
+
+error:
+ GST_WARNING ("error parsing \"Picture parameter set\"");
+
+ gst_h264_picture_free (pic);
+ return NULL;
+}
+
+static gboolean
+gst_h264_slice_parse_pred_weight_table (GstH264Slice * slice,
+ GstNalReader * reader,
+ const GstH264Sequence * seq, const GstH264Picture * pic)
+{
+ GstH264PredWeightTable *p;
+ gint i;
+
+ GST_DEBUG ("parsing \"Prediction weight table\"");
+
+ p = &slice->pred_weight_table;
+
+ READ_UE_ALLOWED (reader, p->luma_log2_weight_denom, 0, 7);
+ /* set default values */
+ memset (p->luma_weight_l0, pow (2, p->luma_log2_weight_denom), 32);
+ memset (p->luma_offset_l0, 0, 32);
+
+ if (seq->ChromaArrayType != 0) {
+ READ_UE_ALLOWED (reader, p->chroma_log2_weight_denom, 0, 7);
+ /* set default values */
+ memset (p->chroma_weight_l0, pow (2, p->chroma_log2_weight_denom), 64);
+ memset (p->chroma_offset_l0, 0, 64);
+ }
+
+ for (i = 0; i <= pic->num_ref_idx_l0_active_minus1; i++) {
+ guint8 luma_weight_l0_flag;
+
+ READ_UINT8 (reader, luma_weight_l0_flag, 1);
+ if (luma_weight_l0_flag) {
+ READ_SE_ALLOWED (reader, p->luma_weight_l0[i], -128, 127);
+ READ_SE_ALLOWED (reader, p->luma_offset_l0[i], -128, 127);
+ }
+ if (seq->ChromaArrayType != 0) {
+ guint8 chroma_weight_l0_flag;
+ gint j;
+
+ READ_UINT8 (reader, chroma_weight_l0_flag, 1);
+ for (j = 0; j <= 2; j++) {
+ READ_SE_ALLOWED (reader, p->chroma_weight_l0[i][j], -128, 127);
+ READ_SE_ALLOWED (reader, p->chroma_offset_l0[i][j], -128, 127);
+ }
+ }
+ }
+
+ if (GST_H264_IS_B_SLICE (slice->type)) {
+ for (i = 0; i <= pic->num_ref_idx_l1_active_minus1; i++) {
+ guint8 luma_weight_l1_flag;
+
+ READ_UINT8 (reader, luma_weight_l1_flag, 1);
+ if (luma_weight_l1_flag) {
+ READ_SE_ALLOWED (reader, p->luma_weight_l1[i], -128, 127);
+ READ_SE_ALLOWED (reader, p->luma_offset_l1[i], -128, 127);
+ }
+ if (seq->ChromaArrayType != 0) {
+ guint8 chroma_weight_l1_flag;
+ gint j;
+
+ READ_UINT8 (reader, chroma_weight_l1_flag, 1);
+ for (j = 0; j <= 2; j++) {
+ READ_SE_ALLOWED (reader, p->chroma_weight_l1[i][j], -128, 127);
+ READ_SE_ALLOWED (reader, p->chroma_offset_l1[i][j], -128, 127);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Prediction weight table\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_slice_parse_ref_pic_list_reordering (GstH264Slice * slice,
+ GstNalReader * reader)
+{
+ GST_DEBUG ("parsing \"Reference picture list reordering\"");
+
+ if (!GST_H264_IS_I_SLICE (slice->type) && !GST_H264_IS_SI_SLICE (slice->type)) {
+ guint8 ref_pic_list_reordering_flag_l0;
+ guint8 reordering_of_pic_nums_idc;
+
+ READ_UINT8 (reader, ref_pic_list_reordering_flag_l0, 1);
+ if (ref_pic_list_reordering_flag_l0)
+ do {
+ READ_UE_ALLOWED (reader, reordering_of_pic_nums_idc, 0, 3);
+ if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
+ guint32 abs_diff_pic_num_minus1;
+
+ READ_UE_ALLOWED (reader, abs_diff_pic_num_minus1, 0,
+ slice->MaxPicNum - 1);
+ } else if (reordering_of_pic_nums_idc == 2) {
+ guint32 long_term_pic_num;
+
+ READ_UE (reader, long_term_pic_num);
+ }
+ } while (reordering_of_pic_nums_idc != 3);
+ }
+
+ if (GST_H264_IS_B_SLICE (slice->type)) {
+ guint8 ref_pic_list_reordering_flag_l1;
+ guint8 reordering_of_pic_nums_idc;
+
+ READ_UINT8 (reader, ref_pic_list_reordering_flag_l1, 1);
+ if (ref_pic_list_reordering_flag_l1)
+ do {
+ READ_UE_ALLOWED (reader, reordering_of_pic_nums_idc, 0, 3);
+ if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
+ guint32 abs_diff_num_minus1;
+ READ_UE (reader, abs_diff_num_minus1);
+ } else if (reordering_of_pic_nums_idc == 3) {
+ guint32 long_term_pic_num;
+
+ READ_UE (reader, long_term_pic_num);
+ }
+ } while (reordering_of_pic_nums_idc != 3);
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Reference picture list reordering\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_slice_parse_dec_ref_pic_marking (GstH264Slice * slice,
+ GstNalReader * reader)
+{
+ GstH264DecRefPicMarking *m;
+
+ GST_DEBUG ("parsing \"Decoded reference picture marking\"");
+
+ m = &slice->dec_ref_pic_marking;
+
+ if (slice->nal_unit.IdrPicFlag) {
+ READ_UINT8 (reader, m->no_output_of_prior_pics_flag, 1);
+ READ_UINT8 (reader, m->long_term_reference_flag, 1);
+ } else {
+ READ_UINT8 (reader, m->adaptive_ref_pic_marking_mode_flag, 1);
+ if (m->adaptive_ref_pic_marking_mode_flag) {
+ guint8 memory_management_control_operation;
+
+ do {
+ READ_UE_ALLOWED (reader, memory_management_control_operation, 0, 6);
+ if (memory_management_control_operation == 1 ||
+ memory_management_control_operation == 3) {
+ guint32 difference_of_pic_nums_minus1;
+
+ READ_UE (reader, difference_of_pic_nums_minus1);
+ }
+ if (memory_management_control_operation == 2) {
+ guint32 long_term_pic_num;
+
+ READ_UE (reader, long_term_pic_num);
+ }
+ if (memory_management_control_operation == 3 ||
+ memory_management_control_operation == 6) {
+ guint32 long_term_frame_idx;
+
+ READ_UE (reader, long_term_frame_idx);
+ }
+ if (memory_management_control_operation == 4) {
+ guint32 max_long_term_frame_idx_plus1;
+
+ READ_UE (reader, max_long_term_frame_idx_plus1);
+ }
+ }
+ while (memory_management_control_operation != 0);
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Decoded reference picture marking\"");
+ return FALSE;
+}
+
+gboolean
+gst_h264_parser_parse_slice_header (GstH264Parser * parser,
+ GstH264Slice * slice, guint8 * data, guint size, GstNalUnit nal_unit)
+{
+ GstNalReader reader = GST_NAL_READER_INIT (data, size);
+ gint pic_parameter_set_id;
+ GstH264Picture *pic;
+ GstH264Sequence *seq;
+
+ g_return_val_if_fail (GST_IS_H264_PARSER (parser), FALSE);
+ g_return_val_if_fail (slice != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (size > 0, FALSE);
+
+ GST_DEBUG ("parsing \"Slice header\"");
+
+ memcpy (&slice->nal_unit, &nal_unit, sizeof (GstNalUnit));
+
+ READ_UE (&reader, slice->first_mb_in_slice);
+ READ_UE (&reader, slice->type);
+
+ READ_UE_ALLOWED (&reader, pic_parameter_set_id, 0, 255);
+ pic = g_hash_table_lookup (parser->pictures, &pic_parameter_set_id);
+ if (!pic) {
+ GST_WARNING ("couldn't find associated picture parameter set with id: %d",
+ pic_parameter_set_id);
+ goto error;
+ }
+ slice->picture = pic;
+ seq = pic->sequence;
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ slice->field_pic_flag = 0;
+ slice->bottom_field_flag = 0;
+ slice->delta_pic_order_cnt_bottom = 0;
+ slice->delta_pic_order_cnt[0] = 0;
+ slice->delta_pic_order_cnt[1] = 0;
+ slice->redundant_pic_cnt = 0;
+ slice->num_ref_idx_l0_active_minus1 = pic->num_ref_idx_l0_active_minus1;
+ slice->num_ref_idx_l1_active_minus1 = pic->num_ref_idx_l1_active_minus1;
+
+ if (seq->separate_colour_plane_flag)
+ READ_UINT8 (&reader, slice->colour_plane_id, 2);
+
+ READ_UINT16 (&reader, slice->frame_num, seq->log2_max_frame_num_minus4 + 4);
+
+ if (!seq->frame_mbs_only_flag) {
+ READ_UINT8 (&reader, slice->field_pic_flag, 1);
+ if (slice->field_pic_flag)
+ READ_UINT8 (&reader, slice->bottom_field_flag, 1);
+ }
+
+ /* calculate MaxPicNum */
+ if (slice->field_pic_flag)
+ slice->MaxPicNum = seq->MaxFrameNum;
+ else
+ slice->MaxPicNum = 2 * seq->MaxFrameNum;
+
+ if (nal_unit.type == 5)
+ READ_UE_ALLOWED (&reader, slice->idr_pic_id, 0, 65535);
+
+ if (seq->pic_order_cnt_type == 0) {
+ READ_UINT16 (&reader, slice->pic_order_cnt_lsb,
+ seq->log2_max_pic_order_cnt_lsb_minus4 + 4);
+ if (pic->pic_order_present_flag && !slice->field_pic_flag)
+ READ_SE (&reader, slice->delta_pic_order_cnt_bottom);
+ }
+
+ if (seq->pic_order_cnt_type == 1 && !seq->delta_pic_order_always_zero_flag) {
+ READ_SE (&reader, slice->delta_pic_order_cnt[0]);
+ if (pic->pic_order_present_flag && !slice->field_pic_flag)
+ READ_SE (&reader, slice->delta_pic_order_cnt[1]);
+ }
+
+ if (pic->redundant_pic_cnt_present_flag)
+ READ_UE_ALLOWED (&reader, slice->redundant_pic_cnt, 0, 127);
+
+ if (GST_H264_IS_B_SLICE (slice->type))
+ READ_UINT8 (&reader, slice->direct_spatial_mv_pred_flag, 1);
+
+ if (GST_H264_IS_P_SLICE (slice->type) ||
+ GST_H264_IS_SP_SLICE (slice->type) || GST_H264_IS_B_SLICE (slice->type)) {
+ guint8 num_ref_idx_active_override_flag;
+
+ READ_UINT8 (&reader, num_ref_idx_active_override_flag, 1);
+ if (num_ref_idx_active_override_flag) {
+ READ_UE_ALLOWED (&reader, slice->num_ref_idx_l0_active_minus1, 0, 31);
+
+ if (GST_H264_IS_B_SLICE (slice->type))
+ READ_UE_ALLOWED (&reader, slice->num_ref_idx_l1_active_minus1, 0, 31);
+ }
+ }
+
+ if (!gst_h264_slice_parse_ref_pic_list_reordering (slice, &reader))
+ return FALSE;
+
+ if ((pic->weighted_pred_flag && (GST_H264_IS_P_SLICE (slice->type) ||
+ GST_H264_IS_SP_SLICE (slice->type)))
+ || (pic->weighted_bipred_idc == 1 && GST_H264_IS_B_SLICE (slice->type))) {
+ if (!gst_h264_slice_parse_pred_weight_table (slice, &reader, seq, pic))
+ return FALSE;
+ }
+
+ if (nal_unit.ref_idc != 0) {
+ if (!gst_h264_slice_parse_dec_ref_pic_marking (slice, &reader))
+ return FALSE;
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Slice header\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_buffering_period (GstH264Parser * parser,
+ GstH264BufferingPeriod * per, guint8 * data, guint size)
+{
+ GstNalReader reader = GST_NAL_READER_INIT (data, size);
+
+ GstH264Sequence *seq;
+ guint8 seq_parameter_set_id;
+
+ GST_DEBUG ("parsing \"Buffering period\"");
+
+ READ_UE_ALLOWED (&reader, seq_parameter_set_id, 0, 31);
+ seq = g_hash_table_lookup (parser->sequences, &seq_parameter_set_id);
+ if (!seq) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ seq_parameter_set_id);
+ goto error;
+ }
+ per->seq = seq;
+
+ if (seq->vui_parameters_present_flag) {
+ GstH264VUIParameters *vui = &seq->vui_parameters;
+
+ if (vui->nal_hrd_parameters_present_flag) {
+ GstH264HRDParameters *hrd = &vui->nal_hrd_parameters;
+ guint8 SchedSelIdx;
+
+ for (SchedSelIdx = 0; SchedSelIdx <= hrd->cpb_cnt_minus1; SchedSelIdx++) {
+ READ_UINT8 (&reader, per->nal_initial_cpb_removal_delay[SchedSelIdx],
+ 5);
+ READ_UINT8 (&reader,
+ per->nal_initial_cpb_removal_delay_offset[SchedSelIdx], 5);
+ }
+ }
+
+ if (vui->vcl_hrd_parameters_present_flag) {
+ GstH264HRDParameters *hrd = &vui->vcl_hrd_parameters;
+ guint8 SchedSelIdx;
+
+ for (SchedSelIdx = 0; SchedSelIdx <= hrd->cpb_cnt_minus1; SchedSelIdx++) {
+ READ_UINT8 (&reader, per->vcl_initial_cpb_removal_delay[SchedSelIdx],
+ 5);
+ READ_UINT8 (&reader,
+ per->vcl_initial_cpb_removal_delay_offset[SchedSelIdx], 5);
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Buffering period\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parse_clock_timestamp (GstH264ClockTimestamp * tim,
+ GstH264VUIParameters * vui, GstNalReader * reader)
+{
+ guint8 full_timestamp_flag;
+ guint8 time_offset_length;
+
+ GST_DEBUG ("parsing \"Clock timestamp\"");
+
+ /* defalt values */
+ tim->time_offset = 0;
+
+ READ_UINT8 (reader, tim->ct_type, 2);
+ READ_UINT8 (reader, tim->nuit_field_based_flag, 1);
+ READ_UINT8 (reader, tim->counting_type, 5);
+ READ_UINT8 (reader, full_timestamp_flag, 1);
+ READ_UINT8 (reader, tim->discontinuity_flag, 1);
+ READ_UINT8 (reader, tim->cnt_dropped_flag, 1);
+ READ_UINT8 (reader, tim->n_frames, 8);
+
+ if (full_timestamp_flag) {
+ tim->seconds_flag = TRUE;
+ READ_UINT8 (reader, tim->seconds_value, 6);
+
+ tim->minutes_flag = TRUE;
+ READ_UINT8 (reader, tim->minutes_value, 6);
+
+ tim->hours_flag = TRUE;
+ READ_UINT8 (reader, tim->hours_value, 5);
+ } else {
+ READ_UINT8 (reader, tim->seconds_flag, 1);
+ if (tim->seconds_flag) {
+ READ_UINT8 (reader, tim->seconds_value, 6);
+ READ_UINT8 (reader, tim->minutes_flag, 1);
+ if (tim->minutes_flag) {
+ READ_UINT8 (reader, tim->minutes_value, 6);
+ READ_UINT8 (reader, tim->hours_flag, 1);
+ if (tim->hours_flag)
+ READ_UINT8 (reader, tim->hours_value, 5);
+ }
+ }
+ }
+
+ time_offset_length = 0;
+ if (vui->nal_hrd_parameters_present_flag)
+ time_offset_length = vui->nal_hrd_parameters.time_offset_length;
+ else if (vui->vcl_hrd_parameters_present_flag)
+ time_offset_length = vui->vcl_hrd_parameters.time_offset_length;
+
+ if (time_offset_length > 0)
+ READ_UINT32 (reader, tim->time_offset, time_offset_length);
+
+error:
+ GST_WARNING ("error parsing \"Clock timestamp\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_pic_timing (GstH264Parser * parser, GstH264Sequence * seq,
+ GstH264PicTiming * tim, guint8 * data, guint size)
+{
+ GstNalReader reader = GST_NAL_READER_INIT (data, size);
+
+ GST_DEBUG ("parsing \"Picture timing\"");
+
+ if (!seq) {
+ GST_WARNING ("didn't get the associated sequence paramater set for the "
+ "current access unit");
+ goto error;
+ }
+
+ /* default values */
+ memset (tim->clock_timestamp_flag, 0, 3);
+
+ if (seq->vui_parameters_present_flag) {
+ GstH264VUIParameters *vui = &seq->vui_parameters;
+
+ if (vui->nal_hrd_parameters_present_flag) {
+ READ_UINT8 (&reader, tim->cpb_removal_delay,
+ vui->nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1);
+ READ_UINT8 (&reader, tim->dpb_output_delay,
+ vui->nal_hrd_parameters.dpb_output_delay_length_minus1 + 1);
+ } else if (vui->nal_hrd_parameters_present_flag) {
+ READ_UINT8 (&reader, tim->cpb_removal_delay,
+ vui->vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1);
+ READ_UINT8 (&reader, tim->dpb_output_delay,
+ vui->vcl_hrd_parameters.dpb_output_delay_length_minus1 + 1);
+ }
+
+ if (vui->pic_struct_present_flag) {
+ const guint8 num_clock_ts_table[9] = {
+ 1, 1, 1, 2, 2, 3, 3, 2, 3
+ };
+ guint8 NumClockTs;
+ guint i;
+
+ READ_UINT8 (&reader, tim->pic_struct, 4);
+ CHECK_ALLOWED (tim->pic_struct, 0, 8);
+
+ NumClockTs = num_clock_ts_table[tim->pic_struct];
+ for (i = 0; i < NumClockTs; i++) {
+ READ_UINT8 (&reader, tim->clock_timestamp_flag[i], 1);
+ if (tim->clock_timestamp_flag[i]) {
+ if (!gst_h264_parse_clock_timestamp (&tim->clock_timestamp[i], vui,
+ &reader))
+ goto error;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Picture timing\"");
+ return FALSE;
+}
+
+gboolean
+gst_h264_parser_parse_sei_message (GstH264Parser * parser,
+ GstH264Sequence * seq, GstH264SEIMessage * sei, guint8 * data, guint size)
+{
+ GstNalReader reader;
+
+ guint32 payloadSize;
+ guint8 payload_type_byte, payload_size_byte;
+
+ guint8 *payload_data;
+ guint remaining, payload_size;
+ gboolean res;
+
+ g_return_val_if_fail (GST_IS_H264_PARSER (parser), FALSE);
+ g_return_val_if_fail (sei != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (size > 0, FALSE);
+
+ GST_DEBUG ("parsing \"Sei message\"");
+
+ gst_nal_reader_init (&reader, data, size);
+
+ sei->payloadType = 0;
+ do {
+ READ_UINT8 (&reader, payload_type_byte, 8);
+ sei->payloadType += payload_type_byte;
+ }
+ while (payload_type_byte == 0xff);
+
+ payloadSize = 0;
+ do {
+ READ_UINT8 (&reader, payload_size_byte, 8);
+ payloadSize += payload_size_byte;
+ }
+ while (payload_size_byte == 0xff);
+
+ payload_data = data + gst_nal_reader_get_pos (&reader) * 8;
+ remaining = gst_nal_reader_get_remaining (&reader) * 8;
+ payload_size = payloadSize < remaining ? payloadSize : remaining;
+
+ if (sei->payloadType == 0)
+ res =
+ gst_h264_parser_parse_buffering_period (parser,
+ &sei->buffering_period, payload_data, payload_size);
+ else if (sei->payloadType == 1)
+ res = gst_h264_parser_parse_pic_timing (parser, seq, &sei->pic_timing,
+ payload_data, payload_size);
+ else
+ res = TRUE;
+
+ return res;
+
+error:
+ GST_WARNING ("error parsing \"Sei message\"");
+ return FALSE;
+}
+
+#undef CHECK_ALLOWED
+#undef READ_UINT8
+#undef READ_UINT16
+#undef READ_UINT32
+#undef READ_UINT64
+#undef READ_UE
+#undef READ_UE_ALLOWED
+#undef READ_SE
+#undef READ_SE_ALLOWED
+
+static void
+gst_h264_parser_init (GstH264Parser * object)
+{
+ GstH264Parser *parser = GST_H264_PARSER (object);
+
+ parser->sequences = g_hash_table_new_full (g_int_hash, g_int_equal, NULL,
+ gst_h264_sequence_free);
+ parser->pictures = g_hash_table_new_full (g_int_hash, g_int_equal, NULL,
+ gst_h264_picture_free);
+}
+
+static void
+gst_h264_parser_finalize (GObject * object)
+{
+ GstH264Parser *parser = GST_H264_PARSER (object);
+
+ g_hash_table_destroy (parser->sequences);
+ g_hash_table_destroy (parser->pictures);
+
+ G_OBJECT_CLASS (gst_h264_parser_parent_class)->finalize (object);
+}
+
+static void
+gst_h264_parser_class_init (GstH264ParserClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gst_h264_parser_finalize;
+}
diff --git a/sys/vdpau/h264/gsth264parser.h b/sys/vdpau/h264/gsth264parser.h
new file mode 100644
index 000000000..868c0e878
--- /dev/null
+++ b/sys/vdpau/h264/gsth264parser.h
@@ -0,0 +1,411 @@
+/* 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_H264_PARSER_H_
+#define _GST_H264_PARSER_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GST_NAL_UNKNOWN = 0,
+ GST_NAL_SLICE = 1,
+ GST_NAL_SLICE_DPA = 2,
+ GST_NAL_SLICE_DPB = 3,
+ GST_NAL_SLICE_DPC = 4,
+ GST_NAL_SLICE_IDR = 5,
+ GST_NAL_SEI = 6,
+ GST_NAL_SPS = 7,
+ GST_NAL_PPS = 8,
+ GST_NAL_AU_DELIMITER = 9,
+ GST_NAL_SEQ_END = 10,
+ GST_NAL_STREAM_END = 11,
+ GST_NAL_FILTER_DATA = 12
+} GstNalUnitType;
+
+typedef enum
+{
+ GST_H264_P_SLICE,
+ GST_H264_B_SLICE,
+ GST_H264_I_SLICE,
+ GST_H264_SP_SLICE,
+ GST_H264_SI_SLICE,
+ GST_H264_S_P_SLICE,
+ GST_H264_S_B_SLICE,
+ GST_H264_S_I_SLICE,
+ GST_H264_S_SP_SLICE,
+ GST_H264_S_SI_SLICE
+} GstH264SliceType;
+
+#define GST_H264_IS_P_SLICE(type) ((type % 5) == GST_H264_P_SLICE)
+#define GST_H264_IS_B_SLICE(type) ((type % 5) == GST_H264_B_SLICE)
+#define GST_H264_IS_I_SLICE(type) ((type % 5) == GST_H264_I_SLICE)
+#define GST_H264_IS_SP_SLICE(type) ((type % 5) == GST_H264_SP_SLICE)
+#define GST_H264_IS_SI_SLICE(type) ((type % 5) == GST_H264_SI_SLICE)
+
+typedef struct _GstNalUnit GstNalUnit;
+
+typedef struct _GstH264HRDParameters GstH264HRDParameters;
+typedef struct _GstH264VUIParameters GstH264VUIParameters;
+typedef struct _GstH264Sequence GstH264Sequence;
+
+typedef struct _GstH264Picture GstH264Picture;
+
+typedef struct _GstH264DecRefPicMarking GstH264DecRefPicMarking;
+typedef struct _GstH264PredWeightTable GstH264PredWeightTable;
+typedef struct _GstH264Slice GstH264Slice;
+
+typedef struct _GstH264ClockTimestamp GstH264ClockTimestamp;
+typedef struct _GstH264PicTiming GstH264PicTiming;
+typedef struct _GstH264BufferingPeriod GstH264BufferingPeriod;
+typedef struct _GstH264SEIMessage GstH264SEIMessage;
+
+struct _GstNalUnit
+{
+ guint16 ref_idc;
+ guint16 type;
+
+ /* calculated values */
+ guint8 IdrPicFlag;
+};
+
+struct _GstH264HRDParameters
+{
+ guint8 cpb_cnt_minus1;
+ guint8 bit_rate_scale;
+ guint8 cpb_size_scale;
+
+ guint32 bit_rate_value_minus1[32];
+ guint32 cpb_size_value_minus1[32];
+ guint8 cbr_flag[32];
+
+ guint8 initial_cpb_removal_delay_length_minus1;
+ guint8 cpb_removal_delay_length_minus1;
+ guint8 dpb_output_delay_length_minus1;
+ guint8 time_offset_length;
+};
+
+struct _GstH264VUIParameters
+{
+ guint8 aspect_ratio_idc;
+ /* if aspect_ratio_idc == 255 */
+ guint16 sar_width;
+ guint16 sar_height;
+
+ guint8 overscan_info_present_flag;
+ /* if overscan_info_present_flag */
+ guint8 overscan_appropriate_flag;
+
+ guint8 video_format;
+ guint8 video_full_range_flag;
+ guint8 colour_description_present_flag;
+ guint8 colour_primaries;
+ guint8 transfer_characteristics;
+ guint8 matrix_coefficients;
+
+ guint8 chroma_sample_loc_type_top_field;
+ guint8 chroma_sample_loc_type_bottom_field;
+
+ guint8 timing_info_present_flag;
+ /* if timing_info_present_flag */
+ guint32 num_units_in_tick;
+ guint32 time_scale;
+ guint8 fixed_frame_rate_flag;
+
+ guint8 nal_hrd_parameters_present_flag;
+ /* if nal_hrd_parameters_present_flag */
+ GstH264HRDParameters nal_hrd_parameters;
+
+ guint8 vcl_hrd_parameters_present_flag;
+ /* if nal_hrd_parameters_present_flag */
+ GstH264HRDParameters vcl_hrd_parameters;
+
+ guint8 low_delay_hrd_flag;
+ guint8 pic_struct_present_flag;
+};
+
+struct _GstH264Sequence
+{
+ gint id;
+
+ guint8 profile_idc;
+ guint8 constraint_set0_flag;
+ guint8 constraint_set1_flag;
+ guint8 constraint_set2_flag;
+ guint8 constraint_set3_flag;
+ guint8 level_idc;
+
+ guint8 chroma_format_idc;
+ guint8 separate_colour_plane_flag;
+ guint8 bit_depth_luma_minus8;
+ guint8 bit_depth_chroma_minus8;
+ guint8 qpprime_y_zero_transform_bypass_flag;
+
+ guint8 scaling_matrix_present_flag;
+ guint8 scaling_lists_4x4[6][16];
+ guint8 scaling_lists_8x8[6][64];
+
+ guint8 log2_max_frame_num_minus4;
+ guint8 pic_order_cnt_type;
+
+ /* if pic_order_cnt_type == 0 */
+ guint8 log2_max_pic_order_cnt_lsb_minus4;
+
+ /* else if pic_order_cnt_type == 1 */
+ guint8 delta_pic_order_always_zero_flag;
+ gint32 offset_for_non_ref_pic;
+ gint32 offset_for_top_to_bottom_field;
+ guint8 num_ref_frames_in_pic_order_cnt_cycle;
+ gint32 offset_for_ref_frame[255];
+
+ guint32 num_ref_frames;
+ guint8 gaps_in_frame_num_value_allowed_flag;
+ guint32 pic_width_in_mbs_minus1;
+ guint32 pic_height_in_map_units_minus1;
+ guint8 frame_mbs_only_flag;
+
+ /* if !frame_mbs_only_flag */
+ guint8 mb_adaptive_frame_field_flag;
+
+ guint8 direct_8x8_inference_flag;
+
+ guint32 frame_crop_left_offset;
+ guint32 frame_crop_right_offset;
+ guint32 frame_crop_top_offset;
+ guint32 frame_crop_bottom_offset;
+
+ guint8 vui_parameters_present_flag;
+ /* if vui_parameters_present_flag */
+ GstH264VUIParameters vui_parameters;
+
+ /* calculated values */
+ guint8 ChromaArrayType;
+ guint32 MaxFrameNum;
+};
+
+struct _GstH264Picture
+{
+ gint id;
+
+ GstH264Sequence *sequence;
+
+ guint8 entropy_coding_mode_flag;
+ guint8 pic_order_present_flag;
+
+ guint32 num_slice_groups_minus1;
+
+ /* if num_slice_groups_minus1 > 0 */
+ guint8 slice_group_map_type;
+ /* and if slice_group_map_type == 0 */
+ guint32 run_length_minus1[8];
+ /* or if slice_group_map_type == 2 */
+ guint32 top_left[8];
+ guint32 bottom_right[8];
+ /* or if slice_group_map_type == (3, 4, 5) */
+ guint8 slice_group_change_direction_flag;
+ guint32 slice_group_change_rate_minus1;
+ /* or if slice_group_map_type == 6 */
+ guint32 pic_size_in_map_units_minus1;
+ guint8 *slice_group_id;
+
+ guint8 num_ref_idx_l0_active_minus1;
+ guint8 num_ref_idx_l1_active_minus1;
+ guint8 weighted_pred_flag;
+ guint8 weighted_bipred_idc;
+ gint8 pic_init_qp_minus26;
+ gint8 pic_init_qs_minus26;
+ gint8 chroma_qp_index_offset;
+ guint8 deblocking_filter_control_present_flag;
+ guint8 constrained_intra_pred_flag;
+ guint8 redundant_pic_cnt_present_flag;
+
+ guint8 transform_8x8_mode_flag;
+
+ guint8 scaling_matrix_present_flag;
+ /* if scaling_matrix_present_flag == 1 */
+ guint8 scaling_lists_4x4[6][16];
+ guint8 scaling_lists_8x8[6][64];
+
+ guint8 second_chroma_qp_index_offset;
+};
+
+struct _GstH264DecRefPicMarking
+{
+ /* if slice->nal_unit.IdrPicFlag */
+ guint8 no_output_of_prior_pics_flag;
+ guint8 long_term_reference_flag;
+
+ /* else */
+ guint8 adaptive_ref_pic_marking_mode_flag;
+};
+
+struct _GstH264PredWeightTable
+{
+ guint8 luma_log2_weight_denom;
+ guint8 chroma_log2_weight_denom;
+
+ guint8 luma_weight_l0[32];
+ guint8 luma_offset_l0[32];
+
+ /* if seq->ChromaArrayType != 0 */
+ guint8 chroma_weight_l0[32][2];
+ guint8 chroma_offset_l0[32][2];
+
+ /* if slice->slice_type % 5 == 1 */
+ guint8 luma_weight_l1[32];
+ guint8 luma_offset_l1[32];
+ /* and if seq->ChromaArrayType != 0 */
+ guint8 chroma_weight_l1[32][2];
+ guint8 chroma_offset_l1[32][2];
+};
+
+struct _GstH264Slice
+{
+ GstNalUnit nal_unit;
+
+ guint32 first_mb_in_slice;
+ guint32 type;
+
+ GstH264Picture *picture;
+
+ /* if seq->separate_colour_plane_flag */
+ guint8 colour_plane_id;
+
+ guint16 frame_num;
+
+ guint8 field_pic_flag;
+ guint8 bottom_field_flag;
+
+ /* if nal_unit.type == 5 */
+ guint16 idr_pic_id;
+
+ /* if seq->pic_order_cnt_type == 0 */
+ guint16 pic_order_cnt_lsb;
+ gint32 delta_pic_order_cnt_bottom;
+
+ gint32 delta_pic_order_cnt[2];
+ guint8 redundant_pic_cnt;
+
+ /* if slice_type == B_SLICE */
+ guint8 direct_spatial_mv_pred_flag;
+
+ guint8 num_ref_idx_l0_active_minus1;
+ guint8 num_ref_idx_l1_active_minus1;
+
+ GstH264PredWeightTable pred_weight_table;
+ /* if nal_unit.ref_idc != 0 */
+ GstH264DecRefPicMarking dec_ref_pic_marking;
+
+ /* calculated values */
+ guint32 MaxPicNum;
+};
+
+struct _GstH264ClockTimestamp
+{
+ guint8 ct_type;
+ guint8 nuit_field_based_flag;
+ guint8 counting_type;
+ guint8 discontinuity_flag;
+ guint8 cnt_dropped_flag;
+ guint8 n_frames;
+
+ guint8 seconds_flag;
+ guint8 seconds_value;
+
+ guint8 minutes_flag;
+ guint8 minutes_value;
+
+ guint8 hours_flag;
+ guint8 hours_value;
+
+ guint32 time_offset;
+};
+
+struct _GstH264PicTiming
+{
+ guint8 cpb_removal_delay;
+ guint8 dpb_output_delay;
+
+ guint8 pic_struct_present_flag;
+ /* if pic_struct_present_flag */
+ guint8 pic_struct;
+
+ guint8 clock_timestamp_flag[3];
+ GstH264ClockTimestamp clock_timestamp[3];
+};
+
+struct _GstH264BufferingPeriod
+{
+ GstH264Sequence *seq;
+
+ /* seq->vui_parameters->nal_hrd_parameters_present_flag */
+ guint8 nal_initial_cpb_removal_delay[32];
+ guint8 nal_initial_cpb_removal_delay_offset[32];
+
+ /* seq->vui_parameters->vcl_hrd_parameters_present_flag */
+ guint8 vcl_initial_cpb_removal_delay[32];
+ guint8 vcl_initial_cpb_removal_delay_offset[32];
+};
+
+struct _GstH264SEIMessage
+{
+ guint32 payloadType;
+
+ union {
+ GstH264BufferingPeriod buffering_period;
+ GstH264PicTiming pic_timing;
+ };
+};
+
+#define GST_TYPE_H264_PARSER (gst_h264_parser_get_type ())
+#define GST_H264_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_H264_PARSER, GstH264Parser))
+#define GST_H264_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_H264_PARSER, GstH264ParserClass))
+#define GST_IS_H264_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_H264_PARSER))
+#define GST_IS_H264_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_H264_PARSER))
+#define GST_H264_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_H264_PARSER, GstH264ParserClass))
+
+typedef struct _GstH264ParserClass GstH264ParserClass;
+typedef struct _GstH264Parser GstH264Parser;
+
+struct _GstH264ParserClass
+{
+ GObjectClass parent_class;
+};
+
+struct _GstH264Parser
+{
+ GObject parent_instance;
+
+ GHashTable *sequences;
+ GHashTable *pictures;
+};
+
+GType gst_h264_parser_get_type (void) G_GNUC_CONST;
+
+GstH264Sequence *gst_h264_parser_parse_sequence (GstH264Parser * parser, guint8 * data, guint size);
+GstH264Picture *gst_h264_parser_parse_picture (GstH264Parser * parser, guint8 * data, guint size);
+gboolean gst_h264_parser_parse_slice_header (GstH264Parser * parser, GstH264Slice * slice, guint8 * data, guint size, GstNalUnit nal_unit);
+gboolean gst_h264_parser_parse_sei_message (GstH264Parser * parser, GstH264Sequence *seq, GstH264SEIMessage * sei, guint8 * data, guint size);
+
+G_END_DECLS
+
+#endif /* _GST_H264_PARSER_H_ */
diff --git a/sys/vdpau/h264/gstnalreader.c b/sys/vdpau/h264/gstnalreader.c
new file mode 100644
index 000000000..ca78d3a7f
--- /dev/null
+++ b/sys/vdpau/h264/gstnalreader.c
@@ -0,0 +1,503 @@
+/* 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstnalreader.h"
+
+static gboolean gst_nal_reader_read (GstNalReader * reader, guint nbits);
+
+/**
+ * SECTION:gstnalreader
+ * @short_description: Bit reader which automatically skips
+ * emulation_prevention bytes
+ *
+ * #GstNalReader provides a bit reader which automatically skips
+ * emulation_prevention bytes. It provides functions for reading any number of bits
+ * into 8, 16, 32 and 64 bit variables. It also provides functions for reading
+ * Exp-Golomb values.
+ */
+
+/**
+ * gst_nal_reader_new:
+ * @data: Data from which the #GstNalReader should read
+ * @size: Size of @data in bytes
+ *
+ * Create a new #GstNalReader instance, which will read from @data.
+ *
+ * Returns: a new #GstNalReader instance
+ *
+ * Since: 0.10.22
+ */
+GstNalReader *
+gst_nal_reader_new (const guint8 * data, guint size)
+{
+ GstNalReader *ret = g_slice_new0 (GstNalReader);
+
+ ret->data = data;
+ ret->size = size;
+
+ ret->first_byte = 0xff;
+ ret->cache = 0xffffffff;
+
+ return ret;
+}
+
+/**
+ * gst_nal_reader_new_from_buffer:
+ * @buffer: Buffer from which the #GstNalReader should read
+ *
+ * Create a new #GstNalReader instance, which will read from the
+ * #GstBuffer @buffer.
+ *
+ * Returns: a new #GstNalReader instance
+ *
+ * Since: 0.10.22
+ */
+GstNalReader *
+gst_nal_reader_new_from_buffer (const GstBuffer * buffer)
+{
+ g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
+
+ return gst_nal_reader_new (GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+}
+
+/**
+ * gst_nal_reader_free:
+ * @reader: a #GstNalReader instance
+ *
+ * Frees a #GstNalReader instance, which was previously allocated by
+ * gst_nal_reader_new() or gst_nal_reader_new_from_buffer().
+ *
+ * Since: 0.10.22
+ */
+void
+gst_nal_reader_free (GstNalReader * reader)
+{
+ g_return_if_fail (reader != NULL);
+
+ g_slice_free (GstNalReader, reader);
+}
+
+/**
+ * gst_nal_reader_init:
+ * @reader: a #GstNalReader instance
+ * @data: Data from which the #GstNalReader should read
+ * @size: Size of @data in bytes
+ *
+ * Initializes a #GstNalReader instance to read from @data. This function
+ * can be called on already initialized instances.
+ *
+ * Since: 0.10.22
+ */
+void
+gst_nal_reader_init (GstNalReader * reader, const guint8 * data, guint size)
+{
+ g_return_if_fail (reader != NULL);
+
+ reader->data = data;
+ reader->size = size;
+
+ reader->byte = 0;
+ reader->bits_in_cache = 0;
+ /* fill with something other than 0 to detect emulation prevention bytes */
+ reader->first_byte = 0xff;
+ reader->cache = 0xffffffff;
+}
+
+/**
+ * gst_nal_reader_init_from_buffer:
+ * @reader: a #GstNalReader instance
+ * @buffer: Buffer from which the #GstNalReader should read
+ *
+ * Initializes a #GstNalReader instance to read from @buffer. This function
+ * can be called on already initialized instances.
+ *
+ * Since: 0.10.22
+ */
+void
+gst_nal_reader_init_from_buffer (GstNalReader * reader,
+ const GstBuffer * buffer)
+{
+ g_return_if_fail (GST_IS_BUFFER (buffer));
+
+ gst_nal_reader_init (reader, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+}
+
+/**
+ * gst_nal_reader_skip:
+ * @reader: a #GstNalReader instance
+ * @nbits: the number of bits to skip
+ *
+ * Skips @nbits bits of the #GstNalReader instance.
+ *
+ * Returns: %TRUE if @nbits bits could be skipped, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+gboolean
+gst_nal_reader_skip (GstNalReader * reader, guint nbits)
+{
+ g_return_val_if_fail (reader != NULL, FALSE);
+
+ if (G_UNLIKELY (!gst_nal_reader_read (reader, nbits)))
+ return FALSE;
+
+ reader->bits_in_cache -= nbits;
+
+ return TRUE;
+}
+
+/**
+ * gst_nal_reader_skip_to_byte:
+ * @reader: a #GstNalReader instance
+ *
+ * Skips until the next byte.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+gboolean
+gst_nal_reader_skip_to_byte (GstNalReader * reader)
+{
+ g_return_val_if_fail (reader != NULL, FALSE);
+
+ if (reader->bits_in_cache == 0) {
+ if (G_LIKELY ((reader->size - reader->byte) > 0))
+ reader->byte++;
+ else
+ return FALSE;
+ }
+
+ reader->bits_in_cache = 0;
+
+ return TRUE;
+}
+
+/**
+ * gst_nal_reader_get_pos:
+ * @reader: a #GstNalReader instance
+ *
+ * Returns the current position of a GstNalReader instance in bits.
+ *
+ * Returns: The current position in bits
+ *
+ */
+guint
+gst_nal_reader_get_pos (const GstNalReader * reader)
+{
+ return reader->byte * 8 - reader->bits_in_cache;
+}
+
+/**
+ * gst_nal_reader_get_remaining:
+ * @reader: a #GstNalReader instance
+ *
+ * Returns the remaining number of bits of a GstNalReader instance.
+ *
+ * Returns: The remaining number of bits.
+ *
+ */
+guint
+gst_nal_reader_get_remaining (const GstNalReader * reader)
+{
+ return (reader->size - reader->byte) * 8 + reader->bits_in_cache;
+}
+
+/**
+ * gst_nal_reader_get_bits_uint8:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint8 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_nal_reader_get_bits_uint16:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint16 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_nal_reader_get_bits_uint32:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint32 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_nal_reader_get_bits_uint64:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint64 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_nal_reader_peek_bits_uint8:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint8 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_nal_reader_peek_bits_uint16:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint16 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_nal_reader_peek_bits_uint32:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint32 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_nal_reader_peek_bits_uint64:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint64 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 0.10.22
+ */
+
+static gboolean
+gst_nal_reader_read (GstNalReader * reader, guint nbits)
+{
+ if (G_UNLIKELY (reader->byte * 8 + (nbits - reader->bits_in_cache) >
+ reader->size * 8))
+ return FALSE;
+
+ while (reader->bits_in_cache < nbits) {
+ guint8 byte;
+ gboolean check_three_byte;
+
+ check_three_byte = TRUE;
+ next_byte:
+ if (G_UNLIKELY (reader->byte >= reader->size))
+ return FALSE;
+
+ byte = reader->data[reader->byte++];
+
+ /* check if the byte is a emulation_prevention_three_byte */
+ if (check_three_byte && byte == 0x03 && reader->first_byte == 0x00 &&
+ ((reader->cache & 0xff) == 0)) {
+ /* next byte goes unconditionally to the cache, even if it's 0x03 */
+ check_three_byte = FALSE;
+ goto next_byte;
+ }
+ reader->cache = (reader->cache << 8) | reader->first_byte;
+ reader->first_byte = byte;
+ reader->bits_in_cache += 8;
+ }
+
+ return TRUE;
+}
+
+#define GST_NAL_READER_READ_BITS(bits) \
+gboolean \
+gst_nal_reader_get_bits_uint##bits (GstNalReader *reader, guint##bits *val, guint nbits) \
+{ \
+ guint shift; \
+ \
+ g_return_val_if_fail (reader != NULL, FALSE); \
+ g_return_val_if_fail (val != NULL, FALSE); \
+ g_return_val_if_fail (nbits <= bits, FALSE); \
+ \
+ if (!gst_nal_reader_read (reader, nbits)) \
+ return FALSE; \
+ \
+ /* bring the required bits down and truncate */ \
+ shift = reader->bits_in_cache - nbits; \
+ *val = reader->first_byte >> shift; \
+ \
+ *val |= reader->cache << (8 - shift); \
+ /* mask out required bits */ \
+ if (nbits < bits) \
+ *val &= ((guint##bits)1 << nbits) - 1; \
+ \
+ reader->bits_in_cache = shift; \
+ \
+ return TRUE; \
+} \
+\
+gboolean \
+gst_nal_reader_peek_bits_uint##bits (const GstNalReader *reader, guint##bits *val, guint nbits) \
+{ \
+ GstNalReader tmp; \
+ \
+ g_return_val_if_fail (reader != NULL, FALSE); \
+ tmp = *reader; \
+ return gst_nal_reader_get_bits_uint##bits (&tmp, val, nbits); \
+}
+
+GST_NAL_READER_READ_BITS (8);
+GST_NAL_READER_READ_BITS (16);
+GST_NAL_READER_READ_BITS (32);
+GST_NAL_READER_READ_BITS (64);
+
+/**
+ * gst_nal_reader_get_ue:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Reads an unsigned Exp-Golomb value into val
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_nal_reader_get_ue (GstNalReader * reader, guint32 * val)
+{
+ guint i = 0;
+ guint8 bit;
+ guint32 value;
+
+ if (G_UNLIKELY (!gst_nal_reader_get_bits_uint8 (reader, &bit, 1)))
+ return FALSE;
+
+ while (bit == 0) {
+ i++;
+ if G_UNLIKELY
+ ((!gst_nal_reader_get_bits_uint8 (reader, &bit, 1)))
+ return FALSE;
+ }
+
+ g_return_val_if_fail (i <= 32, FALSE);
+
+ if (G_UNLIKELY (!gst_nal_reader_get_bits_uint32 (reader, &value, i)))
+ return FALSE;
+
+ *val = (1 << i) - 1 + value;
+
+ return TRUE;
+}
+
+/**
+ * gst_nal_reader_peek_ue:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read an unsigned Exp-Golomb value into val but keep the current position
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_nal_reader_peek_ue (const GstNalReader * reader, guint32 * val)
+{
+ GstNalReader tmp;
+
+ g_return_val_if_fail (reader != NULL, FALSE);
+
+ tmp = *reader;
+ return gst_nal_reader_get_ue (&tmp, val);
+}
+
+/**
+ * gst_nal_reader_get_e:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Reads a signed Exp-Golomb value into val
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_nal_reader_get_se (GstNalReader * reader, gint32 * val)
+{
+ guint32 value;
+
+ if (G_UNLIKELY (!gst_nal_reader_get_ue (reader, &value)))
+ return FALSE;
+
+ if (value % 2)
+ *val = -(value / 2);
+ else
+ *val = value / 2;
+
+ return TRUE;
+}
+
+/**
+ * gst_nal_reader_peek_se:
+ * @reader: a #GstNalReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed Exp-Golomb value into val but keep the current position
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_nal_reader_peek_se (const GstNalReader * reader, gint32 * val)
+{
+ GstNalReader tmp;
+
+ g_return_val_if_fail (reader != NULL, FALSE);
+
+ tmp = *reader;
+ return gst_nal_reader_get_se (&tmp, val);
+}
diff --git a/sys/vdpau/h264/gstnalreader.h b/sys/vdpau/h264/gstnalreader.h
new file mode 100644
index 000000000..62dcfd62a
--- /dev/null
+++ b/sys/vdpau/h264/gstnalreader.h
@@ -0,0 +1,99 @@
+/* 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_NAL_READER_H__
+#define __GST_NAL_READER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstNalReader GstNalReader;
+
+struct _GstNalReader
+{
+ const guint8 *data;
+ guint size;
+
+ guint byte; /* Byte position */
+ guint bits_in_cache; /* bitpos in the cache of next bit */
+ guint8 first_byte;
+ guint64 cache; /* cached bytes */
+};
+
+GstNalReader *gst_nal_reader_new (const guint8 *data, guint size);
+GstNalReader *gst_nal_reader_new_from_buffer (const GstBuffer *buffer);
+void gst_nal_reader_free (GstNalReader * reader);
+
+void gst_nal_reader_init (GstNalReader * reader, const guint8 * data, guint size);
+void gst_nal_reader_init_from_buffer (GstNalReader * reader, const GstBuffer * buffer);
+
+gboolean gst_nal_reader_skip (GstNalReader *reader, guint nbits);
+gboolean gst_nal_reader_skip_to_byte (GstNalReader *reader);
+
+guint gst_nal_reader_get_pos (const GstNalReader * reader);
+guint gst_nal_reader_get_remaining (const GstNalReader *reader);
+
+gboolean gst_nal_reader_get_bits_uint8 (GstNalReader *reader, guint8 *val, guint nbits);
+gboolean gst_nal_reader_get_bits_uint16 (GstNalReader *reader, guint16 *val, guint nbits);
+gboolean gst_nal_reader_get_bits_uint32 (GstNalReader *reader, guint32 *val, guint nbits);
+gboolean gst_nal_reader_get_bits_uint64 (GstNalReader *reader, guint64 *val, guint nbits);
+
+gboolean gst_nal_reader_peek_bits_uint8 (const GstNalReader *reader, guint8 *val, guint nbits);
+gboolean gst_nal_reader_peek_bits_uint16 (const GstNalReader *reader, guint16 *val, guint nbits);
+gboolean gst_nal_reader_peek_bits_uint32 (const GstNalReader *reader, guint32 *val, guint nbits);
+gboolean gst_nal_reader_peek_bits_uint64 (const GstNalReader *reader, guint64 *val, guint nbits);
+
+gboolean gst_nal_reader_get_ue (GstNalReader *reader, guint32 *val);
+gboolean gst_nal_reader_peek_ue (const GstNalReader *reader, guint32 *val);
+
+gboolean gst_nal_reader_get_se (GstNalReader *reader, gint32 *val);
+gboolean gst_nal_reader_peek_se (const GstNalReader *reader, gint32 *val);
+
+/**
+ * GST_NAL_READER_INIT:
+ * @data: Data from which the #GstNalReader should read
+ * @size: Size of @data in bytes
+ *
+ * A #GstNalReader must be initialized with this macro, before it can be
+ * used. This macro can used be to initialize a variable, but it cannot
+ * be assigned to a variable. In that case you have to use
+ * gst_bit_reader_init().
+ *
+ * Since: 0.10.22
+ */
+#define GST_NAL_READER_INIT(data, size) {data, size, 0, 0, 0xff, 0xffffffffff}
+
+/**
+ * GST_NAL_READER_INIT_FROM_BUFFER:
+ * @buffer: Buffer from which the #GstNalReader should read
+ *
+ * A #GstNalReader must be initialized with this macro, before it can be
+ * used. This macro can used be to initialize a variable, but it cannot
+ * be assigned to a variable. In that case you have to use
+ * gst_bit_reader_init().
+ *
+ * Since: 0.10.22
+ */
+#define GST_NAL_READER_INIT_FROM_BUFFER(buffer) {GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 0, 0, 0xff, 0xffffffffff}
+
+G_END_DECLS
+
+#endif /* __GST_NAL_READER_H__ */
diff --git a/sys/vdpau/h264/gstvdph264dec.c b/sys/vdpau/h264/gstvdph264dec.c
new file mode 100644
index 000000000..2ba637322
--- /dev/null
+++ b/sys/vdpau/h264/gstvdph264dec.c
@@ -0,0 +1,533 @@
+/* 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., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstbitreader.h>
+#include <string.h>
+
+#include "../gstvdp/gstvdpvideosrcpad.h"
+
+#include "gstvdph264frame.h"
+
+#include "gstvdph264dec.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vdp_h264_dec_debug);
+#define GST_CAT_DEFAULT gst_vdp_h264_dec_debug
+
+static GstStaticPadTemplate sink_template =
+GST_STATIC_PAD_TEMPLATE (GST_BASE_VIDEO_DECODER_SINK_NAME,
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h264, " "parsed = (boolean) false")
+ );
+
+#define DEBUG_INIT(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_vdp_h264_dec_debug, "vdpauh264dec", 0, \
+ "VDPAU h264 decoder");
+
+GST_BOILERPLATE_FULL (GstVdpH264Dec, gst_vdp_h264_dec, GstBaseVideoDecoder,
+ GST_TYPE_BASE_VIDEO_DECODER, DEBUG_INIT);
+
+#define SYNC_CODE_SIZE 3
+
+#define READ_UINT8(reader, val, nbits) { \
+ if (!gst_bit_reader_get_bits_uint8 (reader, &val, nbits)) { \
+ GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
+ return FALSE; \
+ } \
+}
+
+#define READ_UINT16(reader, val, nbits) { \
+ if (!gst_bit_reader_get_bits_uint16 (reader, &val, nbits)) { \
+ GST_WARNING ("failed to read uint16, nbits: %d", nbits); \
+ return FALSE; \
+ } \
+}
+
+#define SKIP(reader, nbits) { \
+ if (!gst_bit_reader_skip (reader, nbits)) { \
+ GST_WARNING ("failed to skip nbits: %d", nbits); \
+ return FALSE; \
+ } \
+}
+
+static gboolean
+gst_vdp_h264_dec_set_sink_caps (GstBaseVideoDecoder * base_video_decoder,
+ GstCaps * caps)
+{
+ GstVdpH264Dec *h264_dec;
+ GstStructure *structure;
+ const GValue *value;
+
+ h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+
+ structure = gst_caps_get_structure (caps, 0);
+ /* packetized video has a codec_data */
+ if ((value = gst_structure_get_value (structure, "codec_data"))) {
+ GstBuffer *buf;
+ GstBitReader reader;
+ guint8 version;
+ guint8 n_sps, n_pps;
+ gint i;
+
+ GST_DEBUG_OBJECT (h264_dec, "have packetized h264");
+ h264_dec->packetized = TRUE;
+
+ buf = gst_value_get_buffer (value);
+ GST_MEMDUMP ("avcC:", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+
+ /* parse the avcC data */
+ if (GST_BUFFER_SIZE (buf) < 7) {
+ GST_ERROR_OBJECT (h264_dec, "avcC size %u < 7", GST_BUFFER_SIZE (buf));
+ return FALSE;
+ }
+
+ gst_bit_reader_init_from_buffer (&reader, buf);
+
+ READ_UINT8 (&reader, version, 8);
+ if (version != 1)
+ return FALSE;
+
+ SKIP (&reader, 30);
+
+ READ_UINT8 (&reader, h264_dec->nal_length_size, 2);
+ h264_dec->nal_length_size += 1;
+ GST_DEBUG_OBJECT (h264_dec, "nal length %u", h264_dec->nal_length_size);
+
+ SKIP (&reader, 3);
+
+ READ_UINT8 (&reader, n_sps, 5);
+ for (i = 0; i < n_sps; i++) {
+ guint16 sps_length;
+ guint8 *data;
+
+ READ_UINT16 (&reader, sps_length, 16);
+ sps_length -= 1;
+ SKIP (&reader, 8);
+
+ data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
+ if (!gst_h264_parser_parse_sequence (h264_dec->parser, data, sps_length))
+ return FALSE;
+
+ SKIP (&reader, sps_length * 8);
+ }
+
+ READ_UINT8 (&reader, n_pps, 8);
+ for (i = 0; i < n_pps; i++) {
+ guint16 pps_length;
+ guint8 *data;
+
+ READ_UINT16 (&reader, pps_length, 16);
+ pps_length -= 1;
+ SKIP (&reader, 8);
+
+ data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
+ if (!gst_h264_parser_parse_picture (h264_dec->parser, data, pps_length))
+ return FALSE;
+
+ SKIP (&reader, pps_length * 8);
+ }
+ }
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_vdp_h264_dec_shape_output (GstBaseVideoDecoder * base_video_decoder,
+ GstBuffer * buf)
+{
+ GstVdpVideoSrcPad *vdp_pad;
+
+ vdp_pad =
+ (GstVdpVideoSrcPad *) GST_BASE_VIDEO_DECODER_SRC_PAD (base_video_decoder);
+
+ return gst_vdp_video_src_pad_push (vdp_pad, GST_VDP_VIDEO_BUFFER (buf));
+}
+
+static GstFlowReturn
+gst_vdp_h264_dec_handle_frame (GstBaseVideoDecoder * base_video_decoder,
+ GstVideoFrame * frame, GstClockTimeDiff deadline)
+{
+ GstVdpH264Frame *h264_frame;
+
+ GST_DEBUG ("handle_frame");
+
+ h264_frame = (GstVdpH264Frame *) frame;
+
+ GST_DEBUG ("frame_num: %d", h264_frame->slice_hdr.frame_num);
+ GST_DEBUG ("pic_order_cnt_type: %d",
+ h264_frame->slice_hdr.picture->sequence->pic_order_cnt_type);
+ GST_DEBUG ("pic_order_cnt_lsb: %d", h264_frame->slice_hdr.pic_order_cnt_lsb);
+ GST_DEBUG ("delta_pic_order_cnt_bottom: %d",
+ h264_frame->slice_hdr.delta_pic_order_cnt_bottom);
+
+ gst_base_video_decoder_skip_frame (base_video_decoder, frame);
+ return GST_FLOW_OK;
+}
+
+static gint
+gst_vdp_h264_dec_scan_for_sync (GstBaseVideoDecoder * base_video_decoder,
+ GstAdapter * adapter)
+{
+ GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+ gint m;
+
+ if (h264_dec->packetized)
+ return 0;
+
+ m = gst_adapter_masked_scan_uint32 (adapter, 0xffffff00, 0x00000100,
+ 0, gst_adapter_available (adapter));
+ if (m == -1)
+ return gst_adapter_available (adapter) - SYNC_CODE_SIZE;
+
+ return m;
+}
+
+static GstBaseVideoDecoderScanResult
+gst_vdp_h264_dec_scan_for_packet_end (GstBaseVideoDecoder * base_video_decoder,
+ GstAdapter * adapter, guint * size, gboolean at_eos)
+{
+ GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+ guint avail;
+
+ avail = gst_adapter_available (adapter);
+ if (avail < h264_dec->nal_length_size)
+ return GST_BASE_VIDEO_DECODER_SCAN_RESULT_NEED_DATA;
+
+ if (h264_dec->packetized) {
+ guint8 *data;
+ gint i;
+ guint32 nal_length;
+
+ data = g_slice_alloc (h264_dec->nal_length_size);
+ gst_adapter_copy (adapter, data, 0, h264_dec->nal_length_size);
+ for (i = 0; i < h264_dec->nal_length_size; i++)
+ nal_length = (nal_length << 8) | data[i];
+
+ g_slice_free1 (h264_dec->nal_length_size, data);
+
+ nal_length += h264_dec->nal_length_size;
+
+ /* check for invalid NALU sizes, assume the size if the available bytes
+ * when something is fishy */
+ if (nal_length <= 1 || nal_length > avail) {
+ nal_length = avail - h264_dec->nal_length_size;
+ GST_DEBUG ("fixing invalid NALU size to %u", nal_length);
+ }
+
+ *size = nal_length;
+ }
+
+ else {
+ guint8 *data;
+ guint32 start_code;
+ guint n;
+
+ data = g_slice_alloc (SYNC_CODE_SIZE);
+ gst_adapter_copy (adapter, data, 0, SYNC_CODE_SIZE);
+ start_code = ((data[0] << 16) && (data[1] << 8) && data[2]);
+ g_slice_free1 (SYNC_CODE_SIZE, data);
+
+ GST_DEBUG ("start_code: %d", start_code);
+ if (start_code == 0x000001)
+ return GST_BASE_VIDEO_DECODER_SCAN_RESULT_LOST_SYNC;
+
+ n = gst_adapter_masked_scan_uint32 (adapter, 0xffffff00, 0x00000100,
+ SYNC_CODE_SIZE, avail - SYNC_CODE_SIZE);
+ if (n == -1)
+ return GST_BASE_VIDEO_DECODER_SCAN_RESULT_NEED_DATA;
+
+ *size = n;
+ }
+
+ GST_DEBUG ("NAL size: %d", *size);
+
+ return GST_BASE_VIDEO_DECODER_SCAN_RESULT_OK;
+}
+
+static GstFlowReturn
+gst_vdp_h264_dec_parse_data (GstBaseVideoDecoder * base_video_decoder,
+ GstBuffer * buf, gboolean at_eos)
+{
+ GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+ GstBitReader reader;
+ GstNalUnit nal_unit;
+ guint8 forbidden_zero_bit;
+
+ guint8 *data;
+ guint size;
+ gint i;
+
+ GstVideoFrame *frame;
+
+ GST_MEMDUMP ("data", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+
+ gst_bit_reader_init_from_buffer (&reader, buf);
+
+ /* skip nal_length or sync code */
+ gst_bit_reader_skip (&reader, h264_dec->nal_length_size * 8);
+
+ if (!gst_bit_reader_get_bits_uint8 (&reader, &forbidden_zero_bit, 1))
+ goto invalid_packet;
+ if (forbidden_zero_bit != 0) {
+ GST_WARNING ("forbidden_zero_bit != 0");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!gst_bit_reader_get_bits_uint16 (&reader, &nal_unit.ref_idc, 2))
+ goto invalid_packet;
+ GST_DEBUG ("nal_ref_idc: %u", nal_unit.ref_idc);
+
+ /* read nal_unit_type */
+ if (!gst_bit_reader_get_bits_uint16 (&reader, &nal_unit.type, 5))
+ goto invalid_packet;
+
+ GST_DEBUG ("nal_unit_type: %u", nal_unit.type);
+ if (nal_unit.type == 14 || nal_unit.type == 20) {
+ if (!gst_bit_reader_skip (&reader, 24))
+ goto invalid_packet;
+ }
+
+ data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
+ size = gst_bit_reader_get_remaining (&reader) / 8;
+
+ i = size - 1;
+ while (size >= 0 && data[i] == 0x00) {
+ size--;
+ i--;
+ }
+
+ frame = gst_base_video_decoder_get_current_frame (base_video_decoder);
+
+ /* does this mark the beginning of a new access unit */
+ if (nal_unit.type == GST_NAL_AU_DELIMITER)
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+
+ if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VDP_H264_FRAME_GOT_PRIMARY)) {
+ if (nal_unit.type == GST_NAL_SPS || nal_unit.type == GST_NAL_PPS ||
+ nal_unit.type == GST_NAL_SEI ||
+ (nal_unit.type >= 14 && nal_unit.type <= 18))
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+ }
+
+ if (nal_unit.type >= GST_NAL_SLICE && nal_unit.type <= GST_NAL_SLICE_IDR) {
+ GstH264Slice slice;
+
+ if (!gst_h264_parser_parse_slice_header (h264_dec->parser, &slice, data,
+ size, nal_unit))
+ goto invalid_packet;
+
+ if (slice.redundant_pic_cnt == 0) {
+ if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VDP_H264_FRAME_GOT_PRIMARY)) {
+ GstH264Slice *p_slice;
+ guint8 pic_order_cnt_type, p_pic_order_cnt_type;
+
+ p_slice = &(GST_VDP_H264_FRAME_CAST (frame)->slice_hdr);
+ pic_order_cnt_type = slice.picture->sequence->pic_order_cnt_type;
+ p_pic_order_cnt_type = p_slice->picture->sequence->pic_order_cnt_type;
+
+ if (slice.frame_num != p_slice->frame_num)
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+
+ else if (slice.picture != p_slice->picture)
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+
+ else if (slice.bottom_field_flag != p_slice->bottom_field_flag)
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+
+ else if (nal_unit.ref_idc != p_slice->nal_unit.ref_idc &&
+ (nal_unit.ref_idc == 0 || p_slice->nal_unit.ref_idc == 0))
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+
+ else if ((pic_order_cnt_type == 0 && p_pic_order_cnt_type == 0) &&
+ (slice.pic_order_cnt_lsb != p_slice->pic_order_cnt_lsb ||
+ slice.delta_pic_order_cnt_bottom !=
+ p_slice->delta_pic_order_cnt_bottom))
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+
+ else if ((p_pic_order_cnt_type == 1 && p_pic_order_cnt_type == 1) &&
+ (slice.delta_pic_order_cnt[0] != p_slice->delta_pic_order_cnt[0] ||
+ slice.delta_pic_order_cnt[1] !=
+ p_slice->delta_pic_order_cnt[1]))
+ gst_base_video_decoder_have_frame (base_video_decoder, &frame);
+ }
+
+ if (!GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VDP_H264_FRAME_GOT_PRIMARY)) {
+ if (GST_H264_IS_I_SLICE (slice.type)
+ || GST_H264_IS_SI_SLICE (slice.type))
+ GST_VIDEO_FRAME_FLAG_SET (frame, GST_VIDEO_FRAME_FLAG_KEYFRAME);
+
+ GST_VDP_H264_FRAME_CAST (frame)->slice_hdr = slice;
+ GST_VIDEO_FRAME_FLAG_SET (frame, GST_VDP_H264_FRAME_GOT_PRIMARY);
+ }
+ }
+ gst_vdp_h264_frame_add_slice ((GstVdpH264Frame *) frame, buf);
+ }
+
+ if (nal_unit.type == GST_NAL_SPS) {
+ if (!gst_h264_parser_parse_sequence (h264_dec->parser, data, size))
+ goto invalid_packet;
+ }
+
+ if (nal_unit.type == GST_NAL_PPS) {
+ if (!gst_h264_parser_parse_picture (h264_dec->parser, data, size))
+ goto invalid_packet;
+ }
+
+ if (nal_unit.type == GST_NAL_SEI) {
+ GstH264Sequence *seq;
+ GstH264SEIMessage sei;
+
+ if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VDP_H264_FRAME_GOT_PRIMARY))
+ seq = GST_VDP_H264_FRAME_CAST (frame)->slice_hdr.picture->sequence;
+ else
+ seq = NULL;
+
+ if (!gst_h264_parser_parse_sei_message (h264_dec->parser, seq, &sei, data,
+ size))
+ goto invalid_packet;
+ }
+
+ gst_buffer_unref (buf);
+ return GST_FLOW_OK;
+
+invalid_packet:
+ GST_WARNING ("Invalid packet size!");
+ gst_buffer_unref (buf);
+
+ return GST_FLOW_OK;
+}
+
+static GstVideoFrame *
+gst_vdp_h264_dec_create_frame (GstBaseVideoDecoder * base_video_decoder)
+{
+ return GST_VIDEO_FRAME_CAST (gst_vdp_h264_frame_new ());
+}
+
+static GstPad *
+gst_vdp_h264_dec_create_srcpad (GstBaseVideoDecoder * base_video_decoder,
+ GstBaseVideoDecoderClass * base_video_decoder_class)
+{
+ GstPadTemplate *pad_template;
+ GstVdpVideoSrcPad *vdp_pad;
+
+ pad_template = gst_element_class_get_pad_template
+ (GST_ELEMENT_CLASS (base_video_decoder_class),
+ GST_BASE_VIDEO_DECODER_SRC_NAME);
+
+ vdp_pad = gst_vdp_video_src_pad_new (pad_template,
+ GST_BASE_VIDEO_DECODER_SRC_NAME);
+
+ return GST_PAD (vdp_pad);
+}
+
+static gboolean
+gst_vdp_h264_dec_flush (GstBaseVideoDecoder * base_video_decoder)
+{
+ return TRUE;
+}
+
+static gboolean
+gst_vdp_h264_dec_start (GstBaseVideoDecoder * base_video_decoder)
+{
+ GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+
+ h264_dec->packetized = FALSE;
+ h264_dec->nal_length_size = SYNC_CODE_SIZE;
+ h264_dec->parser = g_object_new (GST_TYPE_H264_PARSER, NULL);
+
+ return TRUE;
+}
+
+static gboolean
+gst_vdp_h264_dec_stop (GstBaseVideoDecoder * base_video_decoder)
+{
+ GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+
+ g_object_unref (h264_dec->parser);
+
+ return TRUE;
+}
+
+static void
+gst_vdp_h264_dec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ GstCaps *src_caps;
+ GstPadTemplate *src_template;
+
+ gst_element_class_set_details_simple (element_class,
+ "VDPAU H264 Decoder",
+ "Decoder",
+ "Decode h264 stream with vdpau",
+ "Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sink_template));
+
+ src_caps = gst_vdp_video_buffer_get_caps (TRUE, VDP_CHROMA_TYPE_420);
+ src_template = gst_pad_template_new (GST_BASE_VIDEO_DECODER_SRC_NAME,
+ GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
+
+ gst_element_class_add_pad_template (element_class, src_template);
+}
+
+static void
+gst_vdp_h264_dec_init (GstVdpH264Dec * h264_dec, GstVdpH264DecClass * klass)
+{
+}
+
+static void
+gst_vdp_h264_dec_finalize (GObject * object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_vdp_h264_dec_class_init (GstVdpH264DecClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstBaseVideoDecoderClass *base_video_decoder_class =
+ GST_BASE_VIDEO_DECODER_CLASS (klass);
+
+ gobject_class->finalize = gst_vdp_h264_dec_finalize;
+
+ base_video_decoder_class->start = gst_vdp_h264_dec_start;
+ base_video_decoder_class->stop = gst_vdp_h264_dec_stop;
+ base_video_decoder_class->flush = gst_vdp_h264_dec_flush;
+
+ base_video_decoder_class->create_srcpad = gst_vdp_h264_dec_create_srcpad;
+ base_video_decoder_class->set_sink_caps = gst_vdp_h264_dec_set_sink_caps;
+
+ base_video_decoder_class->scan_for_sync = gst_vdp_h264_dec_scan_for_sync;
+ base_video_decoder_class->scan_for_packet_end =
+ gst_vdp_h264_dec_scan_for_packet_end;
+ base_video_decoder_class->parse_data = gst_vdp_h264_dec_parse_data;
+
+ base_video_decoder_class->handle_frame = gst_vdp_h264_dec_handle_frame;
+ base_video_decoder_class->create_frame = gst_vdp_h264_dec_create_frame;
+
+ base_video_decoder_class->shape_output = gst_vdp_h264_dec_shape_output;
+}
diff --git a/sys/vdpau/h264/gstvdph264dec.h b/sys/vdpau/h264/gstvdph264dec.h
new file mode 100644
index 000000000..6f48156eb
--- /dev/null
+++ b/sys/vdpau/h264/gstvdph264dec.h
@@ -0,0 +1,61 @@
+/* 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_VDP_H264_DEC_H__
+#define __GST_VDP_H264_DEC_H__
+
+#include <gst/gst.h>
+
+#include "../basevideodecoder/gstbasevideodecoder.h"
+
+#include "gsth264parser.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VDP_H264_DEC (gst_vdp_h264_dec_get_type())
+#define GST_VDP_H264_DEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VDP_H264_DEC,GstVdpH264Dec))
+#define GST_VDP_H264_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VDP_H264_DEC,GstVdpH264DecClass))
+#define GST_VDP_H264_DEC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_VDP_H264_DEC,GstVdpH264DecClass))
+#define GST_IS_VDP_H264_DEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VDP_H264_DEC))
+#define GST_IS_VDP_H264_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VDP_H264_DEC))
+#define GST_VDP_H264_DEC_CAST(obj) ((GstVdpH264Dec *)(obj))
+
+typedef struct _GstVdpH264Dec GstVdpH264Dec;
+typedef struct _GstVdpH264DecClass GstVdpH264DecClass;
+
+
+struct _GstVdpH264Dec {
+ GstBaseVideoDecoder base_video_decoder;
+
+ GstBuffer *codec_data;
+ gboolean packetized;
+ guint8 nal_length_size;
+ GstH264Parser *parser;
+};
+
+struct _GstVdpH264DecClass {
+ GstBaseVideoDecoderClass base_video_decoder_class;
+};
+
+GType gst_vdp_h264_dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_VDP_H264_DEC_H__ */ \ No newline at end of file
diff --git a/sys/vdpau/h264/gstvdph264frame.c b/sys/vdpau/h264/gstvdph264frame.c
new file mode 100644
index 000000000..a8e6241bf
--- /dev/null
+++ b/sys/vdpau/h264/gstvdph264frame.c
@@ -0,0 +1,104 @@
+/*
+* 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., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstvdph264frame.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vdp_h264_frame_debug);
+#define GST_CAT_DEFAULT gst_vdp_h264_frame_debug
+
+#define DEBUG_INIT(bla) \
+GST_DEBUG_CATEGORY_INIT (gst_vdp_h264_frame_debug, "gstvdph264frame", 0, "Video Frame");
+
+void
+gst_vdp_h264_frame_add_slice (GstVdpH264Frame * h264_frame, GstBuffer * buf)
+{
+ gst_buffer_ref (buf);
+ g_ptr_array_add (h264_frame->slices, buf);
+}
+
+GstVdpH264Frame *
+gst_vdp_h264_frame_new (void)
+{
+ GstVdpH264Frame *frame;
+
+ frame = (GstVdpH264Frame *) gst_mini_object_new (GST_TYPE_VDP_H264_FRAME);
+
+ return frame;
+}
+
+static GObjectClass *gst_vdp_h264_frame_parent_class;
+
+static void
+gst_vdp_h264_frame_finalize (GstVdpH264Frame * h264_frame)
+{
+ g_ptr_array_unref (h264_frame->slices);
+
+ GST_MINI_OBJECT_CLASS (gst_vdp_h264_frame_parent_class)->finalize
+ (GST_MINI_OBJECT (h264_frame));
+}
+
+static void
+gst_vdp_h264_frame_init (GstVdpH264Frame * h264_frame, gpointer g_class)
+{
+ h264_frame->slices = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) gst_buffer_unref);
+}
+
+static void
+gst_vdp_h264_frame_class_init (gpointer g_class, gpointer class_data)
+{
+ GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+
+ gst_vdp_h264_frame_parent_class = g_type_class_peek_parent (g_class);
+
+ mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
+ gst_vdp_h264_frame_finalize;
+}
+
+
+GType
+gst_vdp_h264_frame_get_type (void)
+{
+ static GType _gst_vdp_h264_frame_type = 0;
+
+ if (G_UNLIKELY (_gst_vdp_h264_frame_type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (GstVdpH264FrameClass),
+ NULL,
+ NULL,
+ gst_vdp_h264_frame_class_init,
+ NULL,
+ NULL,
+ sizeof (GstVdpH264Frame),
+ 0,
+ (GInstanceInitFunc) gst_vdp_h264_frame_init,
+ NULL
+ };
+ _gst_vdp_h264_frame_type = g_type_register_static (GST_TYPE_VIDEO_FRAME,
+ "GstVdpH264Frame", &info, 0);
+
+ DEBUG_INIT ();
+ }
+ return _gst_vdp_h264_frame_type;
+}
diff --git a/sys/vdpau/h264/gstvdph264frame.h b/sys/vdpau/h264/gstvdph264frame.h
new file mode 100644
index 000000000..0409dddd9
--- /dev/null
+++ b/sys/vdpau/h264/gstvdph264frame.h
@@ -0,0 +1,60 @@
+/*
+* 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., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _GST_VDP_H264_FRAME_H_
+#define _GST_VDP_H264_FRAME_H_
+
+#include <gst/gst.h>
+
+#include "../basevideodecoder/gstvideoframe.h"
+
+#include "gsth264parser.h"
+
+#define GST_TYPE_VDP_H264_FRAME (gst_vdp_h264_frame_get_type())
+#define GST_IS_VDP_H264_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VDP_H264_FRAME))
+#define GST_VDP_H264_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VDP_H264_FRAME, GstVdpH264Frame))
+#define GST_VDP_H264_FRAME_CAST(obj) ((GstVdpH264Frame *)obj)
+
+#define GST_VDP_H264_FRAME_GOT_PRIMARY GST_VIDEO_FRAME_FLAG_LAST
+
+typedef struct _GstVdpH264Frame GstVdpH264Frame;
+typedef struct _GstVdpH264FrameClass GstVdpH264FrameClass;
+
+struct _GstVdpH264Frame
+{
+ GstVideoFrame video_frame;
+
+ GstH264Slice slice_hdr;
+
+ GPtrArray *slices;
+};
+
+struct _GstVdpH264FrameClass
+{
+ GstVideoFrameClass video_frame_class;
+};
+
+void gst_vdp_h264_frame_add_slice (GstVdpH264Frame *h264_frame, GstBuffer *buf);
+
+GstVdpH264Frame *gst_vdp_h264_frame_new (void);
+
+GType gst_vdp_h264_frame_get_type (void);
+
+#endif \ No newline at end of file