encoding-profile: add gst_encoding_profile_get_file_extension()
authorTim-Philipp Müller <tim@centricular.net>
Sun, 23 Dec 2012 15:26:59 +0000 (15:26 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Sun, 23 Dec 2012 15:26:59 +0000 (15:26 +0000)
API: gst_encoding_profile_get_file_extension()

https://bugzilla.gnome.org/show_bug.cgi?id=636753

gst-libs/gst/pbutils/descriptions.c
gst-libs/gst/pbutils/encoding-profile.c
gst-libs/gst/pbutils/encoding-profile.h
tests/check/libs/profile.c
win32/common/libgstpbutils.def

index 009c6e2..2d08f3c 100644 (file)
@@ -300,7 +300,7 @@ static const FormatInfo formats[] = {
   {"video/x-dv", "Digital Video (DV) System Stream",
       FLAG_CONTAINER | FLAG_SYSTEMSTREAM, "dv"},
   {"video/x-dv", "Digital Video (DV)", FLAG_VIDEO, ""},
-  {"video/x-h263", NULL, FLAG_VIDEO, ""},
+  {"video/x-h263", NULL, FLAG_VIDEO, "h263"},
   {"video/x-h264", NULL, FLAG_VIDEO, "h264"},
   {"video/x-indeo", NULL, FLAG_VIDEO, ""},
   {"video/x-msmpeg", NULL, FLAG_VIDEO, ""},
@@ -1028,6 +1028,79 @@ gst_pb_utils_get_codec_description (const GstCaps * caps)
   return str;
 }
 
+/* internal helper functions for gst_encoding_profile_get_file_extension() */
+const gchar *pb_utils_get_file_extension_from_caps (const GstCaps * caps);
+gboolean pb_utils_is_tag (const GstCaps * caps);
+
+const gchar *
+pb_utils_get_file_extension_from_caps (const GstCaps * caps)
+{
+  const FormatInfo *info;
+  const gchar *ext = NULL;
+  GstCaps *stripped_caps;
+
+  g_assert (GST_IS_CAPS (caps));
+
+  stripped_caps = copy_and_clean_caps (caps);
+
+  g_assert (gst_caps_is_fixed (stripped_caps));
+
+  info = find_format_info (stripped_caps);
+
+  if (info && info->ext[0] != '\0') {
+    ext = info->ext;
+  } else if (info && info->desc == NULL) {
+    const GstStructure *s;
+
+    s = gst_caps_get_structure (stripped_caps, 0);
+
+    /* cases where we have to evaluate the caps more closely */
+    if (strcmp (info->type, "audio/mpeg") == 0) {
+      int version = 0, layer = 3;
+
+      if (gst_structure_get_int (s, "mpegversion", &version)) {
+        if (version == 2 || version == 4) {
+          ext = "aac";
+        } else if (version == 1) {
+          gst_structure_get_int (s, "layer", &layer);
+          if (layer == 1)
+            ext = "mp1";
+          else if (layer == 2)
+            ext = "mp2";
+          else
+            ext = "mp3";
+        }
+      }
+    }
+  }
+
+  gst_caps_unref (stripped_caps);
+  return ext;
+}
+
+gboolean
+pb_utils_is_tag (const GstCaps * caps)
+{
+  const FormatInfo *info;
+  GstCaps *stripped_caps;
+  gboolean is_tag = FALSE;
+
+  g_assert (GST_IS_CAPS (caps));
+
+  stripped_caps = copy_and_clean_caps (caps);
+
+  g_assert (gst_caps_is_fixed (stripped_caps));
+
+  info = find_format_info (stripped_caps);
+
+  if (info) {
+    is_tag = (info->flags & FLAG_TAG) != 0;
+  }
+  gst_caps_unref (stripped_caps);
+
+  return is_tag;
+}
+
 #if 0
 void
 gst_pb_utils_list_all (void)
index 3ae2ea1..274ee99 100644 (file)
 #include "encoding-profile.h"
 #include "encoding-target.h"
 
+#include <string.h>
+
 /* GstEncodingProfile API */
 
 struct _GstEncodingProfile
@@ -902,6 +904,114 @@ gst_encoding_profile_get_type_nick (GstEncodingProfile * profile)
   return NULL;
 }
 
