discoverer: add subtitles API
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Wed, 24 Aug 2011 14:04:50 +0000 (15:04 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 26 Aug 2011 08:05:50 +0000 (10:05 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=639055

gst-libs/gst/pbutils/gstdiscoverer-types.c
gst-libs/gst/pbutils/gstdiscoverer.c
gst-libs/gst/pbutils/gstdiscoverer.h
gst-libs/gst/pbutils/pbutils-private.h
tools/gst-discoverer.c

index 6949c80..f705a94 100644 (file)
@@ -39,6 +39,9 @@ static GstDiscovererAudioInfo
 static GstDiscovererVideoInfo
     * gst_discoverer_video_info_copy_int (GstDiscovererVideoInfo * ptr);
 
+static GstDiscovererSubtitleInfo
+    * gst_discoverer_subtitle_info_copy_int (GstDiscovererSubtitleInfo * ptr);
+
 /* Per-stream information */
 
 G_DEFINE_TYPE (GstDiscovererStreamInfo, gst_discoverer_stream_info,
@@ -110,6 +113,11 @@ gst_discoverer_info_copy_int (GstDiscovererStreamInfo * info,
     ret = (GstDiscovererStreamInfo *)
         gst_discoverer_video_info_copy_int ((GstDiscovererVideoInfo *) info);
 
+  } else if (ltyp == GST_TYPE_DISCOVERER_SUBTITLE_INFO) {
+    ret = (GstDiscovererStreamInfo *)
+        gst_discoverer_subtitle_info_copy_int ((GstDiscovererSubtitleInfo *)
+        info);
+
   } else
     ret = gst_discoverer_stream_info_new ();
 
@@ -233,6 +241,48 @@ gst_discoverer_audio_info_copy_int (GstDiscovererAudioInfo * ptr)
   return ret;
 }
 
+/* Subtitle information */
+G_DEFINE_TYPE (GstDiscovererSubtitleInfo, gst_discoverer_subtitle_info,
+    GST_TYPE_DISCOVERER_STREAM_INFO);
+
+static void
+gst_discoverer_subtitle_info_init (GstDiscovererSubtitleInfo * info)
+{
+  info->language = NULL;
+}
+
+static void
+gst_discoverer_subtitle_info_finalize (GstDiscovererSubtitleInfo * info)
+{
+  g_free (info->language);
+}
+
+static void
+gst_discoverer_subtitle_info_class_init (GstMiniObjectClass * klass)
+{
+  klass->finalize =
+      (GstMiniObjectFinalizeFunction) gst_discoverer_subtitle_info_finalize;
+}
+
+static GstDiscovererSubtitleInfo *
+gst_discoverer_subtitle_info_new (void)
+{
+  return (GstDiscovererSubtitleInfo *)
+      gst_mini_object_new (GST_TYPE_DISCOVERER_SUBTITLE_INFO);
+}
+
+static GstDiscovererSubtitleInfo *
+gst_discoverer_subtitle_info_copy_int (GstDiscovererSubtitleInfo * ptr)
+{
+  GstDiscovererSubtitleInfo *ret;
+
+  ret = gst_discoverer_subtitle_info_new ();
+
+  ret->language = g_strdup (ptr->language);
+
+  return ret;
+}
+
 /* Video information */
 G_DEFINE_TYPE (GstDiscovererVideoInfo, gst_discoverer_video_info,
     GST_TYPE_DISCOVERER_STREAM_INFO);
@@ -440,6 +490,25 @@ gst_discoverer_info_get_video_streams (GstDiscovererInfo * info)
 }
 
 /**
+ * gst_discoverer_info_get_subtitle_streams:
+ * @info: a #GstDiscovererInfo
+ *
+ * Finds all the #GstDiscovererSubtitleInfo contained in @info
+ *
+ * Returns: (transfer full) (element-type Gst.DiscovererStreamInfo): A #GList of
+ * matching #GstDiscovererStreamInfo. The caller should free it with
+ * gst_discoverer_stream_info_list_free().
+ *
+ * Since: 0.10.36
+ */
+GList *
+gst_discoverer_info_get_subtitle_streams (GstDiscovererInfo * info)
+{
+  return gst_discoverer_info_get_streams (info,
+      GST_TYPE_DISCOVERER_SUBTITLE_INFO);
+}
+
+/**
  * gst_discoverer_info_get_container_streams:
  * @info: a #GstDiscovererInfo
  *
@@ -481,6 +550,8 @@ gst_discoverer_stream_info_get_stream_type_nick (GstDiscovererStreamInfo * info)
     else
       return "video";
   }
+  if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
+    return "subtitles";
   return "unknown";
 }
 
@@ -818,6 +889,24 @@ gst_discoverer_video_info_is_image (const GstDiscovererVideoInfo * info)
   return info->is_image;
 }
 
+/* GstDiscovererSubtitleInfo */
+
+#define SUBTITLE_INFO_ACCESSOR_CODE(fieldname, type, failval)                     \
+  GENERIC_ACCESSOR_CODE(gst_discoverer_subtitle_info, GstDiscovererSubtitleInfo*, \
+                       GST_TYPE_DISCOVERER_SUBTITLE_INFO,                        \
+                       fieldname, type, failval)
+
+/**
+ * gst_discoverer_subtitle_info_get_language:
+ * @info: a #GstDiscovererSubtitleInfo
+ *
+ * Returns: the language of the stream, or NULL if unknown.
+ *
+ * Since: 0.10.36
+ */
+
+SUBTITLE_INFO_ACCESSOR_CODE (language, const gchar *, NULL);
+
 /* GstDiscovererInfo */
 
 #define DISCOVERER_INFO_ACCESSOR_CODE(fieldname, type, failval)                \
index c41acee..a824020 100644 (file)
@@ -437,13 +437,9 @@ _event_probe (GstPad * pad, GstEvent * event, PrivateStream * ps)
   return TRUE;
 }
 
