From c1deab84e618c18c23f0ba2827c337e136b3bb33 Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Wed, 26 Sep 2012 18:46:36 +0200 Subject: [PATCH] codecparsers: h264: parse MVC syntax elements. https://bugzilla.gnome.org/show_bug.cgi?id=685215 Signed-off-by: Gwenole Beauchesne --- gst-libs/gst/codecparsers/gsth264parser.c | 133 +++++++++++++++++++--- gst-libs/gst/codecparsers/gsth264parser.h | 57 ++++++++++ 2 files changed, 177 insertions(+), 13 deletions(-) diff --git a/gst-libs/gst/codecparsers/gsth264parser.c b/gst-libs/gst/codecparsers/gsth264parser.c index 66317459c9..5cafa1c3fa 100644 --- a/gst-libs/gst/codecparsers/gsth264parser.c +++ b/gst-libs/gst/codecparsers/gsth264parser.c @@ -204,6 +204,8 @@ static gboolean gst_h264_parse_nalu_header (GstH264NalUnit * nalu) { guint8 *data = nalu->data + nalu->offset; + guint8 svc_extension_flag; + GstBitReader br; if (nalu->size < 1) return FALSE; @@ -211,6 +213,37 @@ gst_h264_parse_nalu_header (GstH264NalUnit * nalu) nalu->type = (data[0] & 0x1f); nalu->ref_idc = (data[0] & 0x60) >> 5; nalu->idr_pic_flag = (nalu->type == 5 ? 1 : 0); + nalu->header_bytes = 1; + + switch (nalu->type) { + case GST_H264_NAL_PREFIX_UNIT: + case GST_H264_NAL_SLICE_EXT: + if (nalu->size < 4) + return FALSE; + gst_bit_reader_init (&br, nalu->data + nalu->offset + nalu->header_bytes, + nalu->size - nalu->header_bytes); + + svc_extension_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (!svc_extension_flag) { /* MVC */ + GstH264NalUnitExtensionMVC *const mvc = &nalu->extension.mvc; + + nalu->extension_type = GST_H264_NAL_EXTENSION_MVC; + mvc->non_idr_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + mvc->priority_id = gst_bit_reader_get_bits_uint8_unchecked (&br, 6); + mvc->view_id = gst_bit_reader_get_bits_uint16_unchecked (&br, 10); + mvc->temporal_id = gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + mvc->anchor_pic_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + mvc->inter_view_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* Update IdrPicFlag (H.7.4.1.1) */ + nalu->idr_pic_flag = !mvc->non_idr_flag; + } + nalu->header_bytes += 3; + break; + default: + nalu->extension_type = GST_H264_NAL_EXTENSION_NONE; + break; + } GST_DEBUG ("Nal type %u, ref_idc %u", nalu->type, nalu->ref_idc); return TRUE; @@ -497,7 +530,7 @@ error: static gboolean slice_parse_ref_pic_list_modification_1 (GstH264SliceHdr * slice, - NalReader * nr, guint list) + NalReader * nr, guint list, gboolean is_mvc) { GstH264RefPicListModification *entries; guint8 *ref_pic_list_modification_flag, *n_ref_pic_list_modification; @@ -526,7 +559,11 @@ slice_parse_ref_pic_list_modification_1 (GstH264SliceHdr * slice, slice->max_pic_num - 1); } else if (modification_of_pic_nums_idc == 2) { READ_UE (nr, entries[i].value.long_term_pic_num); - } + } else if (is_mvc && (modification_of_pic_nums_idc == 4 || + modification_of_pic_nums_idc == 5)) { + READ_UE (nr, entries[i].value.abs_diff_view_idx_minus1); + } else + continue; entries[i++].modification_of_pic_nums_idc = modification_of_pic_nums_idc; } } @@ -540,15 +577,16 @@ error: } static gboolean -slice_parse_ref_pic_list_modification (GstH264SliceHdr * slice, NalReader * nr) +slice_parse_ref_pic_list_modification (GstH264SliceHdr * slice, NalReader * nr, + gboolean is_mvc) { if (!GST_H264_IS_I_SLICE (slice) && !GST_H264_IS_SI_SLICE (slice)) { - if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 0)) + if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 0, is_mvc)) return FALSE; } if (GST_H264_IS_B_SLICE (slice)) { - if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 1)) + if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 1, is_mvc)) return FALSE; } return TRUE; @@ -1288,9 +1326,11 @@ gst_h264_parse_sps_data (NalReader * nr, GstH264SPS * sps, READ_UINT8 (nr, sps->constraint_set1_flag, 1); READ_UINT8 (nr, sps->constraint_set2_flag, 1); READ_UINT8 (nr, sps->constraint_set3_flag, 1); + READ_UINT8 (nr, sps->constraint_set4_flag, 1); + READ_UINT8 (nr, sps->constraint_set5_flag, 1); - /* skip reserved_zero_4bits */ - if (!nal_reader_skip (nr, 4)) + /* skip reserved_zero_2bits */ + if (!nal_reader_skip (nr, 2)) goto error; READ_UINT8 (nr, sps->level_idc, 8); @@ -1300,7 +1340,8 @@ gst_h264_parse_sps_data (NalReader * nr, GstH264SPS * sps, if (sps->profile_idc == 100 || sps->profile_idc == 110 || sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc == 44 || sps->profile_idc == 83 || - sps->profile_idc == 86) { + sps->profile_idc == 86 || sps->profile_idc == 118 || + sps->profile_idc == 128) { READ_UE_ALLOWED (nr, sps->chroma_format_idc, 0, 3); if (sps->chroma_format_idc == 3) READ_UINT8 (nr, sps->separate_colour_plane_flag, 1); @@ -1449,7 +1490,8 @@ gst_h264_parse_sps (GstH264NalUnit * nalu, GstH264SPS * sps, INITIALIZE_DEBUG_CATEGORY; GST_DEBUG ("parsing SPS"); - nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes, + nalu->size - nalu->header_bytes); if (!gst_h264_parse_sps_data (&nr, sps, parse_vui_params)) goto error; @@ -1464,6 +1506,67 @@ error: return GST_H264_PARSER_ERROR; } +/** + * gst_h264_parser_parse_subset_sps: + * @nalparser: a #GstH264NalParser + * @nalu: The #GST_H264_NAL_SUBSET_SPS #GstH264NalUnit to parse + * @sps: The #GstH264SPS to fill. + * @parse_vui_params: Whether to parse the vui_params or not + * + * Parses @data, and fills in the @sps structure. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_parse_subset_sps (GstH264NalParser * nalparser, + GstH264NalUnit * nalu, GstH264SPS * sps, gboolean parse_vui_params) +{ + GstH264ParserResult res; + + res = gst_h264_parse_subset_sps (nalu, sps, parse_vui_params); + if (res == GST_H264_PARSER_OK) { + GST_DEBUG ("adding sequence parameter set with id: %d to array", sps->id); + + nalparser->sps[sps->id] = *sps; + nalparser->last_sps = &nalparser->sps[sps->id]; + } + return res; +} + +/** + * gst_h264_parse_subset_sps: + * @nalu: The #GST_H264_NAL_SUBSET_SPS #GstH264NalUnit to parse + * @sps: The #GstH264SPS to fill. + * @parse_vui_params: Whether to parse the vui_params or not + * + * Parses @data, and fills in the @sps structure. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parse_subset_sps (GstH264NalUnit * nalu, GstH264SPS * sps, + gboolean parse_vui_params) +{ + NalReader nr; + + INITIALIZE_DEBUG_CATEGORY; + GST_DEBUG ("parsing Subset SPS"); + + nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes, + nalu->size - nalu->header_bytes); + + if (!gst_h264_parse_sps_data (&nr, sps, parse_vui_params)) + goto error; + + sps->valid = TRUE; + return GST_H264_PARSER_OK; + +error: + GST_WARNING ("error parsing \"Subset sequence parameter set\""); + sps->valid = FALSE; + return GST_H264_PARSER_ERROR; +} + /** * gst_h264_parse_pps: * @nalparser: a #GstH264NalParser @@ -1491,7 +1594,8 @@ gst_h264_parse_pps (GstH264NalParser * nalparser, GstH264NalUnit * nalu, INITIALIZE_DEBUG_CATEGORY; GST_DEBUG ("parsing PPS"); - nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes, + nalu->size - nalu->header_bytes); READ_UE_ALLOWED (&nr, pps->id, 0, GST_H264_MAX_PPS_COUNT - 1); READ_UE_ALLOWED (&nr, sps_id, 0, GST_H264_MAX_SPS_COUNT - 1); @@ -1676,7 +1780,8 @@ gst_h264_parser_parse_slice_hdr (GstH264NalParser * nalparser, } - nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes, + nalu->size - nalu->header_bytes); READ_UE (&nr, slice->first_mb_in_slice); READ_UE (&nr, slice->type); @@ -1768,7 +1873,8 @@ gst_h264_parser_parse_slice_hdr (GstH264NalParser * nalparser, } } - if (!slice_parse_ref_pic_list_modification (slice, &nr)) + if (!slice_parse_ref_pic_list_modification (slice, &nr, + GST_H264_IS_MVC_NALU (nalu))) goto error; if ((pps->weighted_pred_flag && (GST_H264_IS_P_SLICE (slice) @@ -1846,7 +1952,8 @@ gst_h264_parser_parse_sei (GstH264NalParser * nalparser, GstH264NalUnit * nalu, GstH264ParserResult res; GST_DEBUG ("parsing SEI nal"); - nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes, + nalu->size - nalu->header_bytes); *messages = g_array_new (FALSE, FALSE, sizeof (GstH264SEIMessage)); do { diff --git a/gst-libs/gst/codecparsers/gsth264parser.h b/gst-libs/gst/codecparsers/gsth264parser.h index 27e8214550..a78f3075c8 100644 --- a/gst-libs/gst/codecparsers/gsth264parser.h +++ b/gst-libs/gst/codecparsers/gsth264parser.h @@ -48,6 +48,9 @@ G_BEGIN_DECLS #define GST_H264_IS_SP_SLICE(slice) (((slice)->type % 5) == GST_H264_SP_SLICE) #define GST_H264_IS_SI_SLICE(slice) (((slice)->type % 5) == GST_H264_SI_SLICE) +#define GST_H264_IS_MVC_NALU(nalu) \ + ((nalu)->extension_type == GST_H264_NAL_EXTENSION_MVC) + /** * GstH264Profile: * @GST_H264_PROFILE_BASELINE: Baseline profile (A.2.1) @@ -131,6 +134,19 @@ typedef enum GST_H264_NAL_SLICE_EXT = 20 } GstH264NalUnitType; +/** + * GstH264NalUnitExtensionType: + * @GST_H264_NAL_EXTENSION_NONE: No NAL unit header extension is available + * @GST_H264_NAL_EXTENSION_MVC: NAL unit header extension for MVC (Annex H) + * + * Indicates the type of H.264 NAL unit extension. + */ +typedef enum +{ + GST_H264_NAL_EXTENSION_NONE = 0, + GST_H264_NAL_EXTENSION_MVC, +} GstH264NalUnitExtensionType; + /** * GstH264ParserResult: * @GST_H264_PARSER_OK: The parsing succeded @@ -221,6 +237,7 @@ typedef enum typedef struct _GstH264NalParser GstH264NalParser; typedef struct _GstH264NalUnit GstH264NalUnit; +typedef struct _GstH264NalUnitExtensionMVC GstH264NalUnitExtensionMVC; typedef struct _GstH264SPS GstH264SPS; typedef struct _GstH264PPS GstH264PPS; @@ -239,6 +256,29 @@ typedef struct _GstH264BufferingPeriod GstH264BufferingPeriod; typedef struct _GstH264RecoveryPoint GstH264RecoveryPoint; typedef struct _GstH264SEIMessage GstH264SEIMessage; +/** + * GstH264NalUnitExtensionMVC: + * @non_idr_flag: If equal to 0, it specifies that the current access + * unit is an IDR access unit + * @priority_id: The priority identifier for the NAL unit + * @view_id: The view identifier for the NAL unit + * @temporal_id: The temporal identifier for the NAL unit + * @anchor_pic_flag: If equal to 1, it specifies that the current + * access unit is an anchor access unit + * @inter_view_flag: If equal to 0, it specifies that the current view + * component is not used for inter-view prediction by any other view + * component in the current access unit + */ +struct _GstH264NalUnitExtensionMVC +{ + guint8 non_idr_flag; + guint8 priority_id; + guint16 view_id; + guint8 temporal_id; + guint8 anchor_pic_flag; + guint8 inter_view_flag; +}; + /** * GstH264NalUnit: * @ref_idc: not equal to 0 specifies that the content of the NAL unit @@ -257,6 +297,7 @@ typedef struct _GstH264SEIMessage GstH264SEIMessage; * @valid: If the nal unit is valid, which means it has * already been parsed * @data: The data from which the Nalu has been parsed + * @header_bytes: The size of the NALU header in bytes * * Structure defining the Nal unit headers */ @@ -273,6 +314,12 @@ struct _GstH264NalUnit gboolean valid; guint8 *data; + + guint8 header_bytes; + guint8 extension_type; + union { + GstH264NalUnitExtensionMVC mvc; + } extension; }; /** @@ -439,6 +486,8 @@ struct _GstH264SPS guint8 constraint_set1_flag; guint8 constraint_set2_flag; guint8 constraint_set3_flag; + guint8 constraint_set4_flag; + guint8 constraint_set5_flag; guint8 level_idc; guint8 chroma_format_idc; @@ -556,6 +605,8 @@ struct _GstH264RefPicListModification guint32 abs_diff_pic_num_minus1; /* if modification_of_pic_nums_idc == 2 */ guint32 long_term_pic_num; + /* if modification_of_pic_nums_idc == 4 || 5 */ + guint32 abs_diff_view_idx_minus1; } value; }; @@ -768,6 +819,9 @@ GstH264ParserResult gst_h264_parser_parse_slice_hdr (GstH264NalParser *nalpars GstH264SliceHdr *slice, gboolean parse_pred_weight_table, gboolean parse_dec_ref_pic_marking); +GstH264ParserResult gst_h264_parser_parse_subset_sps (GstH264NalParser *nalparser, GstH264NalUnit *nalu, + GstH264SPS *sps, gboolean parse_vui_params); + GstH264ParserResult gst_h264_parser_parse_sps (GstH264NalParser *nalparser, GstH264NalUnit *nalu, GstH264SPS *sps, gboolean parse_vui_params); @@ -779,6 +833,9 @@ GstH264ParserResult gst_h264_parser_parse_sei (GstH264NalParser *nalpars void gst_h264_nal_parser_free (GstH264NalParser *nalparser); +GstH264ParserResult gst_h264_parse_subset_sps (GstH264NalUnit *nalu, + GstH264SPS *sps, gboolean parse_vui_params); + GstH264ParserResult gst_h264_parse_sps (GstH264NalUnit *nalu, GstH264SPS *sps, gboolean parse_vui_params);