merge the formfield patch from ooo-build
[ooovba.git] / avmedia / source / gstreamer / gstplayer.cxx
blobf1a53e7403d9ee97411f9a0fc13acd39b4a9a0d1
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile$
7 * $Revision$
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,
32 * MA 02111-1307 USA
34 ************************************************************************/
36 #include <math.h>
38 #ifndef __RTL_USTRING_
39 #include <rtl/string.hxx>
40 #endif
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"
51 #if DEBUG
52 #define DBG OSL_TRACE
53 #else
54 #define DBG(...)
55 #endif
57 using namespace ::com::sun::star;
59 namespace avmedia { namespace gstreamer {
61 // ----------------
62 // - Player -
63 // ----------------
65 Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
66 mxMgr( rxMgr ),
67 mpPlaybin( NULL ),
68 mbFakeVideo (sal_False ),
69 mnUnmutedVolume( 0 ),
70 mbPlayPending ( false ),
71 mbMuted( false ),
72 mbLooping( false ),
73 mbInitialized( false ),
74 mnWindowID( 0 ),
75 mpXOverlay( NULL ),
76 mnDuration( 0 ),
77 mnWidth( 0 ),
78 mnHeight( 0 ),
79 maSizeCondition( osl_createCondition() )
81 // Initialize GStreamer library
82 int argc = 1;
83 char *arguments[] = { "openoffice.org" };
84 char** argv = arguments;
85 GError* pError = NULL;
87 mbInitialized = gst_init_check( &argc, &argv, &pError );
89 if (pError != NULL)
90 // TODO: thow an exception?
91 g_error_free (pError);
94 // ------------------------------------------------------------------------------
96 Player::~Player()
98 // Release the elements and pipeline
99 if( mbInitialized )
101 if( mpPlaybin )
103 gst_element_set_state( mpPlaybin, GST_STATE_NULL );
104 gst_object_unref( GST_OBJECT( mpPlaybin ) );
106 mpPlaybin = NULL;
109 if( mpXOverlay ) {
110 g_object_unref( G_OBJECT ( mpXOverlay ) );
111 mpXOverlay = NULL;
116 // ------------------------------------------------------------------------------
118 static gboolean gst_pipeline_bus_callback( GstBus *, GstMessage *message, gpointer data )
120 Player* pPlayer = (Player *) data;
122 pPlayer->processMessage( message );
124 return TRUE;
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;
145 if (mbLooping)
146 start();
147 break;
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 &&
156 mpXOverlay )
157 gst_x_overlay_expose( mpXOverlay );
159 if (mbPlayPending)
160 mbPlayPending = ((newstate == GST_STATE_READY) || (newstate == GST_STATE_PAUSED));
162 default:
163 break;
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 ) {
176 if( mpXOverlay )
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 );
181 return GST_BUS_DROP;
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;
205 if( mnWidth == 0 ) {
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 );
213 if( !pInfo )
214 continue;
216 int nType;
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,
219 nType );
221 if( !g_strcasecmp( pValue->value_nick, "video" ) ) {
222 GstStructure *pStructure;
223 GstPad *pPad;
225 g_object_get( pInfo, "object", &pPad, NULL );
226 pStructure = gst_caps_get_structure( GST_PAD_CAPS( pPad ), 0 );
227 if( pStructure ) {
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 ) {
241 if( mnWidth == 0 ) {
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 );
248 return GST_BUS_PASS;
251 void Player::preparePlaybin( const ::rtl::OUString& rURL, bool bFakeVideo )
253 GstBus *pBus;
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 );
266 if( bFakeVideo )
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 )
283 bool bRet = false;
285 // create all the elements and link them
287 if( mbInitialized )
289 preparePlaybin( rURL, true );
291 gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
292 mbPlayPending = false;
294 bRet = true;
298 if( bRet )
299 maURL = rURL;
300 else
301 maURL = ::rtl::OUString();
303 return bRet;
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
327 if( mpPlaybin )
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 );
349 return 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 );
366 return duration;
369 // ------------------------------------------------------------------------------
371 void SAL_CALL Player::setMediaTime( double fTime )
372 throw (uno::RuntimeException)
374 if( mpPlaybin ) {
375 gint64 gst_position = llround (fTime * 1E9);
377 gst_element_seek( mpPlaybin, 1.0,
378 GST_FORMAT_TIME,
379 GST_SEEK_FLAG_FLUSH,
380 GST_SEEK_TYPE_SET, gst_position,
381 GST_SEEK_TYPE_NONE, 0 );
382 if( !isPlaying() )
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;
396 if( mpPlaybin ) {
397 // get current position in the stream
398 GstFormat format = GST_FORMAT_TIME;
399 gint64 gst_position;
400 if( gst_element_query_position( mpPlaybin, &format, &gst_position ) && format == GST_FORMAT_TIME && gst_position > 0L )
401 position = gst_position / 1E9;
404 return position;
407 // ------------------------------------------------------------------------------
409 void SAL_CALL Player::setStopTime( double fTime )
410 throw (uno::RuntimeException)
412 // TODO implement
415 // ------------------------------------------------------------------------------
417 double SAL_CALL Player::getStopTime( )
418 throw (uno::RuntimeException)
420 // Get the time at which to stop
422 return 0;
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)
438 double rate = 0.0;
440 // TODO get the window rate
441 if( mbInitialized )
446 return rate;
449 // ------------------------------------------------------------------------------
451 void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
452 throw (uno::RuntimeException)
454 // TODO check how to do with GST
455 mbLooping = bSet;
458 // ------------------------------------------------------------------------------
460 sal_Bool SAL_CALL Player::isPlaybackLoop( )
461 throw (uno::RuntimeException)
463 // TODO check how to do with GST
464 return mbLooping;
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;
478 if( bSet )
480 nVolume = 0.0;
483 g_object_set( G_OBJECT( mpPlaybin ), "volume", nVolume, NULL );
485 mbMuted = bSet;
489 // ------------------------------------------------------------------------------
491 sal_Bool SAL_CALL Player::isMute( )
492 throw (uno::RuntimeException)
494 return mbMuted;
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 );
506 // change volume
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)
518 sal_Int16 nVolumeDB;
520 if( mpPlaybin ) {
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 );
530 return nVolumeDB;
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 );
545 if( mbFakeVideo ) {
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;
560 return aSize;
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 );
577 xRet = pWindow;
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 >();
588 return xRet;
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 );
602 xRet = pGrabber;
604 if( !pGrabber->create( maURL ) )
605 xRet.clear();
608 return xRet;
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 ) );
635 return aRet;
638 } // namespace gstreamer
639 } // namespace avmedia