-static void
-uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
-    GstDiscoverer * dc)
+static gboolean
+is_subtitle_caps (const GstCaps * caps)
 {
-  PrivateStream *ps;
-  GstPad *sinkpad = NULL;
-  GstCaps *caps;
   static GstCaps *subs_caps = NULL;
 
   if (!subs_caps) {
@@ -453,6 +449,17 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
         "video/x-dvd-subpicture; ");
   }
 
+  return gst_caps_can_intersect (caps, subs_caps);
+}
+
+static void
+uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
+    GstDiscoverer * dc)
+{
+  PrivateStream *ps;
+  GstPad *sinkpad = NULL;
+  GstCaps *caps;
+
   GST_DEBUG_OBJECT (dc, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
 
   ps = g_slice_new0 (PrivateStream);
@@ -470,8 +477,8 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
 
   caps = gst_pad_get_caps_reffed (pad);
 
-  if (gst_caps_can_intersect (caps, subs_caps)) {
-    /* Subtitle streams are sparse and don't provide any information - don't
+  if (is_subtitle_caps (caps)) {
+    /* Subtitle streams are sparse and may not provide any information - don't
      * wait for data to preroll */
     g_object_set (ps->sink, "async", FALSE, NULL);
   }
@@ -714,6 +721,36 @@ collect_information (GstDiscoverer * dc, const GstStructure * st,
 
     return (GstDiscovererStreamInfo *) info;
 
+  } else if (is_subtitle_caps (caps)) {
+    GstDiscovererSubtitleInfo *info;
+
+    if (parent)
+      info = (GstDiscovererSubtitleInfo *) parent;
+    else {
+      info = (GstDiscovererSubtitleInfo *)
+          gst_mini_object_new (GST_TYPE_DISCOVERER_SUBTITLE_INFO);
+      info->parent.caps = caps;
+    }
+
+    if (gst_structure_id_has_field (st, _TAGS_QUARK)) {
+      const gchar *language;
+
+      gst_structure_id_get (st, _TAGS_QUARK,
+          GST_TYPE_STRUCTURE, &tags_st, NULL);
+
+      language = gst_structure_get_string (caps_st, GST_TAG_LANGUAGE_CODE);
+      if (language)
+        info->language = g_strdup (language);
+
+      /* FIXME: Is it worth it to remove the tags we've parsed? */
+      info->parent.tags = gst_tag_list_merge (info->parent.tags,
+          (GstTagList *) tags_st, GST_TAG_MERGE_REPLACE);
+      gst_structure_free (tags_st);
+
+    }
+
+    return (GstDiscovererStreamInfo *) info;
+
   } else {
     /* None of the above - populate what information we can */
     GstDiscovererStreamInfo *info;
@@ -977,7 +1014,7 @@ discoverer_collect (GstDiscoverer * dc)
      * caps named image/<foo> (th exception being MJPEG video which is also
      * type image/jpeg), and should consist of precisely one stream (actually
      * initially there are 2, the image and raw stream, but we squash these
-     * while parsing the stream topology). At some ponit, if we find that these
+     * while parsing the stream topology). At some point, if we find that these
      * conditions are not sufficient, we can count the number of decoders and
      * parsers in the chain, and if there's more than one decoder, or any
      * parser at all, we should not mark this as an image.
@@ -989,8 +1026,8 @@ discoverer_collect (GstDiscoverer * dc)
           gst_caps_get_structure (dc->priv->current_info->stream_info->caps, 0);
 
       if (g_str_has_prefix (gst_structure_get_name (st), "image/"))
-        ((GstDiscovererVideoInfo *) dc->priv->current_info->
-            stream_info)->is_image = TRUE;
+        ((GstDiscovererVideoInfo *) dc->priv->current_info->stream_info)->
+            is_image = TRUE;
     }
   }
 
