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:
parent
0aacc1a6a9
commit
4545d199c3
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user