|
1 /* GStreamer |
|
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
|
3 * 2000 Wim Taymans <wtay@chello.be> |
|
4 * 2004 Thomas Vander Stichele <thomas@apestaart.org> |
|
5 * |
|
6 * gst-launch.c: tool to launch GStreamer pipelines from the command line |
|
7 * |
|
8 * This library is free software; you can redistribute it and/or |
|
9 * modify it under the terms of the GNU Library General Public |
|
10 * License as published by the Free Software Foundation; either |
|
11 * version 2 of the License, or (at your option) any later version. |
|
12 * |
|
13 * This library is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * Library General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU Library General Public |
|
19 * License along with this library; if not, write to the |
|
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
21 * Boston, MA 02111-1307, USA. |
|
22 */ |
|
23 |
|
24 #ifdef HAVE_CONFIG_H |
|
25 # include "config.h" |
|
26 #endif |
|
27 |
|
28 /* FIXME: hack alert */ |
|
29 #ifdef WIN32 |
|
30 #define DISABLE_FAULT_HANDLER |
|
31 #endif |
|
32 |
|
33 #include <string.h> |
|
34 #include <signal.h> |
|
35 #ifdef HAVE_UNISTD_H |
|
36 #include <unistd.h> |
|
37 #endif |
|
38 #ifndef DISABLE_FAULT_HANDLER |
|
39 #include <sys/wait.h> |
|
40 #endif |
|
41 #include <locale.h> /* for LC_ALL */ |
|
42 #include "tools.h" |
|
43 |
|
44 /* FIXME: This is just a temporary hack. We should have a better |
|
45 * check for siginfo handling. */ |
|
46 #ifdef SA_SIGINFO |
|
47 #define USE_SIGINFO |
|
48 #endif |
|
49 |
|
50 extern volatile gboolean glib_on_error_halt; |
|
51 |
|
52 #ifndef DISABLE_FAULT_HANDLER |
|
53 static void fault_restore (void); |
|
54 static void fault_spin (void); |
|
55 static void sigint_restore (void); |
|
56 static gboolean caught_intr = FALSE; |
|
57 #endif |
|
58 |
|
59 static GstElement *pipeline; |
|
60 static gboolean caught_error = FALSE; |
|
61 static gboolean tags = FALSE; |
|
62 static gboolean messages = FALSE; |
|
63 static gboolean is_live = FALSE; |
|
64 |
|
65 |
|
66 #ifndef GST_DISABLE_LOADSAVE |
|
67 static GstElement * |
|
68 xmllaunch_parse_cmdline (const gchar ** argv) |
|
69 { |
|
70 GstElement *pipeline = NULL, *e; |
|
71 GstXML *xml; |
|
72 gboolean err; |
|
73 const gchar *arg; |
|
74 gchar *element, *property, *value; |
|
75 GList *l; |
|
76 gint i = 0; |
|
77 |
|
78 if (!(arg = argv[0])) { |
|
79 g_print (_ |
|
80 ("Usage: gst-xmllaunch <file.xml> [ element.property=value ... ]\n")); |
|
81 exit (1); |
|
82 } |
|
83 |
|
84 xml = gst_xml_new (); |
|
85 /* FIXME guchar from gstxml.c */ |
|
86 err = gst_xml_parse_file (xml, (guchar *) arg, NULL); |
|
87 |
|
88 if (err != TRUE) { |
|
89 fprintf (stderr, _("ERROR: parse of xml file '%s' failed.\n"), arg); |
|
90 exit (1); |
|
91 } |
|
92 |
|
93 l = gst_xml_get_topelements (xml); |
|
94 if (!l) { |
|
95 fprintf (stderr, _("ERROR: no toplevel pipeline element in file '%s'.\n"), |
|
96 arg); |
|
97 exit (1); |
|
98 } |
|
99 |
|
100 if (l->next) |
|
101 fprintf (stderr, |
|
102 _("WARNING: only one toplevel element is supported at this time.")); |
|
103 |
|
104 pipeline = GST_ELEMENT (l->data); |
|
105 |
|
106 while ((arg = argv[++i])) { |
|
107 element = g_strdup (arg); |
|
108 property = strchr (element, '.'); |
|
109 value = strchr (element, '='); |
|
110 |
|
111 if (!(element < property && property < value)) { |
|
112 fprintf (stderr, |
|
113 _("ERROR: could not parse command line argument %d: %s.\n"), i, |
|
114 element); |
|
115 g_free (element); |
|
116 exit (1); |
|
117 } |
|
118 |
|
119 *property++ = '\0'; |
|
120 *value++ = '\0'; |
|
121 |
|
122 e = gst_bin_get_by_name (GST_BIN (pipeline), element); |
|
123 if (!e) { |
|
124 fprintf (stderr, _("WARNING: element named '%s' not found.\n"), element); |
|
125 } else { |
|
126 gst_util_set_object_arg (G_OBJECT (e), property, value); |
|
127 } |
|
128 g_free (element); |
|
129 } |
|
130 |
|
131 if (!l) |
|
132 return NULL; |
|
133 |
|
134 gst_object_ref (pipeline); |
|
135 gst_object_unref (xml); |
|
136 return pipeline; |
|
137 } |
|
138 #endif |
|
139 |
|
140 #ifndef DISABLE_FAULT_HANDLER |
|
141 #ifndef USE_SIGINFO |
|
142 static void |
|
143 fault_handler_sighandler (int signum) |
|
144 { |
|
145 fault_restore (); |
|
146 |
|
147 /* printf is used instead of g_print(), since it's less likely to |
|
148 * deadlock */ |
|
149 switch (signum) { |
|
150 case SIGSEGV: |
|
151 printf ("Caught SIGSEGV\n"); |
|
152 break; |
|
153 case SIGQUIT: |
|
154 printf ("Caught SIGQUIT\n"); |
|
155 break; |
|
156 default: |
|
157 printf ("signo: %d\n", signum); |
|
158 break; |
|
159 } |
|
160 |
|
161 fault_spin (); |
|
162 } |
|
163 |
|
164 #else /* USE_SIGINFO */ |
|
165 |
|
166 static void |
|
167 fault_handler_sigaction (int signum, siginfo_t * si, void *misc) |
|
168 { |
|
169 fault_restore (); |
|
170 |
|
171 /* printf is used instead of g_print(), since it's less likely to |
|
172 * deadlock */ |
|
173 switch (si->si_signo) { |
|
174 case SIGSEGV: |
|
175 printf ("Caught SIGSEGV accessing address %p\n", si->si_addr); |
|
176 break; |
|
177 case SIGQUIT: |
|
178 printf ("Caught SIGQUIT\n"); |
|
179 break; |
|
180 default: |
|
181 printf ("signo: %d\n", si->si_signo); |
|
182 printf ("errno: %d\n", si->si_errno); |
|
183 printf ("code: %d\n", si->si_code); |
|
184 break; |
|
185 } |
|
186 |
|
187 fault_spin (); |
|
188 } |
|
189 #endif /* USE_SIGINFO */ |
|
190 |
|
191 static void |
|
192 fault_spin (void) |
|
193 { |
|
194 int spinning = TRUE; |
|
195 |
|
196 glib_on_error_halt = FALSE; |
|
197 g_on_error_stack_trace ("gst-launch"); |
|
198 |
|
199 wait (NULL); |
|
200 |
|
201 /* FIXME how do we know if we were run by libtool? */ |
|
202 printf ("Spinning. Please run 'gdb gst-launch %d' to continue debugging, " |
|
203 "Ctrl-C to quit, or Ctrl-\\ to dump core.\n", (gint) getpid ()); |
|
204 while (spinning) |
|
205 g_usleep (1000000); |
|
206 } |
|
207 |
|
208 static void |
|
209 fault_restore (void) |
|
210 { |
|
211 struct sigaction action; |
|
212 |
|
213 memset (&action, 0, sizeof (action)); |
|
214 action.sa_handler = SIG_DFL; |
|
215 |
|
216 sigaction (SIGSEGV, &action, NULL); |
|
217 sigaction (SIGQUIT, &action, NULL); |
|
218 } |
|
219 |
|
220 static void |
|
221 fault_setup (void) |
|
222 { |
|
223 struct sigaction action; |
|
224 |
|
225 memset (&action, 0, sizeof (action)); |
|
226 #ifdef USE_SIGINFO |
|
227 action.sa_sigaction = fault_handler_sigaction; |
|
228 action.sa_flags = SA_SIGINFO; |
|
229 #else |
|
230 action.sa_handler = fault_handler_sighandler; |
|
231 #endif |
|
232 |
|
233 sigaction (SIGSEGV, &action, NULL); |
|
234 sigaction (SIGQUIT, &action, NULL); |
|
235 } |
|
236 #endif /* DISABLE_FAULT_HANDLER */ |
|
237 |
|
238 static void |
|
239 print_tag (const GstTagList * list, const gchar * tag, gpointer unused) |
|
240 { |
|
241 gint i, count; |
|
242 |
|
243 count = gst_tag_list_get_tag_size (list, tag); |
|
244 |
|
245 for (i = 0; i < count; i++) { |
|
246 gchar *str; |
|
247 |
|
248 if (gst_tag_get_type (tag) == G_TYPE_STRING) { |
|
249 if (!gst_tag_list_get_string_index (list, tag, i, &str)) |
|
250 g_assert_not_reached (); |
|
251 } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) { |
|
252 GstBuffer *img; |
|
253 |
|
254 img = gst_value_get_buffer (gst_tag_list_get_value_index (list, tag, i)); |
|
255 if (img) { |
|
256 gchar *caps_str; |
|
257 |
|
258 caps_str = GST_BUFFER_CAPS (img) ? |
|
259 gst_caps_to_string (GST_BUFFER_CAPS (img)) : g_strdup ("unknown"); |
|
260 str = g_strdup_printf ("buffer of %u bytes, type: %s", |
|
261 GST_BUFFER_SIZE (img), caps_str); |
|
262 g_free (caps_str); |
|
263 } else { |
|
264 str = g_strdup ("NULL buffer"); |
|
265 } |
|
266 } else { |
|
267 str = |
|
268 g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i)); |
|
269 } |
|
270 |
|
271 if (i == 0) { |
|
272 g_print ("%16s: %s\n", gst_tag_get_nick (tag), str); |
|
273 } else { |
|
274 g_print ("%16s: %s\n", "", str); |
|
275 } |
|
276 |
|
277 g_free (str); |
|
278 } |
|
279 } |
|
280 |
|
281 #ifndef DISABLE_FAULT_HANDLER |
|
282 /* we only use sighandler here because the registers are not important */ |
|
283 static void |
|
284 sigint_handler_sighandler (int signum) |
|
285 { |
|
286 g_print ("Caught interrupt -- "); |
|
287 |
|
288 sigint_restore (); |
|
289 |
|
290 /* we set a flag that is checked by the mainloop, we cannot do much in the |
|
291 * interrupt handler (no mutex or other blocking stuff) */ |
|
292 caught_intr = TRUE; |
|
293 } |
|
294 |
|
295 /* is called every 50 milliseconds (20 times a second), the interrupt handler |
|
296 * will set a flag for us. We react to this by posting a message. */ |
|
297 static gboolean |
|
298 check_intr (GstElement * pipeline) |
|
299 { |
|
300 if (!caught_intr) { |
|
301 return TRUE; |
|
302 } else { |
|
303 caught_intr = FALSE; |
|
304 g_print ("handling interrupt.\n"); |
|
305 |
|
306 /* post an application specific message */ |
|
307 gst_element_post_message (GST_ELEMENT (pipeline), |
|
308 gst_message_new_application (GST_OBJECT (pipeline), |
|
309 gst_structure_new ("GstLaunchInterrupt", |
|
310 "message", G_TYPE_STRING, "Pipeline interrupted", NULL))); |
|
311 |
|
312 /* remove timeout handler */ |
|
313 return FALSE; |
|
314 } |
|
315 } |
|
316 |
|
317 static void |
|
318 sigint_setup (void) |
|
319 { |
|
320 struct sigaction action; |
|
321 |
|
322 memset (&action, 0, sizeof (action)); |
|
323 action.sa_handler = sigint_handler_sighandler; |
|
324 |
|
325 sigaction (SIGINT, &action, NULL); |
|
326 } |
|
327 |
|
328 static void |
|
329 sigint_restore (void) |
|
330 { |
|
331 struct sigaction action; |
|
332 |
|
333 memset (&action, 0, sizeof (action)); |
|
334 action.sa_handler = SIG_DFL; |
|
335 |
|
336 sigaction (SIGINT, &action, NULL); |
|
337 } |
|
338 |
|
339 static void |
|
340 play_handler (int signum) |
|
341 { |
|
342 switch (signum) { |
|
343 case SIGUSR1: |
|
344 g_print ("Caught SIGUSR1 - Play request.\n"); |
|
345 gst_element_set_state (pipeline, GST_STATE_PLAYING); |
|
346 break; |
|
347 case SIGUSR2: |
|
348 g_print ("Caught SIGUSR2 - Stop request.\n"); |
|
349 gst_element_set_state (pipeline, GST_STATE_NULL); |
|
350 break; |
|
351 } |
|
352 } |
|
353 |
|
354 static void |
|
355 play_signal_setup (void) |
|
356 { |
|
357 struct sigaction action; |
|
358 |
|
359 memset (&action, 0, sizeof (action)); |
|
360 action.sa_handler = play_handler; |
|
361 sigaction (SIGUSR1, &action, NULL); |
|
362 sigaction (SIGUSR2, &action, NULL); |
|
363 } |
|
364 #endif /* DISABLE_FAULT_HANDLER */ |
|
365 |
|
366 /* returns TRUE if there was an error or we caught a keyboard interrupt. */ |
|
367 static gboolean |
|
368 event_loop (GstElement * pipeline, gboolean blocking, GstState target_state) |
|
369 { |
|
370 GstBus *bus; |
|
371 GstMessage *message = NULL; |
|
372 gboolean res = FALSE; |
|
373 gboolean buffering = FALSE; |
|
374 |
|
375 bus = gst_element_get_bus (GST_ELEMENT (pipeline)); |
|
376 |
|
377 #ifndef DISABLE_FAULT_HANDLER |
|
378 g_timeout_add (50, (GSourceFunc) check_intr, pipeline); |
|
379 #endif |
|
380 |
|
381 while (TRUE) { |
|
382 message = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0); |
|
383 |
|
384 /* if the poll timed out, only when !blocking */ |
|
385 if (message == NULL) |
|
386 goto exit; |
|
387 |
|
388 /* check if we need to dump messages to the console */ |
|
389 if (messages) { |
|
390 const GstStructure *s; |
|
391 |
|
392 s = gst_message_get_structure (message); |
|
393 |
|
394 g_print (_("Got Message from element \"%s\" (%s): "), |
|
395 GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))), |
|
396 gst_message_type_get_name (GST_MESSAGE_TYPE (message))); |
|
397 if (s) { |
|
398 gchar *sstr; |
|
399 |
|
400 sstr = gst_structure_to_string (s); |
|
401 g_print ("%s\n", sstr); |
|
402 g_free (sstr); |
|
403 } else { |
|
404 g_print ("no message details\n"); |
|
405 } |
|
406 } |
|
407 |
|
408 switch (GST_MESSAGE_TYPE (message)) { |
|
409 case GST_MESSAGE_NEW_CLOCK: |
|
410 { |
|
411 GstClock *clock; |
|
412 |
|
413 gst_message_parse_new_clock (message, &clock); |
|
414 |
|
415 g_print ("New clock: %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); |
|
416 break; |
|
417 } |
|
418 case GST_MESSAGE_EOS: |
|
419 g_print (_ |
|
420 ("Got EOS from element \"%s\".\n"), |
|
421 GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); |
|
422 goto exit; |
|
423 case GST_MESSAGE_TAG: |
|
424 if (tags) { |
|
425 GstTagList *tags; |
|
426 |
|
427 gst_message_parse_tag (message, &tags); |
|
428 g_print (_("FOUND TAG : found by element \"%s\".\n"), |
|
429 GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); |
|
430 gst_tag_list_foreach (tags, print_tag, NULL); |
|
431 gst_tag_list_free (tags); |
|
432 } |
|
433 break; |
|
434 case GST_MESSAGE_INFO:{ |
|
435 GError *gerror; |
|
436 gchar *debug; |
|
437 gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message)); |
|
438 |
|
439 gst_message_parse_info (message, &gerror, &debug); |
|
440 if (debug) { |
|
441 g_print (_("INFO:\n%s\n"), debug); |
|
442 } |
|
443 g_error_free (gerror); |
|
444 g_free (debug); |
|
445 g_free (name); |
|
446 break; |
|
447 } |
|
448 case GST_MESSAGE_WARNING:{ |
|
449 GError *gerror; |
|
450 gchar *debug; |
|
451 gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message)); |
|
452 |
|
453 /* dump graph on warning */ |
|
454 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), |
|
455 GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.warning"); |
|
456 |
|
457 gst_message_parse_warning (message, &gerror, &debug); |
|
458 g_print (_("WARNING: from element %s: %s\n"), name, gerror->message); |
|
459 if (debug) { |
|
460 g_print (_("Additional debug info:\n%s\n"), debug); |
|
461 } |
|
462 g_error_free (gerror); |
|
463 g_free (debug); |
|
464 g_free (name); |
|
465 break; |
|
466 } |
|
467 case GST_MESSAGE_ERROR:{ |
|
468 GError *gerror; |
|
469 gchar *debug; |
|
470 |
|
471 /* dump graph on error */ |
|
472 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), |
|
473 GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.error"); |
|
474 |
|
475 gst_message_parse_error (message, &gerror, &debug); |
|
476 gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); |
|
477 g_error_free (gerror); |
|
478 g_free (debug); |
|
479 /* we have an error */ |
|
480 res = TRUE; |
|
481 goto exit; |
|
482 } |
|
483 case GST_MESSAGE_STATE_CHANGED:{ |
|
484 GstState old, new, pending; |
|
485 |
|
486 gst_message_parse_state_changed (message, &old, &new, &pending); |
|
487 |
|
488 /* we only care about pipeline state change messages */ |
|
489 if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline)) |
|
490 break; |
|
491 |
|
492 /* dump graph for pipeline state changes */ |
|
493 { |
|
494 gchar *dump_name = g_strdup_printf ("gst-launch.%s_%s", |
|
495 gst_element_state_get_name (old), |
|
496 gst_element_state_get_name (new)); |
|
497 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), |
|
498 GST_DEBUG_GRAPH_SHOW_ALL, dump_name); |
|
499 g_free (dump_name); |
|
500 } |
|
501 |
|
502 /* ignore when we are buffering since then we mess with the states |
|
503 * ourselves. */ |
|
504 if (buffering) { |
|
505 fprintf (stderr, |
|
506 _("Prerolled, waiting for buffering to finish...\n")); |
|
507 break; |
|
508 } |
|
509 |
|
510 /* if we reached the final target state, exit */ |
|
511 if (target_state == GST_STATE_PAUSED && new == target_state) |
|
512 goto exit; |
|
513 |
|
514 /* else not an interesting message */ |
|
515 break; |
|
516 } |
|
517 case GST_MESSAGE_BUFFERING:{ |
|
518 gint percent; |
|
519 |
|
520 gst_message_parse_buffering (message, &percent); |
|
521 fprintf (stderr, _("buffering... %d \r"), percent); |
|
522 |
|
523 /* no state management needed for live pipelines */ |
|
524 if (is_live) |
|
525 break; |
|
526 |
|
527 if (percent == 100) { |
|
528 /* a 100% message means buffering is done */ |
|
529 buffering = FALSE; |
|
530 /* if the desired state is playing, go back */ |
|
531 if (target_state == GST_STATE_PLAYING) { |
|
532 fprintf (stderr, |
|
533 _("Done buffering, setting pipeline to PLAYING ...\n")); |
|
534 gst_element_set_state (pipeline, GST_STATE_PLAYING); |
|
535 } else |
|
536 goto exit; |
|
537 } else { |
|
538 /* buffering busy */ |
|
539 if (buffering == FALSE && target_state == GST_STATE_PLAYING) { |
|
540 /* we were not buffering but PLAYING, PAUSE the pipeline. */ |
|
541 fprintf (stderr, _("Buffering, setting pipeline to PAUSED ...\n")); |
|
542 gst_element_set_state (pipeline, GST_STATE_PAUSED); |
|
543 } |
|
544 buffering = TRUE; |
|
545 } |
|
546 break; |
|
547 } |
|
548 case GST_MESSAGE_APPLICATION:{ |
|
549 const GstStructure *s; |
|
550 |
|
551 s = gst_message_get_structure (message); |
|
552 |
|
553 if (gst_structure_has_name (s, "GstLaunchInterrupt")) { |
|
554 /* this application message is posted when we caught an interrupt and |
|
555 * we need to stop the pipeline. */ |
|
556 fprintf (stderr, _("Interrupt: Stopping pipeline ...\n")); |
|
557 /* return TRUE when we caught an interrupt */ |
|
558 res = TRUE; |
|
559 goto exit; |
|
560 } |
|
561 } |
|
562 default: |
|
563 /* just be quiet by default */ |
|
564 break; |
|
565 } |
|
566 if (message) |
|
567 gst_message_unref (message); |
|
568 } |
|
569 g_assert_not_reached (); |
|
570 |
|
571 exit: |
|
572 { |
|
573 if (message) |
|
574 gst_message_unref (message); |
|
575 gst_object_unref (bus); |
|
576 return res; |
|
577 } |
|
578 } |
|
579 |
|
580 int |
|
581 main (int argc, char *argv[]) |
|
582 { |
|
583 /* options */ |
|
584 gboolean verbose = FALSE; |
|
585 gboolean no_fault = FALSE; |
|
586 gboolean trace = FALSE; |
|
587 gchar *savefile = NULL; |
|
588 gchar *exclude_args = NULL; |
|
589 GOptionEntry options[] = { |
|
590 {"tags", 't', 0, G_OPTION_ARG_NONE, &tags, |
|
591 N_("Output tags (also known as metadata)"), NULL}, |
|
592 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, |
|
593 N_("Output status information and property notifications"), NULL}, |
|
594 {"messages", 'm', 0, G_OPTION_ARG_NONE, &messages, |
|
595 N_("Output messages"), NULL}, |
|
596 {"exclude", 'X', 0, G_OPTION_ARG_NONE, &exclude_args, |
|
597 N_("Do not output status information of TYPE"), N_("TYPE1,TYPE2,...")}, |
|
598 #ifndef GST_DISABLE_LOADSAVE |
|
599 {"output", 'o', 0, G_OPTION_ARG_STRING, &savefile, |
|
600 N_("Save xml representation of pipeline to FILE and exit"), N_("FILE")}, |
|
601 #endif |
|
602 {"no-fault", 'f', 0, G_OPTION_ARG_NONE, &no_fault, |
|
603 N_("Do not install a fault handler"), NULL}, |
|
604 {"trace", 'T', 0, G_OPTION_ARG_NONE, &trace, |
|
605 N_("Print alloc trace (if enabled at compile time)"), NULL}, |
|
606 GST_TOOLS_GOPTION_VERSION, |
|
607 {NULL} |
|
608 }; |
|
609 GOptionContext *ctx; |
|
610 GError *err = NULL; |
|
611 gchar **argvn; |
|
612 GError *error = NULL; |
|
613 gint res = 0; |
|
614 |
|
615 free (malloc (8)); /* -lefence */ |
|
616 |
|
617 #ifdef ENABLE_NLS |
|
618 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); |
|
619 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); |
|
620 textdomain (GETTEXT_PACKAGE); |
|
621 #endif |
|
622 |
|
623 if (!g_thread_supported ()) |
|
624 g_thread_init (NULL); |
|
625 |
|
626 gst_alloc_trace_set_flags_all (GST_ALLOC_TRACE_LIVE); |
|
627 |
|
628 ctx = g_option_context_new ("PIPELINE-DESCRIPTION"); |
|
629 g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE); |
|
630 g_option_context_add_group (ctx, gst_init_get_option_group ()); |
|
631 if (!g_option_context_parse (ctx, &argc, &argv, &err)) { |
|
632 if (err) |
|
633 g_print ("Error initializing: %s\n", GST_STR_NULL (err->message)); |
|
634 else |
|
635 g_print ("Error initializing: Unknown error!\n"); |
|
636 exit (1); |
|
637 } |
|
638 g_option_context_free (ctx); |
|
639 |
|
640 gst_tools_print_version ("gst-launch"); |
|
641 |
|
642 #ifndef DISABLE_FAULT_HANDLER |
|
643 if (!no_fault) |
|
644 fault_setup (); |
|
645 |
|
646 sigint_setup (); |
|
647 play_signal_setup (); |
|
648 #endif |
|
649 |
|
650 if (trace) { |
|
651 if (!gst_alloc_trace_available ()) { |
|
652 g_warning ("Trace not available (recompile with trace enabled)."); |
|
653 } |
|
654 gst_alloc_trace_print_live (); |
|
655 } |
|
656 |
|
657 /* make a null-terminated version of argv */ |
|
658 argvn = g_new0 (char *, argc); |
|
659 memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1)); |
|
660 #ifndef GST_DISABLE_LOADSAVE |
|
661 if (strstr (argv[0], "gst-xmllaunch")) { |
|
662 pipeline = xmllaunch_parse_cmdline ((const gchar **) argvn); |
|
663 } else |
|
664 #endif |
|
665 { |
|
666 pipeline = |
|
667 (GstElement *) gst_parse_launchv ((const gchar **) argvn, &error); |
|
668 } |
|
669 g_free (argvn); |
|
670 |
|
671 if (!pipeline) { |
|
672 if (error) { |
|
673 fprintf (stderr, _("ERROR: pipeline could not be constructed: %s.\n"), |
|
674 GST_STR_NULL (error->message)); |
|
675 g_error_free (error); |
|
676 } else { |
|
677 fprintf (stderr, _("ERROR: pipeline could not be constructed.\n")); |
|
678 } |
|
679 return 1; |
|
680 } else if (error) { |
|
681 fprintf (stderr, _("WARNING: erroneous pipeline: %s\n"), |
|
682 GST_STR_NULL (error->message)); |
|
683 g_error_free (error); |
|
684 return 1; |
|
685 } |
|
686 |
|
687 if (verbose) { |
|
688 gchar **exclude_list = |
|
689 exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL; |
|
690 g_signal_connect (pipeline, "deep_notify", |
|
691 G_CALLBACK (gst_object_default_deep_notify), exclude_list); |
|
692 } |
|
693 #ifndef GST_DISABLE_LOADSAVE |
|
694 if (savefile) { |
|
695 gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w")); |
|
696 } |
|
697 #endif |
|
698 |
|
699 if (!savefile) { |
|
700 GstState state, pending; |
|
701 GstStateChangeReturn ret; |
|
702 |
|
703 /* If the top-level object is not a pipeline, place it in a pipeline. */ |
|
704 if (!GST_IS_PIPELINE (pipeline)) { |
|
705 GstElement *real_pipeline = gst_element_factory_make ("pipeline", NULL); |
|
706 |
|
707 if (real_pipeline == NULL) { |
|
708 fprintf (stderr, _("ERROR: the 'pipeline' element wasn't found.\n")); |
|
709 return 1; |
|
710 } |
|
711 gst_bin_add (GST_BIN (real_pipeline), pipeline); |
|
712 pipeline = real_pipeline; |
|
713 } |
|
714 fprintf (stderr, _("Setting pipeline to PAUSED ...\n")); |
|
715 ret = gst_element_set_state (pipeline, GST_STATE_PAUSED); |
|
716 |
|
717 switch (ret) { |
|
718 case GST_STATE_CHANGE_FAILURE: |
|
719 fprintf (stderr, _("ERROR: Pipeline doesn't want to pause.\n")); |
|
720 res = -1; |
|
721 event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING); |
|
722 goto end; |
|
723 case GST_STATE_CHANGE_NO_PREROLL: |
|
724 fprintf (stderr, _("Pipeline is live and does not need PREROLL ...\n")); |
|
725 is_live = TRUE; |
|
726 break; |
|
727 case GST_STATE_CHANGE_ASYNC: |
|
728 fprintf (stderr, _("Pipeline is PREROLLING ...\n")); |
|
729 caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED); |
|
730 if (caught_error) { |
|
731 fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n")); |
|
732 goto end; |
|
733 } |
|
734 state = GST_STATE_PAUSED; |
|
735 /* fallthrough */ |
|
736 case GST_STATE_CHANGE_SUCCESS: |
|
737 fprintf (stderr, _("Pipeline is PREROLLED ...\n")); |
|
738 break; |
|
739 } |
|
740 |
|
741 caught_error = event_loop (pipeline, FALSE, GST_STATE_PLAYING); |
|
742 |
|
743 if (caught_error) { |
|
744 fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n")); |
|
745 } else { |
|
746 GstClockTime tfthen, tfnow; |
|
747 GstClockTimeDiff diff; |
|
748 |
|
749 fprintf (stderr, _("Setting pipeline to PLAYING ...\n")); |
|
750 if (gst_element_set_state (pipeline, |
|
751 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { |
|
752 GstMessage *err_msg; |
|
753 GstBus *bus; |
|
754 |
|
755 fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n")); |
|
756 bus = gst_element_get_bus (pipeline); |
|
757 if ((err_msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0))) { |
|
758 GError *gerror; |
|
759 gchar *debug; |
|
760 |
|
761 gst_message_parse_error (err_msg, &gerror, &debug); |
|
762 gst_object_default_error (GST_MESSAGE_SRC (err_msg), gerror, debug); |
|
763 gst_message_unref (err_msg); |
|
764 g_error_free (gerror); |
|
765 g_free (debug); |
|
766 } |
|
767 gst_object_unref (bus); |
|
768 res = -1; |
|
769 goto end; |
|
770 } |
|
771 |
|
772 tfthen = gst_util_get_timestamp (); |
|
773 caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING); |
|
774 tfnow = gst_util_get_timestamp (); |
|
775 |
|
776 diff = GST_CLOCK_DIFF (tfthen, tfnow); |
|
777 |
|
778 g_print (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff); |
|
779 } |
|
780 |
|
781 /* iterate mainloop to process pending stuff */ |
|
782 while (g_main_context_iteration (NULL, FALSE)); |
|
783 |
|
784 fprintf (stderr, _("Setting pipeline to PAUSED ...\n")); |
|
785 gst_element_set_state (pipeline, GST_STATE_PAUSED); |
|
786 if (!caught_error) |
|
787 gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE); |
|
788 fprintf (stderr, _("Setting pipeline to READY ...\n")); |
|
789 gst_element_set_state (pipeline, GST_STATE_READY); |
|
790 gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE); |
|
791 |
|
792 end: |
|
793 fprintf (stderr, _("Setting pipeline to NULL ...\n")); |
|
794 gst_element_set_state (pipeline, GST_STATE_NULL); |
|
795 gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE); |
|
796 } |
|
797 |
|
798 fprintf (stderr, _("FREEING pipeline ...\n")); |
|
799 gst_object_unref (pipeline); |
|
800 |
|
801 gst_deinit (); |
|
802 if (trace) |
|
803 gst_alloc_trace_print_live (); |
|
804 |
|
805 return res; |
|
806 } |