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.
37 #include <glib-object.h>
41 #include <gst/pbutils/pbutils.h>
43 #include <libgupnp-dlna/profile-loading.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;
56 GUPnPDLNADiscoverer *dc;
62 * The following functions are from gst-discoverer.c (gst-convenience/tools)
64 #define my_g_string_append_printf(str, format, ...) \
65 g_string_append_printf (str, "%*s" format, 2*depth, " ", ##__VA_ARGS__)
68 gst_stream_audio_information_to_string (GstDiscovererStreamInfo * info,
74 const GstStructure *misc;
75 const GstTagList *taglist;
76 const GstDiscovererAudioInfo *audio_info;
79 g_return_val_if_fail (info != NULL, NULL);
81 audio_info = GST_DISCOVERER_AUDIO_INFO (info);
82 s = g_string_sized_new (len);
84 my_g_string_append_printf (s, "Codec:\n");
85 caps = gst_discoverer_stream_info_get_caps (info);
86 tmp = gst_caps_to_string (caps);
87 my_g_string_append_printf (s, " %s\n", tmp);
88 gst_caps_unref (caps);
91 my_g_string_append_printf (s, "Additional info:\n");
92 misc = gst_discoverer_stream_info_get_misc (info);
94 tmp = gst_structure_to_string (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",
102 gst_discoverer_audio_info_get_channels (audio_info));
103 my_g_string_append_printf (s, "Sample rate: %u\n",
104 gst_discoverer_audio_info_get_sample_rate (audio_info));
105 my_g_string_append_printf (s, "Depth: %u\n",
106 gst_discoverer_audio_info_get_depth (audio_info));
108 my_g_string_append_printf (s, "Bitrate: %u\n",
109 gst_discoverer_audio_info_get_bitrate (audio_info));
110 my_g_string_append_printf (s, "Max bitrate: %u\n",
111 gst_discoverer_audio_info_get_max_bitrate (audio_info));
113 my_g_string_append_printf (s, "Tags:\n");
114 taglist = gst_discoverer_stream_info_get_tags (info);
116 tmp = gst_structure_to_string ((GstStructure *) taglist);
117 my_g_string_append_printf (s, " %s\n", tmp);
120 my_g_string_append_printf (s, " None\n");
123 return g_string_free (s, FALSE);
127 gst_stream_video_information_to_string (GstDiscovererStreamInfo * info,
132 const GstStructure *misc;
133 const GstTagList *taglist;
134 const GstDiscovererVideoInfo *video_info;
138 g_return_val_if_fail (info != NULL, NULL);
140 video_info = GST_DISCOVERER_VIDEO_INFO (info);
142 s = g_string_sized_new (len);
144 my_g_string_append_printf (s, "Codec:\n");
145 caps = gst_discoverer_stream_info_get_caps (info);
146 tmp = gst_caps_to_string (caps);
147 my_g_string_append_printf (s, " %s\n", tmp);
148 gst_caps_unref (caps);
151 my_g_string_append_printf (s, "Additional info:\n");
152 misc = gst_discoverer_stream_info_get_misc (info);
154 tmp = gst_structure_to_string (misc);
155 my_g_string_append_printf (s, " %s\n", tmp);
158 my_g_string_append_printf (s, " None\n");
161 my_g_string_append_printf (s, "Width: %u\n",
162 gst_discoverer_video_info_get_width (video_info));
163 my_g_string_append_printf (s, "Height: %u\n",
164 gst_discoverer_video_info_get_height (video_info));
165 my_g_string_append_printf (s, "Depth: %u\n",
166 gst_discoverer_video_info_get_depth (video_info));
168 my_g_string_append_printf (s, "Frame rate: %u/%u\n",
169 gst_discoverer_video_info_get_framerate_num (video_info),
170 gst_discoverer_video_info_get_framerate_denom (video_info));
172 my_g_string_append_printf (s, "Pixel aspect ratio: %u/%u\n",
173 gst_discoverer_video_info_get_par_num (video_info),
174 gst_discoverer_video_info_get_par_denom (video_info));
176 my_g_string_append_printf (s, "Interlaced: %s\n",
177 gst_discoverer_video_info_is_interlaced (video_info) ? "true" : "false");
179 my_g_string_append_printf (s, "Bitrate: %u\n",
180 gst_discoverer_video_info_get_bitrate (video_info));
182 my_g_string_append_printf (s, "Max bitrate: %u\n",
183 gst_discoverer_video_info_get_max_bitrate (video_info));
185 my_g_string_append_printf (s, "Tags:\n");
186 taglist = gst_discoverer_stream_info_get_tags (info);
188 tmp = gst_structure_to_string ((GstStructure *) taglist);
189 my_g_string_append_printf (s, " %s\n", tmp);
192 my_g_string_append_printf (s, " None\n");
196 return g_string_free (s, FALSE);
200 print_stream_info (GstDiscovererStreamInfo * info, void *depth)
205 caps = gst_discoverer_stream_info_get_caps (info);
207 desc = gst_caps_to_string (caps);
210 g_print ("%*s%s: %s\n", 2 * GPOINTER_TO_INT (depth), " ",
211 gst_discoverer_stream_info_get_stream_type_nick (info),
219 if (GST_IS_DISCOVERER_AUDIO_INFO (info))
220 desc = gst_stream_audio_information_to_string (
222 GPOINTER_TO_INT (depth) + 1);
223 else if (GST_IS_DISCOVERER_VIDEO_INFO (info))
224 desc = gst_stream_video_information_to_string (
226 GPOINTER_TO_INT (depth) + 1);
229 g_print ("%s", desc);
235 print_topology (GstDiscovererStreamInfo * info, gint depth)
237 GstDiscovererStreamInfo *next;
241 print_stream_info (info, GINT_TO_POINTER (depth));
243 next = gst_discoverer_stream_info_get_next (info);
245 print_topology (next, depth + 1);
246 gst_discoverer_stream_info_unref (next);
247 } else if (GST_IS_DISCOVERER_CONTAINER_INFO (info)) {
248 GList *tmp, *streams;
249 GstDiscovererContainerInfo *container =
250 GST_DISCOVERER_CONTAINER_INFO (info);
252 streams = gst_discoverer_container_info_get_streams (container);
253 for (tmp = streams; tmp; tmp = tmp->next) {
254 GstDiscovererStreamInfo *tmpinf =
255 GST_DISCOVERER_STREAM_INFO (tmp->data);
256 print_topology (tmpinf, depth + 1);
262 print_duration (GstDiscovererInfo * info, gint tab)
264 g_print ("%*s%" GST_TIME_FORMAT "\n", tab + 1, " ",
265 GST_TIME_ARGS (gst_discoverer_info_get_duration (info)));
269 print_gst_info (GstDiscovererInfo *info, GError *err)
271 GstDiscovererResult result = gst_discoverer_info_get_result (info);
272 GstDiscovererStreamInfo *sinfo;
275 case GST_DISCOVERER_OK:
277 case GST_DISCOVERER_URI_INVALID:
278 g_print ("URI is not valid\n");
280 case GST_DISCOVERER_ERROR:
281 g_print ("An error was encountered while discovering the file\n");
282 g_print (" %s\n", err->message);
284 case GST_DISCOVERER_TIMEOUT:
285 g_print ("Analyzing URI timed out\n");
287 case GST_DISCOVERER_BUSY:
288 g_print ("Discoverer was busy\n");
290 case GST_DISCOVERER_MISSING_PLUGINS:
291 g_print ("Missing plugins\n");
294 gst_structure_to_string (gst_discoverer_info_get_misc (info));
295 g_print (" (%s)\n", tmp);
302 if ((sinfo = gst_discoverer_info_get_stream_info (info))) {
303 g_print ("\nTopology:\n");
304 print_topology (sinfo, 1);
305 g_print ("\nDuration:\n");
306 print_duration (info, 1);
307 gst_discoverer_stream_info_unref (sinfo);
315 print_dlna_info (GUPnPDLNAInformation *dlna, GError *err)
317 GstDiscovererInfo *info;
319 info = (GstDiscovererInfo *)gupnp_dlna_information_get_info (dlna);
321 g_print ("\nURI: %s\n", gst_discoverer_info_get_uri (info));
322 g_print ("Profile Name: %s\n", gupnp_dlna_information_get_name (dlna));
323 g_print ("Profile MIME: %s\n", gupnp_dlna_information_get_mime (dlna));
325 print_gst_info ((GstDiscovererInfo *)info, err);
332 discoverer_done (GUPnPDLNADiscoverer *discover,
333 GUPnPDLNAInformation *dlna,
336 print_dlna_info (dlna, err);
341 discoverer_ready (GUPnPDLNADiscoverer *dc, GMainLoop *ml)
343 g_main_loop_quit (ml);
347 process_file (GUPnPDLNADiscoverer *discover, const gchar *filename)
352 GUPnPDLNAInformation *dlna;
354 if(!gst_uri_is_valid (filename)) {
355 if((dir = g_dir_open (filename, 0, NULL))) {
358 while ((entry = g_dir_read_name (dir))) {
360 path = g_strconcat (filename,
364 process_file (discover, path);
372 if (!g_path_is_absolute (filename)) {
375 cur_dir = g_get_current_dir ();
376 path = g_build_filename (cur_dir, filename, NULL);
379 path = g_strdup (filename);
382 uri = g_filename_to_uri (path, NULL, &err);
387 g_warning ("Couldn't convert filename to URI: %s\n",
394 uri = g_strdup (filename);
397 if (async == FALSE) {
398 dlna = gupnp_dlna_discoverer_discover_uri_sync (discover,
402 /* Report error to user, and free error */
404 "Unable to read file: %s\n",
409 print_dlna_info (dlna, err);
412 gupnp_dlna_discoverer_discover_uri (discover, uri);
419 async_idle_loop (PrivStruct * ps)
423 for (i = 1; i < ps->argc; i++)
424 process_file (ps->dc, ps->argv[i]);
431 main (int argc, char **argv)
434 GUPnPDLNADiscoverer *discover;
435 gboolean relaxed_mode = FALSE;
436 gboolean extended_mode = FALSE;
439 GOptionEntry options[] = {
440 {"timeout", 't', 0, G_OPTION_ARG_INT, &timeout,
441 "Specify timeout (in seconds, defaults to 10)", "T"},
442 {"async", 'a', 0, G_OPTION_ARG_NONE, &async,
443 "Run asynchronously", NULL},
444 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
445 "Print lot more information", NULL},
446 {"relaxed mode", 'r', 0, G_OPTION_ARG_NONE, &relaxed_mode,
447 "Enable Relaxed mode", NULL},
448 {"extended mode", 'e', 0, G_OPTION_ARG_NONE, &extended_mode,
449 "Enable extended mode", NULL},
455 if (!g_thread_supported ())
458 ctx = g_option_context_new (" - program to extract DLNA and related metadata");
459 g_option_context_add_main_entries (ctx, options, NULL);
460 g_option_context_add_group (ctx, gst_init_get_option_group ());
462 if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
464 g_print ("Error initializing: %s\n", err->message);
468 g_option_context_free (ctx);
471 g_print ("usage:%s <files>\n", argv[0]);
475 gst_init(&argc, &argv);
477 discover = gupnp_dlna_discoverer_new ((GstClockTime)
478 (timeout * GST_SECOND),
482 if (async == FALSE) {
483 for ( i = 1 ; i < argc ; i++ )
484 process_file (discover, argv[i]);
486 PrivStruct *ps = g_new0 (PrivStruct, 1);
487 GMainLoop *ml = g_main_loop_new (NULL, FALSE);
493 g_idle_add ((GSourceFunc) async_idle_loop, ps);
495 g_signal_connect (discover, "done",
496 (GCallback) discoverer_done, 0);
497 g_signal_connect (discover, "finished",
498 (GCallback) discoverer_ready, ml);
500 gupnp_dlna_discoverer_start (discover);
502 g_main_loop_run (ml);
504 gupnp_dlna_discoverer_stop (discover);
507 g_object_unref (discover);