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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8359>
This commit is contained in:
Carlos Bentzen 2025-01-24 11:17:50 +01:00 committed by GStreamer Marge Bot
parent 0aacc1a6a9
commit 4545d199c3
3 changed files with 611 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}