mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 02:30:35 +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:
|
||||
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
|
||||
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
|
||||
|
||||
|
|
|
@ -1359,9 +1359,10 @@ static const guint8 h265_sample_codec_data[] = {
|
|||
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 *caps2 = NULL;
|
||||
gchar *mime_codec = NULL;
|
||||
GstBuffer *buffer = 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");
|
||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||
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);
|
||||
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");
|
||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||
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);
|
||||
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");
|
||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||
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);
|
||||
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");
|
||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||
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);
|
||||
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");
|
||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||
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);
|
||||
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");
|
||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||
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);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
|
@ -1478,6 +1497,9 @@ GST_START_TEST (test_pb_utils_caps_get_mime_codec)
|
|||
NULL);
|
||||
mime_codec = gst_codec_utils_caps_get_mime_codec (caps);
|
||||
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);
|
||||
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_get_profile_flags_level);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue