From 4545d199c3d3b5318bbe47407d46aead5c9738f9 Mon Sep 17 00:00:00 2001 From: Carlos Bentzen Date: Fri, 24 Jan 2025 11:17:50 +0100 Subject: [PATCH] h266parser: add API to parse VVCDecoderConfigurationRecord VVCDecoderConfigurationRecord is present in ISOBMFF files carrying VVC/H.266 streams via the vvcC box, as defined in ISO/IEC 14496-15. Part-of: --- .../gst-libs/gst/codecparsers/gsth266parser.c | 242 ++++++++++++++++++ .../gst-libs/gst/codecparsers/gsth266parser.h | 178 +++++++++++++ .../tests/check/libs/h266parser.c | 191 ++++++++++++++ 3 files changed, 611 insertions(+) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.c index a881450ce7..9e6db55c1f 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.c @@ -5996,3 +5996,245 @@ gst_h266_profile_from_string (const gchar * string) return GST_H266_PROFILE_INVALID; } + +/** + * gst_h266_decoder_config_record_free: + * @config: (nullable): a #GstH266DecoderConfigRecord data + * + * Free @config data + * + * Since: 1.26 + */ +void +gst_h266_decoder_config_record_free (GstH266DecoderConfigRecord * config) +{ + if (!config) + return; + + if (config->nalu_array) + g_array_unref (config->nalu_array); + + g_free (config); +} + +static void + gst_clear_h266_decoder_config_record_nalu_array + (GstH266DecoderConfigRecordNalUnitArray * array) +{ + if (!array) + return; + + if (array->nalu) + g_array_unref (array->nalu); +} + +static GstH266DecoderConfigRecord * +gst_h266_decoder_config_record_new (void) +{ + GstH266DecoderConfigRecord *config; + + config = g_new0 (GstH266DecoderConfigRecord, 1); + config->nalu_array = g_array_new (FALSE, + FALSE, sizeof (GstH266DecoderConfigRecordNalUnitArray)); + g_array_set_clear_func (config->nalu_array, + (GDestroyNotify) gst_clear_h266_decoder_config_record_nalu_array); + + return config; +} + +#define READ_CONFIG_UINT8(br, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \ + GST_WARNING ("Failed to read " G_STRINGIFY (val)); \ + goto error; \ + } \ +} G_STMT_END; + +#define READ_CONFIG_UINT16(br, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint16 (br, &val, nbits)) { \ + GST_WARNING ("Failed to read " G_STRINGIFY (val)); \ + goto error; \ + } \ +} G_STMT_END; + +#define READ_CONFIG_UINT32(br, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint32 (br, &val, nbits)) { \ + GST_WARNING ("Failed to read " G_STRINGIFY (val)); \ + goto error; \ + } \ +} G_STMT_END; + +#define SKIP_CONFIG_BITS(br, nbits) G_STMT_START { \ + if (!gst_bit_reader_skip (br, nbits)) { \ + GST_WARNING ("Failed to skip %d bits", nbits); \ + goto error; \ + } \ +} G_STMT_END; + +static GstH266ParserResult +gst_h266_parser_parse_ptl_record (GstBitReader * br, GstH266PTLRecord * ptl, + guint8 num_sublayers) +{ + GstH266ParserResult result = GST_H266_PARSER_OK; + gint i; + + SKIP_CONFIG_BITS (br, 2); + READ_CONFIG_UINT8 (br, ptl->num_bytes_constraint_info, 6); + if (!ptl->num_bytes_constraint_info) + GST_WARNING + ("num_bytes_constraint_info is 0, but should be greater than 0"); + READ_CONFIG_UINT8 (br, ptl->general_profile_idc, 7); + READ_CONFIG_UINT8 (br, ptl->general_tier_flag, 1); + READ_CONFIG_UINT8 (br, ptl->general_level_idc, 8); + + READ_CONFIG_UINT8 (br, ptl->ptl_frame_only_constraint_flag, 1); + READ_CONFIG_UINT8 (br, ptl->ptl_multilayer_enabled_flag, 1); + + for (i = 0; i < ptl->num_bytes_constraint_info - 1; i++) + READ_CONFIG_UINT8 (br, ptl->general_constraint_info[i], 8); + READ_CONFIG_UINT8 (br, ptl->general_constraint_info[i], 6); + + for (i = num_sublayers - 2; i >= 0; i--) + READ_CONFIG_UINT8 (br, ptl->ptl_sublayer_level_present_flag[i], 1); + + if (num_sublayers > 1) + SKIP_CONFIG_BITS (br, 9 - num_sublayers); + + for (i = num_sublayers - 2; i >= 0; i--) + if (ptl->ptl_sublayer_level_present_flag[i]) + READ_CONFIG_UINT8 (br, ptl->sublayer_level_idc[i], 8); + + READ_CONFIG_UINT8 (br, ptl->ptl_num_sub_profiles, 8); + for (i = 0; i < ptl->ptl_num_sub_profiles; i++) + READ_CONFIG_UINT32 (br, ptl->general_sub_profile_idc[i], 32); + + return result; + +error: + GST_WARNING ("Failed to parse PTL record"); + result = GST_H266_PARSER_ERROR; + return result; +} + +/** + * gst_h266_parser_parse_decoder_config_record: + * @parser: a #GstH266Parser + * @data: the data to parse + * @size: the size of @data + * @config: (out): parsed #GstH266DecoderConfigRecord data + * + * Parses VVCDecoderConfigurationRecord data and fill into @config. + * The caller must free @config via gst_h266_decoder_config_record_free() + * + * This method does not parse APS, VPS, SPS and PPS and therefore the caller needs to + * parse each NAL unit via appropriate parsing method. + * + * Returns: a #GstH266ParserResult + * + * Since: 1.26 + */ +GstH266ParserResult +gst_h266_parser_parse_decoder_config_record (GstH266Parser * parser, + const guint8 * data, gsize size, GstH266DecoderConfigRecord ** config) +{ + GstH266DecoderConfigRecord *ret; + GstBitReader br; + GstH266ParserResult result = GST_H266_PARSER_OK; + guint i; + guint8 num_of_arrays; + + GST_LOG ("parsing \"Decoder configuration record\""); + + g_return_val_if_fail (parser != NULL, GST_H266_PARSER_ERROR); + g_return_val_if_fail (data != NULL, GST_H266_PARSER_ERROR); + g_return_val_if_fail (config != NULL, GST_H266_PARSER_ERROR); + + *config = NULL; + + if (size < 2) { + GST_WARNING ("Too small size vvcC"); + return GST_H266_PARSER_ERROR; + } + + gst_bit_reader_init (&br, data, size); + ret = gst_h266_decoder_config_record_new (); + + SKIP_CONFIG_BITS (&br, 5); + READ_CONFIG_UINT8 (&br, 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"); + } + READ_CONFIG_UINT8 (&br, ret->ptl_present_flag, 1); + + if (ret->ptl_present_flag) { + READ_CONFIG_UINT16 (&br, ret->ols_idx, 9); + READ_CONFIG_UINT8 (&br, ret->num_sublayers, 3); + READ_CONFIG_UINT8 (&br, ret->constant_frame_rate, 2); + READ_CONFIG_UINT8 (&br, ret->chroma_format_idc, 2); + + READ_CONFIG_UINT8 (&br, ret->bit_depth_minus8, 3); + SKIP_CONFIG_BITS (&br, 5); + + if (gst_h266_parser_parse_ptl_record (&br, &ret->native_ptl, + ret->num_sublayers) != GST_H266_PARSER_OK) + goto error; + + READ_CONFIG_UINT16 (&br, ret->max_picture_width, 16); + READ_CONFIG_UINT16 (&br, ret->max_picture_height, 16); + READ_CONFIG_UINT16 (&br, ret->avg_frame_rate, 16); + } + + READ_CONFIG_UINT8 (&br, num_of_arrays, 8); + for (i = 0; i < num_of_arrays; i++) { + GstH266DecoderConfigRecordNalUnitArray array; + guint8 nalu_type; + GstH266NalUnit nalu; + guint16 num_nalu = 1, j; + guint bit_offset, offset; + + READ_CONFIG_UINT8 (&br, array.array_completeness, 1); + SKIP_CONFIG_BITS (&br, 2); + READ_CONFIG_UINT8 (&br, nalu_type, 5); + array.nal_unit_type = nalu_type; + + if (nalu_type != GST_H266_NAL_DCI && nalu_type != GST_H266_NAL_OPI) + READ_CONFIG_UINT16 (&br, num_nalu, 16); + + bit_offset = gst_bit_reader_get_pos (&br); + g_assert (bit_offset % 8 == 0); + offset = bit_offset / 8; + array.nalu = g_array_sized_new (FALSE, FALSE, sizeof (GstH266NalUnit), + num_nalu); + for (j = 0; j < num_nalu; j++) { + result = gst_h266_parser_identify_nalu_vvc (parser, data, offset, size, + 2, &nalu); + if (result != GST_H266_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 bytes for NAL reading"); + goto error; + } + } + + *config = ret; + return GST_H266_PARSER_OK; + +error: + result = GST_H266_PARSER_ERROR; + gst_h266_decoder_config_record_free (ret); + return result; +} + +#undef READ_CONFIG_UINT8 +#undef READ_CONFIG_UINT16 +#undef READ_CONFIG_UINT32 +#undef SKIP_CONFIG_BITS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.h index 11bdb8009c..a53e0ea615 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth266parser.h @@ -451,6 +451,9 @@ typedef struct _GstH266ScalableNesting GstH266ScalableNesting; typedef struct _GstH266SubPicLevelInfo GstH266SubPicLevelInfo; typedef struct _GstH266FrameFieldInfo GstH266FrameFieldInfo; typedef struct _GstH266SEIMessage GstH266SEIMessage; +typedef struct _GstH266DecoderConfigRecordNalUnitArray GstH266DecoderConfigRecordNalUnitArray; +typedef struct _GstH266PTLRecord GstH266PTLRecord; +typedef struct _GstH266DecoderConfigRecord GstH266DecoderConfigRecord; /** * GstH266NalUnit: @@ -3246,6 +3249,172 @@ struct _GstH266SEIMessage } payload; }; +/** + * GstH266DecoderConfigRecordNalUnitArray: + * + * Contains NAL Unit array data as defined in ISO/IEC 14496-15 + * + * Since: 1.26 + */ +struct _GstH266DecoderConfigRecordNalUnitArray +{ + /** + * GstH266DecoderConfigRecordNalUnitArray.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; + + /** + * GstH266DecoderConfigRecordNalUnitArray.nal_unit_type: + * + * Indicates the type of the NAL units in the following array. + * Shall be VPS, SPS, PPS, prefix APS or suffix APS + */ + GstH266NalUnitType nal_unit_type; + + /** + * GstH266DecoderConfigRecordNalUnitArray.nalu: + * + * Array of identified #GstH266NalUnit + */ + GArray *nalu; +}; + +/** + * GstH266PTLRecord: + * + * Contains VvcPTLRecord data as defined in ISO/IEC 14496-15 + * + * @num_bytes_constraint_info: Number of bytes for constraint information. + * @general_profile_idc: General profile id. + * @general_tier_flag: General tier flag. + * @general_level_idc: General level id. + * @ptl_frame_only_constraint_flag: Frame-only constraint flag. + * @ptl_multilayer_enabled_flag: Multilayer enabled flag. + * @general_constraint_info: Array containing general constraint information. + * @ptl_sublayer_level_present_flag: Array indicating presence of sublayer level. + * @sublayer_level_idc: Array containing sublayer level ids. + * @ptl_num_sub_profiles: Number of sub-profiles. + * @general_sub_profile_idc: Array containing general sub-profile ids. + * + * Since: 1.26 + */ +struct _GstH266PTLRecord { + guint8 num_bytes_constraint_info; + guint8 general_profile_idc; + guint8 general_tier_flag; + guint8 general_level_idc; + guint8 ptl_frame_only_constraint_flag; + guint8 ptl_multilayer_enabled_flag; + guint8 general_constraint_info[63]; + guint8 ptl_sublayer_level_present_flag[7]; + guint8 sublayer_level_idc[7]; + guint8 ptl_num_sub_profiles; + guint32 general_sub_profile_idc[255]; +}; + +/** + * GstH266DecoderConfigRecord: + * + * Contains VVCDecoderConfigurationRecord data as defined in ISO/IEC 14496-15 + * + * Since: 1.26 + */ +struct _GstH266DecoderConfigRecord +{ + /** + * GstH266DecoderConfigRecord.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; + + /** + * GstH266DecoderConfigRecord.ptl_present_flag: + * + * true: profile, tier and level information is present + */ + guint8 ptl_present_flag; + + /** + * GstH266DecoderConfigRecord.ols_idx: + * + * Operating point layer set index + */ + guint16 ols_idx; + + /** + * GstH266DecoderConfigRecord.num_sublayers: + * + * Number of sublayers + */ + guint8 num_sublayers; + + /** + * GstH266DecoderConfigRecord.constant_frame_rate: + * + * Indicates if the frame rate is constant + */ + guint8 constant_frame_rate; + + /** + * GstH266DecoderConfigRecord.chroma_format_idc: + * + * Chroma format indicator + */ + guint8 chroma_format_idc; + + /** + * GstH266DecoderConfigRecord.bit_depth_minus8: + * + * Bit depth minus 8 + */ + guint8 bit_depth_minus8; + + /** + * GstH266DecoderConfigRecord.native_ptl: + * + * Profile, tier and level information + */ + GstH266PTLRecord native_ptl; + + /** + * GstH266DecoderConfigRecord.max_picture_width: + * + * Maximum picture width + */ + guint16 max_picture_width; + + /** + * GstH266DecoderConfigRecord.max_picture_height: + * + * Maximum picture height + */ + guint16 max_picture_height; + + /** + * GstH266DecoderConfigRecord.avg_frame_rate: + * + * Average frame rate + */ + guint16 avg_frame_rate; + + /** + * GstH266DecoderConfigRecord.nalu_array: + * + * Array of #GstH266DecoderConfigRecordNalUnitArray + */ + GArray *nalu_array; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + /** * GstH266Parser: * @@ -3365,4 +3534,13 @@ const gchar * gst_h266_profile_to_string (GstH266Profile profile); GST_CODEC_PARSERS_API GstH266Profile gst_h266_profile_from_string (const gchar * string); +GST_CODEC_PARSERS_API +void gst_h266_decoder_config_record_free (GstH266DecoderConfigRecord * config); + +GST_CODEC_PARSERS_API +GstH266ParserResult gst_h266_parser_parse_decoder_config_record (GstH266Parser * parser, + const guint8 * data, + gsize size, + GstH266DecoderConfigRecord ** config); + G_END_DECLS diff --git a/subprojects/gst-plugins-bad/tests/check/libs/h266parser.c b/subprojects/gst-plugins-bad/tests/check/libs/h266parser.c index 659aab7baa..59fe03da23 100644 --- a/subprojects/gst-plugins-bad/tests/check/libs/h266parser.c +++ b/subprojects/gst-plugins-bad/tests/check/libs/h266parser.c @@ -336,6 +336,195 @@ GST_START_TEST (test_h266_parse_slice_hdr) GST_END_TEST; +GST_START_TEST (test_h266_parse_decoder_config_record) +{ + GstH266Parser *parser; + GstH266ParserResult res; + GstH266DecoderConfigRecord *config; + GstH266DecoderConfigRecordNalUnitArray *nalu_array; + GstH266NalUnit *nalu; + + // vvcC data from standard ITU stream SPATSCAL_A_4.bit after muxing it as MP4 with FFmpeg 7.1: + // ffmpeg -i SPATSCAL_A_4.bit -c:v copy SPATSCAL_A_4.mp4 + static const guint8 vvcc_data[] = { + 0xFF, 0x00, 0x75, 0x5F, 0x01, 0x22, 0x66, 0xC0, 0x00, 0x00, 0x00, 0xB0, + 0x00, 0x90, 0x00, 0x00, 0x03, 0x8E, 0x00, 0x01, 0x00, 0x1C, 0x00, 0x71, + 0x10, 0xB4, 0x03, 0xC7, 0x23, 0x00, 0x00, 0x22, 0x66, 0xC0, 0x00, 0x00, + 0x41, 0x42, 0xA3, 0xC7, 0xC0, 0x58, 0x80, 0xC1, 0x58, 0x05, 0x24, 0x02, + 0x32, 0xB2, 0x8F, 0x00, 0x01, 0x00, 0x64, 0x00, 0x79, 0x01, 0x0D, 0x22, + 0x66, 0xC0, 0x00, 0x40, 0x2C, 0x40, 0x48, 0x8D, 0x40, 0x17, 0xC8, 0xB9, + 0x12, 0x91, 0x35, 0x91, 0x98, 0x4D, 0x95, 0x8C, 0x10, 0x20, 0x9E, 0x08, + 0x68, 0xB8, 0x88, 0x88, 0x89, 0x7C, 0x44, 0x44, 0xBA, 0x88, 0x88, 0x97, + 0x71, 0x11, 0x12, 0xE4, 0x88, 0x88, 0x97, 0x2C, 0x44, 0x44, 0xB9, 0xA2, + 0x22, 0x25, 0xCF, 0x11, 0x11, 0x5B, 0xF2, 0x7E, 0x5F, 0xF2, 0xFE, 0xA5, + 0xFD, 0xCB, 0xF9, 0x25, 0xFC, 0xB2, 0xFE, 0x69, 0x7F, 0x3C, 0xBF, 0x88, + 0x97, 0xD4, 0x44, 0xBE, 0xE2, 0x25, 0xF2, 0x44, 0x4B, 0xE5, 0x88, 0x97, + 0xCD, 0x11, 0x2F, 0x9E, 0x22, 0xE3, 0xFB, 0xEB, 0xB1, 0x88, 0x10, 0x90, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x81, 0x00, 0x00, 0x2C, 0x40, 0x48, 0x8A, + 0x42, 0x00, 0x97, 0xB2, 0x16, 0x59, 0x62, 0x00 + }; + + parser = gst_h266_parser_new (); + + res = gst_h266_parser_parse_decoder_config_record (parser, vvcc_data, + sizeof (vvcc_data), &config); + + assert_equals_int (res, GST_H266_PARSER_OK); + + assert_equals_int (config->length_size_minus_one, 3); + assert_equals_int (config->ptl_present_flag, 1); + assert_equals_int (config->ols_idx, 0); + assert_equals_int (config->num_sublayers, 7); + assert_equals_int (config->constant_frame_rate, 1); + assert_equals_int (config->chroma_format_idc, 1); + assert_equals_int (config->bit_depth_minus8, 2); + + assert_equals_int (config->native_ptl.num_bytes_constraint_info, 1); + assert_equals_int (config->native_ptl.general_profile_idc, + GST_H266_PROFILE_MULTILAYER_MAIN_10); + assert_equals_int (config->native_ptl.general_tier_flag, 0); + assert_equals_int (config->native_ptl.general_level_idc, GST_H266_LEVEL_L6_2); + assert_equals_int (config->native_ptl.ptl_frame_only_constraint_flag, 1); + assert_equals_int (config->native_ptl.ptl_multilayer_enabled_flag, 1); + assert_equals_int (config->native_ptl.general_constraint_info[0], 0); + + assert_equals_int (config->max_picture_width, 176); + assert_equals_int (config->max_picture_height, 144); + assert_equals_int (config->avg_frame_rate, 0); + + assert_equals_int (config->nalu_array->len, 3); + + nalu_array = + &g_array_index (config->nalu_array, + GstH266DecoderConfigRecordNalUnitArray, 0); + assert_equals_int (nalu_array->nal_unit_type, GST_H266_NAL_VPS); + assert_equals_int (nalu_array->nalu->len, 1); + nalu = &g_array_index (nalu_array->nalu, GstH266NalUnit, 0); + assert_equals_int (nalu->type, GST_H266_NAL_VPS); + assert_equals_int (nalu->size, 28); + + nalu_array = + &g_array_index (config->nalu_array, + GstH266DecoderConfigRecordNalUnitArray, 1); + assert_equals_int (nalu_array->nal_unit_type, GST_H266_NAL_SPS); + assert_equals_int (nalu_array->nalu->len, 1); + nalu = &g_array_index (nalu_array->nalu, GstH266NalUnit, 0); + assert_equals_int (nalu->type, GST_H266_NAL_SPS); + assert_equals_int (nalu->size, 100); + + nalu_array = + &g_array_index (config->nalu_array, + GstH266DecoderConfigRecordNalUnitArray, 2); + assert_equals_int (nalu_array->nal_unit_type, GST_H266_NAL_PPS); + assert_equals_int (nalu_array->nalu->len, 1); + nalu = &g_array_index (nalu_array->nalu, GstH266NalUnit, 0); + assert_equals_int (nalu->type, GST_H266_NAL_PPS); + assert_equals_int (nalu->size, 16); + + gst_h266_decoder_config_record_free (config); + gst_h266_parser_free (parser); +} + +GST_END_TEST; + +GST_START_TEST (test_h266_parse_decoder_config_record_gci) +{ + GstH266Parser *parser; + GstH266ParserResult res; + GstH266DecoderConfigRecord *config; + GstH266DecoderConfigRecordNalUnitArray *nalu_array; + GstH266NalUnit *nalu; + gint i; + + // vvcC data from standard ITU stream LMCS_C_1.bit after muxing it as MP4 with FFmpeg 7.1: + // ffmpeg -i LMCS_C_1.bit -c:v copy LMCS_C_1.mp4 + static const guint8 vvcc_data[] = { + 0xFF, 0x00, 0x65, 0x5F, 0x09, 0x02, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x04, 0x38, 0x00, 0x00, + 0x02, 0x8F, 0x00, 0x01, 0x01, 0x0E, 0x00, 0x79, 0x00, 0xAD, 0x02, 0x43, + 0xA0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x07, 0x81, 0x00, 0x21, 0xC8, 0xD4, + 0x00, 0xE6, 0xE8, 0x8D, 0xD1, 0x08, 0xD1, 0x0A, 0x4C, 0x8D, 0x83, 0x65, + 0x38, 0xF0, 0x80, 0x84, 0x8A, 0x20, 0x58, 0x40, 0x36, 0x53, 0x8F, 0x08, + 0x85, 0xC8, 0x9A, 0x14, 0x34, 0x3A, 0x41, 0x28, 0x28, 0x21, 0x10, 0x5A, + 0xE0, 0x02, 0x62, 0x02, 0x08, 0x42, 0x10, 0xB0, 0x84, 0x21, 0x62, 0x21, + 0x0B, 0x24, 0x21, 0x6A, 0x10, 0xBD, 0x1E, 0xAD, 0x49, 0x79, 0x24, 0xD4, + 0x96, 0x48, 0x8B, 0x51, 0x17, 0x88, 0x93, 0x51, 0x12, 0x29, 0x22, 0x24, + 0xC9, 0x11, 0x2E, 0xA4, 0x88, 0xB1, 0x10, 0x85, 0x92, 0x10, 0xB5, 0x08, + 0x5E, 0x10, 0x93, 0x50, 0x84, 0x8A, 0x48, 0x42, 0x4C, 0x90, 0x84, 0xBA, + 0x92, 0x10, 0x90, 0x91, 0x10, 0x84, 0x8A, 0x22, 0x10, 0x93, 0x11, 0x08, + 0x4B, 0xA8, 0x88, 0x42, 0x45, 0x19, 0x08, 0x49, 0x8C, 0x84, 0x25, 0xD4, + 0x64, 0x21, 0x40, 0x82, 0xC2, 0x10, 0x40, 0x62, 0x21, 0x03, 0x24, 0x41, + 0xA9, 0x00, 0x99, 0x82, 0x08, 0x42, 0xC2, 0x00, 0x41, 0x62, 0x01, 0x01, + 0x08, 0x10, 0x08, 0x0A, 0x84, 0x08, 0x04, 0x06, 0x90, 0x81, 0x00, 0x80, + 0xB1, 0x02, 0x01, 0x01, 0x10, 0x40, 0x20, 0x2C, 0x82, 0x01, 0x01, 0x21, + 0x00, 0x81, 0x90, 0x10, 0x11, 0x08, 0x08, 0x0B, 0x21, 0x01, 0x01, 0x22, + 0x02, 0x06, 0x81, 0x01, 0x24, 0x08, 0x1C, 0x10, 0x31, 0x00, 0x85, 0x90, + 0x20, 0x44, 0x20, 0x40, 0xB2, 0x10, 0x20, 0x48, 0x81, 0x06, 0x82, 0x04, + 0x90, 0x41, 0xC2, 0x0C, 0x81, 0x16, 0x84, 0x12, 0x42, 0x1C, 0x43, 0x42, + 0x5C, 0x8E, 0x54, 0x08, 0x2C, 0x20, 0x04, 0x16, 0x20, 0x10, 0x10, 0x81, + 0x00, 0x80, 0xA8, 0x40, 0x80, 0x40, 0xFF, 0xFF, 0xFA, 0xFE, 0x88, 0x10, + 0x90, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x81, 0x00, 0x00, 0x07, 0x81, 0x00, + 0x21, 0xC8, 0xA9, 0x00, 0xC7, 0xB0, 0x20, 0x00 + }; + + parser = gst_h266_parser_new (); + res = gst_h266_parser_parse_decoder_config_record (parser, vvcc_data, + sizeof (vvcc_data), &config); + + assert_equals_int (res, GST_H266_PARSER_OK); + + assert_equals_int (config->length_size_minus_one, 3); + assert_equals_int (config->ptl_present_flag, 1); + assert_equals_int (config->ols_idx, 0); + assert_equals_int (config->num_sublayers, 6); + assert_equals_int (config->constant_frame_rate, 1); + assert_equals_int (config->chroma_format_idc, 1); + assert_equals_int (config->bit_depth_minus8, 2); + + assert_equals_int (config->native_ptl.num_bytes_constraint_info, 9); + assert_equals_int (config->native_ptl.general_profile_idc, + GST_H266_PROFILE_MAIN_10); + assert_equals_int (config->native_ptl.general_tier_flag, 0); + assert_equals_int (config->native_ptl.general_level_idc, GST_H266_LEVEL_L4_1); + assert_equals_int (config->native_ptl.ptl_frame_only_constraint_flag, 1); + assert_equals_int (config->native_ptl.ptl_multilayer_enabled_flag, 0); + for (i = 0; i < 8; i++) + assert_equals_int (config->native_ptl.general_constraint_info[i], 0); + assert_equals_int (config->native_ptl.general_constraint_info[8], 4); + + assert_equals_int (config->max_picture_width, 1920); + assert_equals_int (config->max_picture_height, 1080); + assert_equals_int (config->avg_frame_rate, 0); + + assert_equals_int (config->nalu_array->len, 2); + + nalu_array = + &g_array_index (config->nalu_array, + GstH266DecoderConfigRecordNalUnitArray, 0); + assert_equals_int (nalu_array->nal_unit_type, GST_H266_NAL_SPS); + assert_equals_int (nalu_array->nalu->len, 1); + nalu = &g_array_index (nalu_array->nalu, GstH266NalUnit, 0); + assert_equals_int (nalu->type, GST_H266_NAL_SPS); + assert_equals_int (nalu->size, 270); + + nalu_array = + &g_array_index (config->nalu_array, + GstH266DecoderConfigRecordNalUnitArray, 1); + assert_equals_int (nalu_array->nal_unit_type, GST_H266_NAL_PPS); + assert_equals_int (nalu_array->nalu->len, 1); + nalu = &g_array_index (nalu_array->nalu, GstH266NalUnit, 0); + assert_equals_int (nalu->type, GST_H266_NAL_PPS); + assert_equals_int (nalu->size, 15); + + + gst_h266_decoder_config_record_free (config); + gst_h266_parser_free (parser); +} + +GST_END_TEST; + + static Suite * h266parser_suite (void) { @@ -349,6 +538,8 @@ h266parser_suite (void) tcase_add_test (tc_chain, test_h266_parse_sps); tcase_add_test (tc_chain, test_h266_parse_pps); tcase_add_test (tc_chain, test_h266_parse_slice_hdr); + tcase_add_test (tc_chain, test_h266_parse_decoder_config_record); + tcase_add_test (tc_chain, test_h266_parse_decoder_config_record_gci); return s; }