32#include <com/sun/star/text/GraphicCrop.hpp>
36#include <rtl/string.hxx>
48#include <gst/video/videooverlay.h>
49#include <gst/pbutils/missing-plugins.h>
50#include <gst/pbutils/pbutils.h>
54#define AVVERSION "gst 1.0: "
64 explicit FlagGuard(
bool & flag):
flag_(flag) {
flag_ =
true; }
66 ~FlagGuard() {
flag_ =
false; }
74 MissingPluginInstallerThread(): Thread(
"MissingPluginInstaller") {}
77 void execute()
override;
81class MissingPluginInstaller {
82 friend class MissingPluginInstallerThread;
87 ~MissingPluginInstaller();
94 void detach(Player
const * source);
103 std::map<OString, std::set<rtl::Reference<Player>>>
queued_;
112MissingPluginInstaller::~MissingPluginInstaller() {
113 osl::MutexGuard g(
mutex_);
119void MissingPluginInstaller::report(
123 gchar * det = gst_missing_plugin_message_get_installer_detail(message);
124 if (det ==
nullptr) {
127 "gst_missing_plugin_message_get_installer_detail failed");
130 std::size_t len = std::strlen(det);
131 if (len > SAL_MAX_INT32) {
132 SAL_WARN(
"avmedia.gstreamer",
"detail string too long");
136 OString detStr(det, len);
141 osl::MutexGuard g(
mutex_);
146 bool fresh =
i.empty();
166 LINK(
this, MissingPluginInstaller, launchUi), launch.get());
172 auto i = std::find_if(
175 return el.get() == source;
177 if (i !=
set.end()) {
183void MissingPluginInstaller::detach(Player
const * source) {
186 osl::MutexGuard g(
mutex_);
196 eraseSource(
i->second, source);
197 if (
i->second.empty()) {
220void MissingPluginInstaller::processQueue() {
223 for (
const auto& rEntry :
queued_) {
234 MissingPluginInstallerThread* thread =
static_cast<MissingPluginInstallerThread*
>(
p);
248MissingPluginInstaller& TheMissingPluginInstaller()
250 static MissingPluginInstaller theInstaller;
255void MissingPluginInstallerThread::execute() {
256 MissingPluginInstaller & inst = TheMissingPluginInstaller();
258 std::vector<OString> details;
260 osl::MutexGuard g(inst.mutex_);
261 assert(!inst.currentDetails_.empty());
262 details.swap(inst.currentDetails_);
264 std::vector<char *>
args;
265 args.reserve(details.size());
266 for (
auto const& i : details)
268 args.push_back(
const_cast<char *
>(
i.getStr()));
270 args.push_back(
nullptr);
271 gst_install_plugins_sync(
args.data(),
nullptr);
273 osl::MutexGuard g(inst.mutex_);
274 if (inst.queued_.empty() || inst.launchNewThread_) {
275 inst.launchNewThread_ =
true;
288 mpPlaybin( nullptr ),
289 mpVolumeControl( nullptr ),
290 mbUseGtkSink( false ),
291 mbFakeVideo (false ),
292 mnUnmutedVolume( 0 ),
296 mpDisplay( nullptr ),
298 mpXOverlay( nullptr ),
307 char name[] =
"libreoffice";
308 char *arguments[] = {
name };
309 char** argv = arguments;
310 GError* pError =
nullptr;
316 if (pError !=
nullptr)
319 SAL_INFO(
"avmedia.gstreamer",
AVVERSION <<
this <<
" Player::Player error '" << pError->message <<
"'" );
320 g_error_free (pError);
335 TheMissingPluginInstaller().detach(
this);
348 gst_element_set_state(
mpPlaybin, GST_STATE_NULL );
389 switch( GST_MESSAGE_TYPE( message ) ) {
390 case GST_MESSAGE_EOS:
391 gst_element_set_state(
mpPlaybin, GST_STATE_READY );
395 case GST_MESSAGE_STATE_CHANGED:
396 if (message->src == GST_OBJECT(
mpPlaybin))
398 GstState newstate, pendingstate;
400 gst_message_parse_state_changed (message,
nullptr, &newstate, &pendingstate);
403 pendingstate == GST_STATE_VOID_PENDING &&
mpXOverlay)
414#define LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE "GstWaylandDisplayHandleContextType"
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))
431 gst_structure_set (gst_context_writable_structure (context),
432 "handle", G_TYPE_POINTER, display,
nullptr);
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 <<
"'");
450 else if ( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_WARNING )
455 gst_message_parse_warning( message, &error, &error_debug );
458 "warning: '" << error->message <<
"' debug: '"
459 << error_debug <<
"'");
461 else if ( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_INFO )
466 gst_message_parse_info( message, &error, &error_debug );
469 "info: '" << error->message <<
"' debug: '"
470 << error_debug <<
"'");
476 if (gst_is_video_overlay_prepare_window_handle_message (message) )
478 SAL_INFO(
"avmedia.gstreamer",
AVVERSION <<
this <<
" processSyncMessage prepare window id: " <<
479 GST_MESSAGE_TYPE_NAME( message ) <<
" " <<
static_cast<int>(
mnWindowID) );
482 g_object_set( GST_MESSAGE_SRC( message ),
"force-aspect-ratio",
FALSE,
nullptr );
483 mpXOverlay = GST_VIDEO_OVERLAY( GST_MESSAGE_SRC( message ) );
488 gst_video_overlay_handle_events(
mpXOverlay, 0);
498 gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context);
504 if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ASYNC_DONE ) {
506 gint64 gst_duration = 0;
507 if( gst_element_query_duration(
mpPlaybin, GST_FORMAT_TIME, &gst_duration) )
511 GstPad *pad =
nullptr;
513 g_signal_emit_by_name(
mpPlaybin,
"get-video-pad", 0, &pad );
518 GstCaps *caps = gst_pad_get_current_caps( pad );
520 if( gst_structure_get( gst_caps_get_structure( caps, 0 ),
521 "width", G_TYPE_INT, &
w,
522 "height", G_TYPE_INT, &
h,
530 gst_caps_unref( caps );
531 g_object_unref( pad );
536 }
else if (gst_is_missing_plugin_message(message)) {
537 TheMissingPluginInstaller().report(
this, message);
542 }
else if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR ) {
556 gst_element_set_state(
mpPlaybin, GST_STATE_NULL );
560 mpPlaybin = gst_element_factory_make(
"playbin",
nullptr );
566 GstElement *pAudioSink = gst_element_factory_make(
"autoaudiosink",
nullptr );
567 GstElement* pAudioOutput = gst_bin_new(
"audio-output-bin");
568 assert(pAudioOutput);
570 gst_bin_add(GST_BIN(pAudioOutput), pAudioSink);
577 gst_element_add_pad(GST_ELEMENT(pAudioOutput), gst_ghost_pad_new(
"sink", pPad));
578 gst_object_unref(GST_OBJECT(pPad));
580 g_object_set(G_OBJECT(
mpPlaybin),
"audio-sink", pAudioOutput,
nullptr);
582 if( pSink !=
nullptr )
584 g_object_set( G_OBJECT(
mpPlaybin ),
"video-sink", pSink,
nullptr );
591 g_object_set( G_OBJECT(
mpPlaybin ),
"uri", ascURL.getStr() ,
nullptr );
593 GstBus *pBus = gst_element_get_bus(
mpPlaybin );
603 g_object_unref( pBus );
613 SAL_INFO(
"avmedia.gstreamer",
"create player, URL: '" << rURL <<
"'" );
618 preparePlaybin( rURL, gst_element_factory_make(
"fakesink",
nullptr ) );
620 gst_element_set_state(
mpPlaybin, GST_STATE_PAUSED );
640 gst_element_set_state(
mpPlaybin, GST_STATE_PLAYING );
652 gst_element_set_state(
mpPlaybin, GST_STATE_PAUSED );
666 bRet = GST_STATE_TARGET(
mpPlaybin) == GST_STATE_PLAYING;
677 double duration = 0.3;
694 gint64 gst_position = llround (fTime * GST_SECOND);
699 GST_SEEK_TYPE_SET, gst_position,
700 GST_SEEK_TYPE_NONE, 0 );
702 SAL_INFO(
"avmedia.gstreamer",
AVVERSION "seek to: " << gst_position <<
" ns original: " << fTime <<
" s" );
715 if( gst_element_query_position(
mpPlaybin, GST_FORMAT_TIME, &gst_position ) )
716 position = gst_position / GST_SECOND;
754 g_object_set( G_OBJECT(
mpVolumeControl ),
"volume", nVolume,
nullptr );
789 sal_Int16 nVolumeDB(0);
793 double nGstVolume = 0.0;
795 g_object_get( G_OBJECT(
mpVolumeControl ),
"volume", &nGstVolume,
nullptr );
797 nVolumeDB =
static_cast<sal_Int16
>( 20.0*log10 ( nGstVolume ) );
808 awt::Size aSize( 0, 0 );
810 if(
maURL.isEmpty() )
812 SAL_INFO(
"avmedia.gstreamer",
AVVERSION <<
this <<
" Player::getPreferredPlayerWindowSize - empty URL => 0x0" );
818 osl::Condition::Result aResult =
maSizeCondition.wait( std::chrono::seconds(10) );
820 SAL_INFO(
"avmedia.gstreamer",
AVVERSION <<
this <<
" Player::getPreferredPlayerWindowSize after waitCondition " << aResult <<
", member " <<
mnWidth <<
"x" <<
mnHeight );
834 uno::Reference< ::media::XPlayerWindow > xRet;
836 if (rArguments.getLength() > 1)
844 SAL_INFO(
"avmedia.gstreamer",
AVVERSION "Player::createPlayerWindow " << aSize.Width <<
"x" << aSize.Height <<
" length: " << rArguments.getLength() );
846 if( aSize.Width > 0 && aSize.Height > 0 )
848 if (rArguments.getLength() <= 2)
850 xRet = new ::avmedia::gstreamer::Window;
854 sal_IntPtr pIntPtr = 0;
855 rArguments[ 2 ] >>= pIntPtr;
885 pVideosink = gst_element_factory_make(
"waylandsink",
"video-output");
887 pVideosink = gst_element_factory_make(
"autovideosink",
"video-output");
892 xRet = new ::avmedia::gstreamer::Window;
894 g_object_set(G_OBJECT(
mpPlaybin),
"video-sink", pVideosink,
nullptr);
895 g_object_set(G_OBJECT(
mpPlaybin),
"force-aspect-ratio", FALSE,
nullptr);
897 if ((rArguments.getLength() >= 4) && (rArguments[3] >>= pIntPtr) && pIntPtr)
900 Graphic aGraphic = pItem->getGraphic();
901 const text::GraphicCrop& rCrop = pItem->getCrop();
902 if (!aGraphic.
IsNone() && (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0))
911 GstElement* pVideoFilter = gst_element_factory_make(
"videocrop",
nullptr);
914 g_object_set(G_OBJECT(pVideoFilter),
"left", nLeft,
nullptr);
915 g_object_set(G_OBJECT(pVideoFilter),
"top", nTop,
nullptr);
916 g_object_set(G_OBJECT(pVideoFilter),
"right", nRight,
nullptr);
917 g_object_set(G_OBJECT(pVideoFilter),
"bottom", nBottom,
nullptr);
918 g_object_set(G_OBJECT(
mpPlaybin),
"video-filter", pVideoFilter,
nullptr);
929 gst_element_set_state(
mpPlaybin, GST_STATE_PAUSED );
943 if( ( aPrefSize.Width > 0 ) && ( aPrefSize.Height > 0 ) )
945 SAL_INFO(
"avmedia.gstreamer",
AVVERSION "created FrameGrabber " << pFrameGrabber.get() );
947 return pFrameGrabber;
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
Size GetSizePixel(const OutputDevice *pRefDevice=nullptr) const
constexpr tools::Long getX() const
constexpr tools::Long getY() const
constexpr tools::Long getHeight() const
constexpr tools::Long getWidth() const
void * CreateGStreamerSink()
virtual const SystemEnvData * GetSystemData() const override
mutable::osl::Mutex m_aMutex
virtual Point GetPosPixel() const
SalFrame * ImplGetFrame() const
std::map< OString, std::set< rtl::Reference< Player > > > queued_
constexpr OUStringLiteral AVMEDIA_GST_PLAYER_SERVICENAME
std::set< rtl::Reference< Player > > currentSources_
constexpr OUStringLiteral AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME
rtl::Reference< MissingPluginInstallerThread > currentThread_
std::set< OString > reported_
#define LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE
std::vector< OString > currentDetails_
#define LINK(Instance, Class, Member)
#define DECL_STATIC_LINK(Class, Member, ArgType, RetType)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
void SC_DLLPUBLIC join(const ScDocument *pDoc, ::std::vector< ScTokenRef > &rTokens, const ScTokenRef &pToken, const ScAddress &rPos)
void set(css::uno::UnoInterfaceReference const &value)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
sal_uIntPtr GetWindowHandle(const SalFrame *pReference) const