From 686d2d230325465119c51a2ac451849ef290e37b Mon Sep 17 00:00:00 2001 From: Carl-Anton Ingmarsson Date: Thu, 10 Jun 2010 12:13:50 +0200 Subject: [PATCH] vdpau: add beginning of h264 decoder --- sys/vdpau/Makefile.am | 2 + sys/vdpau/basevideodecoder/gstvideoframe.h | 7 +- sys/vdpau/h264/gsth264parser.c | 1184 ++++++++++++++++++++ sys/vdpau/h264/gsth264parser.h | 411 +++++++ sys/vdpau/h264/gstnalreader.c | 503 +++++++++ sys/vdpau/h264/gstnalreader.h | 99 ++ sys/vdpau/h264/gstvdph264dec.c | 533 +++++++++ sys/vdpau/h264/gstvdph264dec.h | 61 + sys/vdpau/h264/gstvdph264frame.c | 104 ++ sys/vdpau/h264/gstvdph264frame.h | 60 + 10 files changed, 2961 insertions(+), 3 deletions(-) create mode 100644 sys/vdpau/h264/gsth264parser.c create mode 100644 sys/vdpau/h264/gsth264parser.h create mode 100644 sys/vdpau/h264/gstnalreader.c create mode 100644 sys/vdpau/h264/gstnalreader.h create mode 100644 sys/vdpau/h264/gstvdph264dec.c create mode 100644 sys/vdpau/h264/gstvdph264dec.h create mode 100644 sys/vdpau/h264/gstvdph264frame.c create mode 100644 sys/vdpau/h264/gstvdph264frame.h diff --git a/sys/vdpau/Makefile.am b/sys/vdpau/Makefile.am index 10e552c2f0..79a58b64fd 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 fa6e87dc72..8c9e12c65e 100644 --- a/sys/vdpau/basevideodecoder/gstvideoframe.h +++ b/sys/vdpau/basevideodecoder/gstvideoframe.h @@ -23,9 +23,10 @@ #include -#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 0000000000..f082107897 --- /dev/null +++ b/sys/vdpau/h264/gsth264parser.c @@ -0,0 +1,1184 @@ +/* GStreamer + * + * Copyright (C) 2009 Carl-Anton Ingmarsson . + * + * 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 +#include + +#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 0000000000..868c0e878e --- /dev/null +++ b/sys/vdpau/h264/gsth264parser.h @@ -0,0 +1,411 @@ +/* GStreamer + * + * Copyright (C) 2009 Carl-Anton Ingmarsson . + * + * 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 + +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 0000000000..ca78d3a7f1 --- /dev/null +++ b/sys/vdpau/h264/gstnalreader.c @@ -0,0 +1,503 @@ +/* GStreamer + * + * Copyright (C) 2009 Carl-Anton Ingmarsson . + * + * 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 0000000000..62dcfd62a4 --- /dev/null +++ b/sys/vdpau/h264/gstnalreader.h @@ -0,0 +1,99 @@ +/* GStreamer + * + * Copyright (C) 2009 Carl-Anton Ingmarsson . + * + * 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 + +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 0000000000..2ba637322e --- /dev/null +++ b/sys/vdpau/h264/gstvdph264dec.c @@ -0,0 +1,533 @@ +/* GStreamer +* +* Copyright (C) 2009 Carl-Anton Ingmarsson . +* +* 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 +#include +#include + +#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 "); + + 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 0000000000..6f48156eb3 --- /dev/null +++ b/sys/vdpau/h264/gstvdph264dec.h @@ -0,0 +1,61 @@ +/* GStreamer + * + * Copyright (C) 2009 Carl-Anton Ingmarsson . + * + * 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 + +#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 0000000000..a8e6241bff --- /dev/null +++ b/sys/vdpau/h264/gstvdph264frame.c @@ -0,0 +1,104 @@ +/* +* GStreamer +* Copyright (C) 2009 Carl-Anton Ingmarsson +* +* 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 0000000000..0409dddd97 --- /dev/null +++ b/sys/vdpau/h264/gstvdph264frame.h @@ -0,0 +1,60 @@ +/* +* GStreamer +* Copyright (C) 2009 Carl-Anton Ingmarsson +* +* 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 + +#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