1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <sal/log.hxx>
34 #include <rtl/string.hxx>
35 #include <salhelper/thread.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/syschild.hxx>
38 #include <vcl/sysdata.hxx>
40 #include "gstplayer.hxx"
41 #include "gstframegrabber.hxx"
42 #include "gstwindow.hxx"
44 #include <gst/video/videooverlay.h>
45 #define AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_GStreamer"
46 #define AVMEDIA_GST_PLAYER_SERVICENAME "com.sun.star.media.Player_GStreamer"
48 #include <gst/pbutils/missing-plugins.h>
49 #include <gst/pbutils/pbutils.h>
51 #define AVVERSION "gst 1.0: "
53 using namespace ::com::sun::star
;
55 namespace avmedia::gstreamer
{
61 explicit FlagGuard(bool & flag
): flag_(flag
) { flag_
= true; }
63 ~FlagGuard() { flag_
= false; }
69 class MissingPluginInstallerThread
: public salhelper::Thread
{
71 MissingPluginInstallerThread(): Thread("MissingPluginInstaller") {}
74 void execute() override
;
78 class MissingPluginInstaller
{
79 friend class MissingPluginInstallerThread
;
82 MissingPluginInstaller(): launchNewThread_(true), inCleanUp_(false) {}
84 ~MissingPluginInstaller();
86 void report(rtl::Reference
<Player
> const & source
, GstMessage
* message
);
88 // Player::~Player calls Player::disposing calls
89 // MissingPluginInstaller::detach, so do not take Player by rtl::Reference
90 // here (which would bump its refcount back from 0 to 1):
91 void detach(Player
const * source
);
96 DECL_STATIC_LINK(MissingPluginInstaller
, launchUi
, void*, void);
99 std::set
<OString
> reported_
;
100 std::map
<OString
, std::set
<rtl::Reference
<Player
>>> queued_
;
101 rtl::Reference
<MissingPluginInstallerThread
> currentThread_
;
102 std::vector
<OString
> currentDetails_
;
103 std::set
<rtl::Reference
<Player
>> currentSources_
;
104 bool launchNewThread_
;
109 MissingPluginInstaller::~MissingPluginInstaller() {
110 osl::MutexGuard
g(mutex_
);
111 SAL_WARN_IF(currentThread_
.is(), "avmedia.gstreamer", "unjoined thread");
116 void MissingPluginInstaller::report(
117 rtl::Reference
<Player
> const & source
, GstMessage
* message
)
119 // assert(gst_is_missing_plugin_message(message));
120 gchar
* det
= gst_missing_plugin_message_get_installer_detail(message
);
121 if (det
== nullptr) {
124 "gst_missing_plugin_message_get_installer_detail failed");
127 std::size_t len
= std::strlen(det
);
128 if (len
> SAL_MAX_INT32
) {
129 SAL_WARN("avmedia.gstreamer", "detail string too long");
133 OString
detStr(det
, len
);
135 rtl::Reference
<MissingPluginInstallerThread
> join
;
136 rtl::Reference
<MissingPluginInstallerThread
> launch
;
138 osl::MutexGuard
g(mutex_
);
139 if (reported_
.find(detStr
) != reported_
.end()) {
142 auto & i
= queued_
[detStr
];
143 bool fresh
= i
.empty();
145 if (!(fresh
&& launchNewThread_
)) {
148 join
= currentThread_
;
149 currentThread_
= new MissingPluginInstallerThread
;
151 FlagGuard
f(inCleanUp_
);
152 currentSources_
.clear();
155 launchNewThread_
= false;
156 launch
= currentThread_
;
162 Application::PostUserEvent(
163 LINK(this, MissingPluginInstaller
, launchUi
), launch
.get());
167 void eraseSource(std::set
<rtl::Reference
<Player
>> & set
, Player
const * source
)
169 auto i
= std::find_if(
170 set
.begin(), set
.end(),
171 [source
](rtl::Reference
<Player
> const & el
) {
172 return el
.get() == source
;
174 if (i
!= set
.end()) {
180 void MissingPluginInstaller::detach(Player
const * source
) {
181 rtl::Reference
<MissingPluginInstallerThread
> join
;
183 osl::MutexGuard
g(mutex_
);
185 // Guard against ~MissingPluginInstaller with erroneously un-joined
186 // currentThread_ (thus non-empty currentSources_) calling
187 // destructor of currentSources_, calling ~Player, calling here,
188 // which would use currentSources_ while it is already being
192 for (auto i
= queued_
.begin(); i
!= queued_
.end();) {
193 eraseSource(i
->second
, source
);
194 if (i
->second
.empty()) {
195 i
= queued_
.erase(i
);
200 if (currentThread_
.is()) {
201 assert(!currentSources_
.empty());
202 eraseSource(currentSources_
, source
);
203 if (currentSources_
.empty()) {
204 join
= currentThread_
;
205 currentThread_
.clear();
206 launchNewThread_
= true;
211 // missing cancellability of gst_install_plugins_sync
217 void MissingPluginInstaller::processQueue() {
218 assert(!queued_
.empty());
219 assert(currentDetails_
.empty());
220 for (const auto& rEntry
: queued_
) {
221 reported_
.insert(rEntry
.first
);
222 currentDetails_
.push_back(rEntry
.first
);
223 currentSources_
.insert(rEntry
.second
.begin(), rEntry
.second
.end());
229 IMPL_STATIC_LINK(MissingPluginInstaller
, launchUi
, void *, p
, void)
231 MissingPluginInstallerThread
* thread
= static_cast<MissingPluginInstallerThread
*>(p
);
232 rtl::Reference
<MissingPluginInstallerThread
> ref(thread
, SAL_NO_ACQUIRE
);
234 // not thread safe; hopefully fine to consistently call from our event
235 // loop (which is the only reason to have this
236 // Application::PostUserEvent diversion, in case
237 // MissingPluginInstaller::report might be called from outside our event
238 // loop), and hopefully fine to call gst_is_missing_plugin_message and
239 // gst_missing_plugin_message_get_installer_detail before calling
245 struct TheMissingPluginInstaller
:
246 public rtl::Static
<MissingPluginInstaller
, TheMissingPluginInstaller
>
250 void MissingPluginInstallerThread::execute() {
251 MissingPluginInstaller
& inst
= TheMissingPluginInstaller::get();
253 std::vector
<OString
> details
;
255 osl::MutexGuard
g(inst
.mutex_
);
256 assert(!inst
.currentDetails_
.empty());
257 details
.swap(inst
.currentDetails_
);
259 std::vector
<char *> args
;
260 args
.reserve(details
.size());
261 for (auto const& i
: details
)
263 args
.push_back(const_cast<char *>(i
.getStr()));
265 args
.push_back(nullptr);
266 gst_install_plugins_sync(args
.data(), nullptr);
268 osl::MutexGuard
g(inst
.mutex_
);
269 if (inst
.queued_
.empty() || inst
.launchNewThread_
) {
270 inst
.launchNewThread_
= true;
278 } // end anonymous namespace
282 GstPlayer_BASE( m_aMutex
),
283 mpPlaybin( nullptr ),
284 mpVolumeControl( nullptr ),
285 mbUseGtkSink( false ),
286 mbFakeVideo (false ),
287 mnUnmutedVolume( 0 ),
288 mbPlayPending ( false ),
291 mbInitialized( false ),
292 mpDisplay( nullptr ),
294 mpXOverlay( nullptr ),
301 // Initialize GStreamer library
303 char name
[] = "libreoffice";
304 char *arguments
[] = { name
};
305 char** argv
= arguments
;
306 GError
* pError
= nullptr;
308 mbInitialized
= gst_init_check( &argc
, &argv
, &pError
);
310 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " Player::Player" );
312 if (pError
!= nullptr)
314 // TODO: throw an exception?
315 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " Player::Player error '" << pError
->message
<< "'" );
316 g_error_free (pError
);
323 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " Player::~Player" );
329 void SAL_CALL
Player::disposing()
331 TheMissingPluginInstaller::get().detach(this);
333 ::osl::MutexGuard
aGuard(m_aMutex
);
337 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " Player::disposing" );
339 // Release the elements and pipeline
344 gst_element_set_state( mpPlaybin
, GST_STATE_NULL
);
345 g_object_unref( G_OBJECT( mpPlaybin
) );
348 mpVolumeControl
= nullptr;
352 g_object_unref( G_OBJECT ( mpXOverlay
) );
353 mpXOverlay
= nullptr;
359 g_source_remove(mnWatchID
);
365 static gboolean
pipeline_bus_callback( GstBus
*, GstMessage
*message
, gpointer data
)
367 Player
* pPlayer
= static_cast<Player
*>(data
);
369 pPlayer
->processMessage( message
);
375 static GstBusSyncReply
pipeline_bus_sync_handler( GstBus
*, GstMessage
* message
, gpointer data
)
377 Player
* pPlayer
= static_cast<Player
*>(data
);
379 return pPlayer
->processSyncMessage( message
);
383 void Player::processMessage( GstMessage
*message
)
385 switch( GST_MESSAGE_TYPE( message
) ) {
386 case GST_MESSAGE_EOS
:
387 gst_element_set_state( mpPlaybin
, GST_STATE_READY
);
388 mbPlayPending
= false;
392 case GST_MESSAGE_STATE_CHANGED
:
393 if (message
->src
== GST_OBJECT(mpPlaybin
))
395 GstState newstate
, pendingstate
;
397 gst_message_parse_state_changed (message
, nullptr, &newstate
, &pendingstate
);
399 if (!mbUseGtkSink
&& newstate
== GST_STATE_PAUSED
&&
400 pendingstate
== GST_STATE_VOID_PENDING
&& mpXOverlay
)
402 gst_video_overlay_expose(mpXOverlay
);
406 mbPlayPending
= ((newstate
== GST_STATE_READY
) || (newstate
== GST_STATE_PAUSED
));
414 #define LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE "GstWaylandDisplayHandleContextType"
416 static bool lcl_is_wayland_display_handle_need_context_message(GstMessage
* msg
)
418 g_return_val_if_fail(GST_IS_MESSAGE(msg
), false);
420 if (GST_MESSAGE_TYPE(msg
) != GST_MESSAGE_NEED_CONTEXT
)
422 const gchar
*type
= nullptr;
423 if (!gst_message_parse_context_type(msg
, &type
))
425 return !g_strcmp0(type
, LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE
);
428 static GstContext
* lcl_wayland_display_handle_context_new(void* display
)
430 GstContext
*context
= gst_context_new(LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE
, true);
431 gst_structure_set (gst_context_writable_structure (context
),
432 "handle", G_TYPE_POINTER
, display
, nullptr);
436 GstBusSyncReply
Player::processSyncMessage( GstMessage
*message
)
438 #if OSL_DEBUG_LEVEL > 0
439 if ( GST_MESSAGE_TYPE( message
) == GST_MESSAGE_ERROR
)
444 gst_message_parse_error( message
, &error
, &error_debug
);
447 "error: '" << error
->message
<< "' debug: '"
448 << error_debug
<< "'");
454 if (gst_is_video_overlay_prepare_window_handle_message (message
) )
456 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " processSyncMessage prepare window id: " <<
457 GST_MESSAGE_TYPE_NAME( message
) << " " << static_cast<int>(mnWindowID
) );
459 g_object_unref( G_OBJECT ( mpXOverlay
) );
460 g_object_set( GST_MESSAGE_SRC( message
), "force-aspect-ratio", FALSE
, nullptr );
461 mpXOverlay
= GST_VIDEO_OVERLAY( GST_MESSAGE_SRC( message
) );
462 g_object_ref( G_OBJECT ( mpXOverlay
) );
463 if ( mnWindowID
!= 0 )
465 gst_video_overlay_set_window_handle( mpXOverlay
, mnWindowID
);
466 gst_video_overlay_handle_events(mpXOverlay
, 0); // Let the parent window handle events.
467 if (maArea
.Width
> 0 && maArea
.Height
> 0)
468 gst_video_overlay_set_render_rectangle(mpXOverlay
, maArea
.X
, maArea
.Y
, maArea
.Width
, maArea
.Height
);
473 else if (lcl_is_wayland_display_handle_need_context_message(message
))
475 GstContext
*context
= lcl_wayland_display_handle_context_new(mpDisplay
);
476 gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message
)), context
);
482 if( GST_MESSAGE_TYPE( message
) == GST_MESSAGE_ASYNC_DONE
) {
483 if( mnDuration
== 0) {
484 gint64 gst_duration
= 0;
485 if( gst_element_query_duration( mpPlaybin
, GST_FORMAT_TIME
, &gst_duration
) )
486 mnDuration
= gst_duration
;
489 GstPad
*pad
= nullptr;
491 g_signal_emit_by_name( mpPlaybin
, "get-video-pad", 0, &pad
);
496 GstCaps
*caps
= gst_pad_get_current_caps( pad
);
498 if( gst_structure_get( gst_caps_get_structure( caps
, 0 ),
499 "width", G_TYPE_INT
, &w
,
500 "height", G_TYPE_INT
, &h
,
505 SAL_INFO( "avmedia.gstreamer", AVVERSION
"queried size: " << mnWidth
<< "x" << mnHeight
);
508 gst_caps_unref( caps
);
509 g_object_unref( pad
);
512 maSizeCondition
.set();
514 } else if (gst_is_missing_plugin_message(message
)) {
515 TheMissingPluginInstaller::get().report(this, message
);
517 // an error occurred, set condition so that OOo thread doesn't wait for us
518 maSizeCondition
.set();
520 } else if( GST_MESSAGE_TYPE( message
) == GST_MESSAGE_ERROR
) {
522 // an error occurred, set condition so that OOo thread doesn't wait for us
523 maSizeCondition
.set();
530 void Player::preparePlaybin( const OUString
& rURL
, GstElement
*pSink
)
532 if (mpPlaybin
!= nullptr)
534 gst_element_set_state( mpPlaybin
, GST_STATE_NULL
);
535 mbPlayPending
= false;
536 g_object_unref( mpPlaybin
);
539 mpPlaybin
= gst_element_factory_make( "playbin", nullptr );
541 //tdf#96989 on systems with flat-volumes setting the volume directly on the
542 //playbin to 100% results in setting the global volume to 100% of the
543 //maximum. We expect to set as % of the current volume.
544 mpVolumeControl
= gst_element_factory_make( "volume", nullptr );
545 GstElement
*pAudioSink
= gst_element_factory_make( "autoaudiosink", nullptr );
546 GstElement
* pAudioOutput
= gst_bin_new("audio-output-bin");
547 assert(pAudioOutput
);
549 gst_bin_add(GST_BIN(pAudioOutput
), pAudioSink
);
552 gst_bin_add(GST_BIN(pAudioOutput
), mpVolumeControl
);
554 gst_element_link(mpVolumeControl
, pAudioSink
);
555 GstPad
*pPad
= gst_element_get_static_pad(mpVolumeControl
, "sink");
556 gst_element_add_pad(GST_ELEMENT(pAudioOutput
), gst_ghost_pad_new("sink", pPad
));
557 gst_object_unref(GST_OBJECT(pPad
));
559 g_object_set(G_OBJECT(mpPlaybin
), "audio-sink", pAudioOutput
, nullptr);
561 if( pSink
!= nullptr ) // used for getting preferred size etc.
563 g_object_set( G_OBJECT( mpPlaybin
), "video-sink", pSink
, nullptr );
569 OString ascURL
= OUStringToOString( rURL
, RTL_TEXTENCODING_UTF8
);
570 g_object_set( G_OBJECT( mpPlaybin
), "uri", ascURL
.getStr() , nullptr );
572 GstBus
*pBus
= gst_element_get_bus( mpPlaybin
);
575 g_source_remove(mnWatchID
);
578 mnWatchID
= gst_bus_add_watch( pBus
, pipeline_bus_callback
, this );
580 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " set sync handler" );
581 gst_bus_set_sync_handler( pBus
, pipeline_bus_sync_handler
, this, nullptr );
582 g_object_unref( pBus
);
586 bool Player::create( const OUString
& rURL
)
590 // create all the elements and link them
592 SAL_INFO( "avmedia.gstreamer", "create player, URL: '" << rURL
<< "'" );
594 if( mbInitialized
&& !rURL
.isEmpty() )
596 // fakesink for pre-roll & sizing ...
597 preparePlaybin( rURL
, gst_element_factory_make( "fakesink", nullptr ) );
599 gst_element_set_state( mpPlaybin
, GST_STATE_PAUSED
);
600 mbPlayPending
= false;
614 void SAL_CALL
Player::start()
616 ::osl::MutexGuard
aGuard(m_aMutex
);
618 // set the pipeline state to READY and run the loop
619 if( mbInitialized
&& mpPlaybin
!= nullptr )
621 gst_element_set_state( mpPlaybin
, GST_STATE_PLAYING
);
622 mbPlayPending
= true;
627 void SAL_CALL
Player::stop()
629 ::osl::MutexGuard
aGuard(m_aMutex
);
631 // set the pipeline in PAUSED STATE
633 gst_element_set_state( mpPlaybin
, GST_STATE_PAUSED
);
635 mbPlayPending
= false;
636 SAL_INFO( "avmedia.gstreamer", AVVERSION
"stop " << mpPlaybin
);
640 sal_Bool SAL_CALL
Player::isPlaying()
642 ::osl::MutexGuard
aGuard(m_aMutex
);
644 bool bRet
= mbPlayPending
;
646 // return whether the pipeline is in PLAYING STATE or not
647 if( !mbPlayPending
&& mbInitialized
&& mpPlaybin
)
649 bRet
= GST_STATE( mpPlaybin
) == GST_STATE_PLAYING
;
652 SAL_INFO( "avmedia.gstreamer", AVVERSION
"isPlaying " << bRet
);
658 double SAL_CALL
Player::getDuration()
660 ::osl::MutexGuard
aGuard(m_aMutex
);
662 // slideshow checks for non-zero duration, so cheat here
663 double duration
= 0.3;
665 if( mpPlaybin
&& mnDuration
> 0 ) {
666 duration
= mnDuration
/ GST_SECOND
;
673 void SAL_CALL
Player::setMediaTime( double fTime
)
675 ::osl::MutexGuard
aGuard(m_aMutex
);
680 gint64 gst_position
= llround (fTime
* GST_SECOND
);
682 gst_element_seek( mpPlaybin
, 1.0,
685 GST_SEEK_TYPE_SET
, gst_position
,
686 GST_SEEK_TYPE_NONE
, 0 );
688 SAL_INFO( "avmedia.gstreamer", AVVERSION
"seek to: " << gst_position
<< " ns original: " << fTime
<< " s" );
692 double SAL_CALL
Player::getMediaTime()
694 ::osl::MutexGuard
aGuard(m_aMutex
);
696 double position
= 0.0;
699 // get current position in the stream
701 if( gst_element_query_position( mpPlaybin
, GST_FORMAT_TIME
, &gst_position
) )
702 position
= gst_position
/ GST_SECOND
;
709 void SAL_CALL
Player::setPlaybackLoop( sal_Bool bSet
)
711 ::osl::MutexGuard
aGuard(m_aMutex
);
712 // TODO check how to do with GST
717 sal_Bool SAL_CALL
Player::isPlaybackLoop()
719 ::osl::MutexGuard
aGuard(m_aMutex
);
720 // TODO check how to do with GST
725 void SAL_CALL
Player::setMute( sal_Bool bSet
)
727 ::osl::MutexGuard
aGuard(m_aMutex
);
729 SAL_INFO( "avmedia.gstreamer", AVVERSION
"set mute: " << bSet
<< " muted: " << mbMuted
<< " unmuted volume: " << mnUnmutedVolume
);
731 // change the volume to 0 or the unmuted volume
732 if (mpVolumeControl
&& mbMuted
!= bool(bSet
))
734 double nVolume
= mnUnmutedVolume
;
740 g_object_set( G_OBJECT( mpVolumeControl
), "volume", nVolume
, nullptr );
747 sal_Bool SAL_CALL
Player::isMute()
749 ::osl::MutexGuard
aGuard(m_aMutex
);
755 void SAL_CALL
Player::setVolumeDB( sal_Int16 nVolumeDB
)
757 ::osl::MutexGuard
aGuard(m_aMutex
);
759 mnUnmutedVolume
= pow( 10.0, nVolumeDB
/ 20.0 );
761 SAL_INFO( "avmedia.gstreamer", AVVERSION
"set volume: " << nVolumeDB
<< " gst volume: " << mnUnmutedVolume
);
764 if (mpVolumeControl
&& !mbMuted
)
766 g_object_set( G_OBJECT( mpVolumeControl
), "volume", mnUnmutedVolume
, nullptr );
771 sal_Int16 SAL_CALL
Player::getVolumeDB()
773 ::osl::MutexGuard
aGuard(m_aMutex
);
775 sal_Int16
nVolumeDB(0);
779 double nGstVolume
= 0.0;
781 g_object_get( G_OBJECT( mpVolumeControl
), "volume", &nGstVolume
, nullptr );
783 nVolumeDB
= static_cast<sal_Int16
>( 20.0*log10 ( nGstVolume
) );
790 awt::Size SAL_CALL
Player::getPreferredPlayerWindowSize()
792 ::osl::MutexGuard
aGuard(m_aMutex
);
794 awt::Size
aSize( 0, 0 );
796 if( maURL
.isEmpty() )
798 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " Player::getPreferredPlayerWindowSize - empty URL => 0x0" );
802 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " pre-Player::getPreferredPlayerWindowSize, member " << mnWidth
<< "x" << mnHeight
);
804 osl::Condition::Result aResult
= maSizeCondition
.wait( std::chrono::seconds(10) );
806 SAL_INFO( "avmedia.gstreamer", AVVERSION
<< this << " Player::getPreferredPlayerWindowSize after waitCondition " << aResult
<< ", member " << mnWidth
<< "x" << mnHeight
);
808 if( mnWidth
!= 0 && mnHeight
!= 0 ) {
809 aSize
.Width
= mnWidth
;
810 aSize
.Height
= mnHeight
;
816 uno::Reference
< ::media::XPlayerWindow
> SAL_CALL
Player::createPlayerWindow( const uno::Sequence
< uno::Any
>& rArguments
)
818 ::osl::MutexGuard
aGuard(m_aMutex
);
820 uno::Reference
< ::media::XPlayerWindow
> xRet
;
822 if (rArguments
.getLength() > 1)
823 rArguments
[1] >>= maArea
;
825 awt::Size aSize
= getPreferredPlayerWindowSize();
828 preparePlaybin( maURL
, nullptr );
830 SAL_INFO( "avmedia.gstreamer", AVVERSION
"Player::createPlayerWindow " << aSize
.Width
<< "x" << aSize
.Height
<< " length: " << rArguments
.getLength() );
832 if( aSize
.Width
> 0 && aSize
.Height
> 0 )
834 if (rArguments
.getLength() <= 2)
836 xRet
= new ::avmedia::gstreamer::Window
;
840 sal_IntPtr pIntPtr
= 0;
841 rArguments
[ 2 ] >>= pIntPtr
;
842 SystemChildWindow
*pParentWindow
= reinterpret_cast< SystemChildWindow
* >( pIntPtr
);
846 const SystemEnvData
* pEnvData
= pParentWindow
->GetSystemData();
850 // tdf#124027: the position of embedded window is identical w/ the position
851 // of media object in all other vclplugs (kf5, gen), in gtk3 w/o gtksink it
852 // needs to be translated
853 if (pEnvData
->toolkit
== SystemEnvData::Toolkit::Gtk3
)
855 Point aPoint
= pParentWindow
->GetPosPixel();
856 maArea
.X
= aPoint
.getX();
857 maArea
.Y
= aPoint
.getY();
860 mbUseGtkSink
= false;
862 GstElement
*pVideosink
= static_cast<GstElement
*>(pParentWindow
->CreateGStreamerSink());
865 if (pEnvData
->toolkit
== SystemEnvData::Toolkit::Gtk3
)
870 if (pEnvData
->platform
== SystemEnvData::Platform::Wayland
)
871 pVideosink
= gst_element_factory_make("waylandsink", "video-output");
873 pVideosink
= gst_element_factory_make("autovideosink", "video-output");
878 xRet
= new ::avmedia::gstreamer::Window
;
880 g_object_set(G_OBJECT(mpPlaybin
), "video-sink", pVideosink
, nullptr);
881 g_object_set(G_OBJECT(mpPlaybin
), "force-aspect-ratio", FALSE
, nullptr);
885 mnWindowID
= pEnvData
->GetWindowHandle(pParentWindow
->ImplGetFrame());
886 mpDisplay
= pEnvData
->pDisplay
;
887 SAL_INFO( "avmedia.gstreamer", AVVERSION
"set window id to " << static_cast<int>(mnWindowID
) << " XOverlay " << mpXOverlay
);
889 gst_element_set_state( mpPlaybin
, GST_STATE_PAUSED
);
890 if (!mbUseGtkSink
&& mpXOverlay
)
891 gst_video_overlay_set_window_handle( mpXOverlay
, mnWindowID
);
897 uno::Reference
< media::XFrameGrabber
> SAL_CALL
Player::createFrameGrabber()
899 ::osl::MutexGuard
aGuard(m_aMutex
);
900 FrameGrabber
* pFrameGrabber
= nullptr;
901 const awt::Size
aPrefSize( getPreferredPlayerWindowSize() );
903 if( ( aPrefSize
.Width
> 0 ) && ( aPrefSize
.Height
> 0 ) )
904 pFrameGrabber
= FrameGrabber::create( maURL
);
905 SAL_INFO( "avmedia.gstreamer", AVVERSION
"created FrameGrabber " << pFrameGrabber
);
907 return pFrameGrabber
;
911 OUString SAL_CALL
Player::getImplementationName()
913 return AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME
;
917 sal_Bool SAL_CALL
Player::supportsService( const OUString
& ServiceName
)
919 return cppu::supportsService(this, ServiceName
);
923 uno::Sequence
< OUString
> SAL_CALL
Player::getSupportedServiceNames()
925 return { AVMEDIA_GST_PLAYER_SERVICENAME
};
930 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */