pbutils: Add function for parsing H.264 extradata

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1265>
This commit is contained in:
Ludvig Rappe 2021-08-25 17:01:19 +02:00 committed by GStreamer Marge Bot
parent 3823f94311
commit 4a1d8eac31
3 changed files with 101 additions and 0 deletions

View file

@ -818,6 +818,58 @@ gst_codec_utils_h264_caps_set_level_and_profile (GstCaps * caps,
return (level != NULL && profile != NULL); return (level != NULL && profile != NULL);
} }
/**
* gst_codec_utils_h264_get_profile_flags_level:
* @codec_data: H264 AVCC extradata
* @len: lenth of @codec_data
* @profile: return location for h264 profile_idc or %NULL
* @flags: return location for h264 constraint set flags or %NULL
* @level: return location h264 level_idc or %NULL
*
* Parses profile, flags, and level from a H264 AVCC extradata/sequence_header.
* These are most commonly retrieved from a video/x-h264 caps with a codec_data
* buffer.
* The format of H264 AVCC extradata/sequence_header is documented in the
* ITU-T H.264 specification section 7.3.2.1.1 as well as in ISO/IEC 14496-15
* section 5.3.3.1.2.
*
* Returns: %TRUE on success, %FALSE on failure
*
* Since: 1.20
*/
gboolean
gst_codec_utils_h264_get_profile_flags_level (const guint8 * codec_data,
guint len, guint8 * profile, guint8 * flags, guint8 * level)
{
gboolean ret = FALSE;
g_return_val_if_fail (codec_data != NULL, FALSE);
if (len < 7) {
GST_WARNING ("avc codec data is too small");
goto done;
}
if (codec_data[0] != 1) {
GST_WARNING ("failed to parse avc codec version, must be 1");
goto done;
}
if (profile) {
*profile = codec_data[1];
}
if (flags) {
*flags = codec_data[2];
}
if (level) {
*level = codec_data[3];
}
ret = TRUE;
done:
return ret;
}
/* forked from gsth265parse.c */ /* forked from gsth265parse.c */
typedef struct typedef struct
{ {

View file

@ -68,6 +68,13 @@ gboolean gst_codec_utils_h264_caps_set_level_and_profile (GstCaps * ca
const guint8 * sps, const guint8 * sps,
guint len); guint len);
GST_PBUTILS_API
gboolean gst_codec_utils_h264_get_profile_flags_level (const guint8 * codecs_data,
guint len,
guint8 * profile,
guint8 * flags,
guint8 * level);
/* H.265 */ /* H.265 */
GST_PBUTILS_API GST_PBUTILS_API

View file

@ -994,6 +994,47 @@ GST_START_TEST (test_pb_utils_h264_profiles)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_pb_utils_h264_get_profile_flags_level)
{
gboolean ret = FALSE;
guint codec_data_len = 7;
guint8 codec_data[] = { 0x01, 0x64, 0x00, 0x32, 0x00, 0x00, 0x00 };
guint8 codec_data_bad_version[] =
{ 0x00, 0x64, 0x00, 0x32, 0x00, 0x00, 0x00 };
guint8 profile;
guint8 flags;
guint8 level;
/* happy path */
ret =
gst_codec_utils_h264_get_profile_flags_level (codec_data, codec_data_len,
&profile, &flags, &level);
fail_unless (ret == TRUE);
fail_unless (profile == 0x64);
fail_unless (flags == 0x00);
fail_unless (level == 0x32);
/* happy path, return locations null */
ret =
gst_codec_utils_h264_get_profile_flags_level (codec_data, codec_data_len,
NULL, NULL, NULL);
fail_unless (ret == TRUE);
/* data too short */
ret =
gst_codec_utils_h264_get_profile_flags_level (codec_data, 6, &profile,
&flags, &level);
fail_unless (ret == FALSE);
/* wrong codec version */
ret =
gst_codec_utils_h264_get_profile_flags_level (codec_data_bad_version,
codec_data_len, &profile, &flags, &level);
fail_unless (ret == FALSE);
}
GST_END_TEST;
#define PROFILE_TIER_LEVEL_LEN 11 #define PROFILE_TIER_LEVEL_LEN 11
static void static void
@ -1318,6 +1359,7 @@ libgstpbutils_suite (void)
tcase_add_test (tc_chain, test_pb_utils_versions); tcase_add_test (tc_chain, test_pb_utils_versions);
tcase_add_test (tc_chain, test_pb_utils_aac_get_profile); tcase_add_test (tc_chain, test_pb_utils_aac_get_profile);
tcase_add_test (tc_chain, test_pb_utils_h264_profiles); tcase_add_test (tc_chain, test_pb_utils_h264_profiles);
tcase_add_test (tc_chain, test_pb_utils_h264_get_profile_flags_level);
tcase_add_test (tc_chain, test_pb_utils_h265_profiles); tcase_add_test (tc_chain, test_pb_utils_h265_profiles);
return s; return s;
} }