summaryrefslogtreecommitdiff
path: root/avmedia/source/gstreamer/gstplayer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'avmedia/source/gstreamer/gstplayer.cxx')
-rwxr-xr-x[-rw-r--r--]avmedia/source/gstreamer/gstplayer.cxx1088
1 files changed, 388 insertions, 700 deletions
diff --git a/avmedia/source/gstreamer/gstplayer.cxx b/avmedia/source/gstreamer/gstplayer.cxx
index f082cfc5c513..f6ea7295a540 100644..100755
--- a/avmedia/source/gstreamer/gstplayer.cxx
+++ b/avmedia/source/gstreamer/gstplayer.cxx
@@ -1,8 +1,9 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * Copyright 2000, 2010 Oracle and/or its affiliates.
+ * Copyright 2010 Novell, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
@@ -25,914 +26,601 @@
*
************************************************************************/
+#include <math.h>
+
+#ifndef __RTL_USTRING_
+#include <rtl/string.hxx>
+#endif
+
#include "gstplayer.hxx"
-#include "gstwindow.hxx"
#include "gstframegrabber.hxx"
-#include <stdio.h>
-#include <unistd.h>
-#include <math.h>
-#include <string>
-#include <gst/gstelement.h>
+#include "gstwindow.hxx"
+
#include <gst/interfaces/xoverlay.h>
+#define AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_GStreamer"
+#define AVMEDIA_GST_PLAYER_SERVICENAME "com.sun.star.media.Player_GStreamer"
-// maximum timeout time in nanoseconds
-#define GST_MAX_TIMEOUT (2500 * GST_MSECOND)
+#if DEBUG
+#define DBG OSL_TRACE
+#else
+#define DBG(...)
+#endif
using namespace ::com::sun::star;
-namespace avmedia
-{
-namespace gst
-{
-const double NANO_TIME_FACTOR = 1000000000.0;
-
-const long VIDEO_DEFAULT_WIDTH = 256;
-const long VIDEO_DEFAULT_HEIGHT = 192;
+namespace avmedia { namespace gstreamer {
// ----------------
-// - GstBusSource -
+// - Player -
// ----------------
-struct GstBusSource : public GSource
+Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
+ mxMgr( rxMgr ),
+ mpPlaybin( NULL ),
+ mbFakeVideo (sal_False ),
+ mnUnmutedVolume( 0 ),
+ mbPlayPending ( false ),
+ mbMuted( false ),
+ mbLooping( false ),
+ mbInitialized( false ),
+ mnWindowID( 0 ),
+ mpXOverlay( NULL ),
+ mnDuration( 0 ),
+ mnWidth( 0 ),
+ mnHeight( 0 ),
+ maSizeCondition( osl_createCondition() )
{
- GstBus* mpBus;
+ // Initialize GStreamer library
+ int argc = 1;
+ char name[] = "libreoffice";
+ char *arguments[] = { name };
+ char** argv = arguments;
+ GError* pError = NULL;
- GstBusSource() :
- mpBus( NULL )
- {}
+ mbInitialized = gst_init_check( &argc, &argv, &pError );
- ~GstBusSource()
- {}
-};
+ if (pError != NULL)
+ // TODO: thow an exception?
+ g_error_free (pError);
+}
-// ---------------
-// - Player -
-// ---------------
-Player::Player( GString* pURI ) :
- mpMutex( g_mutex_new() ),
- mpCond( g_cond_new() ),
- mpThread( NULL ),
- mpContext( NULL ),
- mpLoop( NULL ),
- mpPlayer( NULL ),
- mpURI( pURI ),
- mpPlayerWindow( NULL ),
- mnIsVideoSource( 0 ),
- mnVideoWidth( 0 ),
- mnVideoHeight( 0 ),
- mnInitialized( 0 ),
- mnVolumeDB( 0 ),
- mnLooping( 0 ),
- mnQuit( 0 ),
- mnVideoWindowSet( 0 ),
- mnInitFail( 0 )
-{
- // initialize GStreamer framework only once
- static bool bGstInitialized = false;
+// ------------------------------------------------------------------------------
- if( !bGstInitialized )
+Player::~Player()
+{
+ // Release the elements and pipeline
+ if( mbInitialized )
{
- gst_init( NULL, NULL );
- bGstInitialized = true;
- }
+ if( mpPlaybin )
+ {
+ gst_element_set_state( mpPlaybin, GST_STATE_NULL );
+ gst_object_unref( GST_OBJECT( mpPlaybin ) );
- if( pURI )
- {
- OSL_TRACE( ">>> --------------------------------" );
- OSL_TRACE( ">>> Creating Player object with URL: %s", pURI->str );
+ mpPlaybin = NULL;
+ }
- mpThread = g_thread_create( Player::implThreadFunc, this, true, NULL );
+ if( mpXOverlay ) {
+ g_object_unref( G_OBJECT ( mpXOverlay ) );
+ mpXOverlay = NULL;
+ }
}
}
// ------------------------------------------------------------------------------
-Player::~Player()
+static gboolean gst_pipeline_bus_callback( GstBus *, GstMessage *message, gpointer data )
{
- if( g_atomic_pointer_get( &mpPlayer ) )
- {
- implQuitThread();
- }
+ Player* pPlayer = (Player *) data;
- // cleanup
- g_cond_free( mpCond );
- g_mutex_free( mpMutex );
- g_string_free( mpURI, false );
+ pPlayer->processMessage( message );
+
+ return TRUE;
}
-// ------------------------------------------------------------------------------
-Player* Player::create( const ::rtl::OUString& rURL )
+static GstBusSyncReply gst_pipeline_bus_sync_handler( GstBus *, GstMessage * message, gpointer data )
{
- Player* pPlayer = NULL;
+ Player* pPlayer = (Player *) data;
- if( rURL.getLength() )
- {
- // safely initialize GLib threading framework
- try
- {
- if( !g_thread_supported() )
- {
- g_thread_init( NULL );
- }
- }
- catch( ... )
- {}
+ return pPlayer->processSyncMessage( message );
+}
- if( g_thread_supported() )
- {
- const INetURLObject aURL( rURL );
-
- if( aURL.GetProtocol() != INET_PROT_NOT_VALID )
- {
- GString* pURI = g_string_new( ::rtl::OUStringToOString(
- aURL.GetMainURL( INetURLObject::NO_DECODE ),
- RTL_TEXTENCODING_UTF8 ).getStr() );
-
- if( pURI->len )
- {
- pPlayer = new Player( pURI );
-
- // wait until thread signals that it has finished initialization
- if( pPlayer->mpThread )
- {
- g_mutex_lock( pPlayer->mpMutex );
-
- while( !pPlayer->implIsInitialized() )
- {
- g_cond_wait( pPlayer->mpCond, pPlayer->mpMutex );
- }
+void Player::processMessage( GstMessage *message )
+{
+ switch( GST_MESSAGE_TYPE( message ) ) {
+ case GST_MESSAGE_EOS:
+ gst_element_set_state( mpPlaybin, GST_STATE_READY );
+ mbPlayPending = false;
+ if (mbLooping)
+ start();
+ break;
+ case GST_MESSAGE_STATE_CHANGED:
+ if( message->src == GST_OBJECT( mpPlaybin ) ) {
+ GstState newstate, pendingstate;
- g_mutex_unlock( pPlayer->mpMutex );
- }
+ gst_message_parse_state_changed (message, NULL, &newstate, &pendingstate);
- // check if player pipeline could be initialized
- if( !pPlayer->mpPlayer )
- {
- delete pPlayer;
- pPlayer = NULL;
- }
- }
- else
- {
- g_string_free( pURI, false );
- }
- }
+ if( newstate == GST_STATE_PAUSED &&
+ pendingstate == GST_STATE_VOID_PENDING &&
+ mpXOverlay )
+ gst_x_overlay_expose( mpXOverlay );
+
+ if (mbPlayPending)
+ mbPlayPending = ((newstate == GST_STATE_READY) || (newstate == GST_STATE_PAUSED));
}
+ default:
+ break;
}
-
- return( pPlayer );
}
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::start()
- throw( uno::RuntimeException )
+GstBusSyncReply Player::processSyncMessage( GstMessage *message )
{
- if( implInitPlayer() && !isPlaying() )
- {
- gst_element_set_state( mpPlayer, GST_STATE_PLAYING );
+ DBG( "%p processSyncMessage: %s", this, GST_MESSAGE_TYPE_NAME( message ) );
+
+#if DEBUG
+ if ( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR ) {
+ GError* error;
+ gchar* error_debug;
+
+ gst_message_parse_error( message, &error, &error_debug );
+ DBG("error: '%s' debug: '%s'", error->message, error_debug);
}
-}
+#endif
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::stop()
- throw( uno::RuntimeException )
-{
- if( implInitPlayer() && isPlaying() )
- {
- gst_element_set_state( mpPlayer, GST_STATE_PAUSED );
+ if (message->structure) {
+ if( !strcmp( gst_structure_get_name( message->structure ), "prepare-xwindow-id" ) && mnWindowID != 0 ) {
+ if( mpXOverlay )
+ g_object_unref( G_OBJECT ( mpXOverlay ) );
+ mpXOverlay = GST_X_OVERLAY( GST_MESSAGE_SRC( message ) );
+ g_object_ref( G_OBJECT ( mpXOverlay ) );
+ gst_x_overlay_set_xwindow_id( mpXOverlay, mnWindowID );
+ return GST_BUS_DROP;
+ }
}
-}
-// ------------------------------------------------------------------------------
-sal_Bool SAL_CALL Player::isPlaying()
- throw( uno::RuntimeException )
-{
- GstState aState = GST_STATE_NULL;
+ if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_STATE_CHANGED ) {
+ if( message->src == GST_OBJECT( mpPlaybin ) ) {
+ GstState newstate, pendingstate;
- if( mpPlayer )
- {
- gst_element_get_state( mpPlayer, &aState, NULL, GST_MAX_TIMEOUT );
- }
+ gst_message_parse_state_changed (message, NULL, &newstate, &pendingstate);
- return( GST_STATE_PLAYING == aState );
-}
+ DBG( "%p state change received, new state %d", this, newstate );
+ if( newstate == GST_STATE_PAUSED &&
+ pendingstate == GST_STATE_VOID_PENDING ) {
-// ------------------------------------------------------------------------------
-double SAL_CALL Player::getDuration()
- throw( uno::RuntimeException )
-{
- gint64 nDuration = 0;
+ DBG( "%p change to paused received", this );
- if( implInitPlayer() )
- {
- GstFormat aFormat = GST_FORMAT_TIME;
+ if( mnDuration == 0) {
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 gst_duration = 0L;
- if( !gst_element_query_duration( mpPlayer, &aFormat, &nDuration ) ||
- ( GST_FORMAT_TIME != aFormat ) ||
- ( nDuration < 0 ) )
- {
- nDuration = 0;
- }
- }
+ if( gst_element_query_duration( mpPlaybin, &format, &gst_duration) && format == GST_FORMAT_TIME && gst_duration > 0L )
+ mnDuration = gst_duration;
+ }
- return( static_cast< double >( nDuration ) / NANO_TIME_FACTOR );
-}
+ if( mnWidth == 0 ) {
+ GList *pStreamInfo = NULL;
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::setMediaTime( double fTime )
- throw( uno::RuntimeException )
-{
- if( implInitPlayer() )
- {
- fTime = ::std::min( ::std::max( fTime, 0.0 ), getDuration() );
+ g_object_get( G_OBJECT( mpPlaybin ), "stream-info", &pStreamInfo, NULL );
- gst_element_seek_simple( mpPlayer, GST_FORMAT_TIME,
- (GstSeekFlags) ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ),
- static_cast< gint64 >( fTime * NANO_TIME_FACTOR ) );
- }
-}
+ for ( ; pStreamInfo != NULL; pStreamInfo = pStreamInfo->next) {
+ GObject *pInfo = G_OBJECT( pStreamInfo->data );
-// ------------------------------------------------------------------------------
-double SAL_CALL Player::getMediaTime()
- throw( uno::RuntimeException )
-{
- double fRet = 0.0;
+ if( !pInfo )
+ continue;
- if( implInitPlayer() )
- {
- GstFormat aFormat = GST_FORMAT_TIME;
- gint64 nCurTime = 0;
+ int nType;
+ g_object_get( pInfo, "type", &nType, NULL );
+ GEnumValue *pValue = g_enum_get_value( G_PARAM_SPEC_ENUM( g_object_class_find_property( G_OBJECT_GET_CLASS( pInfo ), "type" ) )->enum_class,
+ nType );
- if( gst_element_query_position( mpPlayer, &aFormat, &nCurTime ) &&
- ( GST_FORMAT_TIME == aFormat ) &&
- ( nCurTime >= 0 ) )
- {
- fRet = static_cast< double >( nCurTime ) / NANO_TIME_FACTOR;
+ if( !g_strcasecmp( pValue->value_nick, "video" ) ) {
+ GstStructure *pStructure;
+ GstPad *pPad;
+
+ g_object_get( pInfo, "object", &pPad, NULL );
+ pStructure = gst_caps_get_structure( GST_PAD_CAPS( pPad ), 0 );
+ if( pStructure ) {
+ gst_structure_get_int( pStructure, "width", &mnWidth );
+ gst_structure_get_int( pStructure, "height", &mnHeight );
+ DBG( "queried size: %d x %d", mnWidth, mnHeight );
+ }
+ }
+ }
+
+#if DEBUG
+ sal_Bool aSuccess =
+#endif
+ osl_setCondition( maSizeCondition );
+ DBG( "%p set condition result: %d", this, aSuccess );
+ }
+ }
+ }
+ } else if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR ) {
+ if( mnWidth == 0 ) {
+ // an error occurred, set condition so that OOo thread doesn't wait for us
+#if DEBUG
+ sal_Bool aSuccess =
+#endif
+ osl_setCondition( maSizeCondition );
+ DBG( "%p set condition result: %d", this, aSuccess );
}
}
- return( fRet );
+ return GST_BUS_PASS;
}
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::setStopTime( double /* fTime */ )
- throw( uno::RuntimeException )
+void Player::preparePlaybin( const ::rtl::OUString& rURL, bool bFakeVideo )
{
- OSL_TRACE( "GStreamer method avmedia::gst::Player::setStopTime needs to be implemented" );
+ GstBus *pBus;
- /* Currently no need for implementation since higher levels of code don't use this method at all
- !!! TODO: needs to be implemented if this functionality is needed at a later point of time
- if( implInitPlayer() )
- {
- }
+ if( mpPlaybin != NULL ) {
+ gst_element_set_state( mpPlaybin, GST_STATE_NULL );
+ mbPlayPending = false;
+ g_object_unref( mpPlaybin );
+ }
- */
-}
+ mpPlaybin = gst_element_factory_make( "playbin", NULL );
-// ------------------------------------------------------------------------------
-double SAL_CALL Player::getStopTime()
- throw( uno::RuntimeException )
-{
- /*
- Currently no need for implementation since higher levels of code don't set a stop time ATM
- !!! TODO: needs to be fully implemented if this functionality is needed at a later point of time
- */
+ if( bFakeVideo )
+ g_object_set( G_OBJECT( mpPlaybin ), "video-sink", gst_element_factory_make( "fakesink", NULL ), NULL );
- return( getDuration() );
-}
+ mbFakeVideo = bFakeVideo;
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::setRate( double /* fRate */ )
- throw( uno::RuntimeException )
-{
- OSL_TRACE( "GStreamer method avmedia::gst::Player::setRate needs to be implemented" );
+ rtl::OString ascURL = OUStringToOString( rURL, RTL_TEXTENCODING_ASCII_US );
+ g_object_set( G_OBJECT( mpPlaybin ), "uri", ascURL.getStr() , NULL );
- /* Currently no need for implementation since higher levels of code don't use this method at all
- !!! TODO: needs to be implemented if this functionality is needed at a later point of time
- */
+ pBus = gst_element_get_bus( mpPlaybin );
+ gst_bus_add_watch( pBus, gst_pipeline_bus_callback, this );
+ DBG( "%p set sync handler", this );
+ gst_bus_set_sync_handler( pBus, gst_pipeline_bus_sync_handler, this );
+ g_object_unref( pBus );
}
-// ------------------------------------------------------------------------------
-double SAL_CALL Player::getRate()
- throw( uno::RuntimeException )
+bool Player::create( const ::rtl::OUString& rURL )
{
- /*
- Currently no need for implementation since higher levels of code don't set a different rate than 1 ATM
- !!! TODO: needs to be fully implemented if this functionality is needed at a later point of time
- */
-
- return( 1.0 );
-}
+ bool bRet = false;
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
- throw( uno::RuntimeException )
-{
- if( bSet && !isPlaybackLoop() )
- g_atomic_int_inc( &mnLooping );
- else if( !bSet && isPlaybackLoop() )
- g_atomic_int_dec_and_test( &mnLooping );
-}
+ // create all the elements and link them
-// ------------------------------------------------------------------------------
-sal_Bool SAL_CALL Player::isPlaybackLoop()
- throw( uno::RuntimeException )
-{
- return( g_atomic_int_get( &mnLooping ) > 0 );
-}
+ DBG("create player, URL: %s", OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 ).getStr());
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::setMute( sal_Bool bSet )
- throw( uno::RuntimeException )
-{
- if( implInitPlayer() && ( bSet != isMute() ) )
+ if( mbInitialized )
{
- if( bSet )
- {
- g_object_set( mpPlayer, "volume", 0.0, NULL );
- }
- else
- {
- setVolumeDB( mnVolumeDB );
- }
- }
-}
+ preparePlaybin( rURL, true );
-// ------------------------------------------------------------------------------
-sal_Bool SAL_CALL Player::isMute()
- throw( uno::RuntimeException )
-{
- gdouble fGstVolume = 1.0;
+ gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
+ mbPlayPending = false;
- if( implInitPlayer() )
- {
- g_object_get( mpPlayer, "volume", &fGstVolume, NULL );
+ bRet = true;
}
- return( 0.0 == fGstVolume );
+
+ if( bRet )
+ maURL = rURL;
+ else
+ maURL = ::rtl::OUString();
+
+ return bRet;
}
// ------------------------------------------------------------------------------
-void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
- throw( uno::RuntimeException )
+
+void SAL_CALL Player::start( )
+ throw (uno::RuntimeException)
{
- if( implInitPlayer() )
+ // set the pipeline state to READY and run the loop
+ if( mbInitialized && NULL != mpPlaybin )
{
- g_mutex_lock( mpMutex );
- mnVolumeDB = nVolumeDB;
- g_mutex_unlock( mpMutex );
-
- // maximum gain for gstreamer volume is 10
- double fGstVolume = pow( 10.0, static_cast< double >( ::std::min(
- nVolumeDB, static_cast< sal_Int16 >( 20 ) ) / 20.0 ) );
-
- g_object_set( mpPlayer, "volume", fGstVolume, NULL );
+ gst_element_set_state( mpPlaybin, GST_STATE_PLAYING );
+ mbPlayPending = true;
}
}
// ------------------------------------------------------------------------------
-sal_Int16 SAL_CALL Player::getVolumeDB()
- throw( uno::RuntimeException )
+
+void SAL_CALL Player::stop( )
+ throw (uno::RuntimeException)
{
- return( static_cast< sal_Int16 >( g_atomic_int_get( &mnVolumeDB ) ) );
+ // set the pipeline in PAUSED STATE
+ if( mpPlaybin )
+ gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
+
+ mbPlayPending = false;
+ DBG( "stop %p", mpPlaybin );
}
// ------------------------------------------------------------------------------
-awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
- throw( uno::RuntimeException )
+
+sal_Bool SAL_CALL Player::isPlaying()
+ throw (uno::RuntimeException)
{
- awt::Size aSize( 0, 0 );
+ bool bRet = mbPlayPending;
- if( implInitPlayer() && ( g_atomic_int_get( &mnIsVideoSource ) > 0 ) )
+ // return whether the pipeline is in PLAYING STATE or not
+ if( !mbPlayPending && mbInitialized && mpPlaybin )
{
- aSize.Width = g_atomic_int_get( &mnVideoWidth );
- aSize.Height = g_atomic_int_get( &mnVideoHeight );
-
- // if we have a video source, but no size is given => use default size
- if( ( aSize.Width <= 0 ) || ( aSize.Height <= 0 ) )
- {
- aSize.Width = VIDEO_DEFAULT_WIDTH;
- aSize.Height = VIDEO_DEFAULT_HEIGHT;
- }
+ bRet = GST_STATE_PLAYING == GST_STATE( mpPlaybin );
}
- OSL_TRACE( ">>> Requested preferred video size is: %d x %d pixel", aSize.Width, aSize.Height );
+ DBG( "isPlaying %d", bRet );
- return( aSize );
+ return bRet;
}
// ------------------------------------------------------------------------------
-uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow(
- const uno::Sequence< uno::Any >& rArguments )
- throw( uno::RuntimeException )
-{
- uno::Reference< ::media::XPlayerWindow > xRet;
- awt::Size aSize( getPreferredPlayerWindowSize() );
-
- OSL_ENSURE( !g_atomic_pointer_get( &mpPlayerWindow ), "::avmedia::gst::Player already has a player window" );
- if( ( aSize.Width > 0 ) && ( aSize.Height > 0 ) )
- {
- Window* pPlayerWindow = new Window( *this );
-
- xRet = pPlayerWindow;
+double SAL_CALL Player::getDuration( )
+ throw (uno::RuntimeException)
+{
+ // slideshow checks for non-zero duration, so cheat here
+ double duration = 0.01;
- if( !pPlayerWindow->create( rArguments ) )
- {
- xRet.clear();
- }
- else
- {
- // try to use gconf user configurable video sink first
- GstElement* pVideoSink = gst_element_factory_make( "gconfvideosink", NULL );
-
- if( ( NULL != pVideoSink ) ||
- ( NULL != ( pVideoSink = gst_element_factory_make( "autovideosink", NULL ) ) ) ||
- ( NULL != ( pVideoSink = gst_element_factory_make( "xvimagesink", NULL ) ) ) ||
- ( NULL != ( pVideoSink = gst_element_factory_make( "ximagesink", NULL ) ) ) )
- {
- GstState aOldState = GST_STATE_NULL;
-
- mpPlayerWindow = pPlayerWindow;
- gst_element_get_state( mpPlayer, &aOldState, NULL, GST_MAX_TIMEOUT );
- gst_element_set_state( mpPlayer, GST_STATE_READY );
- g_object_set( mpPlayer, "video-sink", pVideoSink, NULL );
- gst_element_set_state( mpPlayer, aOldState );
- }
- }
+ if( mpPlaybin && mnDuration > 0 ) {
+ duration = mnDuration / 1E9;
}
- return( xRet );
+ return duration;
}
// ------------------------------------------------------------------------------
-uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
- throw( ::com::sun::star::uno::RuntimeException )
+
+void SAL_CALL Player::setMediaTime( double fTime )
+ throw (uno::RuntimeException)
{
- FrameGrabber* pFrameGrabber = NULL;
- const awt::Size aPrefSize( getPreferredPlayerWindowSize() );
+ if( mpPlaybin ) {
+ gint64 gst_position = llround (fTime * 1E9);
- if( ( aPrefSize.Width > 0 ) && ( aPrefSize.Height > 0 ) )
- {
- pFrameGrabber = FrameGrabber::create( mpURI );
- }
+ gst_element_seek( mpPlaybin, 1.0,
+ GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, gst_position,
+ GST_SEEK_TYPE_NONE, 0 );
+ if( !isPlaying() )
+ gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
- return( pFrameGrabber );
+ DBG( "seek to: %lld ns original: %lf s", gst_position, fTime );
+ }
}
// ------------------------------------------------------------------------------
-void SAL_CALL Player::dispose()
- throw( uno::RuntimeException )
+
+double SAL_CALL Player::getMediaTime( )
+ throw (uno::RuntimeException)
{
- if( mpPlayer )
- {
- stop();
- implQuitThread();
+ double position = 0.0;
+
+ if( mpPlaybin ) {
+ // get current position in the stream
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 gst_position;
+ if( gst_element_query_position( mpPlaybin, &format, &gst_position ) && format == GST_FORMAT_TIME && gst_position > 0L )
+ position = gst_position / 1E9;
}
- OSL_ASSERT( NULL == mpPlayer );
+ return position;
}
// ------------------------------------------------------------------------------
-void SAL_CALL Player::addEventListener( const uno::Reference< lang::XEventListener >& /*rxListener*/ )
- throw( uno::RuntimeException )
-{}
-
-// ------------------------------------------------------------------------------
-void SAL_CALL Player::removeEventListener( const uno::Reference< lang::XEventListener >& /*rxListener*/ )
- throw( uno::RuntimeException )
-{}
-// ------------------------------------------------------------------------------
-::rtl::OUString SAL_CALL Player::getImplementationName()
- throw( uno::RuntimeException )
+void SAL_CALL Player::setStopTime( double /*fTime*/ )
+ throw (uno::RuntimeException)
{
- return( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_IMPLEMENTATIONNAME ) ) );
+ // TODO implement
}
// ------------------------------------------------------------------------------
-sal_Bool SAL_CALL Player::supportsService( const ::rtl::OUString& ServiceName )
- throw( uno::RuntimeException )
-{
- return( ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_SERVICENAME ) ) );
-}
-// ------------------------------------------------------------------------------
-uno::Sequence< ::rtl::OUString > SAL_CALL Player::getSupportedServiceNames()
- throw( uno::RuntimeException )
+double SAL_CALL Player::getStopTime( )
+ throw (uno::RuntimeException)
{
- uno::Sequence< ::rtl::OUString > aRet( 1 );
- aRet[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_SERVICENAME ) );
+ // Get the time at which to stop
- return( aRet );
+ return 0;
}
// ------------------------------------------------------------------------------
-void Player::implQuitThread()
-{
- if( mpThread )
- {
- // set quit flag to 1 so that the main loop will be quit in idle
- // handler the next time it is called from the thread's main loop
- g_atomic_int_inc( &mnQuit );
- // wait until loop and as such the thread has quit
- g_thread_join( mpThread );
- mpThread = NULL;
- }
+void SAL_CALL Player::setRate( double /*fRate*/ )
+ throw (uno::RuntimeException)
+{
+ // TODO set the window rate
}
// ------------------------------------------------------------------------------
-bool Player::implInitPlayer()
+
+double SAL_CALL Player::getRate( )
+ throw (uno::RuntimeException)
{
- bool bRet = false;
+ double rate = 0.0;
- if( mpPlayer && (mnInitFail < 3) )
+ // TODO get the window rate
+ if( mbInitialized )
{
- GstState aState = GST_STATE_NULL;
-
- if( gst_element_get_state( mpPlayer, &aState, NULL, GST_MAX_TIMEOUT ) == GST_STATE_CHANGE_SUCCESS )
- {
- bRet = ( GST_STATE_PAUSED == aState ) || ( GST_STATE_PLAYING == aState );
-
- if( !bRet )
- {
- gst_element_set_state( mpPlayer, GST_STATE_PAUSED );
- bRet = ( gst_element_get_state( mpPlayer, &aState, NULL,
- GST_MAX_TIMEOUT ) == GST_STATE_CHANGE_SUCCESS ) &&
- ( GST_STATE_PAUSED == aState );
- }
- }
- if( ! bRet )
- mnInitFail++;
}
- return( bRet );
+ return rate;
}
// ------------------------------------------------------------------------------
-gboolean Player::implBusPrepare( GSource* pSource,
- gint* pTimeout )
-{
- if( pTimeout )
- {
- *pTimeout = 0;
- }
-
- return( implBusCheck( pSource ) );
-}
-// ------------------------------------------------------------------------------
-gboolean Player::implBusCheck( GSource* pSource )
+void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
+ throw (uno::RuntimeException)
{
- GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
-
- return( pBusSource &&
- GST_IS_BUS( pBusSource->mpBus ) &&
- gst_bus_have_pending( GST_BUS_CAST( pBusSource->mpBus ) ) );
+ // TODO check how to do with GST
+ mbLooping = bSet;
}
// ------------------------------------------------------------------------------
-gboolean Player::implBusDispatch( GSource* pSource,
- GSourceFunc /*aCallback*/,
- gpointer pData )
-{
- GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
- gboolean bRet = false;
-
- if( pData && pBusSource && GST_IS_BUS( pBusSource->mpBus ) )
- {
- GstMessage* pMsg = gst_bus_pop( pBusSource->mpBus );
-
- if( pMsg )
- {
- bRet = static_cast< Player* >( pData )->busCallback( pBusSource->mpBus, pMsg );
- gst_message_unref( pMsg );
- }
- }
-
- return( bRet );
-}
-// ------------------------------------------------------------------------------
-void Player::implBusFinalize( GSource* pSource )
+sal_Bool SAL_CALL Player::isPlaybackLoop( )
+ throw (uno::RuntimeException)
{
- GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
-
- if( pBusSource && pBusSource->mpBus )
- {
- gst_object_unref( pBusSource->mpBus );
- pBusSource->mpBus = NULL;
- }
+ // TODO check how to do with GST
+ return mbLooping;
}
// ------------------------------------------------------------------------------
-gboolean Player::busCallback( GstBus* /*pBus*/,
- GstMessage* pMsg )
+
+void SAL_CALL Player::setMute( sal_Bool bSet )
+ throw (uno::RuntimeException)
{
- if( pMsg && mpLoop )
+ DBG( "set mute: %d muted: %d unmuted volume: %lf", bSet, mbMuted, mnUnmutedVolume );
+
+ // change the volume to 0 or the unmuted volume
+ if( mpPlaybin && mbMuted != bSet )
{
- switch( GST_MESSAGE_TYPE( pMsg ) )
+ double nVolume = mnUnmutedVolume;
+ if( bSet )
{
- case ( GST_MESSAGE_EOS ):
- {
- if( g_atomic_int_get( &mnLooping ) > 0 )
- {
- setMediaTime( 0.0 );
- start();
- }
- else
- {
- stop();
- }
- }
- break;
-
- case ( GST_MESSAGE_ERROR ):
- {
- gchar* pDebug;
- GError* pErr;
-
- gst_message_parse_error( pMsg, &pErr, &pDebug );
- fprintf( stderr, "Error: %s\n", pErr->message );
+ nVolume = 0.0;
+ }
- g_free( pDebug );
- g_error_free( pErr );
- }
- break;
+ g_object_set( G_OBJECT( mpPlaybin ), "volume", nVolume, NULL );
- default:
- {
- break;
- }
- }
+ mbMuted = bSet;
}
-
- return( true );
}
// ------------------------------------------------------------------------------
-gboolean Player::implIdleFunc( gpointer pData )
-{
- return( pData ? static_cast< Player* >( pData )->idle() : true );
-}
-// ------------------------------------------------------------------------------
-gpointer Player::implThreadFunc( gpointer pData )
+sal_Bool SAL_CALL Player::isMute( )
+ throw (uno::RuntimeException)
{
- return( pData ? static_cast< Player* >( pData )->run() : NULL );
+ return mbMuted;
}
// ------------------------------------------------------------------------------
-GstBusSyncReply Player::implHandleCreateWindowFunc( GstBus* pBus,
- GstMessage* pMsg,
- gpointer pData )
-{
- return( pData ? static_cast< Player* >( pData )->handleCreateWindow( pBus, pMsg ) : GST_BUS_PASS );
-}
-// ------------------------------------------------------------------------------
-void Player::implHandleNewElementFunc( GstBin* /* pBin */,
- GstElement* pElement,
- gpointer pData )
+void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
+ throw (uno::RuntimeException)
{
- if( pElement )
- {
-#ifdef DEBUG
- gchar* pElementName = gst_element_get_name( pElement );
+ mnUnmutedVolume = pow( 10.0, nVolumeDB / 20.0 );
- if( pElementName )
- {
- OSL_TRACE( ">>> Bin has element: %s", pElementName );
- g_free( pElementName );
- }
-#endif
-
- if( GST_IS_BIN( pElement ) )
- {
- // set this handler in case we have a GstBin element
- g_signal_connect( GST_BIN( pElement ), "element-added",
- G_CALLBACK( Player::implHandleNewElementFunc ), pData );
- }
+ DBG( "set volume: %d gst volume: %lf", nVolumeDB, mnUnmutedVolume );
- // watch for all pads that are going to be added to this element;
- g_signal_connect( pElement, "pad-added",
- G_CALLBACK( Player::implHandleNewPadFunc ), pData );
- }
+ // change volume
+ if( !mbMuted && mpPlaybin )
+ {
+ g_object_set( G_OBJECT( mpPlaybin ), "volume", (gdouble) mnUnmutedVolume, NULL );
+ }
}
// ------------------------------------------------------------------------------
-void Player::implHandleNewPadFunc( GstElement* pElement,
- GstPad* pPad,
- gpointer pData )
+
+sal_Int16 SAL_CALL Player::getVolumeDB( )
+ throw (uno::RuntimeException)
{
- Player* pPlayer = static_cast< Player* >( pData );
+ sal_Int16 nVolumeDB(0);
- if( pPlayer && pElement && pPad )
- {
-#ifdef DEBUG
- gchar* pElementName = gst_element_get_name( pElement );
- gchar* pPadName = gst_pad_get_name( pPad );
+ if( mpPlaybin ) {
+ double nGstVolume = 0.0;
- OSL_TRACE( ">>> Element %s has pad: %s", pElementName, pPadName );
+ g_object_get( G_OBJECT( mpPlaybin ), "volume", &nGstVolume, NULL );
- g_free( pPadName );
- g_free( pElementName );
-#endif
+ nVolumeDB = (sal_Int16) ( 20.0*log10 ( nGstVolume ) );
+ }
- GstCaps* pCaps = gst_pad_get_caps( pPad );
+ return nVolumeDB;
+}
- // we are interested only in getting video properties
- // width and height or if we have a video source at all
- if( pCaps )
- {
- for( gint i = 0, nSize = gst_caps_get_size( pCaps ); i < nSize; ++i )
- {
- const GstStructure* pStruct = gst_caps_get_structure( pCaps, i );
+// ------------------------------------------------------------------------------
- if( pStruct )
- {
- const gchar* pStructName = gst_structure_get_name( pStruct );
+awt::Size SAL_CALL Player::getPreferredPlayerWindowSize( )
+ throw (uno::RuntimeException)
+{
+ awt::Size aSize( 0, 0 );
-#ifdef DEBUG
- OSL_TRACE( "\t>>> Pad has structure: %s", pStructName );
+ DBG( "%p Player::getPreferredPlayerWindowSize, member %d x %d", this, mnWidth, mnHeight );
- for( gint n = 0, nFields = gst_structure_n_fields( pStruct ); n < nFields; ++n )
- {
- OSL_TRACE( "\t\t>>> Structure has field: %s", gst_structure_nth_field_name( pStruct, n ) );
- }
+ TimeValue aTimeout = { 10, 0 };
+#if DEBUG
+ oslConditionResult aResult =
#endif
+ osl_waitCondition( maSizeCondition, &aTimeout );
- // just look for structures having 'video' in their names
- if( ::std::string( pStructName ).find( "video" ) != ::std::string::npos )
- {
- g_atomic_int_inc( &pPlayer->mnIsVideoSource );
-
- for( gint n = 0, nFields = gst_structure_n_fields( pStruct ); n < nFields; ++n )
- {
- const gchar* pFieldName = gst_structure_nth_field_name( pStruct, n );
- gint nValue;
-
- if( ( ::std::string( pFieldName ).find( "width" ) != ::std::string::npos ) &&
- gst_structure_get_int( pStruct, pFieldName, &nValue ) )
- {
- const gint nDiff = nValue - g_atomic_int_get( &pPlayer->mnVideoWidth );
- g_atomic_int_add( &pPlayer->mnVideoWidth, ::std::max( nDiff, 0 ) );
- }
- else if( ( ::std::string( pFieldName ).find( "height" ) != ::std::string::npos ) &&
- gst_structure_get_int( pStruct, pFieldName, &nValue ) )
- {
- const gint nDiff = nValue - g_atomic_int_get( &pPlayer->mnVideoHeight );
- g_atomic_int_add( &pPlayer->mnVideoHeight, ::std::max( nDiff, 0 ) );
- }
- }
- }
- }
- }
+ if( mbFakeVideo ) {
+ mbFakeVideo = sal_False;
- gst_caps_unref( pCaps );
- }
+ g_object_set( G_OBJECT( mpPlaybin ), "video-sink", NULL, NULL );
+ gst_element_set_state( mpPlaybin, GST_STATE_READY );
+ gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
}
-}
-// ------------------------------------------------------------------------------
-gboolean Player::idle()
-{
- // test if main loop should quit and set flag mnQuit to 1
- bool bQuit = g_atomic_int_compare_and_exchange( &mnQuit, 1, 1 );
+ DBG( "%p Player::getPreferredPlayerWindowSize after waitCondition %d, member %d x %d", this, aResult, mnWidth, mnHeight );
- if( bQuit )
- {
- // set mnQuit back to 0 to avoid mutiple g_main_loop_quit calls
- // in case Player::idle() is called again later;
- // the flag should have been set only once within Ctor called from
- // the application thread
- g_atomic_int_dec_and_test( &mnQuit );
- g_main_loop_quit( mpLoop );
+ if( mnWidth != 0 && mnHeight != 0 ) {
+ aSize.Width = mnWidth;
+ aSize.Height = mnHeight;
}
- // don't eat up all cpu time
- usleep( 1000 );
-
- return( true );
+ return aSize;
}
// ------------------------------------------------------------------------------
-gpointer Player::run()
+
+uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& rArguments )
+ throw (uno::RuntimeException)
{
- static GSourceFuncs aSourceFuncs =
- {
- Player::implBusPrepare,
- Player::implBusCheck,
- Player::implBusDispatch,
- Player::implBusFinalize,
- NULL,
- NULL
- };
-
- if( NULL != ( mpPlayer = gst_element_factory_make( "playbin", NULL ) ) )
- {
- // initialization
- // no mutex necessary since initialization
- // is synchronous until loop is started
- mpContext = g_main_context_new();
- mpLoop = g_main_loop_new( mpContext, false );
-
- // add idle callback
- GSource* pIdleSource = g_idle_source_new();
- g_source_set_callback( pIdleSource, Player::implIdleFunc, this, NULL );
- g_source_attach( pIdleSource, mpContext );
-
- // add bus callback
- GSource* pBusSource = g_source_new( &aSourceFuncs, sizeof( GstBusSource ) );
- static_cast< GstBusSource* >( pBusSource )->mpBus = gst_pipeline_get_bus( GST_PIPELINE( mpPlayer ) );
- g_source_set_callback( pBusSource, NULL, this, NULL );
- g_source_attach( pBusSource, mpContext );
-
- // add bus sync handler to intercept video window creation for setting our own window
- gst_bus_set_sync_handler( static_cast< GstBusSource* >( pBusSource )->mpBus,
- Player::implHandleCreateWindowFunc, this );
-
- // watch for all elements (and pads) that will be added to the playbin,
- // in order to retrieve properties like video width and height
- g_signal_connect( GST_BIN( mpPlayer ), "element-added",
- G_CALLBACK( Player::implHandleNewElementFunc ), this );
-
- // set source URI for player
- g_object_set( mpPlayer, "uri", mpURI->str, NULL );
-
- // set video fake sink first, since we only create a player without window here
- // and don't want to have the gstreamer default window appearing
- g_object_set( mpPlayer, "video-sink", gst_element_factory_make( "fakesink", NULL ), NULL );
-
- // set state of player to READY or destroy object in case of FAILURE
- if( gst_element_set_state( mpPlayer, GST_STATE_READY ) == GST_STATE_CHANGE_FAILURE )
- {
- gst_object_unref( mpPlayer );
- mpPlayer = NULL;
- }
+ uno::Reference< ::media::XPlayerWindow > xRet;
+ awt::Size aSize( getPreferredPlayerWindowSize() );
- g_atomic_int_add( &mnInitialized, 1 );
- g_cond_signal( mpCond );
+ DBG( "Player::createPlayerWindow %d %d length: %d", aSize.Width, aSize.Height, rArguments.getLength() );
- // run the main loop
- g_main_loop_run( mpLoop );
+ if( aSize.Width > 0 && aSize.Height > 0 )
+ {
+ ::avmedia::gstreamer::Window* pWindow = new ::avmedia::gstreamer::Window( mxMgr, *this );
- // clenanup
- // no mutex necessary since other thread joined us (this thread)
- // after setting the quit flag
- if( mpPlayer )
- {
- gst_element_set_state( mpPlayer, GST_STATE_NULL );
- gst_object_unref( mpPlayer );
- mpPlayer = NULL;
- }
+ xRet = pWindow;
- g_main_loop_unref( mpLoop );
- mpLoop = NULL;
+ if( rArguments.getLength() > 2 ) {
+ rArguments[ 2 ] >>= mnWindowID;
+ DBG( "window ID: %ld", mnWindowID );
+ }
+ }
- g_source_destroy( pBusSource );
- g_source_unref( pBusSource );
+ return xRet;
+}
- g_source_destroy( pIdleSource );
- g_source_unref( pIdleSource );
+// ------------------------------------------------------------------------------
- g_main_context_unref( mpContext );
- mpContext = NULL;
- }
- else
- {
- g_atomic_int_add( &mnInitialized, 1 );
- g_cond_signal( mpCond );
- }
+uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber( )
+ throw (uno::RuntimeException)
+{
+ uno::Reference< media::XFrameGrabber > xRet;
- return( NULL );
+ return xRet;
}
// ------------------------------------------------------------------------------
-GstBusSyncReply Player::handleCreateWindow( GstBus* /* pBus */,
- GstMessage* pMsg )
+
+::rtl::OUString SAL_CALL Player::getImplementationName( )
+ throw (uno::RuntimeException)
{
- GstBusSyncReply eRet = GST_BUS_PASS;
+ return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME ) );
+}
- if( pMsg &&
- ( GST_MESSAGE_TYPE( pMsg ) == GST_MESSAGE_ELEMENT ) &&
- gst_structure_has_name( pMsg->structure, "prepare-xwindow-id" ) &&
- g_atomic_pointer_get( &mpPlayerWindow ) )
- {
- OSL_TRACE( ">>> Got Request to create XOverlay" );
+// ------------------------------------------------------------------------------
- gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( GST_MESSAGE_SRC( pMsg ) ),
- static_cast< Window* >( g_atomic_pointer_get(
- &mpPlayerWindow ) )->getXWindowHandle() );
+sal_Bool SAL_CALL Player::supportsService( const ::rtl::OUString& ServiceName )
+ throw (uno::RuntimeException)
+{
+ return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( AVMEDIA_GST_PLAYER_SERVICENAME ) );
+}
- gst_message_unref( pMsg );
- eRet = GST_BUS_DROP;
- }
+// ------------------------------------------------------------------------------
- return( eRet );
+uno::Sequence< ::rtl::OUString > SAL_CALL Player::getSupportedServiceNames( )
+ throw (uno::RuntimeException)
+{
+ uno::Sequence< ::rtl::OUString > aRet(1);
+ aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( AVMEDIA_GST_PLAYER_SERVICENAME ) );
+
+ return aRet;
}
-} // namespace gst
+
+} // namespace gstreamer
} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */