From 4b5bfb1fd4955b33675fcdbaa0182922c9bc3b89 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 24 Aug 2011 15:04:50 +0100 Subject: [PATCH] discoverer: add subtitles API https://bugzilla.gnome.org/show_bug.cgi?id=639055 --- gst-libs/gst/pbutils/gstdiscoverer-types.c | 89 ++++++++++++++++++++++ gst-libs/gst/pbutils/gstdiscoverer.c | 59 +++++++++++--- gst-libs/gst/pbutils/gstdiscoverer.h | 21 +++++ gst-libs/gst/pbutils/pbutils-private.h | 6 ++ tools/gst-discoverer.c | 55 +++++++++++++ 5 files changed, 219 insertions(+), 11 deletions(-) diff --git a/gst-libs/gst/pbutils/gstdiscoverer-types.c b/gst-libs/gst/pbutils/gstdiscoverer-types.c index 6949c804ff..f705a94c6b 100644 --- a/gst-libs/gst/pbutils/gstdiscoverer-types.c +++ b/gst-libs/gst/pbutils/gstdiscoverer-types.c @@ -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); @@ -439,6 +489,25 @@ gst_discoverer_info_get_video_streams (GstDiscovererInfo * info) return gst_discoverer_info_get_streams (info, GST_TYPE_DISCOVERER_VIDEO_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) \ diff --git a/gst-libs/gst/pbutils/gstdiscoverer.c b/gst-libs/gst/pbutils/gstdiscoverer.c index c41acee6bd..a8240203f8 100644 --- a/gst-libs/gst/pbutils/gstdiscoverer.c +++ b/gst-libs/gst/pbutils/gstdiscoverer.c @@ -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/ (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; } } diff --git a/gst-libs/gst/pbutils/gstdiscoverer.h b/gst-libs/gst/pbutils/gstdiscoverer.h index 671dbaa4ed..f0100b6ed0 100644 --- a/gst-libs/gst/pbutils/gstdiscoverer.h +++ b/gst-libs/gst/pbutils/gstdiscoverer.h @@ -140,6 +140,26 @@ guint gst_discoverer_video_info_get_bitrate(const GstDiscovererVideoIn guint gst_discoverer_video_info_get_max_bitrate(const GstDiscovererVideoInfo* info); 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 @@ -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); diff --git a/gst-libs/gst/pbutils/pbutils-private.h b/gst-libs/gst/pbutils/pbutils-private.h index 5031df0345..99606bc63a 100644 --- a/gst-libs/gst/pbutils/pbutils-private.h +++ b/gst-libs/gst/pbutils/pbutils-private.h @@ -64,6 +64,12 @@ struct _GstDiscovererVideoInfo { gboolean is_image; }; +struct _GstDiscovererSubtitleInfo { + GstDiscovererStreamInfo parent; + + gchar *language; +}; + struct _GstDiscovererInfo { GstMiniObject parent; diff --git a/tools/gst-discoverer.c b/tools/gst-discoverer.c index 00d2d0f415..19aef907ff 100644 --- a/tools/gst-discoverer.c +++ b/tools/gst-discoverer.c @@ -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 : ""); + + 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);