Modified in accordance to coding guidelines for header and C files.
[glsdk/dual-decode.git] / src / gst-controller.c
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  */                                                                             
41                                                                                 
42 /**                                                                             
43  * @file  gst-controller.c                                                                 
44  *                                                                              
45  * @brief Imeplements GStreamer related functions                                                                      
46  */ 
47 #include <stdint.h>
48 #include <string.h>
49 #include <gst/gst.h>
51 #include "gst-controller.h"
53 gchar * fsinkArr [] = {"fsink0", "fsink1"};
54 static gint fsinkCounter = 0;
55 static void getTime (gint64 arr[], gint64 time);
57 /******************************************************************************
58                      
59                            Static Functions
61 ******************************************************************************/
62 static gboolean attachPipeElements (Pipeline *pipePtr, GstElement *sink0, 
63                              GstElement *sink1)
64 {
65     gboolean ret = TRUE;
66     GstElement *fsink0 = NULL; 
67     GstElement *fsink1 = NULL;
68     GstElement *bin = NULL;   
69     GstElement *tee = NULL;                                                     
70     GstElement *queue0 = NULL;                                                  
71     GstElement *queue1 = NULL;                                                  
72     GstPad *pad = NULL;   
73     
74     bin = gst_bin_new ("vsinkbin");
75     tee = gst_element_factory_make ("tee","splitter"); 
76     queue0 = gst_element_factory_make ("queue","q0");  
77     queue1 = gst_element_factory_make ("queue","q1");
79     if (NULL == sink0)
80        fsink0 = gst_element_factory_make ("fakesink", fsinkArr[fsinkCounter++]);
81     if (NULL == sink1)                         
82         fsink1 = gst_element_factory_make ("fakesink", fsinkArr[fsinkCounter++]); 
83                 
84     if (!bin || !tee || !queue0 || !queue1) {
85         ret = FALSE;
86         goto exit;
87     }
88     if (NULL == sink0 && NULL == sink1) {           
89         gst_bin_add_many (GST_BIN (bin), tee, fsink0, fsink1, queue0, queue1,
90                           NULL); 
91         gst_element_link (queue0, fsink0);
92         gst_element_link (queue1,fsink1);
93     }
95     else if (NULL != sink0 && NULL == sink1) {
96         gst_bin_add_many (GST_BIN (bin), tee, sink0, fsink1, queue0, queue1,
97                           NULL);
98         gst_element_link (queue0, sink0);
99         gst_element_link (queue1,fsink1);
100    }
101    else if (NULL!= sink0 && NULL!=sink1) {
102        gst_bin_add_many (GST_BIN (bin), tee, sink0, sink1, queue0, queue1,
103                          NULL);              
104        gst_element_link (queue0, sink0);                                    
105        gst_element_link (queue1,sink1);                                    
106     }      
107     
108     else {
109         ret = FALSE;
110         goto exit;
111     }
112     /*Connecting the tee through queues is necessary to sync the two displays*/ 
113     gst_element_link (tee,queue0);                                               
114     gst_element_link (tee,queue1);                                               
115     
116     pad = gst_element_get_static_pad (tee, "sink");                             
117     gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));                 
118     gst_object_unref (GST_OBJECT (pad)); 
119     g_object_set (G_OBJECT (pipePtr->pipe), "video-sink", bin, NULL);     
120  
121 exit:    return ret;
124 static gboolean busCallback (GstBus *bus, GstMessage *msg, gpointer data)
125 {    
126         gchar *name             = (gchar *)data;
127     gchar *debugMsg     = NULL;                                                 
128     GError *err         = NULL;                                                 
129     static int count    = 0;
131     switch (GST_MESSAGE_TYPE(msg)) {                                              
132                                                                                 
133     case GST_MESSAGE_EOS:                                                   
134         g_printerr("%s -> Message (EOS) : End of stream.\n",name);                          
135             count++;
136         break;                                                              
137                                                                                
138     case GST_MESSAGE_ERROR: {                                             
139         gst_message_parse_error(msg,&err,&debugMsg);                      
140         g_printerr("%s -> Message (ERROR) : %s : debug ( %s )\n", 
141                             name,err->message,debugMsg);                                                      
142         g_free(debugMsg);                                                   
143         g_error_free(err);                                                  
144             count++;
145         break;                                                              
146     }                                                                       
147     case GST_MESSAGE_WARNING: {                                             
148         gst_message_parse_warning(msg,&err,&debugMsg);                      
149         g_printerr("%s -> Message (WARNING) : %s : debug ( %s )\n",
150                                            name,err->message,debugMsg);                                                      
151         g_free(debugMsg);                                                   
152         g_error_free(err);                                                  
153         break;                                                              
154         }                                                                       
155                                                                                 
156         default:                                                                
157             break;                                                              
158     }                                                                           
159                                                                                 
160     return TRUE;                                                                
163 static void getTime (gint64 arr[], gint64 time)
165     gint8 i = 0;
166     time = time / (gint64) NANOSEC;
168     for (i = 0; i < 3; i++){
169         arr[i] = time % 60;
170         time = time / 60;
171     } 
172     
173
174 /*****************************************************************************
176                           Public Functions
178 ******************************************************************************/       
181 /*****************************************************************************
182 *                         see gst-controller.h
183 ******************************************************************************/
184 Pipeline * DualDecode_createPipeline()
186     Pipeline *pipelinePtr = (Pipeline *) malloc (sizeof(Pipeline));
187     pipelinePtr->pipe = NULL;
188                                                   
189     GstBus *bus = NULL;
190                                                                                 
191            
192     pipelinePtr->pipe = gst_element_factory_make ("playbin2",NULL);                 
193     bus = gst_pipeline_get_bus (GST_PIPELINE (pipelinePtr->pipe));                    
194     pipelinePtr->busSignal = gst_bus_add_watch (bus,busCallback, NULL);                                   
195     gst_object_unref (bus);     
196     pipelinePtr->logFunc = NULL;
197                                                                           
198                                                                                 
199     return pipelinePtr;                
202 gboolean DualDecode_setSinksForPipes (Pipeline **pipes, GstElement *sink0, 
203                                       GstElement *sink1)
205     gboolean ret = TRUE;
206     attachPipeElements (pipes[0], sink0, NULL);
207     attachPipeElements (pipes[1], sink1, NULL);
208        
210     return ret;
212 gboolean DualDecode_seekMedia (Pipeline *pipePtr, gint64 position)
214         if (position < 0) {
215                 return FALSE;
216         }
217         return gst_element_seek_simple (pipePtr->pipe, GST_FORMAT_TIME,
218                                            GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
219                                                position);
223 gboolean DualDecode_pauseMedia (Pipeline *pipePtr)
225     gboolean ret = TRUE;
226     GstStateChangeReturn stateReturn;
227     if (GST_STATE_CHANGE_ASYNC == 
228         gst_element_set_state (pipePtr->pipe, GST_STATE_PAUSED)) {
229         g_print ("STATE CHANGE RETURNED ASYNC \n");
230         stateReturn = gst_element_get_state (pipePtr->pipe,
231                                 NULL,
232                                 NULL,
233                                 TIMEOUT);
234         g_print ("GET STATE RETURNED %s\n", 
235                   gst_element_state_change_return_get_name (stateReturn));
236     
237     }    
238     return ret;
241 gboolean DualDecode_resumeMedia (Pipeline *pipePtr)                              
242 {                                                                               
243     gboolean ret = TRUE;                                                        
244     if (!gst_element_set_state (pipePtr->pipe, GST_STATE_PLAYING))                
245         ret = FALSE;                                                            
246     g_print ("IN RESUME MEDIA\n");                                                                            
247     return ret;                                                                 
248
250 gboolean DualDecode_stopMedia (Pipeline *pipePtr)                             
251 {                                                                               
252     gboolean ret = TRUE;                                                        
253     if (!gst_element_set_state (pipePtr->pipe, GST_STATE_NULL))               
254         ret = FALSE;                                                            
255                                                                                 
256     return ret;                                                                 
257 }  
260 gboolean DualDecode_setLogFunction (Pipeline *pipePtr, LogFunc func, gpointer data)
262     gboolean ret = TRUE;
263      
265     return ret;   
268 GstState DualDecode_getMediaState(Pipeline *pipePtr)
270         GstState state, pending;
271     g_print ("IN GET MEDIA STATE ENTRY\n");
272         if (GST_STATE_CHANGE_SUCCESS != gst_element_get_state(
273                 pipePtr->pipe, &state, &pending, GST_CLOCK_TIME_NONE)) {
274                 /*TODO : a bug here*/
275                 g_printerr ("No state in GstElement\n");
276         } 
277     g_print ("EXITING FROM GET MEDIA STATE\n");
278         return state;
282 gboolean DualDecode_getMediaPosition (Pipeline *pipePtr, gdouble *seekScaleValue,
283                                       gchar **timeLabelText)
285         gboolean ret = TRUE;
286     gint64 position = 0, duration = 0;
287     gint64 pos[3], dur[3];
288     GstFormat format = GST_FORMAT_TIME; 
290     if (TRUE == gst_element_query_position (pipePtr->pipe, &format, &position) 
291     && (TRUE == gst_element_query_duration (pipePtr->pipe, &format, &duration))) {
292        
293         getTime (pos, position);
294         getTime (dur, duration); 
295         *timeLabelText = g_strdup_printf ("%ld:%ld:%ld/%ld:%ld:%ld", 
296         pos[HH], pos[MM], pos[SS], dur[HH], dur[MM], dur[SS]);
297         if (duration)
298             *seekScaleValue = (gdouble)position/ (gdouble)duration * 100;
299         
300     }    
301     else 
302         ret = FALSE;
303     
305     return ret;
310 void DualDecode_setPipelineSink (Pipeline *pipePtr, GstElement *sink0, 
311                                  GstElement *sink1)
313     g_print ("IN SET PIPE IN SINGLE MODE");
314     attachPipeElements (pipePtr, sink0, sink1);
317 gboolean DualDecode_playMedia (Pipeline *pipePtr, gchar *filename, gint64 position)            
318 {                                                                               
319     gboolean ret = TRUE;                                                        
321     g_print ("IN PLAYMEDIA2");                                                                                
322     g_object_set (G_OBJECT (pipePtr->pipe),"uri", filename,NULL);                 
323     gst_element_set_state (pipePtr->pipe, GST_STATE_NULL);                      
324     gst_element_set_state (pipePtr->pipe, GST_STATE_PLAYING);                   
325                                                                                 
326     DualDecode_getMediaState (pipePtr);                                          
327     DualDecode_seekMedia (pipePtr, position);                                    
328     
329     return ret;                                                                            
330                                                                                 
333 gboolean DualDecode_singleToDual (Pipeline **pipes,GstElement * otherWindowSink,
334                                   gint thisWindow, gint otherWindow,
335                                   gchar *filename)
337     gboolean ret = TRUE;
339     GstElement *thisbin   = NULL;
340     GstElement *otherbin  = NULL;
341     GstElement *fsink     = NULL;
342     GstElement *queue0    = NULL;                                                  
343     GstElement *queue1    = NULL;                                                  
344     GstState state0       = GST_STATE_NULL; 
345    
346     gst_element_get_state (pipes[thisWindow]->pipe, &state0, NULL,                                                        
347                            GST_CLOCK_TIME_NONE);  
349     /*Remove  otherWindowsink from this pipeline*/
350     g_object_get (G_OBJECT (pipes[thisWindow]->pipe),"video-sink", &thisbin,NULL);
351     queue1 = gst_bin_get_by_name (GST_BIN (thisbin), "q1");                   
352     gst_element_unlink (queue1, otherWindowSink);          
353     gst_object_ref (otherWindowSink);                      
354     gst_bin_remove (GST_BIN (thisbin), otherWindowSink);       
355     
356     /*Remove a fake sink from the other pipeline*/                                                                            
357     g_object_get (G_OBJECT (pipes[otherWindow]->pipe), "video-sink", &otherbin, NULL);
358     queue0 = gst_bin_get_by_name (GST_BIN (otherbin), "q0");                  
359     fsink = gst_bin_get_by_name (GST_BIN (otherbin), "fsink0");               
360     gst_element_unlink (queue0, fsink);                                   
361     gst_object_ref (fsink);                                               
362     gst_bin_remove (GST_BIN (otherbin), fsink);                               
363       
364     /*Add fakesink to this pipeline*/                                                                          
365     gst_bin_add (GST_BIN (thisbin), fsink);                                  
366     gst_element_sync_state_with_parent (fsink);                          
367     gst_element_link (queue1, fsink);                                    
368     
369     /* Add otherWindowSink to other pipeline */                                                                            
370     gst_element_set_state (otherWindowSink, GST_STATE_READY);
371     gst_bin_add (GST_BIN (otherbin), otherWindowSink);        
372     gst_element_link (queue0, otherWindowSink);           
373                                                                                 
374     DualDecode_playMedia (pipes[otherWindow], filename, 0);
375     gst_element_set_state (pipes[thisWindow]->pipe, state0); 
377     return ret;
379  
380 gboolean DualDecode_dualToSingle (Pipeline **pipes,GstElement * otherWindowSink,
381                                   gint thisWindow, gint otherWindow)  
383     gboolean ret = TRUE;
384     GstElement *bin    = NULL;
385     GstElement *bin2   = NULL;
386     GstElement *fsink  = NULL;
387     GstElement *fsink0 = NULL;
388     GstElement *queue0 = NULL;
389     GstElement *queue1 = NULL; 
390     gchar *name        = NULL;
391     
392     /*Remove otherWindow sink from other pipeline*/
393     gst_element_set_state (pipes[otherWindow]->pipe, GST_STATE_PAUSED);
394     g_object_get (G_OBJECT (pipes[otherWindow]->pipe), "video-sink", &bin2, NULL);
395     queue0 = gst_bin_get_by_name (GST_BIN (bin2), "q0");                  
396     gst_element_unlink (queue0, otherWindowSink);          
397     gst_object_ref (otherWindowSink);                      
398     gst_bin_remove (GST_BIN (bin2), otherWindowSink);       
399     
400     /*Remove fake sink from this pipeline*/                                                                            
401     g_object_get (G_OBJECT (pipes[thisWindow]->pipe), "video-sink", &bin, NULL);
402     queue1 = gst_bin_get_by_name (GST_BIN (bin), "q1");                   
403     fsink = gst_bin_get_by_name (GST_BIN (bin), "fsink0");                
404     if (NULL == fsink)                                                    
405         fsink = gst_bin_get_by_name (GST_BIN (bin), "fsink1");            
406     name = gst_element_get_name (fsink);                                   
407     gst_element_unlink (queue1, fsink);                                   
408     gst_object_ref (fsink);                                               
409     gst_bin_remove (GST_BIN (bin),fsink);                                 
410                                                                                 
411     gst_element_set_state (otherWindowSink, GST_STATE_READY);
412     
413     /*Add fake sink to other pipeline */                                                                            
414     gst_bin_add (GST_BIN (bin2), fsink);                                  
415     gst_element_sync_state_with_parent (fsink);                           
416                                                                                 
417     if (!g_strcmp0 (name, "fsink0")){                                   
418                                                                                 
419         g_print ("NAME IS fsink0\n");                                   
420         gst_element_link (queue0, fsink);                               
421     }                                                                     
422     else if (!g_strcmp0 (name, "fsink1")){                                
423         g_print ("NAME IS fsink1\n");                                     
424         fsink0 = gst_bin_get_by_name (GST_BIN (bin2), "fsink0");          
425         queue1 = gst_bin_get_by_name (GST_BIN (bin2), "q1");              
426         gst_element_unlink (queue1, fsink0);                              
427         gst_element_link (queue1, fsink);                                 
428         gst_element_link (queue0, fsink0);                                
429     }                                                                     
430     g_free (name);
432     /*Add otherWindowSink to this pipeline*/                                                      
433     gst_bin_add (GST_BIN (bin), otherWindowSink);         
434     gst_element_sync_state_with_parent (otherWindowSink); 
435     gst_element_link (queue1, otherWindowSink); 
438     return ret;