1 --- /dev/null 2006-09-07 16:53:33.000000000 +0200
2 +++ avmedia/source/gstreamer/gstplayer.cxx 2006-09-22 14:56:04.000000000 +0200
4 +/*************************************************************************
6 + * OpenOffice.org - a multi-platform office productivity suite
12 + * last change: $Author$ $Date$
14 + * The Contents of this file are made available subject to
15 + * the terms of GNU Lesser General Public License Version 2.1.
18 + * GNU Lesser General Public License Version 2.1
19 + * =============================================
20 + * Copyright 2005 by Sun Microsystems, Inc.
21 + * 901 San Antonio Road, Palo Alto, CA 94303, USA
23 + * This library is free software; you can redistribute it and/or
24 + * modify it under the terms of the GNU Lesser General Public
25 + * License version 2.1, as published by the Free Software Foundation.
27 + * This library is distributed in the hope that it will be useful,
28 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 + * Lesser General Public License for more details.
32 + * You should have received a copy of the GNU Lesser General Public
33 + * License along with this library; if not, write to the Free Software
34 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
37 + ************************************************************************/
41 +#ifndef __RTL_USTRING_
42 +#include <rtl/string.hxx>
45 +#include "gstplayer.hxx"
46 +#include "gstframegrabber.hxx"
47 +#include "gstwindow.hxx"
49 +#include <gst/interfaces/xoverlay.h>
51 +#define AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_GStreamer"
52 +#define AVMEDIA_GST_PLAYER_SERVICENAME "com.sun.star.media.Player_GStreamer"
55 +#define DBG OSL_TRACE
60 +using namespace ::com::sun::star;
62 +namespace avmedia { namespace gstreamer {
68 +Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
71 + mbFakeVideo (sal_False ),
72 + mnUnmutedVolume( 0 ),
75 + mbInitialized( false ),
81 + maSizeCondition( osl_createCondition() )
83 + // Initialize GStreamer library
85 + char *arguments[] = { "openoffice.org" };
86 + char** argv = arguments;
87 + GError* pError = NULL;
89 + mbInitialized = gst_init_check( &argc, &argv, &pError );
92 + // TODO: thow an exception?
93 + g_error_free (pError);
96 +// ------------------------------------------------------------------------------
100 + // Release the elements and pipeline
101 + if( mbInitialized )
105 + gst_element_set_state( mpPlaybin, GST_STATE_NULL );
106 + gst_object_unref( GST_OBJECT( mpPlaybin ) );
112 + g_object_unref( G_OBJECT ( mpXOverlay ) );
118 +// ------------------------------------------------------------------------------
120 +static gboolean gst_pipeline_bus_callback( GstBus *, GstMessage *message, gpointer data )
122 + Player* pPlayer = (Player *) data;
124 + pPlayer->processMessage( message );
129 +static GstBusSyncReply gst_pipeline_bus_sync_handler( GstBus *, GstMessage * message, gpointer data )
131 + Player* pPlayer = (Player *) data;
133 + return pPlayer->processSyncMessage( message );
136 +void Player::processMessage( GstMessage *message )
138 + //DBG ( "gst message received: src name: %s structure type: %s",
139 + // gst_object_get_name (message->src),
140 + // message->structure ? gst_structure_get_name (message->structure) : "<none>");
142 + switch( GST_MESSAGE_TYPE( message ) ) {
143 + case GST_MESSAGE_EOS:
144 + //DBG( "EOS, reset state to NULL" );
145 + gst_element_set_state( mpPlaybin, GST_STATE_READY );
147 + case GST_MESSAGE_STATE_CHANGED:
148 + if( message->src == GST_OBJECT( mpPlaybin ) ) {
149 + GstState newstate, pendingstate;
151 + gst_message_parse_state_changed (message, NULL, &newstate, &pendingstate);
153 + if( newstate == GST_STATE_PAUSED &&
154 + pendingstate == GST_STATE_VOID_PENDING &&
156 + gst_x_overlay_expose( mpXOverlay );
163 +GstBusSyncReply Player::processSyncMessage( GstMessage *message )
165 + DBG( "%p processSyncMessage", this );
166 + //DBG ( "gst message received: src name: %s structure type: %s",
167 + // gst_object_get_name (message->src),
168 + // message->structure ? gst_structure_get_name (message->structure) : "<none>");
170 + if (message->structure) {
171 + if( !strcmp( gst_structure_get_name( message->structure ), "prepare-xwindow-id" ) && mnWindowID != 0 ) {
173 + g_object_unref( G_OBJECT ( mpXOverlay ) );
174 + mpXOverlay = GST_X_OVERLAY( GST_MESSAGE_SRC( message ) );
175 + g_object_ref( G_OBJECT ( mpXOverlay ) );
176 + gst_x_overlay_set_xwindow_id( mpXOverlay, mnWindowID );
177 + return GST_BUS_DROP;
181 + if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_STATE_CHANGED ) {
182 + if( message->src == GST_OBJECT( mpPlaybin ) ) {
183 + GstState newstate, pendingstate;
185 + gst_message_parse_state_changed (message, NULL, &newstate, &pendingstate);
187 + DBG( "%p state change received, new state %d", this, newstate );
188 + if( newstate == GST_STATE_PAUSED &&
189 + pendingstate == GST_STATE_VOID_PENDING ) {
191 + DBG( "%p change to paused received", this );
193 + if( mnDuration == 0) {
194 + GstFormat format = GST_FORMAT_TIME;
195 + gint64 gst_duration = 0L;
197 + if( gst_element_query_duration( mpPlaybin, &format, &gst_duration) && format == GST_FORMAT_TIME && gst_duration > 0L )
198 + mnDuration = gst_duration;
201 + if( mnWidth == 0 ) {
202 + GList *pStreamInfo = NULL;
204 + g_object_get( G_OBJECT( mpPlaybin ), "stream-info", &pStreamInfo, NULL );
206 + for ( ; pStreamInfo != NULL; pStreamInfo = pStreamInfo->next) {
207 + GObject *pInfo = G_OBJECT( pStreamInfo->data );
213 + g_object_get( pInfo, "type", &nType, NULL );
214 + GEnumValue *pValue = g_enum_get_value( G_PARAM_SPEC_ENUM( g_object_class_find_property( G_OBJECT_GET_CLASS( pInfo ), "type" ) )->enum_class,
217 + if( !g_strcasecmp( pValue->value_nick, "video" ) ) {
218 + GstStructure *pStructure;
221 + g_object_get( pInfo, "object", &pPad, NULL );
222 + pStructure = gst_caps_get_structure( GST_PAD_CAPS( pPad ), 0 );
224 + gst_structure_get_int( pStructure, "width", &mnWidth );
225 + gst_structure_get_int( pStructure, "height", &mnHeight );
226 + DBG( "queried size: %d x %d", mnWidth, mnHeight );
231 + sal_Bool aSuccess = osl_setCondition( maSizeCondition );
232 + DBG( "%p set condition result: %d", this, aSuccess );
236 + } else if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR ) {
237 + if( mnWidth == 0 ) {
238 + // an error occured, set condition so that OOo thread doesn't wait for us
239 + sal_Bool aSuccess = osl_setCondition( maSizeCondition );
240 + DBG( "%p set condition result: %d", this, aSuccess );
244 + return GST_BUS_PASS;
247 +void Player::preparePlaybin( const ::rtl::OUString& rURL, bool bFakeVideo )
251 + //sal_Bool aSuccess = osl_setCondition( maSizeCondition );
252 + //DBG( "%p set condition result: %d", this, aSuccess );
254 + if( mpPlaybin != NULL ) {
255 + gst_element_set_state( mpPlaybin, GST_STATE_NULL );
256 + g_object_unref( mpPlaybin );
259 + mpPlaybin = gst_element_factory_make( "playbin", NULL );
262 + g_object_set( G_OBJECT( mpPlaybin ), "video-sink", gst_element_factory_make( "fakesink", NULL ), NULL );
264 + mbFakeVideo = bFakeVideo;
266 + rtl::OString ascURL = OUStringToOString( rURL, RTL_TEXTENCODING_ASCII_US );
267 + g_object_set( G_OBJECT( mpPlaybin ), "uri", ascURL.getStr() , NULL );
269 + pBus = gst_element_get_bus( mpPlaybin );
270 + gst_bus_add_watch( pBus, gst_pipeline_bus_callback, this );
271 + DBG( "%p set sync handler", this );
272 + gst_bus_set_sync_handler( pBus, gst_pipeline_bus_sync_handler, this );
273 + g_object_unref( pBus );
276 +bool Player::create( const ::rtl::OUString& rURL )
280 + // create all the elements and link them
282 + if( mbInitialized )
284 + preparePlaybin( rURL, true );
286 + gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
295 + maURL = ::rtl::OUString();
300 +// ------------------------------------------------------------------------------
302 +void SAL_CALL Player::start( )
303 + throw (uno::RuntimeException)
305 + //DBG ("Player::start");
307 + // set the pipeline state to READY and run the loop
308 + if( mbInitialized && NULL != mpPlaybin )
310 + gst_element_set_state( mpPlaybin, GST_STATE_PLAYING );
314 +// ------------------------------------------------------------------------------
316 +void SAL_CALL Player::stop( )
317 + throw (uno::RuntimeException)
319 + // set the pipeline in PAUSED STATE
321 + gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
323 + DBG( "stop %p", mpPlaybin );
326 +// ------------------------------------------------------------------------------
328 +sal_Bool SAL_CALL Player::isPlaying()
329 + throw (uno::RuntimeException)
333 + // return whether the pipeline is in PLAYING STATE or not
334 + if( mbInitialized && mpPlaybin )
336 + bRet = GST_STATE_PLAYING == GST_STATE( mpPlaybin );
339 + DBG( "isPlaying %d", bRet );
344 +// ------------------------------------------------------------------------------
346 +double SAL_CALL Player::getDuration( )
347 + throw (uno::RuntimeException)
349 + // slideshow checks for non-zero duration, so cheat here
350 + double duration = 0.01;
352 + if( mpPlaybin && mnDuration > 0 ) {
353 + duration = mnDuration / 1E9;
355 + //DBG( "gst duration: %lld ns duration: %lf s", gst_duration, duration );
361 +// ------------------------------------------------------------------------------
363 +void SAL_CALL Player::setMediaTime( double fTime )
364 + throw (uno::RuntimeException)
367 + gint64 gst_position = llround (fTime * 1E9);
369 + gst_element_seek( mpPlaybin, 1.0,
371 + GST_SEEK_FLAG_FLUSH,
372 + GST_SEEK_TYPE_SET, gst_position,
373 + GST_SEEK_TYPE_NONE, 0 );
375 + gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
377 + DBG( "seek to: %lld ns original: %lf s", gst_position, fTime );
381 +// ------------------------------------------------------------------------------
383 +double SAL_CALL Player::getMediaTime( )
384 + throw (uno::RuntimeException)
386 + double position = 0.0;
389 + // get current position in the stream
390 + GstFormat format = GST_FORMAT_TIME;
391 + gint64 gst_position;
392 + if( gst_element_query_position( mpPlaybin, &format, &gst_position ) && format == GST_FORMAT_TIME && gst_position > 0L )
393 + position = gst_position / 1E9;
399 +// ------------------------------------------------------------------------------
401 +void SAL_CALL Player::setStopTime( double fTime )
402 + throw (uno::RuntimeException)
407 +// ------------------------------------------------------------------------------
409 +double SAL_CALL Player::getStopTime( )
410 + throw (uno::RuntimeException)
412 + // Get the time at which to stop
417 +// ------------------------------------------------------------------------------
419 +void SAL_CALL Player::setRate( double fRate )
420 + throw (uno::RuntimeException)
422 + // TODO set the window rate
425 +// ------------------------------------------------------------------------------
427 +double SAL_CALL Player::getRate( )
428 + throw (uno::RuntimeException)
432 + // TODO get the window rate
433 + if( mbInitialized )
441 +// ------------------------------------------------------------------------------
443 +void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
444 + throw (uno::RuntimeException)
446 + // TODO check how to do with GST
450 +// ------------------------------------------------------------------------------
452 +sal_Bool SAL_CALL Player::isPlaybackLoop( )
453 + throw (uno::RuntimeException)
455 + // TODO check how to do with GST
459 +// ------------------------------------------------------------------------------
461 +void SAL_CALL Player::setMute( sal_Bool bSet )
462 + throw (uno::RuntimeException)
464 + DBG( "set mute: %d muted: %d unmuted volume: %lf", bSet, mbMuted, mnUnmutedVolume );
466 + // change the volume to 0 or the unmuted volume
467 + if( mpPlaybin && mbMuted != bSet )
469 + double nVolume = mnUnmutedVolume;
475 + g_object_set( G_OBJECT( mpPlaybin ), "volume", nVolume, NULL );
481 +// ------------------------------------------------------------------------------
483 +sal_Bool SAL_CALL Player::isMute( )
484 + throw (uno::RuntimeException)
489 +// ------------------------------------------------------------------------------
491 +void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
492 + throw (uno::RuntimeException)
494 + mnUnmutedVolume = pow( 10.0, nVolumeDB / 20.0 );
496 + DBG( "set volume: %d gst volume: %lf", nVolumeDB, mnUnmutedVolume );
499 + if( !mbMuted && mpPlaybin )
501 + g_object_set( G_OBJECT( mpPlaybin ), "volume", (gdouble) mnUnmutedVolume, NULL );
505 +// ------------------------------------------------------------------------------
507 +sal_Int16 SAL_CALL Player::getVolumeDB( )
508 + throw (uno::RuntimeException)
510 + sal_Int16 nVolumeDB;
513 + double nGstVolume = 0.0;
515 + g_object_get( G_OBJECT( mpPlaybin ), "volume", &nGstVolume, NULL );
517 + nVolumeDB = (sal_Int16) ( 20.0*log10 ( nGstVolume ) );
519 + //DBG( "get volume: %d gst volume: %lf", nVolumeDB, nGstVolume );
525 +// ------------------------------------------------------------------------------
527 +awt::Size SAL_CALL Player::getPreferredPlayerWindowSize( )
528 + throw (uno::RuntimeException)
530 + awt::Size aSize( 0, 0 );
532 + DBG( "%p Player::getPreferredPlayerWindowSize, member %d x %d", this, mnWidth, mnHeight );
534 + TimeValue aTimeout = { 10, 0 };
535 + oslConditionResult aResult = osl_waitCondition( maSizeCondition, &aTimeout );
537 + if( mbFakeVideo ) {
538 + mbFakeVideo = sal_False;
540 + g_object_set( G_OBJECT( mpPlaybin ), "video-sink", NULL, NULL );
541 + gst_element_set_state( mpPlaybin, GST_STATE_READY );
542 + gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
545 + DBG( "%p Player::getPreferredPlayerWindowSize after waitCondition %d, member %d x %d", this, aResult, mnWidth, mnHeight );
547 + if( mnWidth != 0 && mnHeight != 0 ) {
548 + aSize.Width = mnWidth;
549 + aSize.Height = mnHeight;
555 +// ------------------------------------------------------------------------------
557 +uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& rArguments )
558 + throw (uno::RuntimeException)
560 + uno::Reference< ::media::XPlayerWindow > xRet;
561 + awt::Size aSize( getPreferredPlayerWindowSize() );
563 + DBG( "Player::createPlayerWindow %d %d length: %d", aSize.Width, aSize.Height, rArguments.getLength() );
565 + if( aSize.Width > 0 && aSize.Height > 0 )
567 + ::avmedia::gstreamer::Window* pWindow = new ::avmedia::gstreamer::Window( mxMgr, *this );
571 + if( rArguments.getLength() > 2 ) {
572 + rArguments[ 2 ] >>= mnWindowID;
573 + DBG( "window ID: %ld", mnWindowID );
576 + //if( !pWindow->create( aArguments ) )
577 + //xRet = uno::Reference< ::media::XPlayerWindow >();
583 +// ------------------------------------------------------------------------------
585 +uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber( )
586 + throw (uno::RuntimeException)
588 + uno::Reference< media::XFrameGrabber > xRet;
590 + /*if( maURL.getLength() > 0 )
592 + FrameGrabber* pGrabber = new FrameGrabber( mxMgr );
596 + if( !pGrabber->create( maURL ) )
603 +// ------------------------------------------------------------------------------
605 +::rtl::OUString SAL_CALL Player::getImplementationName( )
606 + throw (uno::RuntimeException)
608 + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME ) );
611 +// ------------------------------------------------------------------------------
613 +sal_Bool SAL_CALL Player::supportsService( const ::rtl::OUString& ServiceName )
614 + throw (uno::RuntimeException)
616 + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( AVMEDIA_GST_PLAYER_SERVICENAME ) );
619 +// ------------------------------------------------------------------------------
621 +uno::Sequence< ::rtl::OUString > SAL_CALL Player::getSupportedServiceNames( )
622 + throw (uno::RuntimeException)
624 + uno::Sequence< ::rtl::OUString > aRet(1);
625 + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( AVMEDIA_GST_PLAYER_SERVICENAME ) );
630 +} // namespace gstreamer
631 +} // namespace avmedia