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;
+}
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;
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);
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);
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);
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);
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);
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);
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);
}
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;
}