blob: af974e460f73b63f192de7e5c64dce71ec320d17 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#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 <gst/interfaces/xoverlay.h>
// maximum timeout time in nanoseconds
#define GST_MAX_TIMEOUT (2500 * GST_MSECOND)
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;
// ----------------
// - GstBusSource -
// ----------------
struct GstBusSource : public GSource
{
GstBus* mpBus;
GstBusSource() :
mpBus( NULL )
{}
~GstBusSource()
{}
};
// -----------------------------------------------------------------------
extern "C"
{
static gpointer
lcl_implThreadFunc( gpointer pData )
{
return( pData ? static_cast< Player* >( pData )->run() : NULL );
}
static gboolean
lcl_implBusCheck( GSource* pSource )
{
GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
return( pBusSource &&
GST_IS_BUS( pBusSource->mpBus ) &&
gst_bus_have_pending( GST_BUS_CAST( pBusSource->mpBus ) ) );
}
static gboolean
lcl_implBusPrepare( GSource* pSource, gint* pTimeout )
{
if (pTimeout)
{
*pTimeout = 0;
}
return lcl_implBusCheck(pSource);
}
static gboolean
lcl_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 );
}
static void
lcl_implBusFinalize( GSource* pSource )
{
GstBusSource* pBusSource = static_cast< GstBusSource* >( pSource );
if( pBusSource && pBusSource->mpBus )
{
gst_object_unref( pBusSource->mpBus );
pBusSource->mpBus = NULL;
}
}
static gboolean
lcl_implIdleFunc( gpointer pData )
{
return( pData ? static_cast< Player* >( pData )->idle() : true );
}
static GstBusSyncReply
lcl_implHandleCreateWindowFunc( GstBus* pBus, GstMessage* pMsg, gpointer pData )
{
return (pData)
? static_cast< Player* >( pData )->handleCreateWindow( pBus, pMsg )
: GST_BUS_PASS;
}
} // extern "C"
// ---------------
// - Player -
// ---------------
Player::Player( GString* pURI ) :
Player_BASE(m_aMutex),
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 )
{
gst_init( NULL, NULL );
bGstInitialized = true;
}
if( pURI )
{
OSL_TRACE( ">>> --------------------------------" );
OSL_TRACE( ">>> Creating Player object with URL: %s", pURI->str );
mpThread = g_thread_create( &lcl_implThreadFunc, this, true, NULL );
}
}
// ------------------------------------------------------------------------------
Player::~Player()
{
if( g_atomic_pointer_get( &mpPlayer ) )
{
implQuitThread();
}
// cleanup
g_cond_free( mpCond );
g_mutex_free( mpMutex );
g_string_free( mpURI, false );
}
// ------------------------------------------------------------------------------
Player* Player::create( const ::rtl::OUString& rURL )
{
Player* pPlayer = NULL;
if( !rURL.isEmpty() )
{
// safely initialize GLib threading framework
try
{
if( !g_thread_supported() )
{
g_thread_init( NULL );
}
}
catch( ... )
{}
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 );
}
g_mutex_unlock( pPlayer->mpMutex );
}
// check if player pipeline could be initialized
if( !pPlayer->mpPlayer )
{
delete pPlayer;
pPlayer = NULL;
}
}
else
{
g_string_free( pURI, false );
}
}
}
}
return( pPlayer );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::start()
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() && !isPlaying() )
{
gst_element_set_state( mpPlayer, GST_STATE_PLAYING );
}
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::stop()
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() && isPlaying() )
{
gst_element_set_state( mpPlayer, GST_STATE_PAUSED );
}
}
// ------------------------------------------------------------------------------
sal_Bool SAL_CALL Player::isPlaying()
throw( uno::RuntimeException )
{
GstState aState = GST_STATE_NULL;
::osl::MutexGuard aGuard(m_aMutex);
if( mpPlayer )
{
gst_element_get_state( mpPlayer, &aState, NULL, GST_MAX_TIMEOUT );
}
return( GST_STATE_PLAYING == aState );
}
// ------------------------------------------------------------------------------
double SAL_CALL Player::getDuration()
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
gint64 nDuration = 0;
if( implInitPlayer() )
{
GstFormat aFormat = GST_FORMAT_TIME;
if( !gst_element_query_duration( mpPlayer, &aFormat, &nDuration ) ||
( GST_FORMAT_TIME != aFormat ) ||
( nDuration < 0 ) )
{
nDuration = 0;
}
}
return( static_cast< double >( nDuration ) / NANO_TIME_FACTOR );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::setMediaTime( double fTime )
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() )
{
fTime = ::std::min( ::std::max( fTime, 0.0 ), getDuration() );
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 ) );
}
}
// ------------------------------------------------------------------------------
double SAL_CALL Player::getMediaTime()
throw( uno::RuntimeException )
{
double fRet = 0.0;
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() )
{
GstFormat aFormat = GST_FORMAT_TIME;
gint64 nCurTime = 0;
if( gst_element_query_position( mpPlayer, &aFormat, &nCurTime ) &&
( GST_FORMAT_TIME == aFormat ) &&
( nCurTime >= 0 ) )
{
fRet = static_cast< double >( nCurTime ) / NANO_TIME_FACTOR;
}
}
return( fRet );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::setStopTime( double /* fTime */ )
throw( uno::RuntimeException )
{
OSL_TRACE( "GStreamer method avmedia::gst::Player::setStopTime needs to be implemented" );
/* 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() )
{
}
*/
}
// ------------------------------------------------------------------------------
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
*/
::osl::MutexGuard aGuard(m_aMutex);
return( getDuration() );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::setRate( double /* fRate */ )
throw( uno::RuntimeException )
{
OSL_TRACE( "GStreamer method avmedia::gst::Player::setRate needs to be implemented" );
/* 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
*/
}
// ------------------------------------------------------------------------------
double SAL_CALL Player::getRate()
throw( uno::RuntimeException )
{
/*
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 );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
if (bSet)
{
g_atomic_int_compare_and_exchange(&mnLooping, 0, 1);
}
else
{
g_atomic_int_compare_and_exchange(&mnLooping, 1, 0);
}
}
// ------------------------------------------------------------------------------
sal_Bool SAL_CALL Player::isPlaybackLoop()
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
return( g_atomic_int_get( &mnLooping ) > 0 );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::setMute( sal_Bool bSet )
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() && ( bSet != isMute() ) )
{
if( bSet )
{
g_object_set( mpPlayer, "volume", 0.0, NULL );
}
else
{
setVolumeDB( mnVolumeDB );
}
}
}
// ------------------------------------------------------------------------------
sal_Bool SAL_CALL Player::isMute()
throw( uno::RuntimeException )
{
gdouble fGstVolume = 1.0;
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() )
{
g_object_get( mpPlayer, "volume", &fGstVolume, NULL );
}
return( 0.0 == fGstVolume );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() )
{
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 );
}
}
// ------------------------------------------------------------------------------
sal_Int16 SAL_CALL Player::getVolumeDB()
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
return( static_cast< sal_Int16 >( g_atomic_int_get( &mnVolumeDB ) ) );
}
// ------------------------------------------------------------------------------
awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
throw( uno::RuntimeException )
{
awt::Size aSize( 0, 0 );
::osl::MutexGuard aGuard(m_aMutex);
if( implInitPlayer() && ( g_atomic_int_get( &mnIsVideoSource ) > 0 ) )
{
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;
}
}
OSL_TRACE( ">>> Requested preferred video size is: %d x %d pixel", aSize.Width, aSize.Height );
return( aSize );
}
// ------------------------------------------------------------------------------
uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow(
const uno::Sequence< uno::Any >& rArguments )
throw( uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
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;
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 );
}
}
}
return( xRet );
}
// ------------------------------------------------------------------------------
uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
throw( ::com::sun::star::uno::RuntimeException )
{
::osl::MutexGuard aGuard(m_aMutex);
FrameGrabber* pFrameGrabber = NULL;
const awt::Size aPrefSize( getPreferredPlayerWindowSize() );
if( ( aPrefSize.Width > 0 ) && ( aPrefSize.Height > 0 ) )
{
pFrameGrabber = FrameGrabber::create( mpURI );
}
return( pFrameGrabber );
}
// ------------------------------------------------------------------------------
void SAL_CALL Player::disposing()
{
::osl::MutexGuard aGuard(m_aMutex);
if( mpPlayer )
{
stop();
implQuitThread();
}
OSL_ASSERT( NULL == mpPlayer );
}
// ------------------------------------------------------------------------------
::rtl::OUString SAL_CALL Player::getImplementationName()
throw( uno::RuntimeException )
{
return( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_IMPLEMENTATIONNAME ) ) );
}
// ------------------------------------------------------------------------------
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 )
{
uno::Sequence< ::rtl::OUString > aRet( 1 );
aRet[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_GSTREAMER_PLAYER_SERVICENAME ) );
return( aRet );
}
// ------------------------------------------------------------------------------
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;
}
}
// ------------------------------------------------------------------------------
bool Player::implInitPlayer()
{
bool bRet = false;
if( mpPlayer && (mnInitFail < 3) )
{
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 );
}
// ------------------------------------------------------------------------------
gboolean Player::busCallback( GstBus* /*pBus*/,
GstMessage* pMsg )
{
if( pMsg && mpLoop )
{
switch( GST_MESSAGE_TYPE( pMsg ) )
{
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 );
g_free( pDebug );
g_error_free( pErr );
}
break;
default:
{
break;
}
}
}
return( true );
}
// ------------------------------------------------------------------------------
void Player::implHandleNewElementFunc( GstBin* /* pBin */,
GstElement* pElement,
gpointer pData )
{
if( pElement )
{
#ifdef DEBUG
gchar* pElementName = gst_element_get_name( pElement );
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 );
}
// watch for all pads that are going to be added to this element;
g_signal_connect( pElement, "pad-added",
G_CALLBACK( Player::implHandleNewPadFunc ), pData );
}
}
// ------------------------------------------------------------------------------
void Player::implHandleNewPadFunc( GstElement* pElement,
GstPad* pPad,
gpointer pData )
{
Player* pPlayer = static_cast< Player* >( pData );
if( pPlayer && pElement && pPad )
{
#ifdef DEBUG
gchar* pElementName = gst_element_get_name( pElement );
gchar* pPadName = gst_pad_get_name( pPad );
OSL_TRACE( ">>> Element %s has pad: %s", pElementName, pPadName );
g_free( pPadName );
g_free( pElementName );
#endif
GstCaps* pCaps = gst_pad_get_caps( pPad );
// 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 );
#ifdef DEBUG
OSL_TRACE( "\t>>> Pad has structure: %s", pStructName );
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 ) );
}
#endif
// 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 ) );
}
}
}
}
}
gst_caps_unref( pCaps );
}
}
}
// ------------------------------------------------------------------------------
gboolean Player::idle()
{
// test if main loop should quit by comparing with 1
// and set flag mnQuit to 0 so we call g_main_loop_quit exactly once
bool const bQuit = g_atomic_int_compare_and_exchange( &mnQuit, 1, 0 );
if( bQuit )
{
g_main_loop_quit( mpLoop );
}
// don't eat up all cpu time
usleep( 1000 );
return( true );
}
// ------------------------------------------------------------------------------
gpointer Player::run()
{
static GSourceFuncs aSourceFuncs =
{
&lcl_implBusPrepare,
&lcl_implBusCheck,
&lcl_implBusDispatch,
&lcl_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, &lcl_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,
&lcl_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;
}
g_atomic_int_add( &mnInitialized, 1 );
g_cond_signal( mpCond );
// run the main loop
g_main_loop_run( mpLoop );
// 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;
}
g_main_loop_unref( mpLoop );
mpLoop = NULL;
g_source_destroy( pBusSource );
g_source_unref( pBusSource );
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 );
}
return( NULL );
}
// ------------------------------------------------------------------------------
GstBusSyncReply Player::handleCreateWindow( GstBus* /* pBus */,
GstMessage* pMsg )
{
GstBusSyncReply eRet = GST_BUS_PASS;
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() );
gst_message_unref( pMsg );
eRet = GST_BUS_DROP;
}
return( eRet );
}
} // namespace gst
} // namespace avmedia