index 671dbaa..f0100b6 100644 (file)
@@ -141,6 +141,26 @@ guint           gst_discoverer_video_info_get_max_bitrate(const GstDiscovererVid
 gboolean        gst_discoverer_video_info_is_image(const GstDiscovererVideoInfo* info);
 
 /**
+ * GstDiscovererSubtitleInfo:
+ *
+ * #GstDiscovererStreamInfo specific to subtitle streams (this includes text and
+ * image based ones).
+ *
+ * Since: 0.10.36
+ */
+#define GST_TYPE_DISCOVERER_SUBTITLE_INFO \
+  (gst_discoverer_subtitle_info_get_type ())
+#define GST_DISCOVERER_SUBTITLE_INFO(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DISCOVERER_SUBTITLE_INFO, GstDiscovererSubtitleInfo))
+#define GST_IS_DISCOVERER_SUBTITLE_INFO(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DISCOVERER_SUBTITLE_INFO))
+typedef struct _GstDiscovererSubtitleInfo GstDiscovererSubtitleInfo;
+typedef GstMiniObjectClass GstDiscovererSubtitleInfoClass;
+GType gst_discoverer_subtitle_info_get_type (void);
+
+const gchar *   gst_discoverer_subtitle_info_get_language(const GstDiscovererSubtitleInfo* info);
+
+/**
  * GstDiscovererResult:
  * @GST_DISCOVERER_OK: The discovery was successful
  * @GST_DISCOVERER_URI_INVALID: the URI is invalid
@@ -199,6 +219,7 @@ GList *                   gst_discoverer_info_get_streams (GstDiscovererInfo *in
                                                           GType streamtype);
 GList *                   gst_discoverer_info_get_audio_streams (GstDiscovererInfo *info);
 GList *                   gst_discoverer_info_get_video_streams (GstDiscovererInfo *info);
+GList *                   gst_discoverer_info_get_subtitle_streams (GstDiscovererInfo *info);
 GList *                   gst_discoverer_info_get_container_streams (GstDiscovererInfo *info);
 
 void                      gst_discoverer_stream_info_list_free (GList *infos);
index 5031df0..99606bc 100644 (file)
@@ -64,6 +64,12 @@ struct _GstDiscovererVideoInfo {
   gboolean is_image;
 };
 
+struct _GstDiscovererSubtitleInfo {
+  GstDiscovererStreamInfo parent;
+
+  gchar *language;
+};
+
 struct _GstDiscovererInfo {
   GstMiniObject parent;
 
index 00d2d0f..19aef90 100644 (file)
@@ -171,6 +171,57 @@ gst_stream_video_information_to_string (GstDiscovererStreamInfo * info,
   return g_string_free (s, FALSE);
 }
 
+static gchar *
+gst_stream_subtitle_information_to_string (GstDiscovererStreamInfo * info,
+    gint depth)
+{
+  GstDiscovererSubtitleInfo *subtitle_info;
+  GString *s;
+  gchar *tmp;
+  const gchar *ctmp;
+  int len = 400;
+  const GstTagList *tags;
+  GstCaps *caps;
+
+  g_return_val_if_fail (info != NULL, NULL);
+
+  s = g_string_sized_new (len);
+
+  my_g_string_append_printf (s, "Codec:\n");
+  caps = gst_discoverer_stream_info_get_caps (info);
+  tmp = gst_caps_to_string (caps);
+  gst_caps_unref (caps);
+  my_g_string_append_printf (s, "  %s\n", tmp);
+  g_free (tmp);
+
+  my_g_string_append_printf (s, "Additional info:\n");
+  if (gst_discoverer_stream_info_get_misc (info)) {
+    tmp = gst_structure_to_string (gst_discoverer_stream_info_get_misc (info));
+    my_g_string_append_printf (s, "  %s\n", tmp);
+    g_free (tmp);
+  } else {
+    my_g_string_append_printf (s, "  None\n");
+  }
+
+  subtitle_info = (GstDiscovererSubtitleInfo *) info;
+  ctmp = gst_discoverer_subtitle_info_get_language (subtitle_info);
+  my_g_string_append_printf (s, "Language: %s\n", ctmp ? ctmp : "<unknown>");
+
+  my_g_string_append_printf (s, "Tags:\n");
+  tags = gst_discoverer_stream_info_get_tags (info);
+  if (tags) {
+    tmp = gst_structure_to_string ((GstStructure *) tags);
+    my_g_string_append_printf (s, "  %s\n", tmp);
+    g_free (tmp);
+  } else {
+    my_g_string_append_printf (s, "  None\n");
+  }
+  if (verbose)
+    my_g_string_append_printf (s, "\n");
+
+  return g_string_free (s, FALSE);
+}
+
 static void
 print_stream_info (GstDiscovererStreamInfo * info, void *depth)
 {
@@ -204,6 +255,10 @@ print_stream_info (GstDiscovererStreamInfo * info, void *depth)
       desc =
           gst_stream_video_information_to_string (info,
           GPOINTER_TO_INT (depth) + 1);
+    else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
+      desc =
+          gst_stream_subtitle_information_to_string (info,
+          GPOINTER_TO_INT (depth) + 1);
     if (desc) {
       g_print ("%s", desc);
       g_free (desc);