mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-29 21:21:12 +00:00
pbutils: Add function to parse RFC 6381 codecs field
This is the opposite of `gst_codec_utils_caps_get_mime_codec()`, which allows elements to get the `GstCaps` Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1894>
This commit is contained in:
parent
6fec258930
commit
bce779e66d
3 changed files with 266 additions and 2 deletions
|
@ -2556,3 +2556,243 @@ gst_codec_utils_caps_get_mime_codec (GstCaps * caps)
|
||||||
done:
|
done:
|
||||||
return mime_codec;
|
return mime_codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
gst_codec_utils_caps_from_mime_codec_single (const gchar * codec)
|
||||||
|
{
|
||||||
|
GstCaps *caps = NULL;
|
||||||
|
gchar **subcodec = NULL;
|
||||||
|
gchar *subcodec0;
|
||||||
|
guint32 codec_fourcc;
|
||||||
|
|
||||||
|
GST_DEBUG ("Analyzing codec '%s'", codec);
|
||||||
|
|
||||||
|
/* rfc 6381 3.3
|
||||||
|
*
|
||||||
|
* For the ISO Base Media File Format, and the QuickTime movie file
|
||||||
|
* format, the first element of a 'codecs' parameter value is a sample
|
||||||
|
* description entry four-character code as registered by the MP4
|
||||||
|
* Registration Authority [MP4RA].
|
||||||
|
*
|
||||||
|
* See Also : http://mp4ra.org/#/codecs
|
||||||
|
*/
|
||||||
|
if (strlen (codec) < 4) {
|
||||||
|
GST_WARNING ("Invalid codec (smaller than 4 characters) : '%s'", codec);
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
subcodec = g_strsplit (codec, ".", 0);
|
||||||
|
subcodec0 = subcodec[0];
|
||||||
|
|
||||||
|
if (subcodec0 == NULL)
|
||||||
|
goto beach;
|
||||||
|
|
||||||
|
/* Skip any leading spaces */
|
||||||
|
while (*subcodec0 == ' ')
|
||||||
|
subcodec0++;
|
||||||
|
|
||||||
|
if (strlen (subcodec0) < 4) {
|
||||||
|
GST_WARNING ("Invalid codec (smaller than 4 characters) : '%s'", subcodec0);
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_LOG ("subcodec[0] '%s'", subcodec0);
|
||||||
|
|
||||||
|
codec_fourcc = GST_READ_UINT32_LE (subcodec0);
|
||||||
|
switch (codec_fourcc) {
|
||||||
|
case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
|
||||||
|
case GST_MAKE_FOURCC ('a', 'v', 'c', '2'):
|
||||||
|
case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
|
||||||
|
case GST_MAKE_FOURCC ('a', 'v', 'c', '4'):
|
||||||
|
{
|
||||||
|
guint8 sps[3];
|
||||||
|
guint64 spsint64;
|
||||||
|
|
||||||
|
/* ISO 14496-15 Annex E : Sub-parameters for the MIME type “codecs”
|
||||||
|
* parameter */
|
||||||
|
caps = gst_caps_new_empty_simple ("video/x-h264");
|
||||||
|
|
||||||
|
if (subcodec[1]) {
|
||||||
|
/* The second element is the hexadecimal representation of the following
|
||||||
|
* three bytes in the (subset) sequence parameter set Network
|
||||||
|
* Abstraction Layer (NAL) unit specified in [AVC]:
|
||||||
|
* * profile_idc
|
||||||
|
* * constraint_set flags
|
||||||
|
* * level_idc
|
||||||
|
* */
|
||||||
|
spsint64 = g_ascii_strtoull (subcodec[1], NULL, 16);
|
||||||
|
sps[0] = spsint64 >> 16;
|
||||||
|
sps[1] = (spsint64 >> 8) & 0xff;
|
||||||
|
sps[2] = spsint64 & 0xff;
|
||||||
|
gst_codec_utils_h264_caps_set_level_and_profile (caps,
|
||||||
|
(const guint8 *) &sps, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
|
||||||
|
{
|
||||||
|
guint64 oti;
|
||||||
|
|
||||||
|
if (!subcodec[1])
|
||||||
|
break;
|
||||||
|
oti = g_ascii_strtoull (subcodec[1], NULL, 16);
|
||||||
|
/* For mp4a, mp4v and mp4s, the second element is the hexadecimal
|
||||||
|
* representation of the MP4 Registration Authority
|
||||||
|
* ObjectTypeIndication */
|
||||||
|
switch (oti) {
|
||||||
|
case 0x40:
|
||||||
|
{
|
||||||
|
guint64 audio_oti;
|
||||||
|
const gchar *profile = NULL;
|
||||||
|
|
||||||
|
/* MPEG-4 Audio (ISO/IEC 14496-3 */
|
||||||
|
caps =
|
||||||
|
gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!subcodec[2])
|
||||||
|
break;
|
||||||
|
/* If present, last element is the audio object type */
|
||||||
|
audio_oti = g_ascii_strtoull (subcodec[2], NULL, 16);
|
||||||
|
|
||||||
|
switch (audio_oti) {
|
||||||
|
case 1:
|
||||||
|
profile = "main";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
profile = "lc";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
profile = "ssr";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
profile = "ltp";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_WARNING ("Unhandled MPEG-4 Audio Object Type: 0x%"
|
||||||
|
G_GUINT64_FORMAT "x", audio_oti);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (profile)
|
||||||
|
gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
GST_WARNING ("Unknown ObjectTypeIndication 0x%" G_GUINT64_FORMAT "x",
|
||||||
|
oti);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
|
||||||
|
case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
|
||||||
|
{
|
||||||
|
/* ISO 14496-15 Annex E : Sub-parameters for the MIME type “codecs”
|
||||||
|
* parameter */
|
||||||
|
caps = gst_caps_new_empty_simple ("video/x-h265");
|
||||||
|
|
||||||
|
/* FIXME : Extract information from the following component */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Following are not defined in rfc 6831 but are registered MP4RA codecs */
|
||||||
|
case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
|
||||||
|
/* ETSI TS 102 366 v1.4.1 - Digital Audio Compression (AC-3, Enhanced AC-3) Standard, Annex F */
|
||||||
|
caps = gst_caps_new_empty_simple ("audio/x-ac3");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('e', 'c', '+', '3'):
|
||||||
|
GST_FIXME
|
||||||
|
("Signalling of ATMOS ('ec+3') isn't defined yet. Falling back to EAC3 caps");
|
||||||
|
/* withdrawn, unused, do not use (was enhanced AC-3 audio with JOC) */
|
||||||
|
case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
|
||||||
|
/* ETSI TS 102 366 v1.4.1 - Digital Audio Compression (AC-3, Enhanced AC-3) Standard, Annex F */
|
||||||
|
caps = gst_caps_new_empty_simple ("audio/x-eac3");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('s', 't', 'p', 'p'):
|
||||||
|
/* IMSC1-conformant TTM XML */
|
||||||
|
caps = gst_caps_new_empty_simple ("application/ttml+xml");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('w', 'v', 't', 't'):
|
||||||
|
/* WebVTT subtitles */
|
||||||
|
caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('v', 'p', '0', '8'):
|
||||||
|
/* VP8 */
|
||||||
|
caps = gst_caps_new_empty_simple ("video/x-vp8");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('v', 'p', '0', '9'):
|
||||||
|
/* VP9 */
|
||||||
|
caps = gst_caps_new_empty_simple ("video/x-vp9");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('a', 'v', '0', '1'):
|
||||||
|
/* AV1 */
|
||||||
|
caps = gst_caps_new_empty_simple ("video/x-av1");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('o', 'p', 'u', 's'):
|
||||||
|
/* Opus */
|
||||||
|
caps = gst_caps_new_empty_simple ("audio/x-opus");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
|
||||||
|
/* ulaw */
|
||||||
|
caps = gst_caps_new_empty_simple ("audio/x-mulaw");
|
||||||
|
break;
|
||||||
|
case GST_MAKE_FOURCC ('g', '7', '2', '6'):
|
||||||
|
/* ulaw */
|
||||||
|
caps =
|
||||||
|
gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING, "g726",
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_WARNING ("Unknown codec '%s' please file a bug", codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
beach:
|
||||||
|
if (subcodec != NULL)
|
||||||
|
g_strfreev (subcodec);
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_codec_utils_caps_from_mime_codec:
|
||||||
|
* @codecs_field: A mime codec string field
|
||||||
|
*
|
||||||
|
* Converts a RFC 6381 compatible codec string to #GstCaps. More than one codec
|
||||||
|
* string can be present (separated by `,`).
|
||||||
|
*
|
||||||
|
* Registered codecs can be found at http://mp4ra.org/#/codecs
|
||||||
|
*
|
||||||
|
* Returns: (transfer full) (nullable): The corresponding #GstCaps or %NULL
|
||||||
|
*
|
||||||
|
* Since: 1.22
|
||||||
|
*/
|
||||||
|
GstCaps *
|
||||||
|
gst_codec_utils_caps_from_mime_codec (const gchar * codecs_field)
|
||||||
|
{
|
||||||
|
gchar **codecs = NULL;
|
||||||
|
GstCaps *caps = NULL;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (codecs_field != NULL, NULL);
|
||||||
|
|
||||||
|
GST_LOG ("codecs_field '%s'", codecs_field);
|
||||||
|
|
||||||
|
codecs = g_strsplit (codecs_field, ",", 0);
|
||||||
|
if (codecs == NULL) {
|
||||||
|
GST_WARNING ("Invalid 'codecs' field : '%s'", codecs_field);
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; codecs[i]; i++) {
|
||||||
|
const gchar *codec = codecs[i];
|
||||||
|
if (caps == NULL)
|
||||||
|
caps = gst_codec_utils_caps_from_mime_codec_single (codec);
|
||||||
|
else
|
||||||
|
gst_caps_append (caps,
|
||||||
|
gst_codec_utils_caps_from_mime_codec_single (codec));
|
||||||
|
}
|
||||||
|
|
||||||
|
beach:
|
||||||
|
g_strfreev (codecs);
|
||||||
|
GST_LOG ("caps %" GST_PTR_FORMAT, caps);
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
|
@ -156,6 +156,8 @@ gboolean gst_codec_utils_opus_parse_header (GstBuffer * header,
|
||||||
GST_PBUTILS_API
|
GST_PBUTILS_API
|
||||||
gchar * gst_codec_utils_caps_get_mime_codec (GstCaps * caps);
|
gchar * gst_codec_utils_caps_get_mime_codec (GstCaps * caps);
|
||||||
|
|
||||||
|
GST_PBUTILS_API
|
||||||
|
GstCaps * gst_codec_utils_caps_from_mime_codec (const gchar *codecs_field);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -1359,9 +1359,10 @@ static const guint8 h265_sample_codec_data[] = {
|
||||||
0x44, 0x01, 0xc0, 0x2c, 0xbc, 0x14, 0xc9
|
0x44, 0x01, 0xc0, 0x2c, 0xbc, 0x14, 0xc9
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
GST_START_TEST (test_pb_utils_caps_mime_codec)
|
||||||
{
|
{
|
||||||
GstCaps *caps = NULL;
|
GstCaps *caps = NULL;
|
||||||
|
GstCaps *caps2 = NULL;
|
||||||
gchar *mime_codec = NULL;
|
gchar *mime_codec = NULL;
|
||||||
GstBuffer *buffer = NULL;
|
GstBuffer *buffer = NULL;
|
||||||
guint8 *codec_data = NULL;
|
guint8 *codec_data = NULL;
|
||||||
|
@ -1371,6 +1372,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
||||||
caps = gst_caps_new_empty_simple ("video/x-h264");
|
caps = gst_caps_new_empty_simple ("video/x-h264");
|
||||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||||
fail_unless_equals_string (mime_codec, "avc1");
|
fail_unless_equals_string (mime_codec, "avc1");
|
||||||
|
caps2 = gst_codec_utils_caps_from_mime_codec (mime_codec);
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps, caps2));
|
||||||
|
gst_caps_unref (caps2);
|
||||||
g_free (mime_codec);
|
g_free (mime_codec);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
@ -1412,6 +1416,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
||||||
caps = gst_caps_new_empty_simple ("video/x-av1");
|
caps = gst_caps_new_empty_simple ("video/x-av1");
|
||||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||||
fail_unless_equals_string (mime_codec, "av01");
|
fail_unless_equals_string (mime_codec, "av01");
|
||||||
|
caps2 = gst_codec_utils_caps_from_mime_codec (mime_codec);
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps, caps2));
|
||||||
|
gst_caps_unref (caps2);
|
||||||
g_free (mime_codec);
|
g_free (mime_codec);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
@ -1419,6 +1426,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
||||||
caps = gst_caps_new_empty_simple ("video/x-vp8");
|
caps = gst_caps_new_empty_simple ("video/x-vp8");
|
||||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||||
fail_unless_equals_string (mime_codec, "vp08");
|
fail_unless_equals_string (mime_codec, "vp08");
|
||||||
|
caps2 = gst_codec_utils_caps_from_mime_codec (mime_codec);
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps, caps2));
|
||||||
|
gst_caps_unref (caps2);
|
||||||
g_free (mime_codec);
|
g_free (mime_codec);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
@ -1426,6 +1436,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
||||||
caps = gst_caps_new_empty_simple ("video/x-vp9");
|
caps = gst_caps_new_empty_simple ("video/x-vp9");
|
||||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||||
fail_unless_equals_string (mime_codec, "vp09");
|
fail_unless_equals_string (mime_codec, "vp09");
|
||||||
|
caps2 = gst_codec_utils_caps_from_mime_codec (mime_codec);
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps, caps2));
|
||||||
|
gst_caps_unref (caps2);
|
||||||
g_free (mime_codec);
|
g_free (mime_codec);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
@ -1462,6 +1475,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
||||||
caps = gst_caps_new_empty_simple ("audio/x-opus");
|
caps = gst_caps_new_empty_simple ("audio/x-opus");
|
||||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||||
fail_unless_equals_string (mime_codec, "opus");
|
fail_unless_equals_string (mime_codec, "opus");
|
||||||
|
caps2 = gst_codec_utils_caps_from_mime_codec (mime_codec);
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps, caps2));
|
||||||
|
gst_caps_unref (caps2);
|
||||||
g_free (mime_codec);
|
g_free (mime_codec);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
@ -1469,6 +1485,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
||||||
caps = gst_caps_new_empty_simple ("audio/x-mulaw");
|
caps = gst_caps_new_empty_simple ("audio/x-mulaw");
|
||||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||||
fail_unless_equals_string (mime_codec, "ulaw");
|
fail_unless_equals_string (mime_codec, "ulaw");
|
||||||
|
caps2 = gst_codec_utils_caps_from_mime_codec (mime_codec);
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps, caps2));
|
||||||
|
gst_caps_unref (caps2);
|
||||||
g_free (mime_codec);
|
g_free (mime_codec);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
@ -1478,6 +1497,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
||||||
NULL);
|
NULL);
|
||||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||||
fail_unless_equals_string (mime_codec, "g726");
|
fail_unless_equals_string (mime_codec, "g726");
|
||||||
|
caps2 = gst_codec_utils_caps_from_mime_codec (mime_codec);
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps, caps2));
|
||||||
|
gst_caps_unref (caps2);
|
||||||
g_free (mime_codec);
|
g_free (mime_codec);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
}
|
}
|
||||||
|
@ -1504,7 +1526,7 @@ libgstpbutils_suite (void)
|
||||||
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_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);
|
||||||
tcase_add_test (tc_chain, test_pb_utils_caps_get_mime_codec);
|
tcase_add_test (tc_chain, test_pb_utils_caps_mime_codec);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue