xref: /AOO41X/main/avmedia/source/gstreamer/gstplayer.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include "gstplayer.hxx"
29*cdf0e10cSrcweir #include "gstwindow.hxx"
30*cdf0e10cSrcweir #include "gstframegrabber.hxx"
31*cdf0e10cSrcweir #include <stdio.h>
32*cdf0e10cSrcweir #include <unistd.h>
33*cdf0e10cSrcweir #include <math.h>
34*cdf0e10cSrcweir #include <string>
35*cdf0e10cSrcweir #include <gst/gstelement.h>
36*cdf0e10cSrcweir #include <gst/interfaces/xoverlay.h>
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir // maximum timeout time in nanoseconds
40*cdf0e10cSrcweir #define GST_MAX_TIMEOUT (2500 * GST_MSECOND)
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir using namespace ::com::sun::star;
43*cdf0e10cSrcweir 
44*cdf0e10cSrcweir namespace avmedia
45*cdf0e10cSrcweir {
46*cdf0e10cSrcweir namespace gst
47*cdf0e10cSrcweir {
48*cdf0e10cSrcweir const double NANO_TIME_FACTOR = 1000000000.0;
49*cdf0e10cSrcweir 
50*cdf0e10cSrcweir const long      VIDEO_DEFAULT_WIDTH = 256;
51*cdf0e10cSrcweir const long      VIDEO_DEFAULT_HEIGHT = 192;
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir // ----------------
54*cdf0e10cSrcweir // - GstBusSource -
55*cdf0e10cSrcweir // ----------------
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir struct GstBusSource : public GSource
58*cdf0e10cSrcweir {
59*cdf0e10cSrcweir     GstBus* mpBus;
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir     GstBusSource() :
62*cdf0e10cSrcweir         mpBus( NULL )
63*cdf0e10cSrcweir     {}
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir     ~GstBusSource()
66*cdf0e10cSrcweir     {}
67*cdf0e10cSrcweir };
68*cdf0e10cSrcweir 
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir // -----------------------------------------------------------------------
71*cdf0e10cSrcweir extern "C"
72*cdf0e10cSrcweir {
73*cdf0e10cSrcweir 
74*cdf0e10cSrcweir static gpointer
75*cdf0e10cSrcweir lcl_implThreadFunc( gpointer pData )
76*cdf0e10cSrcweir {
77*cdf0e10cSrcweir     return( pData ? static_cast< Player* >( pData )->run() : NULL );
78*cdf0e10cSrcweir }
79*cdf0e10cSrcweir 
80*cdf0e10cSrcweir static gboolean
81*cdf0e10cSrcweir lcl_implBusCheck( GSource* pSource )
82*cdf0e10cSrcweir {
83*cdf0e10cSrcweir     GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
84*cdf0e10cSrcweir 
85*cdf0e10cSrcweir     return( pBusSource &&
86*cdf0e10cSrcweir            GST_IS_BUS( pBusSource->mpBus ) &&
87*cdf0e10cSrcweir            gst_bus_have_pending( GST_BUS_CAST( pBusSource->mpBus ) ) );
88*cdf0e10cSrcweir }
89*cdf0e10cSrcweir 
90*cdf0e10cSrcweir 
91*cdf0e10cSrcweir static gboolean
92*cdf0e10cSrcweir lcl_implBusPrepare( GSource* pSource, gint* pTimeout )
93*cdf0e10cSrcweir {
94*cdf0e10cSrcweir     if (pTimeout)
95*cdf0e10cSrcweir     {
96*cdf0e10cSrcweir         *pTimeout = 0;
97*cdf0e10cSrcweir     }
98*cdf0e10cSrcweir 
99*cdf0e10cSrcweir     return lcl_implBusCheck(pSource);
100*cdf0e10cSrcweir }
101*cdf0e10cSrcweir 
102*cdf0e10cSrcweir static gboolean
103*cdf0e10cSrcweir lcl_implBusDispatch( GSource* pSource,
104*cdf0e10cSrcweir                      GSourceFunc /*aCallback*/,
105*cdf0e10cSrcweir                      gpointer pData )
106*cdf0e10cSrcweir {
107*cdf0e10cSrcweir     GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
108*cdf0e10cSrcweir     gboolean bRet = false;
109*cdf0e10cSrcweir 
110*cdf0e10cSrcweir     if( pData && pBusSource && GST_IS_BUS( pBusSource->mpBus ) )
111*cdf0e10cSrcweir     {
112*cdf0e10cSrcweir         GstMessage* pMsg = gst_bus_pop( pBusSource->mpBus );
113*cdf0e10cSrcweir 
114*cdf0e10cSrcweir         if( pMsg )
115*cdf0e10cSrcweir         {
116*cdf0e10cSrcweir             bRet = static_cast< Player* >( pData )->busCallback(
117*cdf0e10cSrcweir                         pBusSource->mpBus, pMsg );
118*cdf0e10cSrcweir             gst_message_unref( pMsg );
119*cdf0e10cSrcweir         }
120*cdf0e10cSrcweir     }
121*cdf0e10cSrcweir 
122*cdf0e10cSrcweir     return( bRet );
123*cdf0e10cSrcweir }
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir static void
126*cdf0e10cSrcweir lcl_implBusFinalize( GSource* pSource )
127*cdf0e10cSrcweir {
128*cdf0e10cSrcweir     GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir     if( pBusSource && pBusSource->mpBus )
131*cdf0e10cSrcweir     {
132*cdf0e10cSrcweir         gst_object_unref( pBusSource->mpBus );
133*cdf0e10cSrcweir         pBusSource->mpBus = NULL;
134*cdf0e10cSrcweir     }
135*cdf0e10cSrcweir }
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir static gboolean
138*cdf0e10cSrcweir lcl_implIdleFunc( gpointer pData )
139*cdf0e10cSrcweir {
140*cdf0e10cSrcweir     return( pData ? static_cast< Player* >( pData )->idle() : true );
141*cdf0e10cSrcweir }
142*cdf0e10cSrcweir 
143*cdf0e10cSrcweir static GstBusSyncReply
144*cdf0e10cSrcweir lcl_implHandleCreateWindowFunc( GstBus* pBus, GstMessage* pMsg, gpointer pData )
145*cdf0e10cSrcweir {
146*cdf0e10cSrcweir     return (pData)
147*cdf0e10cSrcweir         ? static_cast< Player* >( pData )->handleCreateWindow( pBus, pMsg )
148*cdf0e10cSrcweir         : GST_BUS_PASS;
149*cdf0e10cSrcweir }
150*cdf0e10cSrcweir 
151*cdf0e10cSrcweir } // extern "C"
152*cdf0e10cSrcweir 
153*cdf0e10cSrcweir 
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir // ---------------
156*cdf0e10cSrcweir // - Player -
157*cdf0e10cSrcweir // ---------------
158*cdf0e10cSrcweir Player::Player( GString* pURI ) :
159*cdf0e10cSrcweir     Player_BASE(m_aMutex),
160*cdf0e10cSrcweir     mpMutex( g_mutex_new() ),
161*cdf0e10cSrcweir     mpCond( g_cond_new() ),
162*cdf0e10cSrcweir     mpThread( NULL ),
163*cdf0e10cSrcweir     mpContext( NULL ),
164*cdf0e10cSrcweir     mpLoop( NULL ),
165*cdf0e10cSrcweir     mpPlayer( NULL ),
166*cdf0e10cSrcweir     mpURI( pURI ),
167*cdf0e10cSrcweir     mpPlayerWindow( NULL ),
168*cdf0e10cSrcweir     mnIsVideoSource( 0 ),
169*cdf0e10cSrcweir     mnVideoWidth( 0 ),
170*cdf0e10cSrcweir     mnVideoHeight( 0 ),
171*cdf0e10cSrcweir     mnInitialized( 0 ),
172*cdf0e10cSrcweir     mnVolumeDB( 0 ),
173*cdf0e10cSrcweir     mnLooping( 0 ),
174*cdf0e10cSrcweir     mnQuit( 0 ),
175*cdf0e10cSrcweir     mnVideoWindowSet( 0 ),
176*cdf0e10cSrcweir 	mnInitFail( 0 )
177*cdf0e10cSrcweir {
178*cdf0e10cSrcweir     // initialize GStreamer framework only once
179*cdf0e10cSrcweir     static bool bGstInitialized = false;
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir     if( !bGstInitialized )
182*cdf0e10cSrcweir     {
183*cdf0e10cSrcweir         gst_init( NULL, NULL );
184*cdf0e10cSrcweir         bGstInitialized = true;
185*cdf0e10cSrcweir     }
186*cdf0e10cSrcweir 
187*cdf0e10cSrcweir     if( pURI )
188*cdf0e10cSrcweir     {
189*cdf0e10cSrcweir         OSL_TRACE( ">>> --------------------------------" );
190*cdf0e10cSrcweir         OSL_TRACE( ">>> Creating Player object with URL: %s", pURI->str );
191*cdf0e10cSrcweir 
192*cdf0e10cSrcweir         mpThread = g_thread_create( &lcl_implThreadFunc, this, true, NULL );
193*cdf0e10cSrcweir     }
194*cdf0e10cSrcweir }
195*cdf0e10cSrcweir 
196*cdf0e10cSrcweir // ------------------------------------------------------------------------------
197*cdf0e10cSrcweir 
198*cdf0e10cSrcweir Player::~Player()
199*cdf0e10cSrcweir {
200*cdf0e10cSrcweir     if( g_atomic_pointer_get( &mpPlayer ) )
201*cdf0e10cSrcweir     {
202*cdf0e10cSrcweir         implQuitThread();
203*cdf0e10cSrcweir     }
204*cdf0e10cSrcweir 
205*cdf0e10cSrcweir     // cleanup
206*cdf0e10cSrcweir     g_cond_free( mpCond );
207*cdf0e10cSrcweir     g_mutex_free( mpMutex );
208*cdf0e10cSrcweir     g_string_free( mpURI, false );
209*cdf0e10cSrcweir }
210*cdf0e10cSrcweir 
211*cdf0e10cSrcweir // ------------------------------------------------------------------------------
212*cdf0e10cSrcweir Player* Player::create( const ::rtl::OUString& rURL )
213*cdf0e10cSrcweir {
214*cdf0e10cSrcweir     Player* pPlayer = NULL;
215*cdf0e10cSrcweir 
216*cdf0e10cSrcweir     if( rURL.getLength() )
217*cdf0e10cSrcweir     {
218*cdf0e10cSrcweir         // safely initialize GLib threading framework
219*cdf0e10cSrcweir         try
220*cdf0e10cSrcweir         {
221*cdf0e10cSrcweir             if( !g_thread_supported() )
222*cdf0e10cSrcweir             {
223*cdf0e10cSrcweir                 g_thread_init( NULL );
224*cdf0e10cSrcweir             }
225*cdf0e10cSrcweir         }
226*cdf0e10cSrcweir         catch( ... )
227*cdf0e10cSrcweir         {}
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir         if( g_thread_supported() )
230*cdf0e10cSrcweir         {
231*cdf0e10cSrcweir             const INetURLObject aURL( rURL );
232*cdf0e10cSrcweir 
233*cdf0e10cSrcweir             if( aURL.GetProtocol() != INET_PROT_NOT_VALID )
234*cdf0e10cSrcweir             {
235*cdf0e10cSrcweir                 GString* pURI = g_string_new( ::rtl::OUStringToOString(
236*cdf0e10cSrcweir                                                  aURL.GetMainURL( INetURLObject::NO_DECODE ),
237*cdf0e10cSrcweir                                                  RTL_TEXTENCODING_UTF8 ).getStr() );
238*cdf0e10cSrcweir 
239*cdf0e10cSrcweir                 if( pURI->len )
240*cdf0e10cSrcweir                 {
241*cdf0e10cSrcweir                     pPlayer = new Player( pURI );
242*cdf0e10cSrcweir 
243*cdf0e10cSrcweir                     // wait until thread signals that it has finished initialization
244*cdf0e10cSrcweir                     if( pPlayer->mpThread )
245*cdf0e10cSrcweir                     {
246*cdf0e10cSrcweir                         g_mutex_lock( pPlayer->mpMutex );
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir                         while( !pPlayer->implIsInitialized() )
249*cdf0e10cSrcweir                         {
250*cdf0e10cSrcweir                             g_cond_wait( pPlayer->mpCond, pPlayer->mpMutex );
251*cdf0e10cSrcweir                         }
252*cdf0e10cSrcweir 
253*cdf0e10cSrcweir                         g_mutex_unlock( pPlayer->mpMutex );
254*cdf0e10cSrcweir                     }
255*cdf0e10cSrcweir 
256*cdf0e10cSrcweir                     // check if player pipeline could be initialized
257*cdf0e10cSrcweir                     if( !pPlayer->mpPlayer )
258*cdf0e10cSrcweir                     {
259*cdf0e10cSrcweir                         delete pPlayer;
260*cdf0e10cSrcweir                         pPlayer = NULL;
261*cdf0e10cSrcweir                     }
262*cdf0e10cSrcweir                 }
263*cdf0e10cSrcweir                 else
264*cdf0e10cSrcweir                 {
265*cdf0e10cSrcweir                     g_string_free( pURI, false );
266*cdf0e10cSrcweir                 }
267*cdf0e10cSrcweir             }
268*cdf0e10cSrcweir         }
269*cdf0e10cSrcweir     }
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir     return( pPlayer );
272*cdf0e10cSrcweir }
273*cdf0e10cSrcweir 
274*cdf0e10cSrcweir // ------------------------------------------------------------------------------
275*cdf0e10cSrcweir void SAL_CALL Player::start()
276*cdf0e10cSrcweir      throw( uno::RuntimeException )
277*cdf0e10cSrcweir {
278*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
279*cdf0e10cSrcweir     if( implInitPlayer() && !isPlaying() )
280*cdf0e10cSrcweir     {
281*cdf0e10cSrcweir         gst_element_set_state( mpPlayer, GST_STATE_PLAYING );
282*cdf0e10cSrcweir     }
283*cdf0e10cSrcweir }
284*cdf0e10cSrcweir 
285*cdf0e10cSrcweir // ------------------------------------------------------------------------------
286*cdf0e10cSrcweir void SAL_CALL Player::stop()
287*cdf0e10cSrcweir      throw( uno::RuntimeException )
288*cdf0e10cSrcweir {
289*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
290*cdf0e10cSrcweir     if( implInitPlayer() && isPlaying() )
291*cdf0e10cSrcweir     {
292*cdf0e10cSrcweir         gst_element_set_state( mpPlayer, GST_STATE_PAUSED );
293*cdf0e10cSrcweir     }
294*cdf0e10cSrcweir }
295*cdf0e10cSrcweir 
296*cdf0e10cSrcweir // ------------------------------------------------------------------------------
297*cdf0e10cSrcweir sal_Bool SAL_CALL Player::isPlaying()
298*cdf0e10cSrcweir      throw( uno::RuntimeException )
299*cdf0e10cSrcweir {
300*cdf0e10cSrcweir     GstState aState = GST_STATE_NULL;
301*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
302*cdf0e10cSrcweir     if( mpPlayer )
303*cdf0e10cSrcweir     {
304*cdf0e10cSrcweir         gst_element_get_state( mpPlayer, &aState, NULL, GST_MAX_TIMEOUT );
305*cdf0e10cSrcweir     }
306*cdf0e10cSrcweir 
307*cdf0e10cSrcweir     return( GST_STATE_PLAYING == aState );
308*cdf0e10cSrcweir }
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir // ------------------------------------------------------------------------------
311*cdf0e10cSrcweir double SAL_CALL Player::getDuration()
312*cdf0e10cSrcweir      throw( uno::RuntimeException )
313*cdf0e10cSrcweir {
314*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
315*cdf0e10cSrcweir     gint64 nDuration = 0;
316*cdf0e10cSrcweir 
317*cdf0e10cSrcweir     if( implInitPlayer() )
318*cdf0e10cSrcweir     {
319*cdf0e10cSrcweir         GstFormat aFormat = GST_FORMAT_TIME;
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir         if( !gst_element_query_duration( mpPlayer, &aFormat, &nDuration ) ||
322*cdf0e10cSrcweir            ( GST_FORMAT_TIME != aFormat ) ||
323*cdf0e10cSrcweir            ( nDuration < 0 ) )
324*cdf0e10cSrcweir         {
325*cdf0e10cSrcweir             nDuration = 0;
326*cdf0e10cSrcweir         }
327*cdf0e10cSrcweir     }
328*cdf0e10cSrcweir 
329*cdf0e10cSrcweir     return( static_cast< double >( nDuration ) / NANO_TIME_FACTOR );
330*cdf0e10cSrcweir }
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir // ------------------------------------------------------------------------------
333*cdf0e10cSrcweir void SAL_CALL Player::setMediaTime( double fTime )
334*cdf0e10cSrcweir      throw( uno::RuntimeException )
335*cdf0e10cSrcweir {
336*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
337*cdf0e10cSrcweir     if( implInitPlayer() )
338*cdf0e10cSrcweir     {
339*cdf0e10cSrcweir         fTime = ::std::min( ::std::max( fTime, 0.0 ), getDuration() );
340*cdf0e10cSrcweir 
341*cdf0e10cSrcweir         gst_element_seek_simple( mpPlayer, GST_FORMAT_TIME,
342*cdf0e10cSrcweir                                 (GstSeekFlags) ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ),
343*cdf0e10cSrcweir                                 static_cast< gint64 >( fTime * NANO_TIME_FACTOR ) );
344*cdf0e10cSrcweir     }
345*cdf0e10cSrcweir }
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir // ------------------------------------------------------------------------------
348*cdf0e10cSrcweir double SAL_CALL Player::getMediaTime()
349*cdf0e10cSrcweir      throw( uno::RuntimeException )
350*cdf0e10cSrcweir {
351*cdf0e10cSrcweir     double fRet = 0.0;
352*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
353*cdf0e10cSrcweir     if( implInitPlayer() )
354*cdf0e10cSrcweir     {
355*cdf0e10cSrcweir         GstFormat aFormat = GST_FORMAT_TIME;
356*cdf0e10cSrcweir         gint64 nCurTime = 0;
357*cdf0e10cSrcweir 
358*cdf0e10cSrcweir         if( gst_element_query_position( mpPlayer, &aFormat, &nCurTime ) &&
359*cdf0e10cSrcweir            ( GST_FORMAT_TIME == aFormat ) &&
360*cdf0e10cSrcweir            ( nCurTime >= 0 ) )
361*cdf0e10cSrcweir         {
362*cdf0e10cSrcweir             fRet = static_cast< double >( nCurTime ) / NANO_TIME_FACTOR;
363*cdf0e10cSrcweir         }
364*cdf0e10cSrcweir     }
365*cdf0e10cSrcweir 
366*cdf0e10cSrcweir     return( fRet );
367*cdf0e10cSrcweir }
368*cdf0e10cSrcweir 
369*cdf0e10cSrcweir // ------------------------------------------------------------------------------
370*cdf0e10cSrcweir void SAL_CALL Player::setStopTime( double /* fTime */ )
371*cdf0e10cSrcweir      throw( uno::RuntimeException )
372*cdf0e10cSrcweir {
373*cdf0e10cSrcweir     OSL_TRACE( "GStreamer method avmedia::gst::Player::setStopTime needs to be implemented" );
374*cdf0e10cSrcweir 
375*cdf0e10cSrcweir     /*  Currently no need for implementation since higher levels of code don't use this method at all
376*cdf0e10cSrcweir         !!! TODO: needs to be implemented if this functionality is needed at a later point of time
377*cdf0e10cSrcweir     if( implInitPlayer() )
378*cdf0e10cSrcweir     {
379*cdf0e10cSrcweir     }
380*cdf0e10cSrcweir 
381*cdf0e10cSrcweir      */
382*cdf0e10cSrcweir }
383*cdf0e10cSrcweir 
384*cdf0e10cSrcweir // ------------------------------------------------------------------------------
385*cdf0e10cSrcweir double SAL_CALL Player::getStopTime()
386*cdf0e10cSrcweir      throw( uno::RuntimeException )
387*cdf0e10cSrcweir {
388*cdf0e10cSrcweir     /*
389*cdf0e10cSrcweir         Currently no need for implementation since higher levels of code don't set a stop time ATM
390*cdf0e10cSrcweir         !!! TODO: needs to be fully implemented if this functionality is needed at a later point of time
391*cdf0e10cSrcweir     */
392*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
393*cdf0e10cSrcweir     return( getDuration() );
394*cdf0e10cSrcweir }
395*cdf0e10cSrcweir 
396*cdf0e10cSrcweir // ------------------------------------------------------------------------------
397*cdf0e10cSrcweir void SAL_CALL Player::setRate( double /* fRate */ )
398*cdf0e10cSrcweir      throw( uno::RuntimeException )
399*cdf0e10cSrcweir {
400*cdf0e10cSrcweir     OSL_TRACE( "GStreamer method avmedia::gst::Player::setRate needs to be implemented" );
401*cdf0e10cSrcweir 
402*cdf0e10cSrcweir     /*  Currently no need for implementation since higher levels of code don't use this method at all
403*cdf0e10cSrcweir         !!! TODO: needs to be implemented if this functionality is needed at a later point of time
404*cdf0e10cSrcweir     */
405*cdf0e10cSrcweir }
406*cdf0e10cSrcweir 
407*cdf0e10cSrcweir // ------------------------------------------------------------------------------
408*cdf0e10cSrcweir double SAL_CALL Player::getRate()
409*cdf0e10cSrcweir      throw( uno::RuntimeException )
410*cdf0e10cSrcweir {
411*cdf0e10cSrcweir     /*
412*cdf0e10cSrcweir         Currently no need for implementation since higher levels of code don't set a different rate than 1 ATM
413*cdf0e10cSrcweir         !!! TODO: needs to be fully implemented if this functionality is needed at a later point of time
414*cdf0e10cSrcweir     */
415*cdf0e10cSrcweir 
416*cdf0e10cSrcweir     return( 1.0 );
417*cdf0e10cSrcweir }
418*cdf0e10cSrcweir 
419*cdf0e10cSrcweir // ------------------------------------------------------------------------------
420*cdf0e10cSrcweir void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
421*cdf0e10cSrcweir      throw( uno::RuntimeException )
422*cdf0e10cSrcweir {
423*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
424*cdf0e10cSrcweir     if (bSet)
425*cdf0e10cSrcweir     {
426*cdf0e10cSrcweir         g_atomic_int_compare_and_exchange(&mnLooping, 0, 1);
427*cdf0e10cSrcweir     }
428*cdf0e10cSrcweir     else
429*cdf0e10cSrcweir     {
430*cdf0e10cSrcweir         g_atomic_int_compare_and_exchange(&mnLooping, 1, 0);
431*cdf0e10cSrcweir     }
432*cdf0e10cSrcweir }
433*cdf0e10cSrcweir 
434*cdf0e10cSrcweir // ------------------------------------------------------------------------------
435*cdf0e10cSrcweir sal_Bool SAL_CALL Player::isPlaybackLoop()
436*cdf0e10cSrcweir      throw( uno::RuntimeException )
437*cdf0e10cSrcweir {
438*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
439*cdf0e10cSrcweir     return( g_atomic_int_get( &mnLooping ) > 0 );
440*cdf0e10cSrcweir }
441*cdf0e10cSrcweir 
442*cdf0e10cSrcweir // ------------------------------------------------------------------------------
443*cdf0e10cSrcweir void SAL_CALL Player::setMute( sal_Bool bSet )
444*cdf0e10cSrcweir      throw( uno::RuntimeException )
445*cdf0e10cSrcweir {
446*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
447*cdf0e10cSrcweir     if( implInitPlayer() && ( bSet != isMute() ) )
448*cdf0e10cSrcweir     {
449*cdf0e10cSrcweir         if( bSet )
450*cdf0e10cSrcweir         {
451*cdf0e10cSrcweir             g_object_set( mpPlayer, "volume", 0.0, NULL );
452*cdf0e10cSrcweir         }
453*cdf0e10cSrcweir         else
454*cdf0e10cSrcweir         {
455*cdf0e10cSrcweir             setVolumeDB( mnVolumeDB );
456*cdf0e10cSrcweir         }
457*cdf0e10cSrcweir     }
458*cdf0e10cSrcweir }
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir // ------------------------------------------------------------------------------
461*cdf0e10cSrcweir sal_Bool SAL_CALL Player::isMute()
462*cdf0e10cSrcweir      throw( uno::RuntimeException )
463*cdf0e10cSrcweir {
464*cdf0e10cSrcweir     gdouble fGstVolume = 1.0;
465*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
466*cdf0e10cSrcweir 
467*cdf0e10cSrcweir     if( implInitPlayer() )
468*cdf0e10cSrcweir     {
469*cdf0e10cSrcweir         g_object_get( mpPlayer, "volume", &fGstVolume, NULL );
470*cdf0e10cSrcweir     }
471*cdf0e10cSrcweir 
472*cdf0e10cSrcweir     return( 0.0 == fGstVolume );
473*cdf0e10cSrcweir }
474*cdf0e10cSrcweir 
475*cdf0e10cSrcweir // ------------------------------------------------------------------------------
476*cdf0e10cSrcweir void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
477*cdf0e10cSrcweir      throw( uno::RuntimeException )
478*cdf0e10cSrcweir {
479*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
480*cdf0e10cSrcweir     if( implInitPlayer() )
481*cdf0e10cSrcweir     {
482*cdf0e10cSrcweir         g_mutex_lock( mpMutex );
483*cdf0e10cSrcweir         mnVolumeDB = nVolumeDB;
484*cdf0e10cSrcweir         g_mutex_unlock( mpMutex );
485*cdf0e10cSrcweir 
486*cdf0e10cSrcweir         // maximum gain for gstreamer volume is 10
487*cdf0e10cSrcweir         double fGstVolume = pow( 10.0, static_cast< double >( ::std::min(
488*cdf0e10cSrcweir                                                                   nVolumeDB, static_cast< sal_Int16 >( 20 ) ) / 20.0 ) );
489*cdf0e10cSrcweir 
490*cdf0e10cSrcweir         g_object_set( mpPlayer, "volume", fGstVolume, NULL );
491*cdf0e10cSrcweir     }
492*cdf0e10cSrcweir }
493*cdf0e10cSrcweir 
494*cdf0e10cSrcweir // ------------------------------------------------------------------------------
495*cdf0e10cSrcweir sal_Int16 SAL_CALL Player::getVolumeDB()
496*cdf0e10cSrcweir      throw( uno::RuntimeException )
497*cdf0e10cSrcweir {
498*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
499*cdf0e10cSrcweir     return( static_cast< sal_Int16 >( g_atomic_int_get( &mnVolumeDB ) ) );
500*cdf0e10cSrcweir }
501*cdf0e10cSrcweir 
502*cdf0e10cSrcweir // ------------------------------------------------------------------------------
503*cdf0e10cSrcweir awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
504*cdf0e10cSrcweir      throw( uno::RuntimeException )
505*cdf0e10cSrcweir {
506*cdf0e10cSrcweir     awt::Size aSize( 0, 0 );
507*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
508*cdf0e10cSrcweir 
509*cdf0e10cSrcweir     if( implInitPlayer() && ( g_atomic_int_get( &mnIsVideoSource ) > 0 ) )
510*cdf0e10cSrcweir     {
511*cdf0e10cSrcweir         aSize.Width = g_atomic_int_get( &mnVideoWidth );
512*cdf0e10cSrcweir         aSize.Height = g_atomic_int_get( &mnVideoHeight );
513*cdf0e10cSrcweir 
514*cdf0e10cSrcweir         // if we have a video source, but no size is given => use default size
515*cdf0e10cSrcweir         if( ( aSize.Width <= 0 ) || ( aSize.Height <= 0 ) )
516*cdf0e10cSrcweir         {
517*cdf0e10cSrcweir             aSize.Width = VIDEO_DEFAULT_WIDTH;
518*cdf0e10cSrcweir             aSize.Height = VIDEO_DEFAULT_HEIGHT;
519*cdf0e10cSrcweir         }
520*cdf0e10cSrcweir     }
521*cdf0e10cSrcweir 
522*cdf0e10cSrcweir     OSL_TRACE( ">>> Requested preferred video size is: %d x %d pixel", aSize.Width, aSize.Height );
523*cdf0e10cSrcweir 
524*cdf0e10cSrcweir     return( aSize );
525*cdf0e10cSrcweir }
526*cdf0e10cSrcweir 
527*cdf0e10cSrcweir // ------------------------------------------------------------------------------
528*cdf0e10cSrcweir uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow(
529*cdf0e10cSrcweir     const uno::Sequence< uno::Any >& rArguments )
530*cdf0e10cSrcweir      throw( uno::RuntimeException )
531*cdf0e10cSrcweir {
532*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
533*cdf0e10cSrcweir     uno::Reference< ::media::XPlayerWindow > xRet;
534*cdf0e10cSrcweir     awt::Size aSize( getPreferredPlayerWindowSize() );
535*cdf0e10cSrcweir 
536*cdf0e10cSrcweir     OSL_ENSURE( !g_atomic_pointer_get( &mpPlayerWindow ), "::avmedia::gst::Player already has a player window" );
537*cdf0e10cSrcweir 
538*cdf0e10cSrcweir     if( ( aSize.Width > 0 ) && ( aSize.Height > 0 ) )
539*cdf0e10cSrcweir     {
540*cdf0e10cSrcweir         Window* pPlayerWindow = new Window( *this );
541*cdf0e10cSrcweir 
542*cdf0e10cSrcweir         xRet = pPlayerWindow;
543*cdf0e10cSrcweir 
544*cdf0e10cSrcweir         if( !pPlayerWindow->create( rArguments ) )
545*cdf0e10cSrcweir         {
546*cdf0e10cSrcweir             xRet.clear();
547*cdf0e10cSrcweir         }
548*cdf0e10cSrcweir         else
549*cdf0e10cSrcweir         {
550*cdf0e10cSrcweir             // try to use gconf user configurable video sink first
551*cdf0e10cSrcweir             GstElement* pVideoSink = gst_element_factory_make( "gconfvideosink", NULL );
552*cdf0e10cSrcweir 
553*cdf0e10cSrcweir             if( ( NULL != pVideoSink ) ||
554*cdf0e10cSrcweir                 ( NULL != ( pVideoSink = gst_element_factory_make( "autovideosink", NULL ) ) ) ||
555*cdf0e10cSrcweir                 ( NULL != ( pVideoSink = gst_element_factory_make( "xvimagesink", NULL ) ) ) ||
556*cdf0e10cSrcweir                 ( NULL != ( pVideoSink = gst_element_factory_make( "ximagesink", NULL ) ) ) )
557*cdf0e10cSrcweir             {
558*cdf0e10cSrcweir                 GstState aOldState = GST_STATE_NULL;
559*cdf0e10cSrcweir 
560*cdf0e10cSrcweir                 mpPlayerWindow = pPlayerWindow;
561*cdf0e10cSrcweir                 gst_element_get_state( mpPlayer, &aOldState, NULL, GST_MAX_TIMEOUT );
562*cdf0e10cSrcweir                 gst_element_set_state( mpPlayer, GST_STATE_READY );
563*cdf0e10cSrcweir                 g_object_set( mpPlayer, "video-sink", pVideoSink, NULL );
564*cdf0e10cSrcweir                 gst_element_set_state( mpPlayer, aOldState );
565*cdf0e10cSrcweir             }
566*cdf0e10cSrcweir         }
567*cdf0e10cSrcweir     }
568*cdf0e10cSrcweir 
569*cdf0e10cSrcweir     return( xRet );
570*cdf0e10cSrcweir }
571*cdf0e10cSrcweir 
572*cdf0e10cSrcweir // ------------------------------------------------------------------------------
573*cdf0e10cSrcweir uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
574*cdf0e10cSrcweir      throw( ::com::sun::star::uno::RuntimeException )
575*cdf0e10cSrcweir {
576*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
577*cdf0e10cSrcweir     FrameGrabber* pFrameGrabber = NULL;
578*cdf0e10cSrcweir     const awt::Size aPrefSize( getPreferredPlayerWindowSize() );
579*cdf0e10cSrcweir 
580*cdf0e10cSrcweir     if( ( aPrefSize.Width > 0 ) && ( aPrefSize.Height > 0 ) )
581*cdf0e10cSrcweir     {
582*cdf0e10cSrcweir         pFrameGrabber = FrameGrabber::create( mpURI );
583*cdf0e10cSrcweir     }
584*cdf0e10cSrcweir 
585*cdf0e10cSrcweir     return( pFrameGrabber );
586*cdf0e10cSrcweir }
587*cdf0e10cSrcweir 
588*cdf0e10cSrcweir // ------------------------------------------------------------------------------
589*cdf0e10cSrcweir void SAL_CALL Player::disposing()
590*cdf0e10cSrcweir {
591*cdf0e10cSrcweir     ::osl::MutexGuard aGuard(m_aMutex);
592*cdf0e10cSrcweir     if( mpPlayer )
593*cdf0e10cSrcweir     {
594*cdf0e10cSrcweir         stop();
595*cdf0e10cSrcweir         implQuitThread();
596*cdf0e10cSrcweir     }
597*cdf0e10cSrcweir 
598*cdf0e10cSrcweir     OSL_ASSERT( NULL == mpPlayer );
599*cdf0e10cSrcweir }
600*cdf0e10cSrcweir 
601*cdf0e10cSrcweir // ------------------------------------------------------------------------------
602*cdf0e10cSrcweir ::rtl::OUString SAL_CALL Player::getImplementationName()
603*cdf0e10cSrcweir      throw( uno::RuntimeException )
604*cdf0e10cSrcweir {
605*cdf0e10cSrcweir     return( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_IMPLEMENTATIONNAME ) ) );
606*cdf0e10cSrcweir }
607*cdf0e10cSrcweir 
608*cdf0e10cSrcweir // ------------------------------------------------------------------------------
609*cdf0e10cSrcweir sal_Bool SAL_CALL Player::supportsService( const ::rtl::OUString& ServiceName )
610*cdf0e10cSrcweir      throw( uno::RuntimeException )
611*cdf0e10cSrcweir {
612*cdf0e10cSrcweir     return( ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_SERVICENAME ) ) );
613*cdf0e10cSrcweir }
614*cdf0e10cSrcweir 
615*cdf0e10cSrcweir // ------------------------------------------------------------------------------
616*cdf0e10cSrcweir uno::Sequence< ::rtl::OUString > SAL_CALL Player::getSupportedServiceNames()
617*cdf0e10cSrcweir      throw( uno::RuntimeException )
618*cdf0e10cSrcweir {
619*cdf0e10cSrcweir     uno::Sequence< ::rtl::OUString > aRet( 1 );
620*cdf0e10cSrcweir     aRet[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_SERVICENAME ) );
621*cdf0e10cSrcweir 
622*cdf0e10cSrcweir     return( aRet );
623*cdf0e10cSrcweir }
624*cdf0e10cSrcweir 
625*cdf0e10cSrcweir // ------------------------------------------------------------------------------
626*cdf0e10cSrcweir void Player::implQuitThread()
627*cdf0e10cSrcweir {
628*cdf0e10cSrcweir     if( mpThread )
629*cdf0e10cSrcweir     {
630*cdf0e10cSrcweir         // set quit flag to 1 so that the main loop will be quit in idle
631*cdf0e10cSrcweir         // handler the next time it is called from the thread's main loop
632*cdf0e10cSrcweir         g_atomic_int_inc( &mnQuit );
633*cdf0e10cSrcweir 
634*cdf0e10cSrcweir         // wait until loop and as such the thread has quit
635*cdf0e10cSrcweir         g_thread_join( mpThread );
636*cdf0e10cSrcweir         mpThread = NULL;
637*cdf0e10cSrcweir     }
638*cdf0e10cSrcweir }
639*cdf0e10cSrcweir 
640*cdf0e10cSrcweir // ------------------------------------------------------------------------------
641*cdf0e10cSrcweir bool Player::implInitPlayer()
642*cdf0e10cSrcweir {
643*cdf0e10cSrcweir     bool bRet = false;
644*cdf0e10cSrcweir 
645*cdf0e10cSrcweir     if( mpPlayer && (mnInitFail < 3) )
646*cdf0e10cSrcweir     {
647*cdf0e10cSrcweir         GstState aState = GST_STATE_NULL;
648*cdf0e10cSrcweir 
649*cdf0e10cSrcweir         if( gst_element_get_state( mpPlayer, &aState, NULL, GST_MAX_TIMEOUT ) == GST_STATE_CHANGE_SUCCESS )
650*cdf0e10cSrcweir         {
651*cdf0e10cSrcweir             bRet = ( GST_STATE_PAUSED == aState ) || ( GST_STATE_PLAYING == aState );
652*cdf0e10cSrcweir 
653*cdf0e10cSrcweir             if( !bRet )
654*cdf0e10cSrcweir             {
655*cdf0e10cSrcweir                 gst_element_set_state( mpPlayer, GST_STATE_PAUSED );
656*cdf0e10cSrcweir                 bRet = ( gst_element_get_state( mpPlayer, &aState, NULL,
657*cdf0e10cSrcweir                                                 GST_MAX_TIMEOUT ) == GST_STATE_CHANGE_SUCCESS ) &&
658*cdf0e10cSrcweir                     ( GST_STATE_PAUSED == aState );
659*cdf0e10cSrcweir             }
660*cdf0e10cSrcweir         }
661*cdf0e10cSrcweir 
662*cdf0e10cSrcweir 		if( ! bRet )
663*cdf0e10cSrcweir 			mnInitFail++;
664*cdf0e10cSrcweir     }
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir     return( bRet );
667*cdf0e10cSrcweir }
668*cdf0e10cSrcweir 
669*cdf0e10cSrcweir // ------------------------------------------------------------------------------
670*cdf0e10cSrcweir gboolean Player::busCallback( GstBus* /*pBus*/,
671*cdf0e10cSrcweir                               GstMessage* pMsg )
672*cdf0e10cSrcweir {
673*cdf0e10cSrcweir     if( pMsg && mpLoop )
674*cdf0e10cSrcweir     {
675*cdf0e10cSrcweir         switch( GST_MESSAGE_TYPE( pMsg ) )
676*cdf0e10cSrcweir         {
677*cdf0e10cSrcweir             case ( GST_MESSAGE_EOS ):
678*cdf0e10cSrcweir             {
679*cdf0e10cSrcweir                 if( g_atomic_int_get( &mnLooping ) > 0 )
680*cdf0e10cSrcweir                 {
681*cdf0e10cSrcweir                     setMediaTime( 0.0 );
682*cdf0e10cSrcweir                     start();
683*cdf0e10cSrcweir                 }
684*cdf0e10cSrcweir                 else
685*cdf0e10cSrcweir                 {
686*cdf0e10cSrcweir                     stop();
687*cdf0e10cSrcweir                 }
688*cdf0e10cSrcweir             }
689*cdf0e10cSrcweir             break;
690*cdf0e10cSrcweir 
691*cdf0e10cSrcweir             case ( GST_MESSAGE_ERROR ):
692*cdf0e10cSrcweir             {
693*cdf0e10cSrcweir                 gchar* pDebug;
694*cdf0e10cSrcweir                 GError* pErr;
695*cdf0e10cSrcweir 
696*cdf0e10cSrcweir                 gst_message_parse_error( pMsg, &pErr, &pDebug );
697*cdf0e10cSrcweir                 fprintf( stderr, "Error: %s\n", pErr->message );
698*cdf0e10cSrcweir 
699*cdf0e10cSrcweir                 g_free( pDebug );
700*cdf0e10cSrcweir                 g_error_free( pErr );
701*cdf0e10cSrcweir             }
702*cdf0e10cSrcweir             break;
703*cdf0e10cSrcweir 
704*cdf0e10cSrcweir             default:
705*cdf0e10cSrcweir             {
706*cdf0e10cSrcweir                 break;
707*cdf0e10cSrcweir             }
708*cdf0e10cSrcweir         }
709*cdf0e10cSrcweir     }
710*cdf0e10cSrcweir 
711*cdf0e10cSrcweir     return( true );
712*cdf0e10cSrcweir }
713*cdf0e10cSrcweir 
714*cdf0e10cSrcweir // ------------------------------------------------------------------------------
715*cdf0e10cSrcweir void Player::implHandleNewElementFunc( GstBin* /* pBin */,
716*cdf0e10cSrcweir                                        GstElement* pElement,
717*cdf0e10cSrcweir                                        gpointer pData )
718*cdf0e10cSrcweir {
719*cdf0e10cSrcweir     if( pElement )
720*cdf0e10cSrcweir     {
721*cdf0e10cSrcweir #ifdef DEBUG
722*cdf0e10cSrcweir         gchar* pElementName = gst_element_get_name( pElement );
723*cdf0e10cSrcweir 
724*cdf0e10cSrcweir         if( pElementName )
725*cdf0e10cSrcweir         {
726*cdf0e10cSrcweir             OSL_TRACE( ">>> Bin has element: %s", pElementName );
727*cdf0e10cSrcweir             g_free( pElementName );
728*cdf0e10cSrcweir         }
729*cdf0e10cSrcweir #endif
730*cdf0e10cSrcweir 
731*cdf0e10cSrcweir         if( GST_IS_BIN( pElement ) )
732*cdf0e10cSrcweir         {
733*cdf0e10cSrcweir             // set this handler in case we have a GstBin element
734*cdf0e10cSrcweir             g_signal_connect( GST_BIN( pElement ), "element-added",
735*cdf0e10cSrcweir                               G_CALLBACK( Player::implHandleNewElementFunc ), pData );
736*cdf0e10cSrcweir         }
737*cdf0e10cSrcweir 
738*cdf0e10cSrcweir         // watch for all pads that are going to be added to this element;
739*cdf0e10cSrcweir         g_signal_connect( pElement, "pad-added",
740*cdf0e10cSrcweir                           G_CALLBACK( Player::implHandleNewPadFunc ), pData );
741*cdf0e10cSrcweir     }
742*cdf0e10cSrcweir }
743*cdf0e10cSrcweir 
744*cdf0e10cSrcweir // ------------------------------------------------------------------------------
745*cdf0e10cSrcweir void Player::implHandleNewPadFunc( GstElement* pElement,
746*cdf0e10cSrcweir                                    GstPad* pPad,
747*cdf0e10cSrcweir                                    gpointer pData )
748*cdf0e10cSrcweir {
749*cdf0e10cSrcweir     Player* pPlayer = static_cast< Player* >( pData );
750*cdf0e10cSrcweir 
751*cdf0e10cSrcweir     if( pPlayer && pElement && pPad )
752*cdf0e10cSrcweir     {
753*cdf0e10cSrcweir #ifdef DEBUG
754*cdf0e10cSrcweir         gchar* pElementName = gst_element_get_name( pElement );
755*cdf0e10cSrcweir         gchar* pPadName = gst_pad_get_name( pPad );
756*cdf0e10cSrcweir 
757*cdf0e10cSrcweir         OSL_TRACE( ">>> Element %s has pad: %s", pElementName, pPadName );
758*cdf0e10cSrcweir 
759*cdf0e10cSrcweir         g_free( pPadName );
760*cdf0e10cSrcweir         g_free( pElementName );
761*cdf0e10cSrcweir #endif
762*cdf0e10cSrcweir 
763*cdf0e10cSrcweir         GstCaps* pCaps = gst_pad_get_caps( pPad );
764*cdf0e10cSrcweir 
765*cdf0e10cSrcweir         // we are interested only in getting video properties
766*cdf0e10cSrcweir         // width and height or if we have a video source at all
767*cdf0e10cSrcweir         if( pCaps )
768*cdf0e10cSrcweir         {
769*cdf0e10cSrcweir             for( gint i = 0, nSize = gst_caps_get_size( pCaps ); i < nSize; ++i )
770*cdf0e10cSrcweir             {
771*cdf0e10cSrcweir                 const GstStructure* pStruct = gst_caps_get_structure( pCaps, i );
772*cdf0e10cSrcweir 
773*cdf0e10cSrcweir                 if( pStruct )
774*cdf0e10cSrcweir                 {
775*cdf0e10cSrcweir                     const gchar* pStructName = gst_structure_get_name( pStruct );
776*cdf0e10cSrcweir 
777*cdf0e10cSrcweir #ifdef DEBUG
778*cdf0e10cSrcweir                     OSL_TRACE( "\t>>> Pad has structure: %s", pStructName );
779*cdf0e10cSrcweir 
780*cdf0e10cSrcweir                     for( gint n = 0, nFields = gst_structure_n_fields( pStruct ); n < nFields; ++n )
781*cdf0e10cSrcweir                     {
782*cdf0e10cSrcweir                         OSL_TRACE( "\t\t>>> Structure has field: %s", gst_structure_nth_field_name( pStruct, n ) );
783*cdf0e10cSrcweir                     }
784*cdf0e10cSrcweir #endif
785*cdf0e10cSrcweir 
786*cdf0e10cSrcweir                     // just look for structures having 'video' in their names
787*cdf0e10cSrcweir                     if( ::std::string( pStructName ).find( "video" ) != ::std::string::npos )
788*cdf0e10cSrcweir                     {
789*cdf0e10cSrcweir                         g_atomic_int_inc( &pPlayer->mnIsVideoSource );
790*cdf0e10cSrcweir 
791*cdf0e10cSrcweir                         for( gint n = 0, nFields = gst_structure_n_fields( pStruct ); n < nFields; ++n )
792*cdf0e10cSrcweir                         {
793*cdf0e10cSrcweir                             const gchar* pFieldName = gst_structure_nth_field_name( pStruct, n );
794*cdf0e10cSrcweir                             gint nValue;
795*cdf0e10cSrcweir 
796*cdf0e10cSrcweir                             if( ( ::std::string( pFieldName ).find( "width" ) != ::std::string::npos ) &&
797*cdf0e10cSrcweir                                gst_structure_get_int( pStruct, pFieldName, &nValue ) )
798*cdf0e10cSrcweir                             {
799*cdf0e10cSrcweir                                 const gint nDiff = nValue - g_atomic_int_get( &pPlayer->mnVideoWidth );
800*cdf0e10cSrcweir                                 g_atomic_int_add( &pPlayer->mnVideoWidth, ::std::max( nDiff, 0 ) );
801*cdf0e10cSrcweir                             }
802*cdf0e10cSrcweir                             else if( ( ::std::string( pFieldName ).find( "height" ) != ::std::string::npos ) &&
803*cdf0e10cSrcweir                                     gst_structure_get_int( pStruct, pFieldName, &nValue ) )
804*cdf0e10cSrcweir                             {
805*cdf0e10cSrcweir                                 const gint nDiff = nValue - g_atomic_int_get( &pPlayer->mnVideoHeight );
806*cdf0e10cSrcweir                                 g_atomic_int_add( &pPlayer->mnVideoHeight, ::std::max( nDiff, 0 ) );
807*cdf0e10cSrcweir                             }
808*cdf0e10cSrcweir                         }
809*cdf0e10cSrcweir                     }
810*cdf0e10cSrcweir                 }
811*cdf0e10cSrcweir             }
812*cdf0e10cSrcweir 
813*cdf0e10cSrcweir             gst_caps_unref( pCaps );
814*cdf0e10cSrcweir         }
815*cdf0e10cSrcweir     }
816*cdf0e10cSrcweir }
817*cdf0e10cSrcweir 
818*cdf0e10cSrcweir // ------------------------------------------------------------------------------
819*cdf0e10cSrcweir gboolean Player::idle()
820*cdf0e10cSrcweir {
821*cdf0e10cSrcweir     // test if main loop should quit by comparing with 1
822*cdf0e10cSrcweir     // and set flag mnQuit to 0 so we call g_main_loop_quit exactly once
823*cdf0e10cSrcweir     bool const bQuit = g_atomic_int_compare_and_exchange( &mnQuit, 1, 0 );
824*cdf0e10cSrcweir 
825*cdf0e10cSrcweir     if( bQuit )
826*cdf0e10cSrcweir     {
827*cdf0e10cSrcweir         g_main_loop_quit( mpLoop );
828*cdf0e10cSrcweir     }
829*cdf0e10cSrcweir 
830*cdf0e10cSrcweir     // don't eat up all cpu time
831*cdf0e10cSrcweir     usleep( 1000 );
832*cdf0e10cSrcweir 
833*cdf0e10cSrcweir     return( true );
834*cdf0e10cSrcweir }
835*cdf0e10cSrcweir 
836*cdf0e10cSrcweir // ------------------------------------------------------------------------------
837*cdf0e10cSrcweir gpointer Player::run()
838*cdf0e10cSrcweir {
839*cdf0e10cSrcweir     static GSourceFuncs aSourceFuncs =
840*cdf0e10cSrcweir     {
841*cdf0e10cSrcweir         &lcl_implBusPrepare,
842*cdf0e10cSrcweir         &lcl_implBusCheck,
843*cdf0e10cSrcweir         &lcl_implBusDispatch,
844*cdf0e10cSrcweir         &lcl_implBusFinalize,
845*cdf0e10cSrcweir         NULL,
846*cdf0e10cSrcweir         NULL
847*cdf0e10cSrcweir     };
848*cdf0e10cSrcweir 
849*cdf0e10cSrcweir     if( NULL != ( mpPlayer = gst_element_factory_make( "playbin", NULL ) ) )
850*cdf0e10cSrcweir     {
851*cdf0e10cSrcweir         // initialization
852*cdf0e10cSrcweir         // no mutex necessary since initialization
853*cdf0e10cSrcweir         // is synchronous until loop is started
854*cdf0e10cSrcweir         mpContext = g_main_context_new();
855*cdf0e10cSrcweir         mpLoop = g_main_loop_new( mpContext, false );
856*cdf0e10cSrcweir 
857*cdf0e10cSrcweir         // add idle callback
858*cdf0e10cSrcweir         GSource* pIdleSource = g_idle_source_new();
859*cdf0e10cSrcweir         g_source_set_callback( pIdleSource, &lcl_implIdleFunc, this, NULL );
860*cdf0e10cSrcweir         g_source_attach( pIdleSource, mpContext );
861*cdf0e10cSrcweir 
862*cdf0e10cSrcweir         // add bus callback
863*cdf0e10cSrcweir         GSource* pBusSource = g_source_new( &aSourceFuncs, sizeof( GstBusSource ) );
864*cdf0e10cSrcweir         static_cast< GstBusSource* >( pBusSource )->mpBus = gst_pipeline_get_bus( GST_PIPELINE( mpPlayer ) );
865*cdf0e10cSrcweir         g_source_set_callback( pBusSource, NULL, this, NULL );
866*cdf0e10cSrcweir         g_source_attach( pBusSource, mpContext );
867*cdf0e10cSrcweir 
868*cdf0e10cSrcweir         // add bus sync handler to intercept video window creation for setting our own window
869*cdf0e10cSrcweir         gst_bus_set_sync_handler( static_cast< GstBusSource* >( pBusSource )->mpBus,
870*cdf0e10cSrcweir                                   &lcl_implHandleCreateWindowFunc, this );
871*cdf0e10cSrcweir 
872*cdf0e10cSrcweir         // watch for all elements (and pads) that will be added to the playbin,
873*cdf0e10cSrcweir         // in order to retrieve properties like video width and height
874*cdf0e10cSrcweir         g_signal_connect( GST_BIN( mpPlayer ), "element-added",
875*cdf0e10cSrcweir                           G_CALLBACK( Player::implHandleNewElementFunc ), this );
876*cdf0e10cSrcweir 
877*cdf0e10cSrcweir         // set source URI for player
878*cdf0e10cSrcweir         g_object_set( mpPlayer, "uri", mpURI->str, NULL );
879*cdf0e10cSrcweir 
880*cdf0e10cSrcweir         // set video fake sink first, since we only create a player without window here
881*cdf0e10cSrcweir         // and don't want to have the gstreamer default window appearing
882*cdf0e10cSrcweir         g_object_set( mpPlayer, "video-sink", gst_element_factory_make( "fakesink", NULL ), NULL );
883*cdf0e10cSrcweir 
884*cdf0e10cSrcweir         // set state of player to READY or destroy object in case of FAILURE
885*cdf0e10cSrcweir         if( gst_element_set_state( mpPlayer, GST_STATE_READY ) == GST_STATE_CHANGE_FAILURE )
886*cdf0e10cSrcweir         {
887*cdf0e10cSrcweir             gst_object_unref( mpPlayer );
888*cdf0e10cSrcweir             mpPlayer = NULL;
889*cdf0e10cSrcweir         }
890*cdf0e10cSrcweir 
891*cdf0e10cSrcweir         g_atomic_int_add( &mnInitialized, 1 );
892*cdf0e10cSrcweir         g_cond_signal( mpCond );
893*cdf0e10cSrcweir 
894*cdf0e10cSrcweir         // run the main loop
895*cdf0e10cSrcweir         g_main_loop_run( mpLoop );
896*cdf0e10cSrcweir 
897*cdf0e10cSrcweir         // clenanup
898*cdf0e10cSrcweir         // no mutex necessary since other thread joined us (this thread)
899*cdf0e10cSrcweir         // after setting the quit flag
900*cdf0e10cSrcweir         if( mpPlayer )
901*cdf0e10cSrcweir         {
902*cdf0e10cSrcweir             gst_element_set_state( mpPlayer, GST_STATE_NULL );
903*cdf0e10cSrcweir             gst_object_unref( mpPlayer );
904*cdf0e10cSrcweir             mpPlayer = NULL;
905*cdf0e10cSrcweir         }
906*cdf0e10cSrcweir 
907*cdf0e10cSrcweir         g_main_loop_unref( mpLoop );
908*cdf0e10cSrcweir         mpLoop = NULL;
909*cdf0e10cSrcweir 
910*cdf0e10cSrcweir         g_source_destroy( pBusSource );
911*cdf0e10cSrcweir         g_source_unref( pBusSource );
912*cdf0e10cSrcweir 
913*cdf0e10cSrcweir         g_source_destroy( pIdleSource );
914*cdf0e10cSrcweir         g_source_unref( pIdleSource );
915*cdf0e10cSrcweir 
916*cdf0e10cSrcweir         g_main_context_unref( mpContext );
917*cdf0e10cSrcweir         mpContext = NULL;
918*cdf0e10cSrcweir     }
919*cdf0e10cSrcweir     else
920*cdf0e10cSrcweir     {
921*cdf0e10cSrcweir         g_atomic_int_add( &mnInitialized, 1 );
922*cdf0e10cSrcweir         g_cond_signal( mpCond );
923*cdf0e10cSrcweir     }
924*cdf0e10cSrcweir 
925*cdf0e10cSrcweir     return( NULL );
926*cdf0e10cSrcweir }
927*cdf0e10cSrcweir 
928*cdf0e10cSrcweir // ------------------------------------------------------------------------------
929*cdf0e10cSrcweir GstBusSyncReply Player::handleCreateWindow( GstBus* /* pBus */,
930*cdf0e10cSrcweir                                             GstMessage* pMsg )
931*cdf0e10cSrcweir {
932*cdf0e10cSrcweir     GstBusSyncReply eRet = GST_BUS_PASS;
933*cdf0e10cSrcweir 
934*cdf0e10cSrcweir     if( pMsg &&
935*cdf0e10cSrcweir        ( GST_MESSAGE_TYPE( pMsg ) == GST_MESSAGE_ELEMENT ) &&
936*cdf0e10cSrcweir        gst_structure_has_name( pMsg->structure, "prepare-xwindow-id" ) &&
937*cdf0e10cSrcweir        g_atomic_pointer_get( &mpPlayerWindow ) )
938*cdf0e10cSrcweir     {
939*cdf0e10cSrcweir         OSL_TRACE( ">>> Got Request to create XOverlay" );
940*cdf0e10cSrcweir 
941*cdf0e10cSrcweir         gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( GST_MESSAGE_SRC( pMsg ) ),
942*cdf0e10cSrcweir                                      static_cast< Window* >( g_atomic_pointer_get(
943*cdf0e10cSrcweir                                                                 &mpPlayerWindow ) )->getXWindowHandle() );
944*cdf0e10cSrcweir 
945*cdf0e10cSrcweir         gst_message_unref( pMsg );
946*cdf0e10cSrcweir         eRet = GST_BUS_DROP;
947*cdf0e10cSrcweir     }
948*cdf0e10cSrcweir 
949*cdf0e10cSrcweir     return( eRet );
950*cdf0e10cSrcweir }
951*cdf0e10cSrcweir }     // namespace gst
952*cdf0e10cSrcweir } // namespace avmedia
953