From 5227b3c9a65147ff45398e96769611f2cb732cce Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Fri, 15 Jul 2022 00:13:45 +0900 Subject: [PATCH] h265parser: Add an API for HEVCDecoderConfigurationRecord parsing Add a method for HEVC configuration data parsing Part-of: --- .../gst-libs/gst/codecparsers/gsth265parser.c | 291 +++++++++++++++++ .../gst-libs/gst/codecparsers/gsth265parser.h | 308 ++++++++++++++++++ .../tests/check/libs/h265parser.c | 79 +++++ 3 files changed, 678 insertions(+) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c index f81ea3c29a..5f8a393b7f 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.c @@ -4741,3 +4741,294 @@ gst_h265_get_profile_from_sps (GstH265SPS * sps) /* first profile of the synthetic ptl */ return gst_h265_profile_tier_level_get_profile (&tmp_ptl); } + +/* *INDENT-OFF* */ +static void +gst_clear_h265_decoder_config_record_nalu_array ( + GstH265DecoderConfigRecordNalUnitArray * array) +{ + if (!array) + return; + + if (array->nalu) + g_array_unref (array->nalu); +} +/* *INDENT-ON* */ + +/** + * gst_h265_decoder_config_record_free: + * @config: (nullable): a #GstH265DecoderConfigRecord data + * + * Free @config data + * + * Since: 1.24 + */ +void +gst_h265_decoder_config_record_free (GstH265DecoderConfigRecord * config) +{ + if (!config) + return; + + if (config->nalu_array) + g_array_unref (config->nalu_array); + + g_free (config); +} + +static GstH265DecoderConfigRecord * +gst_h265_decoder_config_record_new (void) +{ + GstH265DecoderConfigRecord *config; + + config = g_new0 (GstH265DecoderConfigRecord, 1); + config->nalu_array = g_array_new (FALSE, + FALSE, sizeof (GstH265DecoderConfigRecordNalUnitArray)); + g_array_set_clear_func (config->nalu_array, + (GDestroyNotify) gst_clear_h265_decoder_config_record_nalu_array); + + return config; +} + +/** + * gst_h265_parser_parse_decoder_config_record: + * @parser: a #GstH265Parser + * @data: the data to parse + * @size: the size of @data + * @config: (out): parsed #GstH265DecoderConfigRecord data + * + * Parses HEVCDecoderConfigurationRecord data and fill into @config. + * The caller must free @config via gst_h265_decoder_config_record_free() + * + * This method does not parse VPS, SPS and PPS and therefore the caller needs to + * parse each NAL unit via appropriate parsing method. + * + * Returns: a #GstH265ParserResult + * + * Since: 1.24 + */ +GstH265ParserResult +gst_h265_parser_parse_decoder_config_record (GstH265Parser * parser, + const guint8 * data, gsize size, GstH265DecoderConfigRecord ** config) +{ + GstH265DecoderConfigRecord *ret; + GstBitReader br; + GstH265ParserResult result = GST_H265_PARSER_OK; + guint i; + guint8 num_of_arrays; + + g_return_val_if_fail (parser != NULL, GST_H265_PARSER_ERROR); + g_return_val_if_fail (data != NULL, GST_H265_PARSER_ERROR); + g_return_val_if_fail (config != NULL, GST_H265_PARSER_ERROR); + +#define READ_CONFIG_UINT8(val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint8 (&br, (guint8 *) &val, nbits)) { \ + GST_WARNING ("Failed to read " G_STRINGIFY (val)); \ + result = GST_H265_PARSER_ERROR; \ + goto error; \ + } \ +} G_STMT_END; + +#define READ_CONFIG_UINT16(val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint16 (&br, &val, nbits)) { \ + GST_WARNING ("Failed to read " G_STRINGIFY (val)); \ + result = GST_H265_PARSER_ERROR; \ + goto error; \ + } \ +} G_STMT_END; + +#define SKIP_CONFIG_BITS(nbits) G_STMT_START { \ + if (!gst_bit_reader_skip (&br, nbits)) { \ + GST_WARNING ("Failed to skip %d bits", nbits); \ + result = GST_H265_PARSER_ERROR; \ + goto error; \ + } \ +} G_STMT_END; + + *config = NULL; + + if (size < 23) { + GST_WARNING ("Too small size hvcC"); + return GST_H265_PARSER_ERROR; + } + + gst_bit_reader_init (&br, data, size); + + ret = gst_h265_decoder_config_record_new (); + + READ_CONFIG_UINT8 (ret->configuration_version, 8); + if (ret->configuration_version != 1) { + GST_WARNING ("Wrong configurationVersion %d", ret->configuration_version); + /* Must be 1 but allows 0 for backward compatibility. + * See commit + * https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/63fee31a3f95021fa0bb2429c723f5356c9b3c4b */ + if (ret->configuration_version != 0) { + result = GST_H265_PARSER_ERROR; + goto error; + } + } + + READ_CONFIG_UINT8 (ret->general_profile_space, 2); + READ_CONFIG_UINT8 (ret->general_tier_flag, 1); + READ_CONFIG_UINT8 (ret->general_profile_idc, 5); + + for (i = 0; i < 32; i++) + READ_CONFIG_UINT8 (ret->general_profile_compatibility_flags[i], 1); + + /* 7.3.3 Profile, tier and level syntax */ + READ_CONFIG_UINT8 (ret->general_progressive_source_flag, 1); + READ_CONFIG_UINT8 (ret->general_interlaced_source_flag, 1); + READ_CONFIG_UINT8 (ret->general_non_packed_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_frame_only_constraint_flag, 1); + + if (ret->general_profile_idc == 4 || + ret->general_profile_compatibility_flags[4] || + ret->general_profile_idc == 5 || + ret->general_profile_compatibility_flags[5] || + ret->general_profile_idc == 6 || + ret->general_profile_compatibility_flags[6] || + ret->general_profile_idc == 7 || + ret->general_profile_compatibility_flags[7] || + ret->general_profile_idc == 8 || + ret->general_profile_compatibility_flags[8] || + ret->general_profile_idc == 9 || + ret->general_profile_compatibility_flags[9] || + ret->general_profile_idc == 10 || + ret->general_profile_compatibility_flags[10] || + ret->general_profile_idc == 11 || + ret->general_profile_compatibility_flags[11]) { + READ_CONFIG_UINT8 (ret->general_max_12bit_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_max_10bit_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_max_8bit_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_max_422chroma_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_max_420chroma_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_max_monochrome_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_intra_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_one_picture_only_constraint_flag, 1); + READ_CONFIG_UINT8 (ret->general_lower_bit_rate_constraint_flag, 1); + + if (ret->general_profile_idc == 5 || + ret->general_profile_compatibility_flags[5] || + ret->general_profile_idc == 9 || + ret->general_profile_compatibility_flags[9] || + ret->general_profile_idc == 10 || + ret->general_profile_compatibility_flags[10] || + ret->general_profile_idc == 11 || + ret->general_profile_compatibility_flags[11]) { + READ_CONFIG_UINT8 (ret->general_max_14bit_constraint_flag, 1); + SKIP_CONFIG_BITS (33); + } else { + SKIP_CONFIG_BITS (34); + } + } else if (ret->general_profile_idc == 2 || + ret->general_profile_compatibility_flags[2]) { + SKIP_CONFIG_BITS (7); + READ_CONFIG_UINT8 (ret->general_one_picture_only_constraint_flag, 1); + + SKIP_CONFIG_BITS (35); + } else { + SKIP_CONFIG_BITS (43); + } + + if (ret->general_profile_idc == 1 || + ret->general_profile_compatibility_flags[1] || + ret->general_profile_idc == 2 || + ret->general_profile_compatibility_flags[2] || + ret->general_profile_idc == 3 || + ret->general_profile_compatibility_flags[3] || + ret->general_profile_idc == 4 || + ret->general_profile_compatibility_flags[4] || + ret->general_profile_idc == 5 || + ret->general_profile_compatibility_flags[5] || + ret->general_profile_idc == 9 || + ret->general_profile_compatibility_flags[9] || + ret->general_profile_idc == 11 || + ret->general_profile_compatibility_flags[11]) { + READ_CONFIG_UINT8 (ret->general_inbld_flag, 1); + } else { + SKIP_CONFIG_BITS (1); + } + + g_assert (gst_bit_reader_get_pos (&br) == 12 * 8); + + READ_CONFIG_UINT8 (ret->general_level_idc, 8); + + SKIP_CONFIG_BITS (4); + READ_CONFIG_UINT16 (ret->min_spatial_segmentation_idc, 12); + + SKIP_CONFIG_BITS (6); + READ_CONFIG_UINT8 (ret->parallelism_type, 2); + + SKIP_CONFIG_BITS (6); + READ_CONFIG_UINT8 (ret->chroma_format_idc, 2); + + SKIP_CONFIG_BITS (5); + READ_CONFIG_UINT8 (ret->bit_depth_luma_minus8, 3); + + SKIP_CONFIG_BITS (5); + READ_CONFIG_UINT8 (ret->bit_depth_chroma_minus8, 3); + + READ_CONFIG_UINT16 (ret->avg_frame_rate, 16); + + READ_CONFIG_UINT8 (ret->constant_frame_rate, 2); + READ_CONFIG_UINT8 (ret->num_temporal_layers, 3); + READ_CONFIG_UINT8 (ret->temporal_id_nested, 1); + READ_CONFIG_UINT8 (ret->length_size_minus_one, 2); + if (ret->length_size_minus_one == 2) { + /* "length_size_minus_one + 1" should be 1, 2, or 4 */ + GST_WARNING ("Wrong nal-length-size"); + result = GST_H265_PARSER_ERROR; + goto error; + } + + READ_CONFIG_UINT8 (num_of_arrays, 8); + + g_assert (gst_bit_reader_get_pos (&br) == 23 * 8); + for (i = 0; i < num_of_arrays; i++) { + GstH265DecoderConfigRecordNalUnitArray array; + GstH265NalUnit nalu; + guint16 num_nalu, j; + guint offset; + + READ_CONFIG_UINT8 (array.array_completeness, 1); + SKIP_CONFIG_BITS (1); + READ_CONFIG_UINT8 (array.nal_unit_type, 6); + + READ_CONFIG_UINT16 (num_nalu, 16); + + offset = gst_bit_reader_get_pos (&br) / 8; + array.nalu = g_array_sized_new (FALSE, FALSE, sizeof (GstH265NalUnit), + num_nalu); + for (j = 0; j < num_nalu; j++) { + result = gst_h265_parser_identify_nalu_hevc (parser, data, offset, size, + 2, &nalu); + if (result != GST_H265_PARSER_OK) { + g_array_unref (array.nalu); + goto error; + } + + g_array_append_val (array.nalu, nalu); + offset = nalu.offset + nalu.size; + } + + g_array_append_val (ret->nalu_array, array); + + if (i != num_of_arrays - 1 && !gst_bit_reader_set_pos (&br, offset * 8)) { + GST_WARNING ("Not enough byte for NAL reading"); + result = GST_H265_PARSER_ERROR; + goto error; + } + } + + *config = ret; + return GST_H265_PARSER_OK; + +error: + { + gst_h265_decoder_config_record_free (ret); + return result; + } + +#undef READ_CONFIG_UINT8 +#undef READ_CONFIG_UINT16 +#undef SKIP_CONFIG_BITS +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.h index 679d70c6df..ff01c23711 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth265parser.h @@ -452,6 +452,8 @@ typedef struct _GstH265TimeCode GstH265TimeCode; typedef struct _GstH265MasteringDisplayColourVolume GstH265MasteringDisplayColourVolume; typedef struct _GstH265ContentLightLevel GstH265ContentLightLevel; typedef struct _GstH265SEIMessage GstH265SEIMessage; +typedef struct _GstH265DecoderConfigRecordNalUnitArray GstH265DecoderConfigRecordNalUnitArray; +typedef struct _GstH265DecoderConfigRecord GstH265DecoderConfigRecord; /** * GstH265NalUnit: @@ -1656,6 +1658,303 @@ struct _GstH265SEIMessage } payload; }; +/** + * GstH265DecoderConfigRecordNalUnitArray: + * + * Contains NAL Unit array data as defined in ISO/IEC 14496-15 + * + * Since: 1.24 + */ +struct _GstH265DecoderConfigRecordNalUnitArray +{ + /** + * GstH265DecoderConfigRecordNalUnitArray.array_completeness: + * + * 1: all NAL units of the given type are in this array and none + * are in the stream. + * 0: additional NAL units of the indicated type may be in the stream + */ + guint8 array_completeness; + + /** + * GstH265DecoderConfigRecordNalUnitArray.nal_unit_type: + * + * Indicates the type of the NAL units in the following array. + * Shall be VPS, SPS, PPS, prefix SEI or suffix SEI + */ + GstH265NalUnitType nal_unit_type; + + /** + * GstH265DecoderConfigRecordNalUnitArray.nalu: + * + * Array of identified #GstH265NalUnit + */ + GArray *nalu; +}; + +/** + * GstH265DecoderConfigRecord: + * + * Contains HEVCDecoderConfigurationRecord data as defined in ISO/IEC 14496-15 + * + * Since: 1.24 + */ +struct _GstH265DecoderConfigRecord +{ + /** + * GstH265DecoderConfigRecord.configuration_version: + * + * Indicates configurationVersion, must be 1 + */ + guint8 configuration_version; + + /** + * GstH265DecoderConfigRecord.general_profile_space: + * + * general profile space + */ + guint8 general_profile_space; + + /** + * GstH265DecoderConfigRecord.general_tier_flag: + * + * general tier flag + */ + guint8 general_tier_flag; + + /** + * GstH265DecoderConfigRecord.general_profile_idc: + * + * general profile indiction + */ + guint8 general_profile_idc; + + /** + * GstH265DecoderConfigRecord.general_profile_compatibility_flags: + * + * general profile compatibility flags + */ + guint8 general_profile_compatibility_flags[32]; + + /** + * GstH265DecoderConfigRecord.general_progressive_source_flag: + * + * general_progressive_source_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_progressive_source_flag; + + /** + * GstH265DecoderConfigRecord.general_interlaced_source_flag: + * + * general_interlaced_source_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_interlaced_source_flag; + + /** + * GstH265DecoderConfigRecord.general_non_packed_constraint_flag: + * + * general_non_packed_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_non_packed_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_frame_only_constraint_flag: + * + * general_frame_only_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_frame_only_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_max_12bit_constraint_flag: + * + * general_max_12bit_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_max_12bit_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_max_10bit_constraint_flag: + * + * general_max_10bit_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_max_10bit_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_max_8bit_constraint_flag: + * + * general_max_8bit_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_max_8bit_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_max_422chroma_constraint_flag: + * + * general_max_422chroma_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_max_422chroma_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_max_420chroma_constraint_flag: + * + * general_max_420chroma_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_max_420chroma_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_max_monochrome_constraint_flag: + * + * general_max_monochrome_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_max_monochrome_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_intra_constraint_flag: + * + * general_intra_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_intra_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_one_picture_only_constraint_flag: + * + * general_one_picture_only_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_one_picture_only_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_lower_bit_rate_constraint_flag: + * + * general_lower_bit_rate_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_lower_bit_rate_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_max_14bit_constraint_flag: + * + * general_max_14bit_constraint_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_max_14bit_constraint_flag; + + /** + * GstH265DecoderConfigRecord.general_inbld_flag: + * + * general_inbld_flag parsed from + * HEVCDecoderConfigurationRecord.general_constraint_indicator_flags + */ + guint8 general_inbld_flag; + + /** + * GstH265DecoderConfigRecord.general_level_idc: + * + * general level indication + */ + guint8 general_level_idc; + + /** + * GstH265DecoderConfigRecord.min_spatial_segmentation_idc: + * + * min spatial segmentation indication + */ + guint16 min_spatial_segmentation_idc; + + /** + * GstH265DecoderConfigRecord.parallelism_type: + * + * parallelism type + */ + guint8 parallelism_type; + + /** + * GstH265DecoderConfigRecord.chroma_format_idc: + * + * chroma format indication + */ + guint8 chroma_format_idc; + + /** + * GstH265DecoderConfigRecord.bit_depth_luma_minus8: + * + * bit depth luma minus 8 + */ + guint8 bit_depth_luma_minus8; + + /** + * GstH265DecoderConfigRecord.bit_depth_chroma_minus8: + * + * bit depth chroma minus 8 + */ + guint8 bit_depth_chroma_minus8; + + /** + * GstH265DecoderConfigRecord.avg_frame_rate: + * + * average frame rate in units of frames per 256 seconds, + * or 0 when unspecified + */ + guint16 avg_frame_rate; + + /** + * GstH265DecoderConfigRecord.constant_frame_rate: + * + * constant frame rate. + * 1: stream to which this configuration record applies is constante frame rate + * 2: representation of each temporal layer in the stream is constant frame rate + * 0: unspecified + */ + guint8 constant_frame_rate; + + /** + * GstH265DecoderConfigRecord.num_temporal_layers: + * + * 0: unknown whether the stream is temporally scalable + * otherwise: the number of temporal layers + */ + guint8 num_temporal_layers; + + /** + * GstH265DecoderConfigRecord.temporal_id_nested: + * + * 1: all SPSs that activated when the stream to this configuration record + * applies is decoded have sps_temporal_id_nesting_flags equal to 1 + * and temporal sub-layer up-switching to any higher temporal layer can + * be performed at any semple + * 0: unknown + */ + guint8 temporal_id_nested; + + /** + * GstH265DecoderConfigRecord.length_size_minus_one: + * + * indicates the length in bytes of nal unit length field. + * This value shall be one of 0, 1, or 3 corresponding to a length + * encoded with 1, 2, or 4 bytes, respectively + */ + guint8 length_size_minus_one; + + /** + * GstH265DecoderConfigRecord.nalu_array: + * + * Array of #GstH265DecoderConfigRecordNalUnitArray + */ + GArray *nalu_array; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + /** * GstH265Parser: * @@ -1865,5 +2164,14 @@ GstBuffer * gst_h265_parser_insert_sei_hevc (GstH265Parser * parser, GST_CODEC_PARSERS_API GstH265Profile gst_h265_get_profile_from_sps (GstH265SPS * sps); +GST_CODEC_PARSERS_API +void gst_h265_decoder_config_record_free (GstH265DecoderConfigRecord * config); + +GST_CODEC_PARSERS_API +GstH265ParserResult gst_h265_parser_parse_decoder_config_record (GstH265Parser * parser, + const guint8 * data, + gsize size, + GstH265DecoderConfigRecord ** config); + G_END_DECLS #endif diff --git a/subprojects/gst-plugins-bad/tests/check/libs/h265parser.c b/subprojects/gst-plugins-bad/tests/check/libs/h265parser.c index 8065030604..f7dd95e452 100644 --- a/subprojects/gst-plugins-bad/tests/check/libs/h265parser.c +++ b/subprojects/gst-plugins-bad/tests/check/libs/h265parser.c @@ -1372,6 +1372,84 @@ GST_START_TEST (test_h265_split_hevc) GST_END_TEST; +/* Captured from Apple's HLS test stream + * http://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/v14/prog_index.m3u8 + */ +static const guint8 h265_codec_data[] = { + 0x01, 0x02, 0x00, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7b, 0xf0, 0x00, 0xfc, 0xfd, 0xfa, 0xfa, 0x00, 0x00, 0x0f, 0x03, 0xa0, + 0x00, 0x01, 0x00, 0x18, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x02, 0x20, + 0x00, 0x00, 0x03, 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, + 0x7b, 0x18, 0xb0, 0x24, 0xa1, 0x00, 0x01, 0x00, 0x3c, 0x42, 0x01, 0x01, + 0x02, 0x20, 0x00, 0x00, 0x03, 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x03, 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 0x88, 0x7d, 0xb6, 0x71, 0x8b, + 0x92, 0x44, 0x80, 0x53, 0x88, 0x88, 0x92, 0xcf, 0x24, 0xa6, 0x92, 0x72, + 0xc9, 0x12, 0x49, 0x22, 0xdc, 0x91, 0xaa, 0x48, 0xfc, 0xa2, 0x23, 0xff, + 0x00, 0x01, 0x00, 0x01, 0x6a, 0x02, 0x02, 0x02, 0x01, 0xa2, 0x00, 0x01, + 0x00, 0x08, 0x44, 0x01, 0xc0, 0x25, 0x2f, 0x05, 0x32, 0x40 +}; + +GST_START_TEST (test_h265_decoder_config_record) +{ + GstH265Parser *parser; + GstH265ParserResult ret; + GstH265DecoderConfigRecord *config = NULL; + GstH265VPS vps; + GstH265SPS sps; + GstH265PPS pps; + GstH265DecoderConfigRecordNalUnitArray *nalu_array; + GstH265NalUnit *nalu; + + parser = gst_h265_parser_new (); + + ret = gst_h265_parser_parse_decoder_config_record (parser, + h265_codec_data, sizeof (h265_codec_data), &config); + assert_equals_int (ret, GST_H265_PARSER_OK); + fail_unless (config != NULL); + + assert_equals_int (config->length_size_minus_one, 3); + fail_unless (config->nalu_array != NULL); + assert_equals_int (config->nalu_array->len, 3); + + /* VPS */ + nalu_array = &g_array_index (config->nalu_array, + GstH265DecoderConfigRecordNalUnitArray, 0); + fail_unless (nalu_array->nalu != NULL); + assert_equals_int (nalu_array->nalu->len, 1); + + nalu = &g_array_index (nalu_array->nalu, GstH265NalUnit, 0); + assert_equals_int (nalu->type, GST_H265_NAL_VPS); + ret = gst_h265_parser_parse_vps (parser, nalu, &vps); + assert_equals_int (ret, GST_H265_PARSER_OK); + + /* SPS */ + nalu_array = &g_array_index (config->nalu_array, + GstH265DecoderConfigRecordNalUnitArray, 1); + fail_unless (nalu_array->nalu != NULL); + assert_equals_int (nalu_array->nalu->len, 1); + + nalu = &g_array_index (nalu_array->nalu, GstH265NalUnit, 0); + assert_equals_int (nalu->type, GST_H265_NAL_SPS); + ret = gst_h265_parser_parse_sps (parser, nalu, &sps, TRUE); + assert_equals_int (ret, GST_H265_PARSER_OK); + + /* PPS */ + nalu_array = &g_array_index (config->nalu_array, + GstH265DecoderConfigRecordNalUnitArray, 2); + fail_unless (nalu_array->nalu != NULL); + assert_equals_int (nalu_array->nalu->len, 1); + + nalu = &g_array_index (nalu_array->nalu, GstH265NalUnit, 0); + assert_equals_int (nalu->type, GST_H265_NAL_PPS); + ret = gst_h265_parser_parse_pps (parser, nalu, &pps); + assert_equals_int (ret, GST_H265_PARSER_OK); + + gst_h265_decoder_config_record_free (config); + gst_h265_parser_free (parser); +} + +GST_END_TEST; + static Suite * h265parser_suite (void) { @@ -1395,6 +1473,7 @@ h265parser_suite (void) tcase_add_test (tc_chain, test_h265_sei_registered_user_data); tcase_add_test (tc_chain, test_h265_create_sei); tcase_add_test (tc_chain, test_h265_split_hevc); + tcase_add_test (tc_chain, test_h265_decoder_config_record); return s; }