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,
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 ();
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);
}
/**
+ * 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
*
else
return "video";
}
+ if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
+ return "subtitles";
return "unknown";
}
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) \
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) {
"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);
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);
}
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;
* 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.
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;
}
}
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
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);
gboolean is_image;
};
+struct _GstDiscovererSubtitleInfo {
+ GstDiscovererStreamInfo parent;
+
+ gchar *language;
+};
+
struct _GstDiscovererInfo {
GstMiniObject parent;
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)
{
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);