fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / avmedia / source / gstreamer / gstplayer.cxx
blobd12e8e9324674460ef49020e0e2b62670af6b2ea
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <algorithm>
23 #include <cassert>
24 #include <cstddef>
25 #include <cstring>
26 #include <map>
27 #include <set>
28 #include <vector>
29 #include <math.h>
31 #include <cppuhelper/supportsservice.hxx>
33 #include <rtl/string.hxx>
34 #include <salhelper/thread.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/syschild.hxx>
37 #include <vcl/sysdata.hxx>
39 #include "gstplayer.hxx"
40 #include "gstframegrabber.hxx"
41 #include "gstwindow.hxx"
43 #ifdef AVMEDIA_GST_0_10
44 # define AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_GStreamer_0_10"
45 # define AVMEDIA_GST_PLAYER_SERVICENAME "com.sun.star.media.Player_GStreamer_0_10"
46 #else
47 # include <gst/video/videooverlay.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"
50 #endif
52 #include <gst/pbutils/missing-plugins.h>
53 #include <gst/pbutils/pbutils.h>
55 #if !defined DBG
56 # if OSL_DEBUG_LEVEL > 2
57 #ifdef AVMEDIA_GST_0_10
58 # define AVVERSION "gst 0.10: "
59 #else
60 # define AVVERSION "gst 1.0: "
61 #endif
62 #define DBG(...) do { fprintf (stderr, "%s", AVVERSION); fprintf (stderr, __VA_ARGS__); fprintf (stderr, "\n"); } while (0);
63 # else
64 #define DBG(...)
65 # endif
66 #endif
68 using namespace ::com::sun::star;
70 namespace avmedia { namespace gstreamer {
72 namespace {
74 class FlagGuard {
75 public:
76 explicit FlagGuard(bool & flag): flag_(flag) { flag_ = true; }
78 ~FlagGuard() { flag_ = false; }
80 private:
81 bool & flag_;
84 class MissingPluginInstallerThread: public salhelper::Thread {
85 public:
86 MissingPluginInstallerThread(): Thread("MissingPluginInstaller") {}
88 private:
89 void execute() SAL_OVERRIDE;
92 class MissingPluginInstaller {
93 friend class MissingPluginInstallerThread;
95 public:
96 MissingPluginInstaller(): launchNewThread_(true), inCleanUp_(false) {}
98 ~MissingPluginInstaller();
100 void report(rtl::Reference<Player> const & source, GstMessage * message);
102 // Player::~Player calls Player::disposing calls
103 // MissingPluginInstaller::detach, so do not take Player by rtl::Reference
104 // here (which would bump its refcount back from 0 to 1):
105 void detach(Player const * source);
107 private:
108 void processQueue();
110 DECL_STATIC_LINK(
111 MissingPluginInstaller, launchUi, MissingPluginInstallerThread *);
113 osl::Mutex mutex_;
114 std::set<OString> reported_;
115 std::map<OString, std::set<rtl::Reference<Player>>> queued_;
116 rtl::Reference<MissingPluginInstallerThread> currentThread_;
117 std::vector<OString> currentDetails_;
118 std::set<rtl::Reference<Player>> currentSources_;
119 bool launchNewThread_;
120 bool inCleanUp_;
123 MissingPluginInstaller::~MissingPluginInstaller() {
124 osl::MutexGuard g(mutex_);
125 SAL_WARN_IF(currentThread_.is(), "avmedia.gstreamer", "unjoined thread");
126 inCleanUp_ = true;
129 void MissingPluginInstaller::report(
130 rtl::Reference<Player> const & source, GstMessage * message)
132 // assert(gst_is_missing_plugin_message(message));
133 gchar * det = gst_missing_plugin_message_get_installer_detail(message);
134 if (det == nullptr) {
135 SAL_WARN(
136 "avmedia.gstreamer",
137 "gst_missing_plugin_message_get_installer_detail failed");
138 return;
140 std::size_t len = std::strlen(det);
141 if (len > sal_uInt32(SAL_MAX_INT32)) {
142 SAL_WARN("avmedia.gstreamer", "detail string too long");
143 g_free(det);
144 return;
146 OString detStr(det, len);
147 g_free(det);
148 rtl::Reference<MissingPluginInstallerThread> join;
149 rtl::Reference<MissingPluginInstallerThread> launch;
151 osl::MutexGuard g(mutex_);
152 if (reported_.find(detStr) != reported_.end()) {
153 return;
155 auto & i = queued_[detStr];
156 bool fresh = i.empty();
157 i.insert(source);
158 if (!(fresh && launchNewThread_)) {
159 return;
161 join = currentThread_;
162 currentThread_ = new MissingPluginInstallerThread;
164 FlagGuard f(inCleanUp_);
165 currentSources_.clear();
167 processQueue();
168 launchNewThread_ = false;
169 launch = currentThread_;
171 if (join.is()) {
172 join->join();
174 launch->acquire();
175 Application::PostUserEvent(
176 LINK(this, MissingPluginInstaller, launchUi), launch.get());
179 void eraseSource(std::set<rtl::Reference<Player>> & set, Player const * source)
181 auto i = std::find_if(
182 set.begin(), set.end(),
183 [source](rtl::Reference<Player> const & el) {
184 return el.get() == source;
186 if (i != set.end()) {
187 set.erase(i);
191 void MissingPluginInstaller::detach(Player const * source) {
192 rtl::Reference<MissingPluginInstallerThread> join;
194 osl::MutexGuard g(mutex_);
195 if (inCleanUp_) {
196 // Guard against ~MissingPluginInstaller with erroneously un-joined
197 // currentThread_ (thus non-empty currentSources_) calling
198 // destructor of currentSources_, calling ~Player, calling here,
199 // which would use currentSources_ while it is already being
200 // destroyed:
201 return;
203 for (auto i = queued_.begin(); i != queued_.end();) {
204 eraseSource(i->second, source);
205 if (i->second.empty()) {
206 i = queued_.erase(i);
207 } else {
208 ++i;
211 if (currentThread_.is()) {
212 assert(!currentSources_.empty());
213 eraseSource(currentSources_, source);
214 if (currentSources_.empty()) {
215 join = currentThread_;
216 currentThread_.clear();
217 launchNewThread_ = true;
221 if (join.is()) {
222 // missing cancelability of gst_install_plugins_sync
223 join->join();
227 void MissingPluginInstaller::processQueue() {
228 assert(!queued_.empty());
229 assert(currentDetails_.empty());
230 for (auto i = queued_.begin(); i != queued_.end(); ++i) {
231 reported_.insert(i->first);
232 currentDetails_.push_back(i->first);
233 currentSources_.insert(i->second.begin(), i->second.end());
235 queued_.clear();
238 IMPL_STATIC_LINK(
239 MissingPluginInstaller, launchUi, MissingPluginInstallerThread *, thread)
241 rtl::Reference<MissingPluginInstallerThread> ref(thread, SAL_NO_ACQUIRE);
242 gst_pb_utils_init();
243 // not thread safe; hopefully fine to consistently call from our event
244 // loop (which is the only reason to have this
245 // Application::PostUserEvent diversion, in case
246 // MissingPluginInstaller::report might be called from outside our event
247 // loop), and hopefully fine to call gst_is_missing_plugin_message and
248 // gst_missing_plugin_message_get_installer_detail before calling
249 // gst_pb_utils_init
250 ref->launch();
251 return 0;
254 struct TheMissingPluginInstaller:
255 public rtl::Static<MissingPluginInstaller, TheMissingPluginInstaller>
258 void MissingPluginInstallerThread::execute() {
259 MissingPluginInstaller & inst = TheMissingPluginInstaller::get();
260 for (;;) {
261 std::vector<OString> details;
263 osl::MutexGuard g(inst.mutex_);
264 assert(!inst.currentDetails_.empty());
265 details.swap(inst.currentDetails_);
267 std::vector<char *> args;
268 for (auto const & i: details) {
269 args.push_back(const_cast<char *>(i.getStr()));
271 args.push_back(nullptr);
272 gst_install_plugins_sync(args.data(), nullptr);
274 osl::MutexGuard g(inst.mutex_);
275 if (inst.queued_.empty() || inst.launchNewThread_) {
276 inst.launchNewThread_ = true;
277 break;
279 inst.processQueue();
286 // - Player -
289 Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
290 GstPlayer_BASE( m_aMutex ),
291 mxMgr( rxMgr ),
292 mpPlaybin( NULL ),
293 mbFakeVideo (false ),
294 mnUnmutedVolume( 0 ),
295 mbPlayPending ( false ),
296 mbMuted( false ),
297 mbLooping( false ),
298 mbInitialized( false ),
299 mnWindowID( 0 ),
300 mpXOverlay( NULL ),
301 mnDuration( 0 ),
302 mnWidth( 0 ),
303 mnHeight( 0 ),
304 mnWatchID( 0 ),
305 mbWatchID( false )
307 // Initialize GStreamer library
308 int argc = 1;
309 char name[] = "libreoffice";
310 char *arguments[] = { name };
311 char** argv = arguments;
312 GError* pError = NULL;
314 mbInitialized = gst_init_check( &argc, &argv, &pError );
316 DBG( "%p Player::Player", this );
318 if (pError != NULL)
320 // TODO: throw an exception?
321 DBG( "%p Player::Player error '%s'", this, pError->message );
322 g_error_free (pError);
328 Player::~Player()
330 DBG( "%p Player::~Player", this );
331 if( mbInitialized )
332 disposing();
335 void SAL_CALL Player::disposing()
337 TheMissingPluginInstaller::get().detach(this);
339 ::osl::MutexGuard aGuard(m_aMutex);
341 stop();
343 DBG( "%p Player::disposing", this );
345 // Release the elements and pipeline
346 if( mbInitialized )
348 if( mpPlaybin )
350 gst_element_set_state( mpPlaybin, GST_STATE_NULL );
351 g_object_unref( G_OBJECT( mpPlaybin ) );
353 mpPlaybin = NULL;
356 if( mpXOverlay ) {
357 g_object_unref( G_OBJECT ( mpXOverlay ) );
358 mpXOverlay = NULL;
362 if (mbWatchID)
364 g_source_remove(mnWatchID);
365 mbWatchID = false;
369 static gboolean pipeline_bus_callback( GstBus *, GstMessage *message, gpointer data )
371 Player* pPlayer = static_cast<Player*>(data);
373 pPlayer->processMessage( message );
375 return TRUE;
378 static GstBusSyncReply pipeline_bus_sync_handler( GstBus *, GstMessage * message, gpointer data )
380 Player* pPlayer = static_cast<Player*>(data);
382 return pPlayer->processSyncMessage( message );
385 void Player::processMessage( GstMessage *message )
387 switch( GST_MESSAGE_TYPE( message ) ) {
388 case GST_MESSAGE_EOS:
389 gst_element_set_state( mpPlaybin, GST_STATE_READY );
390 mbPlayPending = false;
391 if (mbLooping)
392 start();
393 break;
394 case GST_MESSAGE_STATE_CHANGED:
395 if( message->src == GST_OBJECT( mpPlaybin ) ) {
396 GstState newstate, pendingstate;
398 gst_message_parse_state_changed (message, NULL, &newstate, &pendingstate);
400 if( newstate == GST_STATE_PAUSED &&
401 pendingstate == GST_STATE_VOID_PENDING &&
402 mpXOverlay )
403 gst_video_overlay_expose( mpXOverlay );
405 if (mbPlayPending)
406 mbPlayPending = ((newstate == GST_STATE_READY) || (newstate == GST_STATE_PAUSED));
408 default:
409 break;
413 static gboolean wrap_element_query_position (GstElement *element, GstFormat format, gint64 *cur)
415 #ifdef AVMEDIA_GST_0_10
416 GstFormat my_format = format;
417 return gst_element_query_position( element, &my_format, cur) && my_format == format && *cur > 0L;
418 #else
419 return gst_element_query_position( element, format, cur );
420 #endif
423 static gboolean wrap_element_query_duration (GstElement *element, GstFormat format, gint64 *duration)
425 #ifdef AVMEDIA_GST_0_10
426 GstFormat my_format = format;
427 return gst_element_query_duration( element, &my_format, duration) && my_format == format && *duration > 0L;
428 #else
429 return gst_element_query_duration( element, format, duration );
430 #endif
433 GstBusSyncReply Player::processSyncMessage( GstMessage *message )
435 // DBG( "%p processSyncMessage has handle: %s", this, GST_MESSAGE_TYPE_NAME( message ) );
437 #if OSL_DEBUG_LEVEL > 0
438 if ( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR )
440 GError* error;
441 gchar* error_debug;
443 gst_message_parse_error( message, &error, &error_debug );
444 SAL_WARN(
445 "avmedia",
446 "gstreamer error: '" << error->message << "' debug: '"
447 << error_debug << "'");
449 #endif
451 #ifdef AVMEDIA_GST_0_10
452 if (message->structure &&
453 !strcmp( gst_structure_get_name( message->structure ), "prepare-xwindow-id" ) )
454 #else
455 if (gst_is_video_overlay_prepare_window_handle_message (message) )
456 #endif
458 DBG( "%p processSyncMessage prepare window id: %s %d", this,
459 GST_MESSAGE_TYPE_NAME( message ), (int)mnWindowID );
460 if( mpXOverlay )
461 g_object_unref( G_OBJECT ( mpXOverlay ) );
462 g_object_set( GST_MESSAGE_SRC( message ), "force-aspect-ratio", FALSE, NULL );
463 mpXOverlay = GST_VIDEO_OVERLAY( GST_MESSAGE_SRC( message ) );
464 g_object_ref( G_OBJECT ( mpXOverlay ) );
465 if ( mnWindowID != 0 )
466 gst_video_overlay_set_window_handle( mpXOverlay, mnWindowID );
467 return GST_BUS_DROP;
470 #ifdef AVMEDIA_GST_0_10
471 if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_STATE_CHANGED ) {
472 if( message->src == GST_OBJECT( mpPlaybin ) ) {
473 GstState newstate, pendingstate;
475 gst_message_parse_state_changed (message, NULL, &newstate, &pendingstate);
477 DBG( "%p state change received, new state %d pending %d", this,
478 (int)newstate, (int)pendingstate );
479 if( newstate == GST_STATE_PAUSED &&
480 pendingstate == GST_STATE_VOID_PENDING ) {
482 DBG( "%p change to paused received", this );
484 if( mnDuration == 0) {
485 gint64 gst_duration = 0L;
486 if( wrap_element_query_duration( mpPlaybin, GST_FORMAT_TIME, &gst_duration) )
487 mnDuration = gst_duration;
490 if( mnWidth == 0 ) {
491 GList *pStreamInfo = NULL;
493 g_object_get( G_OBJECT( mpPlaybin ), "stream-info", &pStreamInfo, NULL );
495 for ( ; pStreamInfo != NULL; pStreamInfo = pStreamInfo->next) {
496 GObject *pInfo = G_OBJECT( pStreamInfo->data );
498 if( !pInfo )
499 continue;
501 int nType;
502 g_object_get( pInfo, "type", &nType, NULL );
503 GEnumValue *pValue = g_enum_get_value( G_PARAM_SPEC_ENUM( g_object_class_find_property( G_OBJECT_GET_CLASS( pInfo ), "type" ) )->enum_class,
504 nType );
506 if( !g_ascii_strcasecmp( pValue->value_nick, "video" ) ) {
507 GstStructure *pStructure;
508 GstPad *pPad;
510 g_object_get( pInfo, "object", &pPad, NULL );
511 pStructure = gst_caps_get_structure( GST_PAD_CAPS( pPad ), 0 );
512 if( pStructure ) {
513 gst_structure_get_int( pStructure, "width", &mnWidth );
514 gst_structure_get_int( pStructure, "height", &mnHeight );
515 DBG( "queried size: %d x %d", mnWidth, mnHeight );
517 g_object_unref (pPad);
521 maSizeCondition.set();
525 #else
526 // We get to use the exciting new playbin2 ! (now known as playbin)
527 if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ASYNC_DONE ) {
528 if( mnDuration == 0) {
529 gint64 gst_duration = 0L;
530 if( wrap_element_query_duration( mpPlaybin, GST_FORMAT_TIME, &gst_duration) )
531 mnDuration = gst_duration;
533 if( mnWidth == 0 ) {
534 GstPad *pad = NULL;
536 g_signal_emit_by_name( mpPlaybin, "get-video-pad", 0, &pad );
538 if( pad ) {
539 int w = 0, h = 0;
541 GstCaps *caps = gst_pad_get_current_caps( pad );
543 if( gst_structure_get( gst_caps_get_structure( caps, 0 ),
544 "width", G_TYPE_INT, &w,
545 "height", G_TYPE_INT, &h,
546 NULL ) ) {
547 mnWidth = w;
548 mnHeight = h;
550 DBG( "queried size: %d x %d", mnWidth, mnHeight );
552 maSizeCondition.set();
554 gst_caps_unref( caps );
555 g_object_unref( pad );
558 #endif
559 } else if (gst_is_missing_plugin_message(message)) {
560 TheMissingPluginInstaller::get().report(this, message);
561 if( mnWidth == 0 ) {
562 // an error occurred, set condition so that OOo thread doesn't wait for us
563 maSizeCondition.set();
565 } else if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR ) {
566 DBG( "Error !\n" );
567 if( mnWidth == 0 ) {
568 // an error occurred, set condition so that OOo thread doesn't wait for us
569 maSizeCondition.set();
573 return GST_BUS_PASS;
576 void Player::preparePlaybin( const OUString& rURL, GstElement *pSink )
578 GstBus *pBus;
580 if( mpPlaybin != NULL ) {
581 gst_element_set_state( mpPlaybin, GST_STATE_NULL );
582 mbPlayPending = false;
583 g_object_unref( mpPlaybin );
586 mpPlaybin = gst_element_factory_make( "playbin", NULL );
587 if( pSink != NULL ) // used for getting preferred size etc.
589 g_object_set( G_OBJECT( mpPlaybin ), "video-sink", pSink, NULL );
590 mbFakeVideo = true;
592 else
593 mbFakeVideo = false;
595 OString ascURL = OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 );
596 g_object_set( G_OBJECT( mpPlaybin ), "uri", ascURL.getStr() , NULL );
598 pBus = gst_element_get_bus( mpPlaybin );
599 if (mbWatchID)
601 g_source_remove(mnWatchID);
602 mbWatchID = false;
604 mnWatchID = gst_bus_add_watch( pBus, pipeline_bus_callback, this );
605 mbWatchID = true;
606 DBG( "%p set sync handler", this );
607 #ifdef AVMEDIA_GST_0_10
608 gst_bus_set_sync_handler( pBus, pipeline_bus_sync_handler, this );
609 #else
610 gst_bus_set_sync_handler( pBus, pipeline_bus_sync_handler, this, NULL );
611 #endif
612 g_object_unref( pBus );
615 bool Player::create( const OUString& rURL )
617 bool bRet = false;
619 // create all the elements and link them
621 DBG("create player, URL: %s", OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 ).getStr());
623 if( mbInitialized && !rURL.isEmpty() )
625 // fakesink for pre-roll & sizing ...
626 preparePlaybin( rURL, gst_element_factory_make( "fakesink", NULL ) );
628 gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
629 mbPlayPending = false;
631 bRet = true;
634 if( bRet )
635 maURL = rURL;
636 else
637 maURL.clear();
639 return bRet;
644 void SAL_CALL Player::start()
645 throw (uno::RuntimeException, std::exception)
647 ::osl::MutexGuard aGuard(m_aMutex);
649 // set the pipeline state to READY and run the loop
650 if( mbInitialized && NULL != mpPlaybin )
652 gst_element_set_state( mpPlaybin, GST_STATE_PLAYING );
653 mbPlayPending = true;
659 void SAL_CALL Player::stop()
660 throw (uno::RuntimeException, std::exception)
662 ::osl::MutexGuard aGuard(m_aMutex);
664 // set the pipeline in PAUSED STATE
665 if( mpPlaybin )
666 gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
668 mbPlayPending = false;
669 DBG( "stop %p", mpPlaybin );
674 sal_Bool SAL_CALL Player::isPlaying()
675 throw (uno::RuntimeException, std::exception)
677 ::osl::MutexGuard aGuard(m_aMutex);
679 bool bRet = mbPlayPending;
681 // return whether the pipeline is in PLAYING STATE or not
682 if( !mbPlayPending && mbInitialized && mpPlaybin )
684 bRet = GST_STATE_PLAYING == GST_STATE( mpPlaybin );
687 DBG( "isPlaying %d", bRet );
689 return bRet;
694 double SAL_CALL Player::getDuration()
695 throw (uno::RuntimeException, std::exception)
697 ::osl::MutexGuard aGuard(m_aMutex);
699 // slideshow checks for non-zero duration, so cheat here
700 double duration = 0.01;
702 if( mpPlaybin && mnDuration > 0 ) {
703 duration = mnDuration / GST_SECOND;
706 return duration;
711 void SAL_CALL Player::setMediaTime( double fTime )
712 throw (uno::RuntimeException, std::exception)
714 ::osl::MutexGuard aGuard(m_aMutex);
716 if( mpPlaybin ) {
717 gint64 gst_position = llround (fTime * GST_SECOND);
719 gst_element_seek( mpPlaybin, 1.0,
720 GST_FORMAT_TIME,
721 GST_SEEK_FLAG_FLUSH,
722 GST_SEEK_TYPE_SET, gst_position,
723 GST_SEEK_TYPE_NONE, 0 );
724 if( !isPlaying() )
725 gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
727 DBG( "seek to: %" SAL_PRIdINT64 " ns original: %lf s", gst_position, fTime );
733 double SAL_CALL Player::getMediaTime()
734 throw (uno::RuntimeException, std::exception)
736 ::osl::MutexGuard aGuard(m_aMutex);
738 double position = 0.0;
740 if( mpPlaybin ) {
741 // get current position in the stream
742 gint64 gst_position;
743 if( wrap_element_query_position( mpPlaybin, GST_FORMAT_TIME, &gst_position ) )
744 position = gst_position / GST_SECOND;
747 return position;
750 void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
751 throw (uno::RuntimeException, std::exception)
753 ::osl::MutexGuard aGuard(m_aMutex);
754 // TODO check how to do with GST
755 mbLooping = bSet;
760 sal_Bool SAL_CALL Player::isPlaybackLoop()
761 throw (uno::RuntimeException, std::exception)
763 ::osl::MutexGuard aGuard(m_aMutex);
764 // TODO check how to do with GST
765 return mbLooping;
770 void SAL_CALL Player::setMute( sal_Bool bSet )
771 throw (uno::RuntimeException, std::exception)
773 ::osl::MutexGuard aGuard(m_aMutex);
775 DBG( "set mute: %d muted: %d unmuted volume: %lf", bSet, mbMuted, mnUnmutedVolume );
777 // change the volume to 0 or the unmuted volume
778 if( mpPlaybin && mbMuted != bool(bSet) )
780 double nVolume = mnUnmutedVolume;
781 if( bSet )
783 nVolume = 0.0;
786 g_object_set( G_OBJECT( mpPlaybin ), "volume", nVolume, NULL );
788 mbMuted = bSet;
794 sal_Bool SAL_CALL Player::isMute()
795 throw (uno::RuntimeException, std::exception)
797 ::osl::MutexGuard aGuard(m_aMutex);
799 return mbMuted;
804 void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
805 throw (uno::RuntimeException, std::exception)
807 ::osl::MutexGuard aGuard(m_aMutex);
809 mnUnmutedVolume = pow( 10.0, nVolumeDB / 20.0 );
811 DBG( "set volume: %d gst volume: %lf", nVolumeDB, mnUnmutedVolume );
813 // change volume
814 if( !mbMuted && mpPlaybin )
816 g_object_set( G_OBJECT( mpPlaybin ), "volume", (gdouble) mnUnmutedVolume, NULL );
822 sal_Int16 SAL_CALL Player::getVolumeDB()
823 throw (uno::RuntimeException, std::exception)
825 ::osl::MutexGuard aGuard(m_aMutex);
827 sal_Int16 nVolumeDB(0);
829 if( mpPlaybin ) {
830 double nGstVolume = 0.0;
832 g_object_get( G_OBJECT( mpPlaybin ), "volume", &nGstVolume, NULL );
834 nVolumeDB = (sal_Int16) ( 20.0*log10 ( nGstVolume ) );
837 return nVolumeDB;
842 awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
843 throw (uno::RuntimeException, std::exception)
845 ::osl::MutexGuard aGuard(m_aMutex);
847 awt::Size aSize( 0, 0 );
849 if( maURL.isEmpty() )
851 DBG( "%p Player::getPreferredPlayerWindowSize - empty URL => 0x0", this );
852 return aSize;
855 DBG( "%p pre-Player::getPreferredPlayerWindowSize, member %d x %d", this, mnWidth, mnHeight );
857 TimeValue aTimeout = { 10, 0 };
858 #if OSL_DEBUG_LEVEL > 2
859 osl::Condition::Result aResult =
860 #endif
861 maSizeCondition.wait( &aTimeout );
863 DBG( "%p Player::getPreferredPlayerWindowSize after waitCondition %d, member %d x %d", this, aResult, mnWidth, mnHeight );
865 if( mnWidth != 0 && mnHeight != 0 ) {
866 aSize.Width = mnWidth;
867 aSize.Height = mnHeight;
870 return aSize;
875 uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& rArguments )
876 throw (uno::RuntimeException, std::exception)
878 ::osl::MutexGuard aGuard(m_aMutex);
880 uno::Reference< ::media::XPlayerWindow > xRet;
881 awt::Size aSize( getPreferredPlayerWindowSize() );
883 if( mbFakeVideo )
884 preparePlaybin( maURL, NULL );
886 DBG( "Player::createPlayerWindow %d %d length: %d", aSize.Width, aSize.Height, rArguments.getLength() );
888 if( aSize.Width > 0 && aSize.Height > 0 )
890 ::avmedia::gstreamer::Window* pWindow = new ::avmedia::gstreamer::Window( mxMgr, *this );
892 xRet = pWindow;
894 if( rArguments.getLength() > 2 )
896 sal_IntPtr pIntPtr = 0;
897 rArguments[ 2 ] >>= pIntPtr;
898 SystemChildWindow *pParentWindow = reinterpret_cast< SystemChildWindow* >( pIntPtr );
899 const SystemEnvData* pEnvData = pParentWindow ? pParentWindow->GetSystemData() : NULL;
900 OSL_ASSERT(pEnvData);
901 if (pEnvData)
903 mnWindowID = pEnvData->aWindow;
904 DBG( "set window id to %d XOverlay %p\n", (int)mnWindowID, mpXOverlay);
905 gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
906 if ( mpXOverlay != NULL )
907 gst_video_overlay_set_window_handle( mpXOverlay, mnWindowID );
912 return xRet;
917 uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
918 throw (uno::RuntimeException, std::exception)
920 ::osl::MutexGuard aGuard(m_aMutex);
921 FrameGrabber* pFrameGrabber = NULL;
922 const awt::Size aPrefSize( getPreferredPlayerWindowSize() );
924 if( ( aPrefSize.Width > 0 ) && ( aPrefSize.Height > 0 ) )
925 pFrameGrabber = FrameGrabber::create( maURL );
926 DBG( "created FrameGrabber %p", pFrameGrabber );
928 return pFrameGrabber;
933 OUString SAL_CALL Player::getImplementationName()
934 throw (uno::RuntimeException, std::exception)
936 return OUString( AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME );
941 sal_Bool SAL_CALL Player::supportsService( const OUString& ServiceName )
942 throw (uno::RuntimeException, std::exception)
944 return cppu::supportsService(this, ServiceName);
949 uno::Sequence< OUString > SAL_CALL Player::getSupportedServiceNames()
950 throw (uno::RuntimeException, std::exception)
952 uno::Sequence< OUString > aRet(1);
953 aRet[0] = AVMEDIA_GST_PLAYER_SERVICENAME ;
955 return aRet;
958 } // namespace gstreamer
959 } // namespace avmedia
961 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */