4 * Copyright (C) 2010 Nokia Corporation
5 * Copyright (C) 2010 Collabora Multimedia
7 * Authors: Parthasarathi Susarla <partha.susarla@collabora.co.uk>
9 * Based on 'gst-discoverer.c' by
10 * Edward Hervey <edward.hervey@collabora.co.uk>
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
36 #include <glib-object.h>
40 #include <gst/profile/gstprofile.h>
41 #include <gst/discoverer/gstdiscoverer.h>
42 #include <gst/pbutils/pbutils.h>
44 #include <libgupnp-dlna/gupnp-dlna-load.h>
45 #include <libgupnp-dlna/gupnp-dlna-profile.h>
46 #include <libgupnp-dlna/gupnp-dlna-discoverer.h>
47 #include <libgupnp-dlna/gupnp-dlna-information.h>
50 static gboolean async = FALSE;
51 static gboolean verbose = FALSE;
52 static gint timeout = 10;
54 static const gchar *_gst_stream_type_to_string[] = {
65 GUPnPDLNADiscoverer *dc;
71 * The following functions are from gst-discoverer.c (gst-convenience/tools)
73 #define my_g_string_append_printf(str, format, ...) \
74 g_string_append_printf (str, "%*s" format, 2*depth, " ", ##__VA_ARGS__)
77 gst_stream_audio_information_to_string (GstStreamAudioInformation * info,
84 g_return_val_if_fail (info != NULL, NULL);
86 s = g_string_sized_new (len);
88 my_g_string_append_printf (s, "Codec:\n");
89 tmp = gst_caps_to_string (info->parent.caps);
90 my_g_string_append_printf (s, " %s\n", tmp);
93 my_g_string_append_printf (s, "Additional info:\n");
94 if (info->parent.misc) {
95 tmp = gst_structure_to_string (info->parent.misc);
96 my_g_string_append_printf (s, " %s\n", tmp);
99 my_g_string_append_printf (s, " None\n");
102 my_g_string_append_printf (s, "Channels: %u\n", info->channels);
103 my_g_string_append_printf (s, "Sample rate: %u\n", info->sample_rate);
104 my_g_string_append_printf (s, "Depth: %u\n", info->depth);
106 my_g_string_append_printf (s, "Bitrate: %u\n", info->bitrate);
107 my_g_string_append_printf (s, "Max bitrate: %u\n", info->max_bitrate);
108 my_g_string_append_printf (s, "VBR: %s\n",
109 info->is_vbr ? "true" : "false");
111 my_g_string_append_printf (s, "Tags:\n");
112 if (info->parent.tags) {
113 tmp = gst_structure_to_string ((GstStructure *) info->parent.tags);
114 my_g_string_append_printf (s, " %s\n", tmp);
117 my_g_string_append_printf (s, " None\n");
120 return g_string_free (s, FALSE);
123 static const gchar *_gst_video_format_to_string[] = {
149 gst_stream_video_information_to_string (GstStreamVideoInformation * info,
156 g_return_val_if_fail (info != NULL, NULL);
158 s = g_string_sized_new (len);
160 my_g_string_append_printf (s, "Codec:\n");
161 tmp = gst_caps_to_string (info->parent.caps);
162 my_g_string_append_printf (s, " %s\n", tmp);
165 my_g_string_append_printf (s, "Additional info:\n");
166 if (info->parent.misc) {
167 tmp = gst_structure_to_string (info->parent.misc);
168 my_g_string_append_printf (s, " %s\n", tmp);
171 my_g_string_append_printf (s, " None\n");
174 my_g_string_append_printf (s, "Width: %u\n", info->width);
175 my_g_string_append_printf (s, "Height: %u\n", info->height);
176 my_g_string_append_printf (s, "Depth: %u\n", info->depth);
178 n = gst_value_get_fraction_numerator (&info->frame_rate);
179 d = gst_value_get_fraction_denominator (&info->frame_rate);
180 my_g_string_append_printf (s, "Frame rate: %u/%u\n", n, d);
182 n = gst_value_get_fraction_numerator (&info->pixel_aspect_ratio);
183 d = gst_value_get_fraction_denominator (&info->pixel_aspect_ratio);
184 my_g_string_append_printf (s, "Pixel aspect ratio: %u/%u\n", n, d);
186 my_g_string_append_printf (s, "Format: %s\n",
187 _gst_video_format_to_string[info->format]);
189 my_g_string_append_printf (s, "Interlaced: %s\n",
190 info->interlaced ? "true" : "false");
192 my_g_string_append_printf (s, "Tags:\n");
193 if (info->parent.tags) {
194 tmp = gst_structure_to_string ((GstStructure *) info->parent.tags);
195 my_g_string_append_printf (s, " %s\n", tmp);
198 my_g_string_append_printf (s, " None\n");
202 return g_string_free (s, FALSE);
206 print_stream_info (GstStreamInformation * info, void *depth)
211 if (gst_caps_is_fixed (info->caps))
212 desc = gst_pb_utils_get_codec_description (info->caps);
214 desc = gst_caps_to_string (info->caps);
217 g_print ("%*s%s: %s\n", 2 * GPOINTER_TO_INT (depth), " ",
218 _gst_stream_type_to_string[info->streamtype], desc);
225 switch (info->streamtype) {
226 case GST_STREAM_AUDIO:
227 desc = gst_stream_audio_information_to_string (
228 (GstStreamAudioInformation *) info,
229 GPOINTER_TO_INT (depth) + 1);
232 case GST_STREAM_VIDEO:
233 case GST_STREAM_IMAGE:
234 desc = gst_stream_video_information_to_string (
235 (GstStreamVideoInformation *) info,
236 GPOINTER_TO_INT (depth) + 1);
244 g_print ("%s", desc);
250 print_topology (GstStreamInformation * info, gint depth)
255 print_stream_info (info, GINT_TO_POINTER (depth));
258 print_topology (info->next, depth + 1);
259 else if (info->streamtype == GST_STREAM_CONTAINER) {
260 GstStreamContainerInformation *cont =
261 (GstStreamContainerInformation *) info;
264 for (tmp = cont->streams; tmp; tmp = tmp->next) {
265 GstStreamInformation *tmpinf =
266 (GstStreamInformation *) tmp->data;
267 print_topology (tmpinf, depth + 1);
273 print_duration (const GstDiscovererInformation * info, gint tab)
275 g_print ("%*s%" GST_TIME_FORMAT "\n", tab + 1, " ",
276 GST_TIME_ARGS (info->duration));
280 print_gst_info (const GstDiscovererInformation *info, GError *err)
282 /* Get done with the error parsing first */
283 if (info->result & GST_DISCOVERER_URI_INVALID)
284 g_print ("URI is not valid\n");
285 else if (info->result & GST_DISCOVERER_TIMEOUT)
286 g_print ("Timeout !\n");
287 if (info->result & GST_DISCOVERER_ERROR) {
288 g_print ("An error while discovering the file\n");
289 g_print (" %s\n", err->message);
290 if (info->result & GST_DISCOVERER_MISSING_PLUGINS) {
291 gchar *tmp = gst_structure_to_string (info->misc);
292 g_print (" (%s)\n", tmp);
299 /* Print Useful information */
302 (GST_DISCOVERER_ERROR | GST_DISCOVERER_TIMEOUT))) {
303 g_print ("\nTopology:\n");
304 print_topology (info->stream_info, 1);
305 g_print ("\nDuration:\n");
306 print_duration (info, 1);
312 print_dlna_info (GUPnPDLNAInformation *dlna, GError *err)
314 g_print ("\nURI: %s\n", gupnp_dlna_information_get_info (dlna)->uri);
315 g_print ("Profile Name: %s\n", gupnp_dlna_information_get_name (dlna));
316 g_print ("Profile MIME: %s\n", gupnp_dlna_information_get_mime (dlna));
318 print_gst_info (gupnp_dlna_information_get_info(dlna), err);
325 discoverer_done (GUPnPDLNADiscoverer *discover,
326 GUPnPDLNAInformation *dlna,
329 print_dlna_info (dlna, err);
334 discoverer_ready (GUPnPDLNADiscoverer *dc, GMainLoop *ml)
336 g_main_loop_quit (ml);
340 process_file (GUPnPDLNADiscoverer *discover, const gchar *filename)
345 GUPnPDLNAInformation *dlna;
347 if(!gst_uri_is_valid (filename)) {
348 if((dir = g_dir_open (filename, 0, NULL))) {
351 while ((entry = g_dir_read_name (dir))) {
353 path = g_strconcat (filename,
357 process_file (discover, path);
365 if (!g_path_is_absolute (filename)) {
368 cur_dir = g_get_current_dir ();
369 path = g_build_filename (cur_dir, filename, NULL);
372 path = g_strdup (filename);
375 uri = g_filename_to_uri (path, NULL, &err);
380 g_warning ("Couldn't convert filename to URI: %s\n",
387 uri = g_strdup (filename);
390 if (async == FALSE) {
391 dlna = gupnp_dlna_discoverer_discover_uri_sync (discover,
395 /* Report error to user, and free error */
397 "Unable to read file: %s\n",
402 print_dlna_info (dlna, err);
405 gupnp_dlna_discoverer_discover_uri (discover, uri);
413 async_idle_loop (PrivStruct * ps)
417 for (i = 1; i < ps->argc; i++)
418 process_file (ps->dc, ps->argv[i]);
425 main (int argc, char **argv)
428 GUPnPDLNADiscoverer *discover;
431 GOptionEntry options[] = {
432 {"timeout", 't', 0, G_OPTION_ARG_INT, &timeout,
433 "Specify timeout (in seconds, defaults to 10)", "T"},
434 {"async", 'a', 0, G_OPTION_ARG_NONE, &async,
435 "Run asynchronously", NULL},
436 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
437 "Print lot more information", NULL},
446 ctx = g_option_context_new (" - program to extract DLNA and related metadata");
447 g_option_context_add_main_entries (ctx, options, NULL);
448 g_option_context_add_group (ctx, gst_init_get_option_group ());
450 if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
452 g_print ("Error initializing: %s\n", err->message);
456 g_option_context_free (ctx);
459 g_print ("usage:%s <files>\n", argv[0]);
463 gst_init(&argc, &argv);
466 discover = gupnp_dlna_discoverer_new ((GstClockTime)
467 (timeout * GST_SECOND),
471 if (async == FALSE) {
472 for ( i = 1 ; i < argc ; i++ ) {
473 process_file (discover, argv[i]);
476 PrivStruct *ps = g_new0 (PrivStruct, 1);
477 GMainLoop *ml = g_main_loop_new (NULL, FALSE);
483 g_idle_add ((GSourceFunc) async_idle_loop, ps);
485 g_signal_connect (discover, "done",
486 (GCallback) discoverer_done, 0);
487 g_signal_connect (discover, "ready",
488 (GCallback) discoverer_ready, ml);
490 gupnp_dlna_discoverer_start (discover);
492 g_main_loop_run (ml);
494 gupnp_dlna_discoverer_stop (discover);
497 g_object_unref (discover);