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