1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
9 * last change: $Author$ $Date$
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 ************************************************************************/
38 #ifndef __RTL_USTRING_
39 #include <rtl/string.hxx>
42 #include "gstplayer.hxx"
43 #include "gstframegrabber.hxx"
44 #include "gstwindow.hxx"
46 #include <gst/interfaces/xoverlay.h>
48 #define AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_GStreamer"
49 #define AVMEDIA_GST_PLAYER_SERVICENAME "com.sun.star.media.Player_GStreamer"
57 using namespace ::com::sun::star
;
59 namespace avmedia
{ namespace gstreamer
{
65 Player::Player( const uno::Reference
< lang::XMultiServiceFactory
>& rxMgr
) :
68 mbFakeVideo (sal_False
),
70 mbPlayPending ( false ),
73 mbInitialized( false ),
79 maSizeCondition( osl_createCondition() )
81 // Initialize GStreamer library
83 char *arguments
[] = { "openoffice.org" };
84 char** argv
= arguments
;
85 GError
* pError
= NULL
;
87 mbInitialized
= gst_init_check( &argc
, &argv
, &pError
);
90 // TODO: thow an exception?
91 g_error_free (pError
);
94 // ------------------------------------------------------------------------------
98 // Release the elements and pipeline
103 gst_element_set_state( mpPlaybin
, GST_STATE_NULL
);
104 gst_object_unref( GST_OBJECT( mpPlaybin
) );
110 g_object_unref( G_OBJECT ( mpXOverlay
) );
116 // ------------------------------------------------------------------------------
118 static gboolean
gst_pipeline_bus_callback( GstBus
*, GstMessage
*message
, gpointer data
)
120 Player
* pPlayer
= (Player
*) data
;
122 pPlayer
->processMessage( message
);
127 static GstBusSyncReply
gst_pipeline_bus_sync_handler( GstBus
*, GstMessage
* message
, gpointer data
)
129 Player
* pPlayer
= (Player
*) data
;
131 return pPlayer
->processSyncMessage( message
);
134 void Player::processMessage( GstMessage
*message
)
136 //DBG ( "gst message received: src name: %s structure type: %s",
137 // gst_object_get_name (message->src),
138 // message->structure ? gst_structure_get_name (message->structure) : "<none>");
140 switch( GST_MESSAGE_TYPE( message
) ) {
141 case GST_MESSAGE_EOS
:
142 //DBG( "EOS, reset state to NULL" );
143 gst_element_set_state( mpPlaybin
, GST_STATE_READY
);
144 mbPlayPending
= false;
148 case GST_MESSAGE_STATE_CHANGED
:
149 if( message
->src
== GST_OBJECT( mpPlaybin
) ) {
150 GstState newstate
, pendingstate
;
152 gst_message_parse_state_changed (message
, NULL
, &newstate
, &pendingstate
);
154 if( newstate
== GST_STATE_PAUSED
&&
155 pendingstate
== GST_STATE_VOID_PENDING
&&
157 gst_x_overlay_expose( mpXOverlay
);
160 mbPlayPending
= ((newstate
== GST_STATE_READY
) || (newstate
== GST_STATE_PAUSED
));
167 GstBusSyncReply
Player::processSyncMessage( GstMessage
*message
)
169 DBG( "%p processSyncMessage", this );
170 //DBG ( "gst message received: src name: %s structure type: %s",
171 // gst_object_get_name (message->src),
172 // message->structure ? gst_structure_get_name (message->structure) : "<none>");
174 if (message
->structure
) {
175 if( !strcmp( gst_structure_get_name( message
->structure
), "prepare-xwindow-id" ) && mnWindowID
!= 0 ) {
177 g_object_unref( G_OBJECT ( mpXOverlay
) );
178 mpXOverlay
= GST_X_OVERLAY( GST_MESSAGE_SRC( message
) );
179 g_object_ref( G_OBJECT ( mpXOverlay
) );
180 gst_x_overlay_set_xwindow_id( mpXOverlay
, mnWindowID
);
185 if( GST_MESSAGE_TYPE( message
) == GST_MESSAGE_STATE_CHANGED
) {
186 if( message
->src
== GST_OBJECT( mpPlaybin
) ) {
187 GstState newstate
, pendingstate
;
189 gst_message_parse_state_changed (message
, NULL
, &newstate
, &pendingstate
);
191 DBG( "%p state change received, new state %d", this, newstate
);
192 if( newstate
== GST_STATE_PAUSED
&&
193 pendingstate
== GST_STATE_VOID_PENDING
) {
195 DBG( "%p change to paused received", this );
197 if( mnDuration
== 0) {
198 GstFormat format
= GST_FORMAT_TIME
;
199 gint64 gst_duration
= 0L;
201 if( gst_element_query_duration( mpPlaybin
, &format
, &gst_duration
) && format
== GST_FORMAT_TIME
&& gst_duration
> 0L )
202 mnDuration
= gst_duration
;
206 GList
*pStreamInfo
= NULL
;
208 g_object_get( G_OBJECT( mpPlaybin
), "stream-info", &pStreamInfo
, NULL
);
210 for ( ; pStreamInfo
!= NULL
; pStreamInfo
= pStreamInfo
->next
) {
211 GObject
*pInfo
= G_OBJECT( pStreamInfo
->data
);
217 g_object_get( pInfo
, "type", &nType
, NULL
);
218 GEnumValue
*pValue
= g_enum_get_value( G_PARAM_SPEC_ENUM( g_object_class_find_property( G_OBJECT_GET_CLASS( pInfo
), "type" ) )->enum_class
,
221 if( !g_strcasecmp( pValue
->value_nick
, "video" ) ) {
222 GstStructure
*pStructure
;
225 g_object_get( pInfo
, "object", &pPad
, NULL
);
226 pStructure
= gst_caps_get_structure( GST_PAD_CAPS( pPad
), 0 );
228 gst_structure_get_int( pStructure
, "width", &mnWidth
);
229 gst_structure_get_int( pStructure
, "height", &mnHeight
);
230 DBG( "queried size: %d x %d", mnWidth
, mnHeight
);
235 sal_Bool aSuccess
= osl_setCondition( maSizeCondition
);
236 DBG( "%p set condition result: %d", this, aSuccess
);
240 } else if( GST_MESSAGE_TYPE( message
) == GST_MESSAGE_ERROR
) {
242 // an error occured, set condition so that OOo thread doesn't wait for us
243 sal_Bool aSuccess
= osl_setCondition( maSizeCondition
);
244 DBG( "%p set condition result: %d", this, aSuccess
);
251 void Player::preparePlaybin( const ::rtl::OUString
& rURL
, bool bFakeVideo
)
255 //sal_Bool aSuccess = osl_setCondition( maSizeCondition );
256 //DBG( "%p set condition result: %d", this, aSuccess );
258 if( mpPlaybin
!= NULL
) {
259 gst_element_set_state( mpPlaybin
, GST_STATE_NULL
);
260 mbPlayPending
= false;
261 g_object_unref( mpPlaybin
);
264 mpPlaybin
= gst_element_factory_make( "playbin", NULL
);
267 g_object_set( G_OBJECT( mpPlaybin
), "video-sink", gst_element_factory_make( "fakesink", NULL
), NULL
);
269 mbFakeVideo
= bFakeVideo
;
271 rtl::OString ascURL
= OUStringToOString( rURL
, RTL_TEXTENCODING_ASCII_US
);
272 g_object_set( G_OBJECT( mpPlaybin
), "uri", ascURL
.getStr() , NULL
);
274 pBus
= gst_element_get_bus( mpPlaybin
);
275 gst_bus_add_watch( pBus
, gst_pipeline_bus_callback
, this );
276 DBG( "%p set sync handler", this );
277 gst_bus_set_sync_handler( pBus
, gst_pipeline_bus_sync_handler
, this );
278 g_object_unref( pBus
);
281 bool Player::create( const ::rtl::OUString
& rURL
)
285 // create all the elements and link them
289 preparePlaybin( rURL
, true );
291 gst_element_set_state( mpPlaybin
, GST_STATE_PAUSED
);
292 mbPlayPending
= false;
301 maURL
= ::rtl::OUString();
306 // ------------------------------------------------------------------------------
308 void SAL_CALL
Player::start( )
309 throw (uno::RuntimeException
)
311 //DBG ("Player::start");
313 // set the pipeline state to READY and run the loop
314 if( mbInitialized
&& NULL
!= mpPlaybin
)
316 gst_element_set_state( mpPlaybin
, GST_STATE_PLAYING
);
317 mbPlayPending
= true;
321 // ------------------------------------------------------------------------------
323 void SAL_CALL
Player::stop( )
324 throw (uno::RuntimeException
)
326 // set the pipeline in PAUSED STATE
328 gst_element_set_state( mpPlaybin
, GST_STATE_PAUSED
);
330 mbPlayPending
= false;
331 DBG( "stop %p", mpPlaybin
);
334 // ------------------------------------------------------------------------------
336 sal_Bool SAL_CALL
Player::isPlaying()
337 throw (uno::RuntimeException
)
339 bool bRet
= mbPlayPending
;
341 // return whether the pipeline is in PLAYING STATE or not
342 if( !mbPlayPending
&& mbInitialized
&& mpPlaybin
)
344 bRet
= GST_STATE_PLAYING
== GST_STATE( mpPlaybin
);
347 DBG( "isPlaying %d", bRet
);
352 // ------------------------------------------------------------------------------
354 double SAL_CALL
Player::getDuration( )
355 throw (uno::RuntimeException
)
357 // slideshow checks for non-zero duration, so cheat here
358 double duration
= 0.01;
360 if( mpPlaybin
&& mnDuration
> 0 ) {
361 duration
= mnDuration
/ 1E9
;
363 //DBG( "gst duration: %lld ns duration: %lf s", gst_duration, duration );
369 // ------------------------------------------------------------------------------
371 void SAL_CALL
Player::setMediaTime( double fTime
)
372 throw (uno::RuntimeException
)
375 gint64 gst_position
= llround (fTime
* 1E9
);
377 gst_element_seek( mpPlaybin
, 1.0,
380 GST_SEEK_TYPE_SET
, gst_position
,
381 GST_SEEK_TYPE_NONE
, 0 );
383 gst_element_set_state( mpPlaybin
, GST_STATE_PAUSED
);
385 DBG( "seek to: %lld ns original: %lf s", gst_position
, fTime
);
389 // ------------------------------------------------------------------------------
391 double SAL_CALL
Player::getMediaTime( )
392 throw (uno::RuntimeException
)
394 double position
= 0.0;
397 // get current position in the stream
398 GstFormat format
= GST_FORMAT_TIME
;
400 if( gst_element_query_position( mpPlaybin
, &format
, &gst_position
) && format
== GST_FORMAT_TIME
&& gst_position
> 0L )
401 position
= gst_position
/ 1E9
;
407 // ------------------------------------------------------------------------------
409 void SAL_CALL
Player::setStopTime( double fTime
)
410 throw (uno::RuntimeException
)
415 // ------------------------------------------------------------------------------
417 double SAL_CALL
Player::getStopTime( )
418 throw (uno::RuntimeException
)
420 // Get the time at which to stop
425 // ------------------------------------------------------------------------------
427 void SAL_CALL
Player::setRate( double fRate
)
428 throw (uno::RuntimeException
)
430 // TODO set the window rate
433 // ------------------------------------------------------------------------------
435 double SAL_CALL
Player::getRate( )
436 throw (uno::RuntimeException
)
440 // TODO get the window rate
449 // ------------------------------------------------------------------------------
451 void SAL_CALL
Player::setPlaybackLoop( sal_Bool bSet
)
452 throw (uno::RuntimeException
)
454 // TODO check how to do with GST
458 // ------------------------------------------------------------------------------
460 sal_Bool SAL_CALL
Player::isPlaybackLoop( )
461 throw (uno::RuntimeException
)
463 // TODO check how to do with GST
467 // ------------------------------------------------------------------------------
469 void SAL_CALL
Player::setMute( sal_Bool bSet
)
470 throw (uno::RuntimeException
)
472 DBG( "set mute: %d muted: %d unmuted volume: %lf", bSet
, mbMuted
, mnUnmutedVolume
);
474 // change the volume to 0 or the unmuted volume
475 if( mpPlaybin
&& mbMuted
!= bSet
)
477 double nVolume
= mnUnmutedVolume
;
483 g_object_set( G_OBJECT( mpPlaybin
), "volume", nVolume
, NULL
);
489 // ------------------------------------------------------------------------------
491 sal_Bool SAL_CALL
Player::isMute( )
492 throw (uno::RuntimeException
)
497 // ------------------------------------------------------------------------------
499 void SAL_CALL
Player::setVolumeDB( sal_Int16 nVolumeDB
)
500 throw (uno::RuntimeException
)
502 mnUnmutedVolume
= pow( 10.0, nVolumeDB
/ 20.0 );
504 DBG( "set volume: %d gst volume: %lf", nVolumeDB
, mnUnmutedVolume
);
507 if( !mbMuted
&& mpPlaybin
)
509 g_object_set( G_OBJECT( mpPlaybin
), "volume", (gdouble
) mnUnmutedVolume
, NULL
);
513 // ------------------------------------------------------------------------------
515 sal_Int16 SAL_CALL
Player::getVolumeDB( )
516 throw (uno::RuntimeException
)
521 double nGstVolume
= 0.0;
523 g_object_get( G_OBJECT( mpPlaybin
), "volume", &nGstVolume
, NULL
);
525 nVolumeDB
= (sal_Int16
) ( 20.0*log10 ( nGstVolume
) );
527 //DBG( "get volume: %d gst volume: %lf", nVolumeDB, nGstVolume );
533 // ------------------------------------------------------------------------------
535 awt::Size SAL_CALL
Player::getPreferredPlayerWindowSize( )
536 throw (uno::RuntimeException
)
538 awt::Size
aSize( 0, 0 );
540 DBG( "%p Player::getPreferredPlayerWindowSize, member %d x %d", this, mnWidth
, mnHeight
);
542 TimeValue aTimeout
= { 10, 0 };
543 oslConditionResult aResult
= osl_waitCondition( maSizeCondition
, &aTimeout
);
546 mbFakeVideo
= sal_False
;
548 g_object_set( G_OBJECT( mpPlaybin
), "video-sink", NULL
, NULL
);
549 gst_element_set_state( mpPlaybin
, GST_STATE_READY
);
550 gst_element_set_state( mpPlaybin
, GST_STATE_PAUSED
);
553 DBG( "%p Player::getPreferredPlayerWindowSize after waitCondition %d, member %d x %d", this, aResult
, mnWidth
, mnHeight
);
555 if( mnWidth
!= 0 && mnHeight
!= 0 ) {
556 aSize
.Width
= mnWidth
;
557 aSize
.Height
= mnHeight
;
563 // ------------------------------------------------------------------------------
565 uno::Reference
< ::media::XPlayerWindow
> SAL_CALL
Player::createPlayerWindow( const uno::Sequence
< uno::Any
>& rArguments
)
566 throw (uno::RuntimeException
)
568 uno::Reference
< ::media::XPlayerWindow
> xRet
;
569 awt::Size
aSize( getPreferredPlayerWindowSize() );
571 DBG( "Player::createPlayerWindow %d %d length: %d", aSize
.Width
, aSize
.Height
, rArguments
.getLength() );
573 if( aSize
.Width
> 0 && aSize
.Height
> 0 )
575 ::avmedia::gstreamer::Window
* pWindow
= new ::avmedia::gstreamer::Window( mxMgr
, *this );
579 if( rArguments
.getLength() > 2 ) {
580 rArguments
[ 2 ] >>= mnWindowID
;
581 DBG( "window ID: %ld", mnWindowID
);
584 //if( !pWindow->create( aArguments ) )
585 //xRet = uno::Reference< ::media::XPlayerWindow >();
591 // ------------------------------------------------------------------------------
593 uno::Reference
< media::XFrameGrabber
> SAL_CALL
Player::createFrameGrabber( )
594 throw (uno::RuntimeException
)
596 uno::Reference
< media::XFrameGrabber
> xRet
;
598 /*if( maURL.getLength() > 0 )
600 FrameGrabber* pGrabber = new FrameGrabber( mxMgr );
604 if( !pGrabber->create( maURL ) )
611 // ------------------------------------------------------------------------------
613 ::rtl::OUString SAL_CALL
Player::getImplementationName( )
614 throw (uno::RuntimeException
)
616 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME
) );
619 // ------------------------------------------------------------------------------
621 sal_Bool SAL_CALL
Player::supportsService( const ::rtl::OUString
& ServiceName
)
622 throw (uno::RuntimeException
)
624 return ServiceName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( AVMEDIA_GST_PLAYER_SERVICENAME
) );
627 // ------------------------------------------------------------------------------
629 uno::Sequence
< ::rtl::OUString
> SAL_CALL
Player::getSupportedServiceNames( )
630 throw (uno::RuntimeException
)
632 uno::Sequence
< ::rtl::OUString
> aRet(1);
633 aRet
[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( AVMEDIA_GST_PLAYER_SERVICENAME
) );
638 } // namespace gstreamer
639 } // namespace avmedia