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 Lesser 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 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser 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>
43 #include <libgupnp-dlna/gupnp-dlna-load.h>
44 #include <libgupnp-dlna/gupnp-dlna-profile.h>
45 #include <libgupnp-dlna/gupnp-dlna-discoverer.h>
46 #include <libgupnp-dlna/gupnp-dlna-information.h>
49 static gboolean async = FALSE;
50 static gboolean verbose = FALSE;
51 static gint timeout = 10;
53 static const gchar *_gst_stream_type_to_string[] = {
64 GUPnPDLNADiscoverer *dc;
70 * The following functions are from gst-discoverer.c (gst-convenience/tools)
72 #define my_g_string_append_printf(str, format, ...) \
73 g_string_append_printf (str, "%*s" format, 2*depth, " ", ##__VA_ARGS__)
76 gst_stream_audio_information_to_string (GstStreamAudioInformation * info,
83 g_return_val_if_fail (info != NULL, NULL);
85 s = g_string_sized_new (len);
87 my_g_string_append_printf (s, "Codec:\n");
88 tmp = gst_caps_to_string (info->parent.caps);
89 my_g_string_append_printf (s, " %s\n", tmp);
92 my_g_string_append_printf (s, "Additional info:\n");
93 if (info->parent.misc) {
94 tmp = gst_structure_to_string (info->parent.misc);
95 my_g_string_append_printf (s, " %s\n", tmp);
98 my_g_string_append_printf (s, " None\n");
101 my_g_string_append_printf (s, "Channels: %u\n", info->channels);
102 my_g_string_append_printf (s, "Sample rate: %u\n", info->sample_rate);
103 my_g_string_append_printf (s, "Depth: %u\n", info->depth);
105 my_g_string_append_printf (s, "Bitrate: %u\n", info->bitrate);
106 my_g_string_append_printf (s, "Max bitrate: %u\n", info->max_bitrate);
107 my_g_string_append_printf (s, "VBR: %s\n",
108 info->is_vbr ? "true" : "false");
110 my_g_string_append_printf (s, "Tags:\n");
111 if (info->parent.tags) {
112 tmp = gst_structure_to_string ((GstStructure *) info->parent.tags);
113 my_g_string_append_printf (s, " %s\n", tmp);
116 my_g_string_append_printf (s, " None\n");
119 return g_string_free (s, FALSE);
122 static const gchar *_gst_video_format_to_string[] = {
148 gst_stream_video_information_to_string (GstStreamVideoInformation * info,
155 g_return_val_if_fail (info != NULL, NULL);
157 s = g_string_sized_new (len);
159 my_g_string_append_printf (s, "Codec:\n");
160 tmp = gst_caps_to_string (info->parent.caps);
161 my_g_string_append_printf (s, " %s\n", tmp);
164 my_g_string_append_printf (s, "Additional info:\n");
165 if (info->parent.misc) {
166 tmp = gst_structure_to_string (info->parent.misc);
167 my_g_string_append_printf (s, " %s\n", tmp);
170 my_g_string_append_printf (s, " None\n");
173 my_g_string_append_printf (s, "Width: %u\n", info->width);
174 my_g_string_append_printf (s, "Height: %u\n", info->height);
175 my_g_string_append_printf (s, "Depth: %u\n", info->depth);
177 n = gst_value_get_fraction_numerator (&info->frame_rate);
178 d = gst_value_get_fraction_denominator (&info->frame_rate);
179 my_g_string_append_printf (s, "Frame rate: %u/%u\n", n, d);
181 n = gst_value_get_fraction_numerator (&info->pixel_aspect_ratio);
182 d = gst_value_get_fraction_denominator (&info->pixel_aspect_ratio);
183 my_g_string_append_printf (s, "Pixel aspect ratio: %u/%u\n", n, d);
185 my_g_string_append_printf (s, "Format: %s\n",
186 _gst_video_format_to_string[info->format]);
188 my_g_string_append_printf (s, "Interlaced: %s\n",
189 info->interlaced ? "true" : "false");
191 my_g_string_append_printf (s, "Tags:\n");
192 if (info->parent.tags) {
193 tmp = gst_structure_to_string ((GstStructure *) info->parent.tags);
194 my_g_string_append_printf (s, " %s\n", tmp);
197 my_g_string_append_printf (s, " None\n");
201 return g_string_free (s, FALSE);
205 print_stream_info (GstStreamInformation * info, void *depth)
210 desc = gst_caps_to_string (info->caps);
213 g_print ("%*s%s: %s\n", 2 * GPOINTER_TO_INT (depth), " ",
214 _gst_stream_type_to_string[info->streamtype], desc);
221 switch (info->streamtype) {
222 case GST_STREAM_AUDIO:
223 desc = gst_stream_audio_information_to_string (
224 (GstStreamAudioInformation *) info,
225 GPOINTER_TO_INT (depth) + 1);
228 case GST_STREAM_VIDEO:
229 case GST_STREAM_IMAGE:
230 desc = gst_stream_video_information_to_string (
231 (GstStreamVideoInformation *) info,
232 GPOINTER_TO_INT (depth) + 1);
240 g_print ("%s", desc);
246 print_topology (GstStreamInformation * info, gint depth)
251 print_stream_info (info, GINT_TO_POINTER (depth));
254 print_topology (info->next, depth + 1);
255 else if (info->streamtype == GST_STREAM_CONTAINER) {
256 GstStreamContainerInformation *cont =
257 (GstStreamContainerInformation *) info;
260 for (tmp = cont->streams; tmp; tmp = tmp->next) {
261 GstStreamInformation *tmpinf =
262 (GstStreamInformation *) tmp->data;
263 print_topology (tmpinf, depth + 1);
269 print_duration (const GstDiscovererInformation * info, gint tab)
271 g_print ("%*s%" GST_TIME_FORMAT "\n", tab + 1, " ",
272 GST_TIME_ARGS (info->duration));
276 print_gst_info (const GstDiscovererInformation *info, GError *err)
278 /* Get done with the error parsing first */
279 if (info->result & GST_DISCOVERER_URI_INVALID)
280 g_print ("URI is not valid\n");
281 else if (info->result & GST_DISCOVERER_TIMEOUT)
282 g_print ("Timeout !\n");
283 if (info->result & GST_DISCOVERER_ERROR) {
284 g_print ("An error while discovering the file\n");
285 g_print (" %s\n", err->message);
286 if (info->result & GST_DISCOVERER_MISSING_PLUGINS) {
287 gchar *tmp = gst_structure_to_string (info->misc);
288 g_print (" (%s)\n", tmp);
295 /* Print Useful information */
298 (GST_DISCOVERER_ERROR | GST_DISCOVERER_TIMEOUT))) {
299 g_print ("\nTopology:\n");
300 print_topology (info->stream_info, 1);
301 g_print ("\nDuration:\n");
302 print_duration (info, 1);
308 print_dlna_info (GUPnPDLNAInformation *dlna, GError *err)
310 g_print ("\nURI: %s\n", gupnp_dlna_information_get_info (dlna)->uri);
311 g_print ("Profile Name: %s\n", gupnp_dlna_information_get_name (dlna));
312 g_print ("Profile MIME: %s\n", gupnp_dlna_information_get_mime (dlna));
314 print_gst_info (gupnp_dlna_information_get_info(dlna), err);
321 discoverer_done (GUPnPDLNADiscoverer *discover,
322 GUPnPDLNAInformation *dlna,
325 print_dlna_info (dlna, err);
330 discoverer_ready (GUPnPDLNADiscoverer *dc, GMainLoop *ml)
332 g_main_loop_quit (ml);
336 process_file (GUPnPDLNADiscoverer *discover, const gchar *filename)
341 GUPnPDLNAInformation *dlna;
343 if(!gst_uri_is_valid (filename)) {
344 if((dir = g_dir_open (filename, 0, NULL))) {
347 while ((entry = g_dir_read_name (dir))) {
349 path = g_strconcat (filename,
353 process_file (discover, path);
361 if (!g_path_is_absolute (filename)) {
364 cur_dir = g_get_current_dir ();
365 path = g_build_filename (cur_dir, filename, NULL);
368 path = g_strdup (filename);
371 uri = g_filename_to_uri (path, NULL, &err);
376 g_warning ("Couldn't convert filename to URI: %s\n",
383 uri = g_strdup (filename);
386 if (async == FALSE) {
387 dlna = gupnp_dlna_discoverer_discover_uri_sync (discover,
391 /* Report error to user, and free error */
393 "Unable to read file: %s\n",
398 print_dlna_info (dlna, err);
401 gupnp_dlna_discoverer_discover_uri (discover, uri);
409 async_idle_loop (PrivStruct * ps)
413 for (i = 1; i < ps->argc; i++)
414 process_file (ps->dc, ps->argv[i]);
421 main (int argc, char **argv)
424 GUPnPDLNADiscoverer *discover;
425 gboolean relaxed_mode = FALSE;
426 gboolean extended_mode = FALSE;
429 GOptionEntry options[] = {
430 {"timeout", 't', 0, G_OPTION_ARG_INT, &timeout,
431 "Specify timeout (in seconds, defaults to 10)", "T"},
432 {"async", 'a', 0, G_OPTION_ARG_NONE, &async,
433 "Run asynchronously", NULL},
434 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
435 "Print lot more information", NULL},
436 {"relaxed mode", 'r', 0, G_OPTION_ARG_NONE, &relaxed_mode,
437 "Enable Relaxed mode", NULL},
438 {"extended mode", 'e', 0, G_OPTION_ARG_NONE, &extended_mode,
439 "Enable extended mode", NULL},
448 ctx = g_option_context_new (" - program to extract DLNA and related metadata");
449 g_option_context_add_main_entries (ctx, options, NULL);
450 g_option_context_add_group (ctx, gst_init_get_option_group ());
452 if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
454 g_print ("Error initializing: %s\n", err->message);
458 g_option_context_free (ctx);
461 g_print ("usage:%s <files>\n", argv[0]);
465 gst_init(&argc, &argv);
468 discover = gupnp_dlna_discoverer_new ((GstClockTime)
469 (timeout * GST_SECOND),
473 if (async == FALSE) {
474 for ( i = 1 ; i < argc ; i++ ) {
475 process_file (discover, argv[i]);
478 PrivStruct *ps = g_new0 (PrivStruct, 1);
479 GMainLoop *ml = g_main_loop_new (NULL, FALSE);
485 g_idle_add ((GSourceFunc) async_idle_loop, ps);
487 g_signal_connect (discover, "done",
488 (GCallback) discoverer_done, 0);
489 g_signal_connect (discover, "ready",
490 (GCallback) discoverer_ready, ml);
492 gupnp_dlna_discoverer_start (discover);
494 g_main_loop_run (ml);
496 gupnp_dlna_discoverer_stop (discover);
499 g_object_unref (discover);