f0a94123e8b7504c60fd221e61d97bb73be3882c
[platform/upstream/gstreamer.git] / tools / gst-launch.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <sys/wait.h>
5 #include <gst/gst.h>
6
7 static guint64 iterations = 0;
8 static guint64 sum = 0;
9 static guint64 min = G_MAXINT64;
10 static guint64 max = 0;
11 static GstClock *s_clock;
12
13 gboolean
14 idle_func (gpointer data)
15 {
16   gboolean busy;
17   GTimeVal tfthen, tfnow;
18   GstClockTimeDiff diff;
19
20   if (s_clock) {
21     //g_print ("%lld\n", gst_clock_get_time (s_clock));
22   }
23
24   g_get_current_time (&tfthen);
25   busy = gst_bin_iterate (GST_BIN (data));
26   iterations++;
27   g_get_current_time (&tfnow);
28
29   diff = GST_TIMEVAL_TO_TIME (tfnow) -
30          GST_TIMEVAL_TO_TIME (tfthen);
31
32   sum += diff; 
33   min = MIN (min, diff);
34   max = MAX (max, diff);
35
36   if (!busy) {
37     gst_main_quit ();
38     g_print ("execution ended after %llu iterations (sum %llu ns, average %llu ns, min %llu ns, max %llu ns)\n", 
39                     iterations, sum, sum/iterations, min, max);
40   }
41
42   return busy;
43 }
44
45 static GstElement*
46 xmllaunch_parse_cmdline (const gchar **argv) 
47 {
48   GstElement *pipeline = NULL, *e;
49   GstXML *xml;
50   gboolean err;
51   const gchar *arg;
52   gchar *element, *property, *value;
53   GList *l;
54   gint i = 0;
55   
56   if (!(arg = argv[0])) {
57     g_print ("usage: gst-xmllaunch <file.xml> [ element.property=value ... ]\n");
58     exit (1);
59   }
60   
61   xml = gst_xml_new ();
62   err = gst_xml_parse_file(xml, arg, NULL);
63   
64   if (err != TRUE) {
65     fprintf (stderr, "ERROR: parse of xml file '%s' failed\n", arg);
66     exit (1);
67   }
68   
69   l = gst_xml_get_topelements (xml);
70   if (!l) {
71     fprintf (stderr, "ERROR: no toplevel pipeline element in file '%s'\n", arg);
72     exit (1);
73   }
74     
75   if (l->next)
76     g_warning ("only one toplevel element is supported at this time");
77   
78   pipeline = GST_ELEMENT (l->data);
79   
80   while ((arg = argv[++i])) {
81     element = g_strdup (arg);
82     property = strchr (element, '.');
83     value = strchr (element, '=');
84     
85     if (!(element < property && property < value)) {
86       fprintf (stderr, "ERROR: could not parse command line argument %d: %s", i, element);
87       g_free (element);
88       exit (1);
89     }
90     
91     *property++ = '\0';
92     *value++ = '\0';
93     
94     e = gst_bin_get_by_name (GST_BIN (pipeline), element);
95     if (!e) {
96       g_warning ("element named '%s' not found", element);
97     } else {
98       gst_util_set_object_arg (G_OBJECT (e), property, value);
99     }
100     g_free (element);
101   }
102   
103   if (!l)
104     return NULL;
105   else
106     return l->data;
107 }
108
109 extern volatile gboolean glib_on_error_halt;
110 void fault_restore(void);
111
112 void fault_handler(int signum, siginfo_t *si, void *misc)
113 {
114         int spinning = TRUE;
115
116         fault_restore();
117
118         if(si->si_signo == SIGSEGV){
119                 g_print ("Caught SIGSEGV accessing address %p\n", si->si_addr);
120         }else if(si->si_signo == SIGQUIT){
121                 g_print ("Caught SIGQUIT\n");
122         }else{
123                 g_print ("signo:  %d\n",si->si_signo);
124                 g_print ("errno:  %d\n",si->si_errno);
125                 g_print ("code:   %d\n",si->si_code);
126         }
127
128         glib_on_error_halt = FALSE;
129         g_on_error_stack_trace("gst-launch");
130
131         wait(NULL);
132
133 #if 1
134         /* FIXME how do we know if we were run by libtool? */
135         g_print("Spinning.  Please run 'gdb gst-launch %d' to continue debugging, "
136                 "Ctrl-C to quit, or Ctrl-\\ to dump core.\n",
137                 getpid());
138         while(spinning)usleep(1000000);
139 #else
140         /* This spawns a gdb and attaches it to gst-launch. */
141         {
142                 char str[40];
143                 sprintf(str,"gdb -quiet gst-launch %d",getpid());
144                 system(str);
145         }
146
147         _exit(0);
148 #endif
149
150 }
151
152 void fault_restore(void)
153 {
154         struct sigaction action;
155
156         memset(&action,0,sizeof(action));
157         action.sa_handler = SIG_DFL;
158
159         sigaction(SIGSEGV, &action, NULL);
160         sigaction(SIGQUIT, &action, NULL);
161 }
162
163 void fault_setup(void)
164 {
165         struct sigaction action;
166
167         memset(&action,0,sizeof(action));
168         action.sa_sigaction = fault_handler;
169         action.sa_flags = SA_SIGINFO;
170
171         sigaction(SIGSEGV, &action, NULL);
172         sigaction(SIGQUIT, &action, NULL);
173 }
174
175 int
176 main(int argc, char *argv[])
177 {
178   /* options */
179   gboolean silent = FALSE;
180   gchar *savefile = NULL;
181   gchar *exclude_args = NULL;
182   struct poptOption options[] = {
183     {"silent",  's',  POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   &silent,   0,
184      "do not output status information", NULL},
185     {"exclude", 'X',  POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &exclude_args,  0,
186      "do not output status information of TYPE", "TYPE1,TYPE2,..."},
187     {"output",  'o',  POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0,
188      "save xml representation of pipeline to FILE and exit", "FILE"},
189     POPT_TABLEEND
190   };
191
192   GstElement *pipeline;
193   gchar **argvn;
194   GError *error = NULL;
195   gint res = 0;
196
197   free (malloc (8)); /* -lefence */
198
199         fault_setup();
200
201   gst_init_with_popt_table (&argc, &argv, options);
202   
203   /* make a null-terminated version of argv */
204   argvn = g_new0 (char*, argc);
205   memcpy (argvn, argv+1, sizeof (char*) * (argc-1));
206   if (strstr (argv[0], "gst-xmllaunch")) {
207     pipeline = xmllaunch_parse_cmdline ((const gchar**)argvn);
208   } else {
209     pipeline = (GstElement*) gst_parse_launchv ((const gchar**)argvn, &error);
210   }
211   g_free (argvn);
212
213   if (!pipeline) {
214     if (error)
215       fprintf(stderr, "ERROR: pipeline could not be constructed: %s\n", error->message);
216     else
217       fprintf(stderr, "ERROR: pipeline could not be constructed\n");
218     exit(1);
219   }
220   
221   if (!silent)
222   {
223     gchar **exclude_list = exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
224     g_signal_connect (pipeline, "deep_notify", G_CALLBACK (gst_element_default_deep_notify), exclude_list);
225   }
226   g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error), NULL);
227   
228 #ifndef GST_DISABLE_LOADSAVE
229   if (savefile) {
230     gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w"));
231   }
232 #endif
233   
234   if (!savefile) {
235     gst_buffer_print_stats();
236     gst_event_print_stats();
237
238     fprintf(stderr,"RUNNING pipeline\n");
239     if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_FAILURE) {
240       fprintf(stderr,"pipeline doesn't want to play\n");
241       res = -1;
242       goto end;
243     }
244
245     s_clock = gst_bin_get_clock (GST_BIN (pipeline));
246
247     if (!GST_FLAG_IS_SET (GST_OBJECT (pipeline), GST_BIN_SELF_SCHEDULABLE)) {
248         g_idle_add (idle_func, pipeline);
249         gst_main ();
250     } else {
251         g_print ("waiting for the state change...\n");
252         gst_element_wait_state_change (pipeline);
253         g_print ("got the state change...\n");
254     }
255
256     gst_element_set_state (pipeline, GST_STATE_NULL);
257   }
258
259 end:
260   gst_buffer_print_stats();
261   gst_event_print_stats();
262
263   gst_object_unref (GST_OBJECT (pipeline));
264
265   return res;
266 }
267