1 /*
2 * Copyright (c) 2012-2013, Texas Instruments Incorporated
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Texas Instruments Incorporated nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Contact information for paper mail:
32 * Texas Instruments
33 * Post Office Box 655303
34 * Dallas, Texas 75265
35 * Contact information:
36 * http://www-k.ext.ti.com/sc/technical-support/product-information-centers.htm?
37 * DCMP=TIHomeTracking&HQS=Other+OT+home_d_contact
38 * ============================================================================
39 *
40 */
43 /**
44 * @file gui.c
45 *
46 * @brief Defines the functions exported by the GUI.
47 * Also, defines the static functions and the callback funtions
48 */
49 #include <string.h>
50 #include <linux/limits.h>
51 #include <gtk/gtk.h>
52 #include <gdk/gdkx.h>
53 #include <gst/interfaces/xoverlay.h>
55 #include <gui.h>
56 #include <common.h>
57 #include <gst-controller.h>
59 /******************************************************************************
61 Static variables declaration
63 *****************************************************************************/
64 static GUIWindow *window[] = {NULL, NULL};
65 static Pipeline *pipes[] = {NULL, NULL};
66 static GtkWidget *logWindow[] = {NULL, NULL};
67 static GtkWidget *helpWindow = NULL;
70 /******************************************************************************
72 Static functions declaration
74 ******************************************************************************/
75 static gint setAbsolutePathname (gchar *file, gchar **uri) ;
76 static void setControlMode (GUIWindow *thisWindow,gint modeFlag,gint activeFlag);
77 static void setControlActive (GUIWindow *window, gboolean activeFlag);
78 static void setup();
79 static void setDecodeSwitch (gint decodeSwitch);
80 static GtkWidget *createLogWindow ();
81 static GtkWidget *createHelpWindow ();
82 static GstElement *createImageSinkFromWindow (GtkWidget * window, gchar *name);
83 static void setWindowSizeLocation ();
84 static GUIWindow *createWindow ();
86 static gboolean cbOpenClicked (GtkWidget *widget, gpointer data);
87 static gboolean cbPlayClicked (GtkWidget *widget, gpointer data);
88 static gboolean cbPauseClicked (GtkWidget *widget, gpointer data);
89 static gboolean cbStopClicked (GtkWidget *widget, gpointer data);
90 static gboolean cbForwardClicked (GtkWidget *widget, gpointer data);
91 static gboolean cbRewindClicked (GtkWidget *widget, gpointer data);
92 static gboolean cbWindowClosed (GtkWidget *widget, gpointer data);
93 static gboolean cbHelpClicked (GtkWidget *widget, gpointer data);
94 static gboolean cbTimerInterval (gpointer data);
95 static gboolean cbSeekValueChanged (GtkWidget *widget, gpointer data);
96 static gboolean cbSwitchButtonClicked (GtkWidget *widget, gpointer data);
97 static gboolean cbHelpClosed (GtkWidget *widget, gpointer data);
99 static gint setAbsolutePathname (gchar *file, gchar **uri)
100 {
101 gchar *realPath = NULL;
102 gint ret = ERR_SUCCESS;
104 if (NULL == uri){
105 return ERR_INVALIDPARAM;
106 }
108 if (NULL == file){
109 /*A BUG Here*/
110 g_printerr ("BUG: file: " __FILE__ " line: %d" "\n", __LINE__);
111 return ERR_BUG;
112 }
114 *uri = (gchar *) g_malloc (sizeof(gchar) * PATH_MAX_LEN);
115 realPath = realpath (file, realPath);
116 if (NULL == realPath) {
117 /*TODO: a debug trace here*/
118 g_printerr ("File %s not found\n", file);
119 ret = ERR_FILENOTFOUND;
120 goto destroy;
121 }
122 g_snprintf (*uri,PATH_MAX_LEN,"file://%s",realPath);
124 goto last;
126 destroy:
127 g_free(*uri);
128 *uri=NULL;
129 last:
130 free (realPath);
131 return ret;
132 }
133 /******************************************************************************
135 Callback functions definition
137 ******************************************************************************/
139 /*Timer Interval Callback Function*/
140 static gboolean cbTimerInterval(gpointer data)
141 {
142 gdouble seekScaleValue = 0.0;
143 gchar *timeLabelText = TIME_LABEL_ORIGIN;
144 GUIWindow *thisWindow = (GUIWindow *)data;
145 gboolean ret = TRUE;
147 if (DECODE_MODE_SINGLE == decodeMode) {
148 ret = DualDecode_getMediaPosition(pipes[DECODER_INDEX_SINGLE],
149 &seekScaleValue, &timeLabelText);
151 g_signal_handler_block (window[DECODER_INDEX_SINGLE]->seekScale,
152 window[DECODER_INDEX_SINGLE]->seekSignal);
153 gtk_range_set_value (GTK_RANGE(window[DECODER_INDEX_SINGLE]->seekScale),
154 seekScaleValue);
155 gtk_label_set_text (GTK_LABEL (window[DECODER_INDEX_SINGLE]->timeLabel),
156 timeLabelText);
157 g_signal_handler_unblock (GTK_RANGE (window[DECODER_INDEX_SINGLE]->seekScale),
158 window[DECODER_INDEX_SINGLE]->seekSignal);
160 g_signal_handler_block (GTK_RANGE (window[DECODER_INDEX_DOUBLE]->seekScale),
161 window[DECODER_INDEX_DOUBLE]->seekSignal);
162 gtk_range_set_value (GTK_RANGE (window[DECODER_INDEX_DOUBLE]->seekScale),
163 seekScaleValue);
164 gtk_label_set_text (GTK_LABEL (window[DECODER_INDEX_DOUBLE]->timeLabel),
165 timeLabelText);
166 g_signal_handler_unblock (GTK_RANGE (window[DECODER_INDEX_DOUBLE]->seekScale),
167 window[DECODER_INDEX_DOUBLE]->seekSignal);
168 }
169 else {
170 if (window[DECODER_INDEX_SINGLE] == thisWindow){
171 ret = DualDecode_getMediaPosition (pipes[DECODER_INDEX_SINGLE],
172 &seekScaleValue, &timeLabelText);
174 g_signal_handler_block (GTK_RANGE(window[DECODER_INDEX_SINGLE]->seekScale),
175 window[DECODER_INDEX_SINGLE]->seekSignal);
176 gtk_range_set_value (GTK_RANGE (window[DECODER_INDEX_SINGLE]->seekScale),
177 seekScaleValue);
178 gtk_label_set_text (GTK_LABEL (window[DECODER_INDEX_SINGLE]->timeLabel),
179 timeLabelText);
180 g_signal_handler_unblock (GTK_RANGE (window[DECODER_INDEX_SINGLE]->seekScale),
181 window[DECODER_INDEX_SINGLE]->seekSignal);
182 }
183 else {
184 ret = DualDecode_getMediaPosition (pipes[DECODER_INDEX_DOUBLE],
185 &seekScaleValue, &timeLabelText);
187 g_signal_handler_block (GTK_RANGE (window[DECODER_INDEX_DOUBLE]->seekScale),
188 window[DECODER_INDEX_DOUBLE]->seekSignal);
189 gtk_range_set_value (GTK_RANGE (window[DECODER_INDEX_DOUBLE]->seekScale),
190 seekScaleValue);
191 gtk_label_set_text (GTK_LABEL(window[DECODER_INDEX_DOUBLE]->timeLabel),
192 timeLabelText);
193 g_signal_handler_unblock (GTK_RANGE (window[DECODER_INDEX_DOUBLE]->seekScale),
194 window[DECODER_INDEX_DOUBLE]->seekSignal);
195 }
196 }
197 if (ret) {
198 g_free (timeLabelText);
199 }
200 return ret;
201 }
203 /*Seek Scale Changed Value Callback Function*/
204 static gboolean cbSeekValueChanged (GtkWidget *widget, gpointer data)
205 {
206 gboolean ret = TRUE;
207 GstFormat format = GST_FORMAT_TIME;
208 gint64 duration = 0;
209 gint seekPoint = 0;
210 gdouble percent = gtk_range_get_value ((GtkRange *)widget);
211 g_print ("PERCENT %f\n", percent);
212 GUIWindow *thisWindow = (GUIWindow *)data;
214 g_print ("IN SEEK VALUE CHANGED\n");
215 if (DECODE_MODE_SINGLE == decodeMode) {
217 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
218 &format,&duration);
219 seekPoint = (gint64) (duration * percent/ (gdouble)100);
220 g_print ("SEEK POINT %d\n", seekPoint);
221 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_SINGLE], seekPoint);
222 }
223 else {
224 if (window[DECODER_INDEX_SINGLE] == thisWindow){
225 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
226 &format,&duration);
227 seekPoint = (gint64) (duration * percent/ (gdouble)100);
228 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_SINGLE], seekPoint);
229 }
230 else {
231 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
232 &format,&duration);
233 seekPoint = (gint64) (duration * percent/ (gdouble)100);
234 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_DOUBLE], seekPoint);
235 }
236 }
238 return ret;
239 }
241 /*Open Button Clicked Callback Function*/
242 static gboolean cbOpenClicked (GtkWidget *widget, gpointer data)
243 {
244 gboolean ret = TRUE;
245 gchar *uri = NULL;
246 gchar *file = NULL;
247 GUIWindow *thisWindow = (GUIWindow *)data;
248 GtkWidget *fileChooser = gtk_file_chooser_dialog_new ("Open",
249 GTK_WINDOW(thisWindow->window),
250 GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_OPEN,
251 GTK_RESPONSE_OK, GTK_STOCK_CANCEL,
252 GTK_RESPONSE_CANCEL, NULL);
253 gtk_window_set_modal (GTK_WINDOW (fileChooser),TRUE);
254 gtk_window_set_destroy_with_parent (GTK_WINDOW (fileChooser),TRUE);
255 gtk_widget_set_sensitive (thisWindow->window,FALSE);
257 if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (fileChooser))) {
259 file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(fileChooser));
260 if (ERR_SUCCESS != setAbsolutePathname (file, &uri)) {
261 ret = FALSE;
262 goto last;
263 }
264 if (DECODE_MODE_SINGLE == decodeMode) {
265 filename[DECODER_INDEX_SINGLE] = uri;
266 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_PLAYING,
267 window[DECODER_INDEX_SINGLE]->activeFlag);
268 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_PLAYING,
269 window[DECODER_INDEX_DOUBLE]->activeFlag);
270 DualDecode_playMedia (pipes[DECODER_INDEX_SINGLE],
271 filename[DECODER_INDEX_SINGLE], SEEK_START);
272 }
273 else {
274 filename[DECODER_INDEX_SINGLE] = uri;
275 if (window[DECODER_INDEX_SINGLE] == thisWindow) {
276 setControlMode (window[DECODER_INDEX_SINGLE],
277 CONTROL_MODE_PLAYING,
278 window[DECODER_INDEX_SINGLE]->activeFlag);
279 DualDecode_playMedia (pipes[DECODER_INDEX_SINGLE],
280 filename[DECODER_INDEX_SINGLE], SEEK_START);
281 }
282 else {
283 filename[DECODER_INDEX_DOUBLE] = uri;
284 setControlMode (window[DECODER_INDEX_DOUBLE],
285 CONTROL_MODE_PLAYING,
286 window[DECODER_INDEX_DOUBLE]->activeFlag);
287 DualDecode_playMedia (pipes[DECODER_INDEX_DOUBLE],
288 filename[DECODER_INDEX_DOUBLE],
289 SEEK_START);
290 }
291 }
292 }
293 if (GTK_IS_WIDGET (fileChooser))
294 gtk_widget_destroy (fileChooser);
296 if (GTK_IS_WIDGET (thisWindow->window))
297 gtk_widget_set_sensitive (thisWindow->window,TRUE);
299 last: return ret;
300 }
302 /*Play Button Clicked Callback Function*/
303 static gboolean cbPlayClicked (GtkWidget *widget, gpointer data)
304 {
305 gboolean ret = TRUE;
306 GUIWindow *thisWindow = (GUIWindow *)data;
308 if (DECODE_MODE_SINGLE == decodeMode) {
309 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_PLAYING,
310 window[DECODER_INDEX_SINGLE]->activeFlag);
311 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_PLAYING,
312 window[DECODER_INDEX_DOUBLE]->activeFlag);
313 if (GST_STATE_PAUSED ==
314 DualDecode_getMediaState (pipes[DECODER_INDEX_SINGLE])) {
315 DualDecode_resumeMedia (pipes[DECODER_INDEX_SINGLE]);
316 }
317 else {
318 DualDecode_playMedia (pipes[DECODER_INDEX_SINGLE],
319 filename[DECODER_INDEX_SINGLE], SEEK_START);
320 }
321 }
322 else {
323 if (window[DECODER_INDEX_SINGLE] == thisWindow) {
324 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_PLAYING,
325 window[DECODER_INDEX_SINGLE]->activeFlag);
326 if (GST_STATE_PAUSED ==
327 DualDecode_getMediaState (pipes[DECODER_INDEX_SINGLE])) {
328 DualDecode_resumeMedia (pipes[DECODER_INDEX_SINGLE]);
329 }
330 else if (GST_STATE_READY ==
331 DualDecode_getMediaState (pipes[DECODER_INDEX_SINGLE])) {
332 g_print ("\nPipeline state is READY\n");
333 DualDecode_setPipelineSink (pipes[DECODER_INDEX_SINGLE],
334 window[DECODER_INDEX_SINGLE]->sink,
335 NULL);
336 DualDecode_playMedia (pipes[DECODER_INDEX_SINGLE], filename[0],0);
337 }
339 else {
340 DualDecode_playMedia (pipes[DECODER_INDEX_SINGLE],
341 filename[DECODER_INDEX_SINGLE],
342 SEEK_START);
343 }
344 }
345 else {
346 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_PLAYING,
347 window[DECODER_INDEX_DOUBLE]->activeFlag);
348 if (GST_STATE_PAUSED ==
349 DualDecode_getMediaState (pipes[DECODER_INDEX_DOUBLE])) {
350 DualDecode_resumeMedia (pipes[DECODER_INDEX_DOUBLE]);
351 }
352 else if (GST_STATE_READY ==
353 DualDecode_getMediaState (pipes[DECODER_INDEX_DOUBLE])) {
354 DualDecode_resumeMedia (pipes[DECODER_INDEX_DOUBLE]);
355 }
357 else {
358 DualDecode_playMedia (pipes[DECODER_INDEX_DOUBLE],
359 filename[DECODER_INDEX_DOUBLE],
360 SEEK_START);
361 }
362 }
363 }
364 return ret;
365 }
367 /*Pause Button Clicked Callback Function*/
368 static gboolean cbPauseClicked (GtkWidget *widget, gpointer data)
369 {
370 gboolean ret = TRUE;
371 GUIWindow *thisWindow = (GUIWindow *)data;
373 if (DECODE_MODE_SINGLE == decodeMode) {
374 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_PAUSED,
375 window[DECODER_INDEX_SINGLE]->activeFlag);
376 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_PAUSED,
377 window[DECODER_INDEX_DOUBLE]->activeFlag);
378 DualDecode_pauseMedia (pipes[DECODER_INDEX_SINGLE]);
379 }
380 else {
381 if (window[DECODER_INDEX_SINGLE] == thisWindow) {
382 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_PAUSED,
383 window[DECODER_INDEX_SINGLE]->activeFlag);
384 DualDecode_pauseMedia (pipes[DECODER_INDEX_SINGLE]);
385 }
386 else {
387 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_PAUSED,
388 window[DECODER_INDEX_DOUBLE]->activeFlag);
389 DualDecode_pauseMedia (pipes[DECODER_INDEX_DOUBLE]);
390 }
391 }
392 return ret;
393 }
395 /*Stop Button Clicked Callback Function*/
396 static gboolean cbStopClicked (GtkWidget *widget, gpointer data)
397 {
398 gboolean ret = TRUE;
399 GUIWindow *thisWindow = (GUIWindow *)data;
402 if (DECODE_MODE_SINGLE == decodeMode) {
403 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_STOPPED,
404 window[DECODER_INDEX_SINGLE]->activeFlag);
405 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_STOPPED,
406 window[DECODER_INDEX_DOUBLE]->activeFlag);
407 DualDecode_stopMedia (pipes[DECODER_INDEX_SINGLE]);
408 }
409 else {
410 if (window[DECODER_INDEX_SINGLE] == thisWindow) {
411 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_STOPPED,
412 window[DECODER_INDEX_SINGLE]->activeFlag);
413 DualDecode_stopMedia (pipes[DECODER_INDEX_SINGLE]);
414 }
415 else {
416 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_STOPPED,
417 window[DECODER_INDEX_DOUBLE]->activeFlag);
418 DualDecode_stopMedia (pipes[DECODER_INDEX_DOUBLE]);
419 }
420 }
421 return ret;
422 }
423 static gboolean cbForwardClicked (GtkWidget *widget, gpointer data)
424 {
425 gboolean ret = TRUE;
426 GstFormat format = GST_FORMAT_TIME;
427 gint64 duration = 0;
428 gint64 seekPoint = 0;
429 GUIWindow *thisWindow = (GUIWindow *)data;
430 gdouble percent = gtk_range_get_value ((GtkRange *) (thisWindow->seekScale));
432 g_print ("IN FORWARD CLICKED\n");
433 if (DECODE_MODE_SINGLE == decodeMode) {
435 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
436 &format,&duration);
437 seekPoint = (duration * percent/ (gdouble)100)+ FORWARD;
438 g_print ("SEEK POINT %ld\n", seekPoint);
439 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_SINGLE], seekPoint);
440 }
441 else {
442 if (window[DECODER_INDEX_SINGLE] == thisWindow) {
443 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
444 &format, &duration);
445 seekPoint = (duration * percent/ (gdouble)100) + FORWARD;
446 g_print ("SEEK POINT %ld\n", seekPoint);
447 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_SINGLE], seekPoint);
448 }
449 else {
450 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
451 &format,&duration);
452 seekPoint = (duration * percent/ (gdouble)100)+ FORWARD;
453 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_DOUBLE], seekPoint);
454 }
455 }
457 return ret;
458 }
459 static gboolean cbRewindClicked (GtkWidget *widget, gpointer data)
460 {
461 gboolean ret = TRUE;
462 GstFormat format = GST_FORMAT_TIME;
463 gint64 duration = 0;
464 gint64 seekPoint = 0;
465 GUIWindow *thisWindow = (GUIWindow *)data;
466 gdouble percent = gtk_range_get_value ((GtkRange *) (thisWindow->seekScale));
468 g_print ("IN FORWARD CLICKED\n");
469 if (DECODE_MODE_SINGLE == decodeMode) {
471 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
472 &format,&duration);
473 seekPoint = (duration * percent/ (gdouble)100) - REWIND;
474 g_print ("SEEK POINT %ld\n", seekPoint);
475 seekPoint = (seekPoint < 0) ? 0 : seekPoint;
476 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_SINGLE], seekPoint);
477 }
478 else {
479 if (window[DECODER_INDEX_SINGLE] == thisWindow) {
480 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
481 &format, &duration);
482 seekPoint = (duration * percent/ (gdouble)100) - REWIND;
483 g_print ("SEEK POINT %ld\n", seekPoint);
484 seekPoint = (seekPoint < 0) ? 0 : seekPoint;
485 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_SINGLE], seekPoint);
486 }
487 else {
488 gst_element_query_duration (pipes[DECODER_INDEX_SINGLE]->pipe,
489 &format,&duration);
490 seekPoint = (duration * percent/ (gdouble)100) - REWIND;
491 seekPoint = (seekPoint < 0) ? 0 : seekPoint;
492 ret = DualDecode_seekMedia (pipes[DECODER_INDEX_DOUBLE], seekPoint);
493 }
494 }
496 return ret;
497 }
498 static gboolean cbSwitchButtonClicked (GtkWidget *widget, gpointer data)
499 {
500 gboolean ret = TRUE;
501 gboolean noFile = FALSE;
502 GUIWindow *thisWindow = (GUIWindow *) data;
503 gint otherWindowIndex = 0;
504 gint thisWindowIndex = 0;
506 /*No file is given yet to play. Application may be just started. */
507 if (NULL == filename[DECODER_INDEX_SINGLE])
508 noFile = TRUE;
510 if (thisWindow == window[DECODER_INDEX_SINGLE]) {
511 thisWindowIndex = DECODER_INDEX_SINGLE;
512 otherWindowIndex = DECODER_INDEX_DOUBLE;
513 }
514 else
515 {
516 otherWindowIndex = DECODER_INDEX_SINGLE;
517 thisWindowIndex = DECODER_INDEX_DOUBLE;
518 }
520 switch (decodeMode) {
521 case DECODE_MODE_SINGLE :
522 setControlMode (window[otherWindowIndex],
523 window[otherWindowIndex]->modeFlag, CONTROL_MODE_ACTIVE);
524 setControlMode (thisWindow, thisWindow->modeFlag, CONTROL_MODE_ACTIVE);
526 if (FALSE == noFile) {
527 ret = DualDecode_singleToDual (pipes,
528 window[otherWindowIndex]->sink,
529 thisWindowIndex, otherWindowIndex,
530 filename[DECODER_INDEX_SINGLE]);
531 }
532 decodeMode = DECODE_MODE_DUAL;
533 setDecodeSwitch(DECODE_MODE_SINGLE);
534 break;
536 case DECODE_MODE_DUAL :
537 setControlMode (window[otherWindowIndex], thisWindow->modeFlag,
538 CONTROL_MODE_INACTIVE);
540 if (FALSE == noFile) {
541 ret = DualDecode_dualToSingle (pipes,
542 window[otherWindowIndex]->sink,
543 thisWindowIndex, otherWindowIndex);
544 }
545 decodeMode = DECODE_MODE_SINGLE;
546 setDecodeSwitch (DECODE_MODE_DUAL);
547 break;
548 }
551 return ret;
552 }
553 /*Window Close Callback Function*/
554 static gboolean cbWindowClosed (GtkWidget *widget, gpointer data){
555 DualDecode_exitApplication();
556 return TRUE;
557 }
559 static gboolean cbHelpClicked (GtkWidget *widget, gpointer data){
560 g_print ("HELP BUTTON CLICKED\n");
561 gtk_widget_show (helpWindow);
562 return TRUE;
563 }
565 static gboolean cbHelpClosed (GtkWidget *widget, gpointer data){
566 g_print ("IN HELP CLOSED\n");
567 gtk_widget_hide (helpWindow);
568 return TRUE;
569 }
570 /******************************************************************************
572 Static utility functions definition
574 ******************************************************************************/
575 static void setControlActive (GUIWindow *window, gboolean activeFlag)
576 {
577 gtk_widget_set_sensitive (window->playButton,activeFlag);
578 gtk_widget_set_sensitive (window->pauseButton,activeFlag);
579 gtk_widget_set_sensitive (window->stopButton,activeFlag);
580 gtk_widget_set_sensitive (window->rewindButton,activeFlag);
581 gtk_widget_set_sensitive (window->forwardButton,activeFlag);
582 gtk_widget_set_sensitive (window->openButton,activeFlag);
583 gtk_widget_set_sensitive (window->seekScale,activeFlag);
584 gtk_widget_set_sensitive (window->switchButton, activeFlag);
586 }
588 static void setControlMode (GUIWindow *thisWindow, gint modeFlag,
589 gint activeFlag)
590 {
591 setControlActive (thisWindow, activeFlag);
592 if (activeFlag) {
593 switch (modeFlag) {
594 case CONTROL_MODE_NO_FILE:
595 gtk_widget_set_sensitive (thisWindow->playButton,FALSE);
596 gtk_widget_set_sensitive (thisWindow->pauseButton,FALSE);
597 gtk_widget_set_sensitive (thisWindow->stopButton,FALSE);
598 gtk_widget_set_sensitive (thisWindow->rewindButton,FALSE);
599 gtk_widget_set_sensitive (thisWindow->forwardButton,FALSE);
600 gtk_widget_set_sensitive (thisWindow->seekScale,FALSE);
601 break;
602 case CONTROL_MODE_PLAYING:
603 gtk_widget_set_sensitive (thisWindow->playButton,TRUE);
604 gtk_widget_set_sensitive (thisWindow->pauseButton,TRUE);
605 gtk_widget_set_sensitive (thisWindow->stopButton,TRUE);
606 gtk_widget_set_sensitive (thisWindow->rewindButton,TRUE);
607 gtk_widget_set_sensitive (thisWindow->forwardButton,TRUE);
608 gtk_widget_set_sensitive (thisWindow->seekScale,TRUE);
609 break;
610 case CONTROL_MODE_STOPPED:
611 gtk_widget_set_sensitive (thisWindow->playButton,TRUE);
612 gtk_widget_set_sensitive (thisWindow->pauseButton,TRUE);
613 gtk_widget_set_sensitive (thisWindow->stopButton,TRUE);
614 gtk_widget_set_sensitive (thisWindow->rewindButton,TRUE);
615 gtk_widget_set_sensitive (thisWindow->forwardButton,TRUE);
616 gtk_widget_set_sensitive (thisWindow->seekScale,FALSE);
617 break;
618 case CONTROL_MODE_PAUSED:
619 gtk_widget_set_sensitive (thisWindow->playButton,TRUE);
620 gtk_widget_set_sensitive (thisWindow->pauseButton,TRUE);
621 gtk_widget_set_sensitive (thisWindow->stopButton,TRUE);
622 gtk_widget_set_sensitive (thisWindow->rewindButton,TRUE);
623 gtk_widget_set_sensitive (thisWindow->forwardButton,TRUE);
624 gtk_widget_set_sensitive (thisWindow->seekScale,TRUE);
625 break;
626 }
627 }
628 switch (modeFlag) {
629 case CONTROL_MODE_NO_FILE:
630 gtk_widget_show (thisWindow->playButton);
631 gtk_widget_hide (thisWindow->pauseButton);
633 gtk_label_set_text (GTK_LABEL(thisWindow->statusLabel),
634 LABEL_TEXT_NO_FILE);
635 gtk_label_set_text (GTK_LABEL(thisWindow->timeLabel),
636 TIME_LABEL_ORIGIN);
637 if (thisWindow->timerSignal != TIMER_SIGNAL_NONE) {
638 g_source_remove (thisWindow->timerSignal);
639 thisWindow->timerSignal = TIMER_SIGNAL_NONE;
640 }
641 break;
642 case CONTROL_MODE_PLAYING:
643 gtk_widget_show (thisWindow->pauseButton);
644 gtk_widget_hide (thisWindow->playButton);
646 gtk_label_set_text (GTK_LABEL(thisWindow->statusLabel),
647 LABEL_TEXT_PLAYING);
648 gtk_label_set_text (GTK_LABEL(thisWindow->timeLabel),
649 TIME_LABEL_ORIGIN);
651 if (thisWindow->timerSignal != TIMER_SIGNAL_NONE) {
652 g_source_remove (thisWindow->timerSignal);
653 }
654 thisWindow->timerSignal = g_timeout_add (TIMER_INTERVAL, cbTimerInterval,
655 thisWindow);
657 break;
658 case CONTROL_MODE_STOPPED:
659 gtk_widget_show (thisWindow->playButton);
660 gtk_widget_hide (thisWindow->pauseButton);
662 gtk_label_set_text (GTK_LABEL(thisWindow->statusLabel),
663 LABEL_TEXT_STOPPED);
664 gtk_label_set_text (GTK_LABEL(thisWindow->timeLabel), TIME_LABEL_ORIGIN);
666 if (thisWindow->timerSignal != TIMER_SIGNAL_NONE) {
667 g_source_remove(thisWindow->timerSignal);
668 thisWindow->timerSignal = TIMER_SIGNAL_NONE;
669 }
670 break;
671 case CONTROL_MODE_PAUSED:
672 gtk_widget_show(thisWindow->playButton);
673 gtk_widget_hide(thisWindow->pauseButton);
675 gtk_label_set_text (GTK_LABEL (thisWindow->statusLabel),
676 LABEL_TEXT_PAUSED);
677 break;
679 }
680 thisWindow->modeFlag = modeFlag;
681 thisWindow->activeFlag = activeFlag;
682 }
684 static void setDecodeSwitch (gint decodeSwitch)
685 {
686 switch (decodeSwitch) {
687 case DECODE_MODE_SINGLE:
688 gtk_button_set_label (
689 GTK_BUTTON (window[DECODER_INDEX_SINGLE]->switchButton),
690 SWITCH_TEXT_SINGLE);
691 gtk_button_set_label (
692 GTK_BUTTON (window[DECODER_INDEX_DOUBLE]->switchButton),
693 SWITCH_TEXT_SINGLE);
694 break;
695 case DECODE_MODE_DUAL:
696 gtk_button_set_label (
697 GTK_BUTTON(window[DECODER_INDEX_SINGLE]->switchButton),
698 SWITCH_TEXT_DUAL);
699 gtk_button_set_label (
700 GTK_BUTTON(window[DECODER_INDEX_DOUBLE]->switchButton),
701 SWITCH_TEXT_DUAL);
702 }
703 }
705 static void setup()
706 {
708 g_print ("SINK TO BE USED %s\n", sink);
709 gtk_widget_show_all (window[DECODER_INDEX_SINGLE]->window);
710 gtk_widget_show_all (window[DECODER_INDEX_DOUBLE]->window);
712 window[DECODER_INDEX_SINGLE]->sink = createImageSinkFromWindow (
713 window[DECODER_INDEX_SINGLE]->drawArea,
714 "windowsink0");
716 window[DECODER_INDEX_DOUBLE]->sink = createImageSinkFromWindow (
717 window[DECODER_INDEX_DOUBLE]->drawArea,
718 "windowsink1");
720 /*If any of the sinks is NULL the application exits*/
722 if (NULL == window[DECODER_INDEX_SINGLE]->sink ||
723 NULL == window[DECODER_INDEX_DOUBLE]->sink) {
724 DualDecode_exitApplication();
726 }
727 switch (decodeMode) {
728 case DECODE_MODE_NONE:
729 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_NO_FILE,
730 CONTROL_MODE_ACTIVE);
731 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_NO_FILE,
732 CONTROL_MODE_ACTIVE);
733 DualDecode_setPipelineSink (pipes[DECODER_INDEX_SINGLE],
734 window[DECODER_INDEX_SINGLE]->sink, NULL);
735 DualDecode_setPipelineSink (pipes[DECODER_INDEX_DOUBLE],
736 window[DECODER_INDEX_DOUBLE]->sink, NULL);
737 decodeMode = DECODE_MODE_DUAL;
738 setDecodeSwitch (DECODE_MODE_SINGLE);
739 break;
740 case DECODE_MODE_SINGLE:
741 setControlMode (window[DECODER_INDEX_SINGLE],
742 CONTROL_MODE_PLAYING, CONTROL_MODE_ACTIVE);
743 setControlMode (window[DECODER_INDEX_DOUBLE],CONTROL_MODE_PLAYING,
744 CONTROL_MODE_INACTIVE);
745 DualDecode_setPipelineSink (pipes[DECODER_INDEX_SINGLE],
746 window[DECODER_INDEX_SINGLE]->sink,
747 window[DECODER_INDEX_DOUBLE]->sink);
748 DualDecode_setPipelineSink (pipes[DECODER_INDEX_DOUBLE], NULL, NULL);
749 DualDecode_playMedia (pipes[DECODER_INDEX_SINGLE],
750 filename[DECODER_INDEX_SINGLE], SEEK_START);
751 setDecodeSwitch (DECODE_MODE_DUAL);
752 break;
753 case DECODE_MODE_DUAL:
754 setControlMode (window[DECODER_INDEX_SINGLE], CONTROL_MODE_PLAYING,
755 CONTROL_MODE_ACTIVE);
756 DualDecode_setPipelineSink (pipes[DECODER_INDEX_SINGLE],
757 window[DECODER_INDEX_SINGLE]->sink, NULL);
758 DualDecode_setPipelineSink (pipes[DECODER_INDEX_DOUBLE],
759 window[DECODER_INDEX_DOUBLE]->sink, NULL);
761 DualDecode_playMedia (pipes[DECODER_INDEX_SINGLE],
762 filename[DECODER_INDEX_SINGLE], SEEK_START);
763 setControlMode (window[DECODER_INDEX_DOUBLE], CONTROL_MODE_PLAYING,
764 CONTROL_MODE_ACTIVE);
765 DualDecode_playMedia (pipes[DECODER_INDEX_DOUBLE],
766 filename[DECODER_INDEX_DOUBLE], SEEK_START);
767 setDecodeSwitch (DECODE_MODE_SINGLE);
768 break;
769 }
770 }
772 static GUIWindow *createWindow()
773 {
774 GUIWindow *ret = NULL;
775 ret = g_malloc0 (sizeof(GUIWindow));
776 if(NULL == ret){
777 return ret;
778 }
779 DualDecode_builderCreate ();
781 ret->window = DualDecode_getWidget ("decodeWindowSingle");
782 if (NULL == ret->window) {
783 goto memCleanup;
784 }
785 ret->windowCloseSignal = g_signal_connect(G_OBJECT(ret->window),
786 "delete-event",
787 G_CALLBACK(cbWindowClosed),
788 NULL);
790 GtkWidget *toolbar = DualDecode_getWidget ("toolbarSingle");
791 if (NULL == toolbar) {
792 goto memCleanup;
793 }
794 ret->drawArea = DualDecode_getWidget ("videoViewerSingle");
795 if (NULL == ret->drawArea) {
796 goto memCleanup;
797 }
799 ret->openButton = GTK_WIDGET (
800 gtk_tool_button_new_from_stock(GTK_STOCK_OPEN));
801 if (NULL == ret->openButton) {
802 goto memCleanup;
803 }
804 ret->rewindButton = GTK_WIDGET (
805 gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_REWIND));
806 if (NULL == ret->rewindButton) {
807 goto memCleanup;
808 }
809 ret->playButton = GTK_WIDGET (
810 gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY));
811 if (NULL == ret->playButton) {
812 goto memCleanup;
813 }
814 ret->pauseButton = GTK_WIDGET (
815 gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PAUSE));
816 if (NULL == ret->pauseButton) {
817 goto memCleanup;
818 }
819 ret->stopButton = GTK_WIDGET (
820 gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP));
821 if (NULL == ret->stopButton) {
822 goto memCleanup;
823 }
824 ret->forwardButton = GTK_WIDGET (
825 gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_FORWARD));
826 if (NULL == ret->forwardButton) {
827 goto memCleanup;
828 }
829 ret->helpButton = GTK_WIDGET (
830 gtk_tool_button_new_from_stock(GTK_STOCK_HELP));
831 if (NULL == ret->helpButton) {
832 goto memCleanup;
833 }
835 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (ret->openButton),
836 -1);
837 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), gtk_separator_tool_item_new(),
838 -1);
839 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM(ret->rewindButton),
840 -1);
841 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM(ret->playButton),
842 -1);
843 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM(ret->pauseButton),
844 -1);
845 gtk_toolbar_insert (GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(ret->stopButton),
846 -1);
847 gtk_toolbar_insert (GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(ret->forwardButton),
848 -1);
849 gtk_toolbar_insert (GTK_TOOLBAR(toolbar), gtk_separator_tool_item_new(),
850 -1);
851 gtk_toolbar_insert (GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(ret->helpButton),
852 -1);
854 ret->openSignal = g_signal_connect (G_OBJECT (ret->openButton), "clicked",
855 G_CALLBACK (cbOpenClicked), ret);
856 ret->stopSignal = g_signal_connect (G_OBJECT (ret->stopButton), "clicked",
857 G_CALLBACK (cbStopClicked), ret);
858 ret->pauseSignal = g_signal_connect (G_OBJECT (ret->pauseButton), "clicked",
859 G_CALLBACK (cbPauseClicked), ret);
860 ret->playSignal = g_signal_connect (G_OBJECT (ret->playButton), "clicked",
861 G_CALLBACK (cbPlayClicked),
862 ret);
863 ret->forwardSignal = g_signal_connect (G_OBJECT (ret->forwardButton),"clicked",
864 G_CALLBACK (cbForwardClicked), ret);
865 ret->rewindSignal = g_signal_connect (G_OBJECT (ret->rewindButton),"clicked",
866 G_CALLBACK (cbRewindClicked), ret);
868 ret->helpSignal = g_signal_connect (G_OBJECT (ret->helpButton), "clicked",
869 G_CALLBACK(cbHelpClicked), ret);
872 ret->switchButton = DualDecode_getWidget ("switchButtonSingle");
873 if (NULL == ret->switchButton) {
874 goto memCleanup;
875 }
877 ret->switchSignal = g_signal_connect (G_OBJECT (ret->switchButton), "clicked",
878 G_CALLBACK (cbSwitchButtonClicked),
879 ret);
881 ret->seekScale = DualDecode_getWidget ("seekScaleSingle");
882 if (NULL == ret->seekScale) {
883 goto memCleanup;
884 }
886 ret->seekSignal = g_signal_connect (G_OBJECT (ret->seekScale),
887 "value_changed",
888 G_CALLBACK (cbSeekValueChanged), ret);
891 ret->statusLabel = DualDecode_getWidget ("statusLabelSingle");
892 if (NULL == ret->statusLabel) {
893 goto memCleanup;
894 }
896 ret->timeLabel = DualDecode_getWidget ("timeLabelSingle");
897 if (NULL == ret->timeLabel) {
898 goto memCleanup;
899 }
900 ret->activeFlag = FALSE;
902 goto last;
904 gtk_widget_destroy (ret->window);
905 memCleanup:
906 g_free (ret);
907 last:
908 DualDecode_builderClose ();
909 return ret;
910 }
912 static GtkWidget *createLogWindow ()
913 {
914 return gtk_window_new (GTK_WINDOW_TOPLEVEL);
915 }
917 static GtkWidget *createHelpWindow ()
918 {
919 GtkWidget * helpWindow;
920 gint width;
921 gint height;
923 helpWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
924 gtk_window_set_title ( (GtkWindow *) helpWindow, "Help");
925 gtk_window_set_resizable ( (GtkWindow * )helpWindow, FALSE);
927 /*Set size same as display windows*/
928 gtk_widget_get_size_request (window[DECODER_INDEX_SINGLE]->window,
929 &width,
930 &height);
931 gtk_widget_set_size_request (helpWindow, width, height);
932 /*Connect signal to close button handler*/
933 g_signal_connect(G_OBJECT (helpWindow), "delete-event",
934 G_CALLBACK (cbHelpClosed), NULL);
935 g_print ("RETURNING FROM CREATE HELP\n");
936 return helpWindow;
937 }
941 static void setWindowSizeLocation ()
942 {
943 GdkScreen *screen = NULL;
944 gint screenWidth = -1;
945 gint screenHeight = -1;
946 gint windowWidth = -1;
947 gint windowHeight = -1;
949 screen = gdk_screen_get_default ();
950 screenWidth = gdk_screen_get_width (screen);
951 screenHeight = gdk_screen_get_height (screen);
952 windowWidth = screenWidth/SCREEN_WIDTH_FACTOR;
953 windowHeight = screenHeight/SCREEN_HEIGHT_FACTOR;
955 gtk_widget_set_size_request (window[DECODER_INDEX_SINGLE]->window,
956 windowWidth,windowHeight);
957 gtk_widget_set_size_request (window[DECODER_INDEX_DOUBLE]->window,
958 windowWidth,windowHeight);
959 gtk_window_move (GTK_WINDOW (window[DECODER_INDEX_SINGLE]->window),
960 (screenWidth - 2 * windowWidth) / 2, 0);
961 gtk_window_move (GTK_WINDOW (window[DECODER_INDEX_DOUBLE]->window),
962 (screenWidth - 2 * windowWidth) / 2 + windowWidth,
963 0);
964 }
966 static GstElement *createImageSinkFromWindow (GtkWidget * window, gchar *name)
967 {
968 GstElement *sinkElement = NULL;
969 XID xid = 0;
970 GdkDrawable *drawable = NULL;
972 /*make an xvimagesink element from factory*/
974 sinkElement = gst_element_factory_make (sink,name);
975 if (NULL == sinkElement) {
976 g_print ("%s sink cannot be created\n", sink);
977 goto return_pos;
978 }
980 /*get the XID of the display window's drawable*/
981 drawable = gtk_widget_get_window (GTK_WIDGET (window));
982 if (FALSE == GDK_IS_DRAWABLE (drawable)) {
983 /*TODO: A BUG HERE?*/
984 g_object_unref (G_OBJECT (sinkElement));
985 sinkElement=NULL;
986 goto return_pos;
987 }
988 xid = gdk_x11_drawable_get_xid (drawable);
990 /*link the gst sink element to the XID*/
991 gst_x_overlay_set_window_handle (GST_X_OVERLAY (sinkElement),xid);
993 return_pos:
994 return sinkElement;
995 }
997 /******************************************************************************
999 Public Functions
1001 ******************************************************************************/
1003 /******************************************************************************
1004 See gui.h
1005 ******************************************************************************/
1006 void DualDecode_startApplication ()
1007 {
1009 window[DECODER_INDEX_SINGLE] = createWindow();
1010 g_assert (window[DECODER_INDEX_SINGLE] != NULL);
1012 window[DECODER_INDEX_DOUBLE] = createWindow();
1013 g_assert (window[DECODER_INDEX_DOUBLE] != NULL);
1015 setWindowSizeLocation();
1017 helpWindow = createHelpWindow();
1018 g_assert (helpWindow != NULL);
1020 logWindow[DECODER_INDEX_SINGLE] = createLogWindow ();
1021 g_assert (logWindow[DECODER_INDEX_SINGLE] != NULL);
1023 logWindow[DECODER_INDEX_DOUBLE] = createLogWindow ();
1024 g_assert (logWindow[DECODER_INDEX_DOUBLE] != NULL);
1026 pipes[DECODER_INDEX_SINGLE] = DualDecode_createPipeline ();
1027 pipes[DECODER_INDEX_DOUBLE] = DualDecode_createPipeline ();
1028 setup ();
1030 gtk_main ();
1032 }
1034 void DualDecode_exitApplication()
1035 {
1036 gtk_widget_destroy (window[DECODER_INDEX_SINGLE]->window);
1037 gtk_widget_destroy (window[DECODER_INDEX_DOUBLE]->window);
1038 g_free (window[DECODER_INDEX_SINGLE]);
1039 g_free (window[DECODER_INDEX_DOUBLE]);
1040 gtk_widget_destroy (logWindow[DECODER_INDEX_SINGLE]);
1041 gtk_widget_destroy (logWindow[DECODER_INDEX_DOUBLE]);
1042 gtk_widget_destroy (helpWindow);
1044 /*TODO: destroy pipes here*/
1046 if (gtk_main_level())
1047 gtk_main_quit ();
1048 exit (0);
1049 }
1051 gboolean DualDecode_initGUI(gint *argc, char **argv[])
1052 {
1053 return gtk_init_check (argc,argv);
1054 }