2012-05-16 16:16:05 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <gst/gst.h>
|
|
|
|
#include <gst/pbutils/pbutils.h>
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Structure to contain all our information, so we can pass it around */
|
|
|
|
typedef struct _CustomData {
|
|
|
|
GstDiscoverer *discoverer;
|
|
|
|
GMainLoop *loop;
|
|
|
|
} CustomData;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Print a tag in a human-readable format (name: value) */
|
|
|
|
static void print_tag_foreach (const GstTagList *tags, const gchar *tag, gpointer user_data) {
|
|
|
|
GValue val = { 0, };
|
|
|
|
gchar *str;
|
|
|
|
gint depth = GPOINTER_TO_INT (user_data);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
gst_tag_list_copy_value (&val, tags, tag);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
if (G_VALUE_HOLDS_STRING (&val))
|
|
|
|
str = g_value_dup_string (&val);
|
|
|
|
else
|
|
|
|
str = gst_value_serialize (&val);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("%*s%s: %s\n", 2 * depth, " ", gst_tag_get_nick (tag), str);
|
|
|
|
g_free (str);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_value_unset (&val);
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Print information regarding a stream */
|
|
|
|
static void print_stream_info (GstDiscovererStreamInfo *info, gint depth) {
|
|
|
|
gchar *desc = NULL;
|
|
|
|
GstCaps *caps;
|
|
|
|
const GstTagList *tags;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
caps = gst_discoverer_stream_info_get_caps (info);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
if (caps) {
|
|
|
|
if (gst_caps_is_fixed (caps))
|
|
|
|
desc = gst_pb_utils_get_codec_description (caps);
|
|
|
|
else
|
|
|
|
desc = gst_caps_to_string (caps);
|
|
|
|
gst_caps_unref (caps);
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("%*s%s: %s\n", 2 * depth, " ", gst_discoverer_stream_info_get_stream_type_nick (info), (desc ? desc : ""));
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
if (desc) {
|
|
|
|
g_free (desc);
|
|
|
|
desc = NULL;
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
tags = gst_discoverer_stream_info_get_tags (info);
|
|
|
|
if (tags) {
|
|
|
|
g_print ("%*sTags:\n", 2 * (depth + 1), " ");
|
|
|
|
gst_tag_list_foreach (tags, print_tag_foreach, GINT_TO_POINTER (depth + 2));
|
|
|
|
}
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Print information regarding a stream and its substreams, if any */
|
|
|
|
static void print_topology (GstDiscovererStreamInfo *info, gint depth) {
|
|
|
|
GstDiscovererStreamInfo *next;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
if (!info)
|
|
|
|
return;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
print_stream_info (info, depth);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
next = gst_discoverer_stream_info_get_next (info);
|
|
|
|
if (next) {
|
|
|
|
print_topology (next, depth + 1);
|
|
|
|
gst_discoverer_stream_info_unref (next);
|
|
|
|
} else if (GST_IS_DISCOVERER_CONTAINER_INFO (info)) {
|
|
|
|
GList *tmp, *streams;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
streams = gst_discoverer_container_info_get_streams (GST_DISCOVERER_CONTAINER_INFO (info));
|
|
|
|
for (tmp = streams; tmp; tmp = tmp->next) {
|
|
|
|
GstDiscovererStreamInfo *tmpinf = (GstDiscovererStreamInfo *) tmp->data;
|
|
|
|
print_topology (tmpinf, depth + 1);
|
|
|
|
}
|
|
|
|
gst_discoverer_stream_info_list_free (streams);
|
|
|
|
}
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* This function is called every time the discoverer has information regarding
|
|
|
|
* one of the URIs we provided.*/
|
|
|
|
static void on_discovered_cb (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, CustomData *data) {
|
|
|
|
GstDiscovererResult result;
|
|
|
|
const gchar *uri;
|
|
|
|
const GstTagList *tags;
|
|
|
|
GstDiscovererStreamInfo *sinfo;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
uri = gst_discoverer_info_get_uri (info);
|
|
|
|
result = gst_discoverer_info_get_result (info);
|
|
|
|
switch (result) {
|
|
|
|
case GST_DISCOVERER_URI_INVALID:
|
|
|
|
g_print ("Invalid URI '%s'\n", uri);
|
|
|
|
break;
|
|
|
|
case GST_DISCOVERER_ERROR:
|
|
|
|
g_print ("Discoverer error: %s\n", err->message);
|
|
|
|
break;
|
|
|
|
case GST_DISCOVERER_TIMEOUT:
|
|
|
|
g_print ("Timeout\n");
|
|
|
|
break;
|
|
|
|
case GST_DISCOVERER_BUSY:
|
|
|
|
g_print ("Busy\n");
|
|
|
|
break;
|
|
|
|
case GST_DISCOVERER_MISSING_PLUGINS:{
|
|
|
|
const GstStructure *s;
|
|
|
|
gchar *str;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
s = gst_discoverer_info_get_misc (info);
|
|
|
|
str = gst_structure_to_string (s);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("Missing plugins: %s\n", str);
|
|
|
|
g_free (str);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GST_DISCOVERER_OK:
|
|
|
|
g_print ("Discovered '%s'\n", uri);
|
|
|
|
break;
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
if (result != GST_DISCOVERER_OK) {
|
|
|
|
g_printerr ("This URI cannot be played\n");
|
|
|
|
return;
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* If we got no error, show the retrieved information */
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("\nDuration: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (gst_discoverer_info_get_duration (info)));
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
tags = gst_discoverer_info_get_tags (info);
|
|
|
|
if (tags) {
|
|
|
|
g_print ("Tags:\n");
|
|
|
|
gst_tag_list_foreach (tags, print_tag_foreach, GINT_TO_POINTER (1));
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("Seekable: %s\n", (gst_discoverer_info_get_seekable (info) ? "yes" : "no"));
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("\n");
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
sinfo = gst_discoverer_info_get_stream_info (info);
|
|
|
|
if (!sinfo)
|
|
|
|
return;
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("Stream information:\n");
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
print_topology (sinfo, 1);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
gst_discoverer_stream_info_unref (sinfo);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("\n");
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* This function is called when the discoverer has finished examining
|
|
|
|
* all the URIs we provided.*/
|
|
|
|
static void on_finished_cb (GstDiscoverer *discoverer, CustomData *data) {
|
|
|
|
g_print ("Finished discovering\n");
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_main_loop_quit (data->loop);
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
int main (int argc, char **argv) {
|
|
|
|
CustomData data;
|
|
|
|
GError *err = NULL;
|
2016-09-15 20:27:36 +00:00
|
|
|
gchar *uri = "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* if a URI was provided, use it instead of the default one */
|
|
|
|
if (argc > 1) {
|
|
|
|
uri = argv[1];
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Initialize cumstom data structure */
|
|
|
|
memset (&data, 0, sizeof (data));
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Initialize GStreamer */
|
|
|
|
gst_init (&argc, &argv);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
g_print ("Discovering '%s'\n", uri);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Instantiate the Discoverer */
|
|
|
|
data.discoverer = gst_discoverer_new (5 * GST_SECOND, &err);
|
|
|
|
if (!data.discoverer) {
|
|
|
|
g_print ("Error creating discoverer instance: %s\n", err->message);
|
|
|
|
g_clear_error (&err);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Connect to the interesting signals */
|
|
|
|
g_signal_connect (data.discoverer, "discovered", G_CALLBACK (on_discovered_cb), &data);
|
|
|
|
g_signal_connect (data.discoverer, "finished", G_CALLBACK (on_finished_cb), &data);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Start the discoverer process (nothing to do yet) */
|
|
|
|
gst_discoverer_start (data.discoverer);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Add a request to process asynchronously the URI passed through the command line */
|
|
|
|
if (!gst_discoverer_discover_uri_async (data.discoverer, uri)) {
|
|
|
|
g_print ("Failed to start discovering URI '%s'\n", uri);
|
|
|
|
g_object_unref (data.discoverer);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Create a GLib Main Loop and set it to run, so we can wait for the signals */
|
|
|
|
data.loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
g_main_loop_run (data.loop);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Stop the discoverer process */
|
|
|
|
gst_discoverer_stop (data.discoverer);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
/* Free resources */
|
|
|
|
g_object_unref (data.discoverer);
|
|
|
|
g_main_loop_unref (data.loop);
|
2016-11-05 08:18:49 +00:00
|
|
|
|
2012-05-16 16:16:05 +00:00
|
|
|
return 0;
|
2012-05-15 11:53:40 +00:00
|
|
|
}
|