+extern const gchar *pb_utils_get_file_extension_from_caps (const GstCaps *
+    caps);
+gboolean pb_utils_is_tag (const GstCaps * caps);
+
+static gboolean
+gst_encoding_profile_has_format (GstEncodingProfile * profile,
+    const gchar * media_type)
+{
+  GstCaps *caps;
+  gboolean ret;
+
+  caps = gst_encoding_profile_get_format (profile);
+  ret = gst_structure_has_name (gst_caps_get_structure (caps, 0), media_type);
+  gst_caps_unref (caps);
+
+  return ret;
+}
+
+static gboolean
+gst_encoding_container_profile_has_video (GstEncodingContainerProfile * profile)
+{
+  const GList *l;
+
+  for (l = profile->encodingprofiles; l != NULL; l = l->next) {
+    if (GST_IS_ENCODING_VIDEO_PROFILE (l->data))
+      return TRUE;
+    if (GST_IS_ENCODING_CONTAINER_PROFILE (l->data) &&
+        gst_encoding_container_profile_has_video (l->data))
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+ * gst_encoding_profile_get_file_extension:
+ * @profile: a #GstEncodingProfile
+ *
+ * Returns: a suitable file extension for @profile, or NULL.
+ */
+const gchar *
+gst_encoding_profile_get_file_extension (GstEncodingProfile * profile)
+{
+  GstEncodingContainerProfile *cprofile;
+  const gchar *ext = NULL;
+  gboolean has_video;
+  GstCaps *caps;
+  guint num_children;
+
+  g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
+
+  caps = gst_encoding_profile_get_format (profile);
+  ext = pb_utils_get_file_extension_from_caps (caps);
+
+  if (!GST_IS_ENCODING_CONTAINER_PROFILE (profile))
+    goto done;
+
+  cprofile = GST_ENCODING_CONTAINER_PROFILE (profile);
+
+  num_children = g_list_length (cprofile->encodingprofiles);
+
+  /* if it's a tag container profile (e.g. id3mux/apemux), we need
+   * to look at what's inside it */
+  if (pb_utils_is_tag (caps)) {
+    GST_DEBUG ("tag container profile");
+    if (num_children == 1) {
+      GstEncodingProfile *child_profile = cprofile->encodingprofiles->data;
+
+      ext = gst_encoding_profile_get_file_extension (child_profile);
+    } else {
+      GST_WARNING ("expected exactly one child profile with tag profile");
+    }
+    goto done;
+  }
+
+  /* special cases */
+  has_video = gst_encoding_container_profile_has_video (cprofile);
+
+  if (strcmp (ext, "ogg") == 0) {
+    /* ogg with video => .ogv */
+    if (has_video) {
+      ext = "ogv";
+      goto done;
+    }
+    /* ogg with just speex audio => .spx */
+    if (num_children == 1) {
+      GstEncodingProfile *child_profile = cprofile->encodingprofiles->data;
+
+      if (GST_IS_ENCODING_AUDIO_PROFILE (child_profile) &&
+          gst_encoding_profile_has_format (child_profile, "audio/x-speex")) {
+        ext = "spx";
+        goto done;
+      }
+    }
+    /* does anyone actually use .oga for ogg audio files? */
+    goto done;
+  }
+
+  if (has_video && strcmp (ext, "mka") == 0)
+    ext = "mkv";
+
+done:
+
+  GST_INFO ("caps %" GST_PTR_FORMAT ", ext: %s", caps, GST_STR_NULL (ext));
+  gst_caps_unref (caps);
+  return ext;
+}
+
 /**
  * gst_encoding_profile_find:
  * @targetname: (transfer none): The name of the target
index 22342f0..60e148d 100644 (file)
@@ -143,6 +143,8 @@ gboolean        gst_encoding_profile_is_equal           (GstEncodingProfile *a,
 GstCaps *       gst_encoding_profile_get_input_caps     (GstEncodingProfile *profile);
 const gchar *   gst_encoding_profile_get_type_nick      (GstEncodingProfile *profile);
 
+const gchar *   gst_encoding_profile_get_file_extension (GstEncodingProfile * profile);
+
 GstEncodingProfile * gst_encoding_profile_find (const gchar *targetname,
                                                 const gchar *profilename,
                                                 const gchar *category);
index a4fca08..44e9f39 100644 (file)
@@ -605,6 +605,70 @@ test_teardown (void)
   remove_profile_file ();
 }
 
+GST_START_TEST (test_file_extension)
+{
+  GstEncodingContainerProfile *cprof;
+  GstCaps *ogg, *speex, *vorbis, *theora, *id3, *mp3;
+
+  /* 1 - ogg variants */
+  ogg = gst_caps_new_empty_simple ("application/ogg");
+  cprof = gst_encoding_container_profile_new ("myprofile", NULL, ogg, NULL);
+  gst_caps_unref (ogg);
+
+  fail_unless_equals_string (gst_encoding_profile_get_file_extension
+      (GST_ENCODING_PROFILE (cprof)), "ogg");
+
+  speex = gst_caps_new_empty_simple ("audio/x-speex");
+  gst_encoding_container_profile_add_profile (cprof,
+      (GstEncodingProfile *) gst_encoding_audio_profile_new (speex, NULL,
+          NULL, 1));
+  gst_caps_unref (speex);
+
+  fail_unless_equals_string (gst_encoding_profile_get_file_extension
+      (GST_ENCODING_PROFILE (cprof)), "spx");
+
+  vorbis = gst_caps_new_empty_simple ("audio/x-vorbis");
+  gst_encoding_container_profile_add_profile (cprof,
+      (GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, NULL,
+          NULL, 1));
+  gst_caps_unref (vorbis);
+
+  fail_unless_equals_string (gst_encoding_profile_get_file_extension
+      (GST_ENCODING_PROFILE (cprof)), "ogg");
+
+  theora = gst_caps_new_empty_simple ("video/x-theora");
+  gst_encoding_container_profile_add_profile (cprof,
+      (GstEncodingProfile *) gst_encoding_video_profile_new (theora, NULL,
+          NULL, 1));
+  gst_caps_unref (theora);
+
+  fail_unless_equals_string (gst_encoding_profile_get_file_extension
+      (GST_ENCODING_PROFILE (cprof)), "ogv");
+
+  gst_encoding_profile_unref (cprof);
+
+  /* 2 - tag container */
+  id3 = gst_caps_new_empty_simple ("application/x-id3");
+  cprof = gst_encoding_container_profile_new ("myprofile", NULL, id3, NULL);
+  gst_caps_unref (id3);
+
+  fail_unless (gst_encoding_profile_get_file_extension (GST_ENCODING_PROFILE
+          (cprof)) == NULL);
+
+  mp3 = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1,
+      "layer", G_TYPE_INT, 3, NULL);
+  gst_encoding_container_profile_add_profile (cprof,
+      (GstEncodingProfile *) gst_encoding_audio_profile_new (mp3, NULL,
+          NULL, 1));
+  gst_caps_unref (mp3);
+
+  fail_unless_equals_string (gst_encoding_profile_get_file_extension
+      (GST_ENCODING_PROFILE (cprof)), "mp3");
+
+  gst_encoding_profile_unref (cprof);
+}
+
+GST_END_TEST;
 
 static Suite *
 profile_suite (void)
@@ -625,6 +689,7 @@ profile_suite (void)
   tcase_add_test (tc_chain, test_profile_input_caps);
   tcase_add_test (tc_chain, test_target_naming);
   tcase_add_test (tc_chain, test_target_profile);
+  tcase_add_test (tc_chain, test_file_extension);
   if (can_write) {
     tcase_add_test (tc_chain, test_loading_profile);
     tcase_add_test (tc_chain, test_saving_profile);
index 3a56881..e9980ac 100644 (file)
@@ -78,6 +78,7 @@ EXPORTS
        gst_encoding_profile_find
        gst_encoding_profile_from_discoverer
        gst_encoding_profile_get_description
+       gst_encoding_profile_get_file_extension
        gst_encoding_profile_get_format
        gst_encoding_profile_get_input_caps
        gst_encoding_profile_get_name