summaryrefslogtreecommitdiffstats
path: root/avmedia/source
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /avmedia/source
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--avmedia/source/avmediadummy.cxx92
-rw-r--r--avmedia/source/framework/MediaControlBase.cxx262
-rw-r--r--avmedia/source/framework/mediacontrol.cxx238
-rw-r--r--avmedia/source/framework/mediaitem.cxx526
-rw-r--r--avmedia/source/framework/mediaplayer.cxx145
-rw-r--r--avmedia/source/framework/mediatoolbox.cxx134
-rw-r--r--avmedia/source/framework/soundhandler.cxx323
-rw-r--r--avmedia/source/framework/soundhandler.hxx120
-rw-r--r--avmedia/source/gstreamer/avmediagstreamer.component15
-rw-r--r--avmedia/source/gstreamer/gstcommon.hxx43
-rw-r--r--avmedia/source/gstreamer/gstframegrabber.cxx176
-rw-r--r--avmedia/source/gstreamer/gstframegrabber.hxx60
-rw-r--r--avmedia/source/gstreamer/gstmanager.cxx71
-rw-r--r--avmedia/source/gstreamer/gstmanager.hxx47
-rw-r--r--avmedia/source/gstreamer/gstplayer.cxx929
-rw-r--r--avmedia/source/gstreamer/gstplayer.hxx107
-rw-r--r--avmedia/source/gstreamer/gstuno.cxx59
-rw-r--r--avmedia/source/gstreamer/gstwindow.cxx193
-rw-r--r--avmedia/source/gstreamer/gstwindow.hxx82
-rw-r--r--avmedia/source/inc/mediamisc.hxx45
-rw-r--r--avmedia/source/macavf/avmediaMacAVF.component25
-rw-r--r--avmedia/source/macavf/framegrabber.hxx56
-rw-r--r--avmedia/source/macavf/framegrabber.mm106
-rw-r--r--avmedia/source/macavf/macavfcommon.hxx89
-rw-r--r--avmedia/source/macavf/macavfuno.mm55
-rw-r--r--avmedia/source/macavf/manager.hxx52
-rw-r--r--avmedia/source/macavf/manager.mm71
-rw-r--r--avmedia/source/macavf/player.hxx84
-rw-r--r--avmedia/source/macavf/player.mm364
-rw-r--r--avmedia/source/macavf/window.hxx111
-rw-r--r--avmedia/source/macavf/window.mm261
-rw-r--r--avmedia/source/viewer/mediaevent_impl.cxx173
-rw-r--r--avmedia/source/viewer/mediaevent_impl.hxx78
-rw-r--r--avmedia/source/viewer/mediawindow.cxx404
-rw-r--r--avmedia/source/viewer/mediawindow_impl.cxx671
-rw-r--r--avmedia/source/viewer/mediawindow_impl.hxx157
-rw-r--r--avmedia/source/vlc/avmediavlc.component15
-rw-r--r--avmedia/source/vlc/inc/wrapper/Common.hxx29
-rw-r--r--avmedia/source/vlc/inc/wrapper/EventHandler.hxx42
-rw-r--r--avmedia/source/vlc/inc/wrapper/EventManager.hxx55
-rw-r--r--avmedia/source/vlc/inc/wrapper/Instance.hxx41
-rw-r--r--avmedia/source/vlc/inc/wrapper/Media.hxx47
-rw-r--r--avmedia/source/vlc/inc/wrapper/Player.hxx73
-rw-r--r--avmedia/source/vlc/inc/wrapper/ThreadsafeQueue.hxx81
-rw-r--r--avmedia/source/vlc/inc/wrapper/Wrapper.hxx19
-rw-r--r--avmedia/source/vlc/vlccommon.hxx40
-rw-r--r--avmedia/source/vlc/vlcframegrabber.cxx131
-rw-r--r--avmedia/source/vlc/vlcframegrabber.hxx52
-rw-r--r--avmedia/source/vlc/vlcmanager.cxx124
-rw-r--r--avmedia/source/vlc/vlcmanager.hxx54
-rw-r--r--avmedia/source/vlc/vlcplayer.cxx251
-rw-r--r--avmedia/source/vlc/vlcplayer.hxx86
-rw-r--r--avmedia/source/vlc/vlcuno.cxx76
-rw-r--r--avmedia/source/vlc/vlcwindow.cxx197
-rw-r--r--avmedia/source/vlc/vlcwindow.hxx74
-rw-r--r--avmedia/source/vlc/wrapper/Common.cxx45
-rw-r--r--avmedia/source/vlc/wrapper/EventHandler.cxx42
-rw-r--r--avmedia/source/vlc/wrapper/EventManager.cxx84
-rw-r--r--avmedia/source/vlc/wrapper/Instance.cxx62
-rw-r--r--avmedia/source/vlc/wrapper/Media.cxx109
-rw-r--r--avmedia/source/vlc/wrapper/Player.cxx241
-rw-r--r--avmedia/source/vlc/wrapper/SymbolLoader.hxx126
-rw-r--r--avmedia/source/vlc/wrapper/Types.hxx58
-rw-r--r--avmedia/source/win/avmediawin.component25
-rw-r--r--avmedia/source/win/framegrabber.cxx225
-rw-r--r--avmedia/source/win/framegrabber.hxx57
-rw-r--r--avmedia/source/win/interface.hxx120
-rw-r--r--avmedia/source/win/manager.cxx77
-rw-r--r--avmedia/source/win/manager.hxx51
-rw-r--r--avmedia/source/win/player.cxx463
-rw-r--r--avmedia/source/win/player.hxx119
-rw-r--r--avmedia/source/win/wincommon.hxx44
-rw-r--r--avmedia/source/win/window.cxx495
-rw-r--r--avmedia/source/win/window.hxx114
-rw-r--r--avmedia/source/win/winuno.cxx59
75 files changed, 10527 insertions, 0 deletions
diff --git a/avmedia/source/avmediadummy.cxx b/avmedia/source/avmediadummy.cxx
new file mode 100644
index 000000000..6c6ada016
--- /dev/null
+++ b/avmedia/source/avmediadummy.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <avmedia/mediaitem.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::com::sun::star;
+
+namespace avmedia
+{
+MediaItem::MediaItem( sal_uInt16 i_nWhich, AVMediaSetMask )
+ : SfxPoolItem( i_nWhich )
+{
+}
+
+MediaItem::MediaItem( const MediaItem& rItem )
+ : SfxPoolItem( rItem )
+{
+}
+
+MediaItem::~MediaItem()
+{
+}
+
+struct MediaItem::Impl
+{
+};
+
+bool MediaItem::QueryValue( css::uno::Any&, sal_uInt8 ) const
+{
+ return false;
+}
+
+bool MediaItem::GetPresentation( SfxItemPresentation, MapUnit, MapUnit, OUString&, const IntlWrapper& ) const
+{
+ return false;
+}
+
+bool MediaItem::PutValue( const css::uno::Any&, sal_uInt8 )
+{
+ return false;
+}
+
+AVMediaSetMask MediaItem::getMaskSet() const
+{
+ return AVMediaSetMask::NONE;
+}
+
+SfxPoolItem* MediaItem::CreateDefault()
+{
+ return new MediaItem;
+}
+
+
+MediaItem* MediaItem::Clone( SfxItemPool*) const
+{
+ return nullptr;
+}
+
+bool MediaItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem)); (void)rItem;
+ return false;
+}
+
+} // namespace avmedia
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* SAL_CALL
+com_sun_star_comp_framework_SoundHandler_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return NULL;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/framework/MediaControlBase.cxx b/avmedia/source/framework/MediaControlBase.cxx
new file mode 100644
index 000000000..e84586d76
--- /dev/null
+++ b/avmedia/source/framework/MediaControlBase.cxx
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+#include <avmedia/MediaControlBase.hxx>
+#include <avmedia/mediaplayer.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <svtools/miscopt.hxx>
+#include <tools/time.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <helpids.h>
+#include <mediamisc.hxx>
+
+using ::rtl::OUString;
+
+namespace avmedia {
+
+MediaControlBase::MediaControlBase()
+ : mbCurrentlySettingZoom(false)
+{
+}
+
+void MediaControlBase::UpdateTimeField( MediaItem const & aMediaItem, double fTime )
+{
+ if( aMediaItem.getURL().isEmpty())
+ return;
+
+ OUString aTimeString;
+
+ SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
+
+ aTimeString += rLocaleData.getDuration( tools::Time( 0, 0, static_cast< sal_uInt32 >( floor( fTime ) ) ) ) +
+ " / " +
+ rLocaleData.getDuration( tools::Time( 0, 0, static_cast< sal_uInt32 >( floor( aMediaItem.getDuration() ) )) );
+
+ if( mxTimeEdit->get_text() != aTimeString )
+ mxTimeEdit->set_text( aTimeString );
+}
+
+void MediaControlBase::UpdateVolumeSlider( MediaItem const & aMediaItem )
+{
+ if( aMediaItem.getURL().isEmpty() )
+ mxVolumeSlider->set_sensitive(false);
+ else
+ {
+ mxVolumeSlider->set_sensitive(true);
+ const sal_Int32 nVolumeDB = aMediaItem.getVolumeDB();
+ mxVolumeSlider->set_value( std::min( std::max( nVolumeDB, static_cast< sal_Int32 >( AVMEDIA_DB_RANGE ) ),
+ static_cast< sal_Int32 >( 0 ) ) );
+ }
+}
+
+void MediaControlBase::UpdateTimeSlider( MediaItem const & aMediaItem )
+{
+ if( aMediaItem.getURL().isEmpty() )
+ mxTimeSlider->set_sensitive(false);
+ else
+ {
+ mxTimeSlider->set_sensitive(true);
+
+ const double fDuration = aMediaItem.getDuration();
+
+ if( fDuration > 0.0 )
+ {
+ const double fTime = std::min( aMediaItem.getTime(), fDuration );
+
+ bool bChanged(false);
+ int nStep(0), nPage(0);
+ if (!nStep)
+ {
+ nStep = AVMEDIA_TIME_RANGE * AVMEDIA_LINEINCREMENT / fDuration;
+ bChanged = true;
+ }
+ if (!nPage)
+ {
+ nPage = AVMEDIA_TIME_RANGE * AVMEDIA_PAGEINCREMENT / fDuration;
+ bChanged = true;
+ }
+ if (bChanged)
+ mxTimeSlider->set_increments(nStep, nPage);
+
+ mxTimeSlider->set_value(fTime / fDuration * AVMEDIA_TIME_RANGE);
+ }
+ }
+}
+
+void MediaControlBase::InitializeWidgets()
+{
+ mxPlayToolBox->set_item_help_id("play", HID_AVMEDIA_TOOLBOXITEM_PLAY);
+ mxPlayToolBox->set_item_label("play", AvmResId(AVMEDIA_STR_PLAY));
+ mxPlayToolBox->set_item_help_id("pause", HID_AVMEDIA_TOOLBOXITEM_PAUSE);
+ mxPlayToolBox->set_item_label("pause", AvmResId(AVMEDIA_STR_PAUSE));
+ mxPlayToolBox->set_item_help_id("stop", HID_AVMEDIA_TOOLBOXITEM_STOP);
+ mxPlayToolBox->set_item_label("stop", AvmResId(AVMEDIA_STR_STOP));
+ mxPlayToolBox->set_item_help_id("loop", HID_AVMEDIA_TOOLBOXITEM_LOOP);
+ mxPlayToolBox->set_item_label("loop", AvmResId(AVMEDIA_STR_LOOP));
+ mxMuteToolBox->set_item_help_id("mute", HID_AVMEDIA_TOOLBOXITEM_MUTE);
+ mxMuteToolBox->set_item_label("mute", AvmResId(AVMEDIA_STR_MUTE));
+
+ mxZoomListBox->append(OUString::number(AVMEDIA_ZOOMLEVEL_50), AvmResId( AVMEDIA_STR_ZOOM_50 ));
+ mxZoomListBox->append(OUString::number(AVMEDIA_ZOOMLEVEL_100), AvmResId( AVMEDIA_STR_ZOOM_100 ));
+ mxZoomListBox->append(OUString::number(AVMEDIA_ZOOMLEVEL_200), AvmResId( AVMEDIA_STR_ZOOM_200 ));
+ mxZoomListBox->append(OUString::number(AVMEDIA_ZOOMLEVEL_FIT), AvmResId( AVMEDIA_STR_ZOOM_FIT ));
+ mxZoomListBox->set_help_id( HID_AVMEDIA_ZOOMLISTBOX );
+ mxZoomListBox->set_tooltip_text(AvmResId( AVMEDIA_STR_ZOOM_TOOLTIP ));
+
+ const OUString aTimeText( " 00:00:00/00:00:00 " );
+ mxTimeEdit->set_text( aTimeText );
+ mxTimeEdit->set_help_id( HID_AVMEDIA_TIMEEDIT );
+ mxTimeEdit->set_sensitive(false);
+
+ mxVolumeSlider->set_range(AVMEDIA_DB_RANGE, 0);
+ mxVolumeSlider->set_tooltip_text( AvmResId( AVMEDIA_STR_VOLUME ));
+ mxVolumeSlider->set_help_id( HID_AVMEDIA_VOLUMESLIDER );
+
+ mxTimeSlider->set_range( 0, AVMEDIA_TIME_RANGE );
+ mxTimeSlider->set_tooltip_text( AvmResId( AVMEDIA_STR_POSITION ));
+}
+
+void MediaControlBase::UpdateToolBoxes(const MediaItem& rMediaItem)
+{
+ const bool bValidURL = !rMediaItem.getURL().isEmpty();
+ mxPlayToolBox->set_item_sensitive("play", bValidURL);
+ mxPlayToolBox->set_item_sensitive("pause", bValidURL);
+ mxPlayToolBox->set_item_sensitive("stop", bValidURL);
+ mxPlayToolBox->set_item_sensitive("loop", bValidURL);
+ mxMuteToolBox->set_item_sensitive("mute", bValidURL);
+ if( !bValidURL )
+ {
+ mxZoomListBox->set_sensitive(false);
+ mxMuteToolBox->set_sensitive(false);
+ }
+ else
+ {
+ mxPlayToolBox->set_sensitive(true);
+ mxMuteToolBox->set_sensitive(true);
+ if( rMediaItem.getState() == MediaState::Play )
+ {
+ mxPlayToolBox->set_item_active("play", true);
+ mxPlayToolBox->set_item_active("pause", false);
+ mxPlayToolBox->set_item_active("stop", false);
+ }
+ else if( rMediaItem.getState() == MediaState::Pause )
+ {
+ mxPlayToolBox->set_item_active("play", false);
+ mxPlayToolBox->set_item_active("pause", true);
+ mxPlayToolBox->set_item_active("stop", false);
+ }
+ else
+ {
+ mxPlayToolBox->set_item_active("play", false);
+ mxPlayToolBox->set_item_active("pause", false);
+ mxPlayToolBox->set_item_active("stop", true);
+ }
+ mxPlayToolBox->set_item_active("loop", rMediaItem.isLoop());
+ mxMuteToolBox->set_item_active("mute", rMediaItem.isMute());
+ if (!mbCurrentlySettingZoom)
+ {
+ sal_uInt16 nSelectEntryPos ;
+
+ switch( rMediaItem.getZoom() )
+ {
+ case css::media::ZoomLevel_ZOOM_1_TO_2:
+ nSelectEntryPos = AVMEDIA_ZOOMLEVEL_50;
+ break;
+ case css::media::ZoomLevel_ORIGINAL:
+ nSelectEntryPos = AVMEDIA_ZOOMLEVEL_100;
+ break;
+ case css::media::ZoomLevel_ZOOM_2_TO_1:
+ nSelectEntryPos = AVMEDIA_ZOOMLEVEL_200;
+ break;
+ case css::media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT:
+ nSelectEntryPos = AVMEDIA_ZOOMLEVEL_FIT;
+ break;
+ case css::media::ZoomLevel_FIT_TO_WINDOW:
+ nSelectEntryPos = AVMEDIA_ZOOMLEVEL_SCALED;
+ break;
+
+ default:
+ nSelectEntryPos = AVMEDIA_ZOOMLEVEL_INVALID;
+ break;
+ }
+
+ if( nSelectEntryPos != AVMEDIA_ZOOMLEVEL_INVALID )
+ {
+ mxZoomListBox->show();
+ mxZoomListBox->set_sensitive(true);
+ mxZoomListBox->set_active(nSelectEntryPos);
+ }
+ else
+ mxZoomListBox->set_sensitive(false);
+ }
+ }
+}
+
+void MediaControlBase::SelectPlayToolBoxItem( MediaItem& aExecItem, MediaItem const & aItem, const OString& rId)
+{
+ if (rId == "apply")
+ {
+ MediaFloater* pFloater = avmedia::getMediaFloater();
+
+ if( pFloater )
+ pFloater->dispatchCurrentURL();
+ }
+ else if (rId == "play")
+ {
+ aExecItem.setState( MediaState::Play );
+
+ if( aItem.getTime() == aItem.getDuration() )
+ aExecItem.setTime( 0.0 );
+ else
+ aExecItem.setTime( aItem.getTime() );
+ }
+ else if (rId == "pause")
+ {
+ aExecItem.setState( MediaState::Pause );
+ }
+ else if (rId == "stop")
+ {
+ aExecItem.setState( MediaState::Stop );
+ aExecItem.setTime( 0.0 );
+ }
+ else if (rId == "mute")
+ {
+ aExecItem.setMute( mxMuteToolBox->get_item_active("mute") );
+ }
+ else if (rId == "loop")
+ {
+ aExecItem.setLoop( mxPlayToolBox->get_item_active("loop") );
+ }
+}
+
+void MediaControlBase::disposeWidgets()
+{
+ mxZoomListBox.reset();
+ mxTimeEdit.reset();
+ mxVolumeSlider.reset();
+ mxMuteToolBox.reset();
+ mxTimeSlider.reset();
+ mxPlayToolBox.reset();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/framework/mediacontrol.cxx b/avmedia/source/framework/mediacontrol.cxx
new file mode 100644
index 000000000..66818fc07
--- /dev/null
+++ b/avmedia/source/framework/mediacontrol.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <mediacontrol.hxx>
+#include <strings.hrc>
+#include <mediamisc.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <helpids.h>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/syslocale.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <math.h>
+#include <algorithm>
+#include <avmedia/MediaControlBase.hxx>
+
+namespace avmedia
+{
+
+MediaControl::MediaControl( vcl::Window* pParent, MediaControlStyle eControlStyle ) :
+ // MEDIACONTROLSTYLE_MULTILINE is the normal docking windows of tools->media player
+ // MEDIACONTROLSTYLE_SINGLELINE is the toolbar of view->toolbar->media playback
+ InterimItemWindow(pParent, eControlStyle == MEDIACONTROLSTYLE_MULTILINE ?
+ OUString("svx/ui/mediawindow.ui") :
+ OUString("svx/ui/medialine.ui"),
+ "MediaWindow"),
+ MediaControlBase(),
+ maIdle( "avmedia MediaControl Idle" ),
+ maChangeTimeIdle( "avmedia MediaControl Change Time Idle" ),
+ maItem( 0, AVMediaSetMask::ALL ),
+ mbLocked( false ),
+ meControlStyle( eControlStyle ),
+ mfTime(0.0)
+{
+ mxPlayToolBox = m_xBuilder->weld_toolbar("playtoolbox");
+ mxTimeSlider = m_xBuilder->weld_scale("timeslider");
+ mxMuteToolBox = m_xBuilder->weld_toolbar("mutetoolbox");
+ mxVolumeSlider = m_xBuilder->weld_scale("volumeslider");
+ mxZoomListBox = m_xBuilder->weld_combo_box("zoombox");
+ mxTimeEdit = m_xBuilder->weld_entry("timeedit");
+ mxMediaPath = m_xBuilder->weld_label("url");
+
+ // TODO SetParentClipMode( ParentClipMode::NoClip );
+
+ InitializeWidgets();
+
+ mxPlayToolBox->connect_clicked( LINK( this, MediaControl, implSelectHdl ) );
+
+ mxTimeSlider->connect_value_changed( LINK( this, MediaControl, implTimeHdl ) );
+ // when changing the time, use this to do the time change after active scrolling
+ // has stopped for a little which
+ maChangeTimeIdle.SetPriority( TaskPriority::LOWEST );
+ maChangeTimeIdle.SetInvokeHandler( LINK( this, MediaControl, implTimeEndHdl ) );
+
+ const OUString aTimeText( " 00:00:00/00:00:00 " );
+ mxTimeEdit->set_text(aTimeText);
+ Size aTextSize = mxTimeEdit->get_preferred_size();
+ mxTimeEdit->set_size_request(aTextSize.Width(), aTextSize.Height());
+ mxTimeEdit->set_text(OUString());
+
+ mxMuteToolBox->connect_clicked( LINK( this, MediaControl, implSelectHdl ) );
+ mxVolumeSlider->connect_value_changed( LINK( this, MediaControl, implVolumeHdl ) );
+
+ mxZoomListBox->connect_changed( LINK( this, MediaControl, implZoomSelectHdl ) );
+ mxZoomListBox->set_help_id(HID_AVMEDIA_ZOOMLISTBOX);
+
+ const OUString aMediaPath( AvmResId( AVMEDIA_MEDIA_PATH_DEFAULT ) );
+ mxMediaPath->set_label(aMediaPath);
+ if (meControlStyle == MEDIACONTROLSTYLE_SINGLELINE)
+ mxMediaPath->set_size_request(mxMediaPath->get_preferred_size().Width() + 400, -1); // maybe extend the no. 400 to span the screen width
+
+ // we want time field + progress slider to update as the media plays
+ // give this task a lower prio than REPAINT so that UI updates are not starved
+ maIdle.SetPriority( TaskPriority::POST_PAINT );
+ maIdle.SetInvokeHandler( LINK( this, MediaControl, implTimeoutHdl ) );
+}
+
+void MediaControl::InitializeWidgets()
+{
+ if( meControlStyle != MEDIACONTROLSTYLE_SINGLELINE )
+ {
+ mxPlayToolBox->set_item_help_id("open", HID_AVMEDIA_TOOLBOXITEM_OPEN);
+ mxPlayToolBox->set_item_label("open", AvmResId(AVMEDIA_STR_OPEN));
+ mxPlayToolBox->set_item_help_id("apply", HID_AVMEDIA_TOOLBOXITEM_INSERT);
+ mxPlayToolBox->set_item_label("apply", AvmResId(AVMEDIA_STR_INSERT));
+ }
+ avmedia::MediaControlBase::InitializeWidgets();
+}
+
+MediaControl::~MediaControl()
+{
+ disposeOnce();
+}
+
+void MediaControl::dispose()
+{
+ disposeWidgets();
+ mxMediaPath.reset();
+ InterimItemWindow::dispose();
+}
+
+void MediaControl::UpdateURLField(MediaItem const & tempItem)
+{
+ const OUString aURL( AvmResId(AVMEDIA_MEDIA_PATH) + ": " + tempItem.getURL() ) ;
+ mxMediaPath->set_label(aURL);
+}
+
+void MediaControl::setState( const MediaItem& rItem )
+{
+ double fTime = rItem.getTime();
+ if( !mbLocked && fTime != mfTime)
+ {
+ mfTime = fTime;
+ maItem.merge( rItem );
+ if( rItem.getURL().isEmpty() && meControlStyle == MEDIACONTROLSTYLE_SINGLELINE )
+ mxPlayToolBox->set_sensitive(false);
+ UpdateToolBoxes( maItem );
+ UpdateTimeSlider( maItem );
+ UpdateVolumeSlider( maItem );
+ UpdateTimeField( maItem, maItem.getTime() );
+ UpdateURLField(maItem);
+ }
+}
+
+IMPL_LINK( MediaControl, implTimeHdl, weld::Scale&, rSlider, void )
+{
+ mbLocked = true;
+ maIdle.Stop();
+ UpdateTimeField(maItem, rSlider.get_value() * maItem.getDuration() / AVMEDIA_TIME_RANGE);
+ maChangeTimeIdle.Start();
+}
+
+IMPL_LINK_NOARG(MediaControl, implTimeEndHdl, Timer*, void)
+{
+ MediaItem aExecItem;
+
+ aExecItem.setTime( mxTimeSlider->get_value() * maItem.getDuration() / AVMEDIA_TIME_RANGE );
+ // keep state (if the media was playing, keep it playing)
+ aExecItem.setState(maItem.getState());
+ execute( aExecItem );
+ update();
+ maIdle.Start();
+ mbLocked = false;
+}
+
+IMPL_LINK( MediaControl, implVolumeHdl, weld::Scale&, rSlider, void )
+{
+ MediaItem aExecItem;
+
+ aExecItem.setVolumeDB(rSlider.get_value());
+ execute( aExecItem );
+ update();
+}
+
+IMPL_LINK( MediaControl, implSelectHdl, const OString&, rIdent, void )
+{
+ MediaItem aExecItem;
+ if (rIdent == "open")
+ {
+ OUString aURL;
+ if (MediaWindow::executeMediaURLDialog(GetFrameWeld(), aURL, nullptr))
+ {
+ if( !MediaWindow::isMediaURL( aURL, ""/*TODO?*/, true ) )
+ MediaWindow::executeFormatErrorBox(GetFrameWeld());
+ else
+ {
+ aExecItem.setURL( aURL, "", ""/*TODO?*/ );
+ aExecItem.setState( MediaState::Play );
+ }
+ }
+ }
+ else
+ SelectPlayToolBoxItem( aExecItem, maItem, rIdent );
+
+ if (aExecItem.getState() == MediaState::Play)
+ maIdle.Start();
+ else if (aExecItem.getState() == MediaState::Pause ||
+ aExecItem.getState() == MediaState::Stop)
+ maIdle.Stop();
+
+ if( aExecItem.getMaskSet() != AVMediaSetMask::NONE )
+ execute( aExecItem );
+
+ update();
+}
+
+IMPL_LINK( MediaControl, implZoomSelectHdl, weld::ComboBox&, rBox, void )
+{
+ bool bCurrentlySettingZoom = mbCurrentlySettingZoom;
+ mbCurrentlySettingZoom = true;
+
+ MediaItem aExecItem;
+ css::media::ZoomLevel eLevel;
+
+ switch (rBox.get_active())
+ {
+ case AVMEDIA_ZOOMLEVEL_50: eLevel = css::media::ZoomLevel_ZOOM_1_TO_2; break;
+ case AVMEDIA_ZOOMLEVEL_100: eLevel = css::media::ZoomLevel_ORIGINAL; break;
+ case AVMEDIA_ZOOMLEVEL_200: eLevel = css::media::ZoomLevel_ZOOM_2_TO_1; break;
+ case AVMEDIA_ZOOMLEVEL_FIT: eLevel = css::media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT; break;
+ case AVMEDIA_ZOOMLEVEL_SCALED: eLevel = css::media::ZoomLevel_FIT_TO_WINDOW; break;
+
+ default: eLevel = css::media::ZoomLevel_NOT_AVAILABLE; break;
+ }
+
+ aExecItem.setZoom( eLevel );
+ execute( aExecItem );
+ update();
+
+ mbCurrentlySettingZoom = bCurrentlySettingZoom;
+}
+
+IMPL_LINK_NOARG(MediaControl, implTimeoutHdl, Timer *, void)
+{
+ update();
+ maIdle.Start();
+}
+
+} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/framework/mediaitem.cxx b/avmedia/source/framework/mediaitem.cxx
new file mode 100644
index 000000000..3b83f3853
--- /dev/null
+++ b/avmedia/source/framework/mediaitem.cxx
@@ -0,0 +1,526 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <avmedia/mediaitem.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+
+#include <sal/log.hxx>
+
+#include <ucbhelper/content.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <mediamisc.hxx>
+#include <osl/file.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+
+namespace avmedia
+{
+
+SfxPoolItem* MediaItem::CreateDefault() { return new MediaItem; }
+
+struct MediaItem::Impl
+{
+ OUString m_URL;
+ OUString m_TempFileURL;
+ OUString m_Referer;
+ OUString m_sMimeType;
+ AVMediaSetMask m_nMaskSet;
+ MediaState m_eState;
+ double m_fTime;
+ double m_fDuration;
+ sal_Int16 m_nVolumeDB;
+ bool m_bLoop;
+ bool m_bMute;
+ css::media::ZoomLevel m_eZoom;
+
+ explicit Impl(AVMediaSetMask nMaskSet)
+ : m_nMaskSet( nMaskSet )
+ , m_eState( MediaState::Stop )
+ , m_fTime( 0.0 )
+ , m_fDuration( 0.0 )
+ , m_nVolumeDB( 0 )
+ , m_bLoop( false )
+ , m_bMute( false )
+ , m_eZoom( css::media::ZoomLevel_NOT_AVAILABLE )
+ {
+ }
+};
+
+
+MediaItem::MediaItem( sal_uInt16 i_nWhich, AVMediaSetMask nMaskSet )
+ : SfxPoolItem( i_nWhich )
+ , m_pImpl( new Impl(nMaskSet) )
+{
+}
+
+
+MediaItem::MediaItem( const MediaItem& rItem )
+ : SfxPoolItem( rItem )
+ , m_pImpl( new Impl(*rItem.m_pImpl) )
+{
+}
+
+
+MediaItem::~MediaItem()
+{
+}
+
+
+bool MediaItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert( SfxPoolItem::operator==(rItem));
+ MediaItem const& rOther(static_cast< const MediaItem& >(rItem));
+ return m_pImpl->m_nMaskSet == rOther.m_pImpl->m_nMaskSet
+ && m_pImpl->m_URL == rOther.m_pImpl->m_URL
+ && m_pImpl->m_Referer == rOther.m_pImpl->m_Referer
+ && m_pImpl->m_sMimeType == rOther.m_pImpl->m_sMimeType
+ && m_pImpl->m_eState == rOther.m_pImpl->m_eState
+ && m_pImpl->m_fDuration == rOther.m_pImpl->m_fDuration
+ && m_pImpl->m_fTime == rOther.m_pImpl->m_fTime
+ && m_pImpl->m_nVolumeDB == rOther.m_pImpl->m_nVolumeDB
+ && m_pImpl->m_bLoop == rOther.m_pImpl->m_bLoop
+ && m_pImpl->m_bMute == rOther.m_pImpl->m_bMute
+ && m_pImpl->m_eZoom == rOther.m_pImpl->m_eZoom;
+}
+
+MediaItem* MediaItem::Clone( SfxItemPool* ) const
+{
+ return new MediaItem( *this );
+}
+
+bool MediaItem::GetPresentation( SfxItemPresentation,
+ MapUnit,
+ MapUnit,
+ OUString& rText,
+ const IntlWrapper& ) const
+{
+ rText.clear();
+ return false;
+}
+
+bool MediaItem::QueryValue( css::uno::Any& rVal, sal_uInt8 ) const
+{
+ uno::Sequence< uno::Any > aSeq( 10 );
+
+ aSeq[ 0 ] <<= m_pImpl->m_URL;
+ aSeq[ 1 ] <<= static_cast<sal_uInt32>(m_pImpl->m_nMaskSet);
+ aSeq[ 2 ] <<= static_cast< sal_Int32 >( m_pImpl->m_eState );
+ aSeq[ 3 ] <<= m_pImpl->m_fTime;
+ aSeq[ 4 ] <<= m_pImpl->m_fDuration;
+ aSeq[ 5 ] <<= m_pImpl->m_nVolumeDB;
+ aSeq[ 6 ] <<= m_pImpl->m_bLoop;
+ aSeq[ 7 ] <<= m_pImpl->m_bMute;
+ aSeq[ 8 ] <<= m_pImpl->m_eZoom;
+ aSeq[ 9 ] <<= m_pImpl->m_sMimeType;
+
+ rVal <<= aSeq;
+
+ return true;
+}
+
+
+bool MediaItem::PutValue( const css::uno::Any& rVal, sal_uInt8 )
+{
+ uno::Sequence< uno::Any > aSeq;
+ bool bRet = false;
+
+ if( ( rVal >>= aSeq ) && ( aSeq.getLength() == 10 ) )
+ {
+ sal_Int32 nInt32 = 0;
+
+ aSeq[ 0 ] >>= m_pImpl->m_URL;
+ aSeq[ 1 ] >>= nInt32;
+ m_pImpl->m_nMaskSet = static_cast<AVMediaSetMask>(nInt32);
+ aSeq[ 2 ] >>= nInt32;
+ m_pImpl->m_eState = static_cast< MediaState >( nInt32 );
+ aSeq[ 3 ] >>= m_pImpl->m_fTime;
+ aSeq[ 4 ] >>= m_pImpl->m_fDuration;
+ aSeq[ 5 ] >>= m_pImpl->m_nVolumeDB;
+ aSeq[ 6 ] >>= m_pImpl->m_bLoop;
+ aSeq[ 7 ] >>= m_pImpl->m_bMute;
+ aSeq[ 8 ] >>= m_pImpl->m_eZoom;
+ aSeq[ 9 ] >>= m_pImpl->m_sMimeType;
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+
+void MediaItem::merge( const MediaItem& rMediaItem )
+{
+ const AVMediaSetMask nMaskSet = rMediaItem.getMaskSet();
+
+ if( AVMediaSetMask::URL & nMaskSet )
+ setURL( rMediaItem.getURL(), rMediaItem.getTempURL(), rMediaItem.getReferer() );
+
+ if( AVMediaSetMask::MIME_TYPE & nMaskSet )
+ setMimeType( rMediaItem.getMimeType() );
+
+ if( AVMediaSetMask::STATE & nMaskSet )
+ setState( rMediaItem.getState() );
+
+ if( AVMediaSetMask::DURATION & nMaskSet )
+ setDuration( rMediaItem.getDuration() );
+
+ if( AVMediaSetMask::TIME & nMaskSet )
+ setTime( rMediaItem.getTime() );
+
+ if( AVMediaSetMask::LOOP & nMaskSet )
+ setLoop( rMediaItem.isLoop() );
+
+ if( AVMediaSetMask::MUTE & nMaskSet )
+ setMute( rMediaItem.isMute() );
+
+ if( AVMediaSetMask::VOLUMEDB & nMaskSet )
+ setVolumeDB( rMediaItem.getVolumeDB() );
+
+ if( AVMediaSetMask::ZOOM & nMaskSet )
+ setZoom( rMediaItem.getZoom() );
+}
+
+
+AVMediaSetMask MediaItem::getMaskSet() const
+{
+ return m_pImpl->m_nMaskSet;
+}
+
+
+void MediaItem::setURL( const OUString& rURL, const OUString& rTempURL, const OUString& rReferer )
+{
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::URL;
+ m_pImpl->m_URL = rURL;
+ m_pImpl->m_TempFileURL = rTempURL;
+ m_pImpl->m_Referer = rReferer;
+}
+
+
+const OUString& MediaItem::getURL() const
+{
+ return m_pImpl->m_URL;
+}
+
+
+const OUString& MediaItem::getTempURL() const
+{
+ return m_pImpl->m_TempFileURL;
+}
+
+
+const OUString& MediaItem::getReferer() const
+{
+ return m_pImpl->m_Referer;
+}
+
+
+void MediaItem::setMimeType( const OUString& rMimeType )
+{
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::MIME_TYPE;
+ m_pImpl->m_sMimeType = rMimeType;
+}
+
+
+OUString MediaItem::getMimeType() const
+{
+ return !m_pImpl->m_sMimeType.isEmpty() ? m_pImpl->m_sMimeType : AVMEDIA_MIMETYPE_COMMON;
+}
+
+
+void MediaItem::setState( MediaState eState )
+{
+ m_pImpl->m_eState = eState;
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::STATE;
+}
+
+
+MediaState MediaItem::getState() const
+{
+ return m_pImpl->m_eState;
+}
+
+
+void MediaItem::setDuration( double fDuration )
+{
+ m_pImpl->m_fDuration = fDuration;
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::DURATION;
+}
+
+
+double MediaItem::getDuration() const
+{
+ return m_pImpl->m_fDuration;
+}
+
+
+void MediaItem::setTime( double fTime )
+{
+ m_pImpl->m_fTime = fTime;
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::TIME;
+}
+
+
+double MediaItem::getTime() const
+{
+ return m_pImpl->m_fTime;
+}
+
+
+void MediaItem::setLoop( bool bLoop )
+{
+ m_pImpl->m_bLoop = bLoop;
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::LOOP;
+}
+
+
+bool MediaItem::isLoop() const
+{
+ return m_pImpl->m_bLoop;
+}
+
+
+void MediaItem::setMute( bool bMute )
+{
+ m_pImpl->m_bMute = bMute;
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::MUTE;
+}
+
+
+bool MediaItem::isMute() const
+{
+ return m_pImpl->m_bMute;
+}
+
+
+void MediaItem::setVolumeDB( sal_Int16 nDB )
+{
+ m_pImpl->m_nVolumeDB = nDB;
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::VOLUMEDB;
+}
+
+
+sal_Int16 MediaItem::getVolumeDB() const
+{
+ return m_pImpl->m_nVolumeDB;
+}
+
+
+void MediaItem::setZoom( css::media::ZoomLevel eZoom )
+{
+ m_pImpl->m_eZoom = eZoom;
+ m_pImpl->m_nMaskSet |= AVMediaSetMask::ZOOM;
+}
+
+
+css::media::ZoomLevel MediaItem::getZoom() const
+{
+ return m_pImpl->m_eZoom;
+}
+
+
+OUString GetFilename(OUString const& rSourceURL)
+{
+ uno::Reference<uri::XUriReferenceFactory> const xUriFactory(
+ uri::UriReferenceFactory::create(
+ comphelper::getProcessComponentContext()));
+ uno::Reference<uri::XUriReference> const xSourceURI(
+ xUriFactory->parse(rSourceURL), uno::UNO_SET_THROW);
+
+ OUString filename;
+ {
+ sal_Int32 const nSegments(xSourceURI->getPathSegmentCount());
+ if (0 < nSegments)
+ {
+ filename = xSourceURI->getPathSegment(nSegments - 1);
+ }
+ }
+ if (!::comphelper::OStorageHelper::IsValidZipEntryFileName(
+ filename, false) || !filename.getLength())
+ {
+ filename = "media";
+ }
+ return filename;
+}
+
+
+uno::Reference<io::XStream>
+CreateStream(uno::Reference<embed::XStorage> const& xStorage,
+ OUString const& rFilename)
+{
+ OUString filename(rFilename);
+
+ if (xStorage->hasByName(filename))
+ {
+ OUString basename;
+ OUString suffix;
+ sal_Int32 const nIndex(rFilename.lastIndexOf('.'));
+ if (0 < nIndex)
+ {
+ basename = rFilename.copy(0, nIndex);
+ suffix = rFilename.copy(nIndex);
+ }
+ sal_Int32 count(0); // sigh... try to generate non-existent name
+ do
+ {
+ ++count;
+ filename = basename + OUString::number(count) + suffix;
+ }
+ while (xStorage->hasByName(filename));
+ }
+
+ uno::Reference<io::XStream> const xStream(
+ xStorage->openStreamElement(filename,
+ embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE),
+ uno::UNO_SET_THROW);
+ uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
+ uno::UNO_QUERY);
+ if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
+ xStreamProps->setPropertyValue("MediaType", uno::Any(OUString(
+ //FIXME how to detect real media type?
+ //but currently xmloff has this one hardcoded anyway...
+ "application/vnd.sun.star.media")));
+ xStreamProps->setPropertyValue( // turn off compression
+ "Compressed", uno::Any(false));
+ }
+ return xStream;
+}
+
+
+bool EmbedMedia(uno::Reference<frame::XModel> const& xModel,
+ OUString const& rSourceURL, OUString & o_rEmbeddedURL, uno::Reference<io::XInputStream> const& xInputStream)
+{
+ try
+ {
+ uno::Reference<document::XStorageBasedDocument> const xSBD(xModel,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<embed::XStorage> const xStorage(
+ xSBD->getDocumentStorage(), uno::UNO_SET_THROW);
+
+ OUString const media("Media");
+ uno::Reference<embed::XStorage> const xSubStorage(
+ xStorage->openStorageElement(media, embed::ElementModes::WRITE));
+
+ OUString filename(GetFilename(rSourceURL));
+
+ uno::Reference<io::XStream> const xStream(
+ CreateStream(xSubStorage, filename), uno::UNO_SET_THROW);
+ uno::Reference<io::XOutputStream> const xOutStream(
+ xStream->getOutputStream(), uno::UNO_SET_THROW);
+
+ if (xInputStream.is())
+ {
+ // Throw Exception if failed.
+ ::comphelper::OStorageHelper::CopyInputToOutput(xInputStream, xOutStream);
+ }
+ else
+ {
+ ::ucbhelper::Content sourceContent(rSourceURL,
+ uno::Reference<ucb::XCommandEnvironment>(),
+ comphelper::getProcessComponentContext());
+
+ if (!sourceContent.openStream(xOutStream)) // copy file to storage
+ {
+ SAL_INFO("avmedia", "openStream to storage failed");
+ return false;
+ }
+ }
+
+ uno::Reference<embed::XTransactedObject> const xSubTransaction(
+ xSubStorage, uno::UNO_QUERY);
+ if (xSubTransaction.is()) {
+ xSubTransaction->commit();
+ }
+ uno::Reference<embed::XTransactedObject> const xTransaction(
+ xStorage, uno::UNO_QUERY);
+ if (xTransaction.is()) {
+ xTransaction->commit();
+ }
+
+ o_rEmbeddedURL = "vnd.sun.star.Package:" + media + "/" + filename;
+ return true;
+ }
+ catch (uno::Exception const&)
+ {
+ SAL_WARN("avmedia",
+ "Exception while trying to embed media");
+ }
+ return false;
+}
+
+bool CreateMediaTempFile(uno::Reference<io::XInputStream> const& xInStream,
+ OUString& o_rTempFileURL, const OUString& rDesiredExtension)
+{
+ OUString tempFileURL;
+ ::osl::FileBase::RC const err =
+ ::osl::FileBase::createTempFile(nullptr, nullptr, & tempFileURL);
+ if (::osl::FileBase::E_None != err)
+ {
+ SAL_WARN("avmedia", "cannot create temp file");
+ return false;
+ }
+
+ if (!rDesiredExtension.isEmpty())
+ {
+ OUString newTempFileURL = tempFileURL + rDesiredExtension;
+ if (osl::File::move(tempFileURL, newTempFileURL) != osl::FileBase::E_None)
+ {
+ SAL_WARN("avmedia", "Could not rename file '" << tempFileURL << "' to '" << newTempFileURL << "'");
+ return false;
+ }
+ tempFileURL = newTempFileURL;
+ }
+
+ try
+ {
+ ::ucbhelper::Content tempContent(tempFileURL,
+ uno::Reference<ucb::XCommandEnvironment>(),
+ comphelper::getProcessComponentContext());
+ tempContent.writeStream(xInStream, true); // copy stream to file
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("avmedia", "");
+ return false;
+ }
+ o_rTempFileURL = tempFileURL;
+ return true;
+}
+
+MediaTempFile::~MediaTempFile()
+{
+ ::osl::File::remove(m_TempFileURL);
+}
+
+} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/framework/mediaplayer.cxx b/avmedia/source/framework/mediaplayer.cxx
new file mode 100644
index 000000000..258f23ff4
--- /dev/null
+++ b/avmedia/source/framework/mediaplayer.cxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <avmedia/mediaplayer.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <mediamisc.hxx>
+#include <strings.hrc>
+#include <helpids.h>
+
+#include <svl/stritem.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+
+namespace avmedia
+{
+
+MediaPlayer::MediaPlayer( vcl::Window* _pParent, sal_uInt16 nId, SfxBindings* _pBindings, SfxChildWinInfo* pInfo ) :
+ SfxChildWindow( _pParent, nId )
+{
+ SetWindow( VclPtr<MediaFloater>::Create( _pBindings, this, _pParent ) );
+ static_cast< MediaFloater* >( GetWindow() )->Initialize( pInfo );
+};
+
+
+MediaPlayer::~MediaPlayer()
+{
+}
+
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( MediaPlayer, SID_AVMEDIA_PLAYER )
+
+
+MediaFloater::MediaFloater( SfxBindings* _pBindings, SfxChildWindow* pCW, vcl::Window* pParent ) :
+ SfxDockingWindow( _pBindings, pCW, pParent, WB_CLOSEABLE | WB_MOVEABLE | WB_SIZEABLE | WB_DOCKABLE ),
+ mpMediaWindow( new MediaWindow( this, true ) )
+{
+ const Size aSize( mpMediaWindow->getPreferredSize() );
+
+ SetPosSizePixel( Point( 0, 0 ), aSize );
+ SetMinOutputSizePixel( aSize );
+ SetText( AvmResId( AVMEDIA_STR_MEDIAPLAYER ) );
+ mpMediaWindow->show();
+}
+
+
+MediaFloater::~MediaFloater()
+{
+ disposeOnce();
+}
+
+void MediaFloater::dispose()
+{
+ if (IsFloatingMode())
+ {
+ Show(false, ShowFlags::NoFocusChange);
+ SetFloatingMode(false);
+ }
+ mpMediaWindow.reset();
+ SfxDockingWindow::dispose();
+}
+
+void MediaFloater::Resize()
+{
+ SfxDockingWindow::Resize();
+
+ if( mpMediaWindow )
+ mpMediaWindow->setPosSize( tools::Rectangle( Point(), GetOutputSizePixel() ) );
+}
+
+void MediaFloater::ToggleFloatingMode()
+{
+ ::avmedia::MediaItem aRestoreItem;
+
+ if (mpMediaWindow)
+ mpMediaWindow->updateMediaItem( aRestoreItem );
+ mpMediaWindow.reset();
+
+ SfxDockingWindow::ToggleFloatingMode();
+
+ if (isDisposed())
+ return;
+
+ mpMediaWindow.reset( new MediaWindow( this, true ) );
+
+ mpMediaWindow->setPosSize( tools::Rectangle( Point(), GetOutputSizePixel() ) );
+ mpMediaWindow->executeMediaItem( aRestoreItem );
+
+ vcl::Window* pWindow = mpMediaWindow->getWindow();
+
+ if( pWindow )
+ pWindow->SetHelpId( HID_AVMEDIA_PLAYERWINDOW );
+
+ mpMediaWindow->show();
+}
+
+
+void MediaFloater::setURL( const OUString& rURL, const OUString& rReferer, bool bPlayImmediately )
+{
+ if( mpMediaWindow )
+ {
+ mpMediaWindow->setURL( rURL, rReferer );
+
+ if( mpMediaWindow->isValid() && bPlayImmediately )
+ mpMediaWindow->start();
+ }
+}
+
+
+void MediaFloater::dispatchCurrentURL()
+{
+ SfxDispatcher* pDispatcher = GetBindings().GetDispatcher();
+
+ if( pDispatcher )
+ {
+ OUString url;
+ if (mpMediaWindow != nullptr) {
+ url = mpMediaWindow->getURL();
+ }
+ const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, url );
+ pDispatcher->ExecuteList(SID_INSERT_AVMEDIA, SfxCallMode::RECORD,
+ { &aMediaURLItem });
+ }
+}
+
+} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/framework/mediatoolbox.cxx b/avmedia/source/framework/mediatoolbox.cxx
new file mode 100644
index 000000000..0eac2eff0
--- /dev/null
+++ b/avmedia/source/framework/mediatoolbox.cxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <avmedia/mediatoolbox.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <mediacontrol.hxx>
+
+#include <tools/debug.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <vcl/toolbox.hxx>
+
+#include <comphelper/propertysequence.hxx>
+
+using namespace ::com::sun::star;
+
+namespace avmedia
+{
+
+class MediaToolBoxControl_Impl : public MediaControl
+{
+public:
+
+ MediaToolBoxControl_Impl( vcl::Window& rParent, MediaToolBoxControl& rControl );
+
+ void update() override;
+ void execute( const MediaItem& rItem ) override;
+
+private:
+
+ MediaToolBoxControl* mpToolBoxControl;
+};
+
+MediaToolBoxControl_Impl::MediaToolBoxControl_Impl( vcl::Window& rParent, MediaToolBoxControl& rControl ) :
+ MediaControl( &rParent, MEDIACONTROLSTYLE_SINGLELINE ),
+ mpToolBoxControl( &rControl )
+{
+ SetSizePixel(m_xContainer->get_preferred_size());
+}
+
+void MediaToolBoxControl_Impl::update()
+{
+ mpToolBoxControl->implUpdateMediaControl();
+}
+
+
+void MediaToolBoxControl_Impl::execute( const MediaItem& rItem )
+{
+ mpToolBoxControl->implExecuteMediaControl( rItem );
+}
+
+
+SFX_IMPL_TOOLBOX_CONTROL( ::avmedia::MediaToolBoxControl, ::avmedia::MediaItem );
+
+
+MediaToolBoxControl::MediaToolBoxControl( sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx ) :
+ SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.Invalidate();
+}
+
+
+MediaToolBoxControl::~MediaToolBoxControl()
+{
+}
+
+
+void MediaToolBoxControl::StateChanged( sal_uInt16, SfxItemState eState, const SfxPoolItem* pState )
+{
+ MediaToolBoxControl_Impl* pCtrl = static_cast< MediaToolBoxControl_Impl* >( GetToolBox().GetItemWindow( GetId() ) );
+
+ DBG_ASSERT( pCtrl, "MediaToolBoxControl::StateChanged: media control not found" );
+
+ if( eState == SfxItemState::DISABLED )
+ {
+ pCtrl->Enable( false, false );
+ pCtrl->SetText( OUString() );
+
+ const MediaItem aEmptyMediaItem( 0, AVMediaSetMask::ALL );
+ pCtrl->setState( aEmptyMediaItem );
+ }
+ else
+ {
+ pCtrl->Enable( true, false );
+
+ const MediaItem* pMediaItem = dynamic_cast<const MediaItem*>( pState );
+
+ if( pMediaItem && ( eState == SfxItemState::DEFAULT ) )
+ pCtrl->setState( *pMediaItem );
+ }
+}
+
+VclPtr<InterimItemWindow> MediaToolBoxControl::CreateItemWindow( vcl::Window *pParent )
+{
+ return ( pParent ? VclPtr<MediaToolBoxControl_Impl>::Create( *pParent, *this ) : nullptr );
+}
+
+void MediaToolBoxControl::implUpdateMediaControl()
+{
+ updateStatus( ".uno:AVMediaToolBox" );
+}
+
+void MediaToolBoxControl::implExecuteMediaControl( const MediaItem& rItem )
+{
+ MediaItem aExecItem( SID_AVMEDIA_TOOLBOX );
+ uno::Any aAny;
+
+ aExecItem.merge( rItem );
+ aExecItem.QueryValue( aAny );
+ auto aArgs(::comphelper::InitPropertySequence({
+ { "AVMediaToolBox", aAny }
+ }));
+
+ Dispatch( ".uno:AVMediaToolBox" , aArgs );
+}
+
+} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/framework/soundhandler.cxx b/avmedia/source/framework/soundhandler.cxx
new file mode 100644
index 000000000..cf341f722
--- /dev/null
+++ b/avmedia/source/framework/soundhandler.cxx
@@ -0,0 +1,323 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "soundhandler.hxx"
+
+#include <unotools/mediadescriptor.hxx>
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/frame/DispatchResultState.hpp>
+
+#include <avmedia/mediawindow.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+namespace avmedia{
+
+
+// XInterface, XTypeProvider, XServiceInfo
+
+
+void SAL_CALL SoundHandler::acquire() throw()
+{
+ /* Don't use mutex in methods of XInterface! */
+ OWeakObject::acquire();
+}
+
+void SAL_CALL SoundHandler::release() throw()
+{
+ /* Don't use mutex in methods of XInterface! */
+ OWeakObject::release();
+}
+
+css::uno::Any SAL_CALL SoundHandler::queryInterface( const css::uno::Type& aType )
+{
+ /* Attention: Don't use mutex or guard in this method!!! Is a method of XInterface. */
+ /* Ask for my own supported interfaces ...*/
+ css::uno::Any aReturn( ::cppu::queryInterface( aType,
+ static_cast< css::lang::XTypeProvider* >(this),
+ static_cast< css::lang::XServiceInfo* >(this),
+ static_cast< css::frame::XNotifyingDispatch* >(this),
+ static_cast< css::frame::XDispatch* >(this),
+ static_cast< css::document::XExtendedFilterDetection* >(this)));
+ /* If searched interface not supported by this class ... */
+ if ( !aReturn.hasValue() )
+ {
+ /* ... ask baseclass for interfaces! */
+ aReturn = OWeakObject::queryInterface( aType );
+ }
+ /* Return result of this search. */
+ return aReturn;
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL SoundHandler::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL SoundHandler::getTypes()
+{
+ static ::cppu::OTypeCollection aTypeCollection(
+ cppu::UnoType<css::lang::XTypeProvider>::get(),
+ cppu::UnoType<css::lang::XServiceInfo>::get(),
+ cppu::UnoType<css::frame::XNotifyingDispatch>::get(),
+ cppu::UnoType<css::frame::XDispatch>::get(),
+ cppu::UnoType<css::document::XExtendedFilterDetection>::get());
+
+ return aTypeCollection.getTypes();
+}
+
+#define IMPLEMENTATIONNAME_SOUNDHANDLER "com.sun.star.comp.framework.SoundHandler"
+
+/*===========================================================================================================*/
+/* XServiceInfo */
+/*===========================================================================================================*/
+OUString SAL_CALL SoundHandler::getImplementationName()
+{
+ return IMPLEMENTATIONNAME_SOUNDHANDLER;
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL SoundHandler::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+// XServiceInfo
+css::uno::Sequence< OUString > SAL_CALL SoundHandler::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ContentHandler" };
+}
+
+/*-************************************************************************************************************
+ @short standard ctor
+ @descr These initialize a new instance of this class with needed information for work.
+
+ @seealso using at owner
+
+ @param "xFactory", reference to service manager for creation of new services
+ @onerror Show an assertion and do nothing else.
+ @threadsafe yes
+*//*-*************************************************************************************************************/
+SoundHandler::SoundHandler()
+ // Init member
+ : m_bError ( false )
+ , m_aUpdateIdle ( "avmedia SoundHandler Update" )
+{
+ m_aUpdateIdle.SetInvokeHandler(LINK(this, SoundHandler, implts_PlayerNotify));
+}
+
+/*-************************************************************************************************************
+ @short standard dtor
+*//*-*************************************************************************************************************/
+SoundHandler::~SoundHandler()
+{
+ if (m_xListener.is())
+ {
+ css::frame::DispatchResultEvent aEvent;
+ aEvent.State = css::frame::DispatchResultState::FAILURE;
+ m_xListener->dispatchFinished(aEvent);
+ m_xListener.clear();
+ }
+}
+
+/*-************************************************************************************************************
+ @interface css::frame::XDispatch
+
+ @short try to load audio file
+ @descr This method try to load given audio file by URL and play it. We use vcl/Sound class to do that.
+ Playing of sound is asynchron every time.
+
+ @attention We must hold us alive by ourself ... because we use async. vcl sound player ... but playing is started
+ in async interface call "dispatch()" too. And caller forget us immediately. But then our uno ref count
+ will decreased to 0 and will die. The only solution is to use own reference to our implementation.
+ But we do it for really started jobs only and release it during call back of vcl.
+
+ @seealso class vcl/Sound
+ @seealso method implts_PlayerNotify()
+
+ @param "aURL" , URL to dispatch.
+ @param "lArguments", list of optional arguments.
+ @onerror We do nothing.
+ @threadsafe yes
+*//*-*************************************************************************************************************/
+void SAL_CALL SoundHandler::dispatchWithNotification(const css::util::URL& aURL ,
+ const css::uno::Sequence< css::beans::PropertyValue >& lDescriptor,
+ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
+{
+ // SAFE {
+ const ::osl::MutexGuard aLock( GetMutex() );
+
+ utl::MediaDescriptor aDescriptor(lDescriptor);
+
+ {
+ //close streams otherwise on windows we can't reopen the file in the
+ //media player when we pass the url to directx as it'll already be open
+ css::uno::Reference< css::io::XInputStream > xInputStream =
+ aDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_INPUTSTREAM(),
+ css::uno::Reference< css::io::XInputStream >());
+ if (xInputStream.is()) xInputStream->closeInput();
+ }
+
+ // If player currently used for other dispatch() requests ...
+ // cancel it by calling stop()!
+ m_aUpdateIdle.Stop();
+ if (m_xPlayer.is())
+ {
+ if (m_xPlayer->isPlaying())
+ m_xPlayer->stop();
+ m_xPlayer.clear();
+ }
+
+ // Try to initialize player.
+ m_xListener = xListener;
+ try
+ {
+ m_bError = false;
+ m_xPlayer.set( avmedia::MediaWindow::createPlayer( aURL.Complete, aDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString()) ), css::uno::UNO_SET_THROW );
+ // OK- we can start async playing ...
+ // Count this request and initialize self-holder against dying by uno ref count ...
+ m_xSelfHold.set(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ m_xPlayer->start();
+ m_aUpdateIdle.SetPriority( TaskPriority::HIGH_IDLE );
+ m_aUpdateIdle.Start();
+ }
+ catch( css::uno::Exception& )
+ {
+ m_bError = true;
+ m_xPlayer.clear();
+ }
+
+ // } SAFE
+}
+
+void SAL_CALL SoundHandler::dispatch( const css::util::URL& aURL ,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments )
+{
+ dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >());
+}
+
+/*-************************************************************************************************************
+ @interface css::document::XExtendedFilterDetection
+
+ @short try to detect file (given as argument included in "lDescriptor")
+ @descr We try to detect, if given file could be handled by this class and is a well known one.
+ If it is - we return right internal type name - otherwise we return nothing!
+ So call can search for another detect service and ask him too.
+
+ @attention a) We don't need any mutex here ... because we don't use any member!
+ b) Don't use internal player instance "m_pPlayer" to detect given sound file!
+ It's not necessary to do that ... and we can use temp. variable to do the same.
+ This way is easy - we don't must synchronize it with currently played sounds!
+ Another reason to do so ... We are a listener on our internal ma_Player object.
+ If you would call "IsSoundFile()" on this instance, he would call us back and
+ we make some unnecessary things ...
+ @param "lDescriptor", description of file to detect
+ @return Internal type name which match this file ... or nothing if it is unknown.
+
+ @onerror We return nothing.
+ @threadsafe yes
+*//*-*************************************************************************************************************/
+OUString SAL_CALL SoundHandler::detect( css::uno::Sequence< css::beans::PropertyValue >& lDescriptor )
+{
+ // Our default is "nothing". So we can return it, if detection failed or file type is really unknown.
+ OUString sTypeName;
+
+ // Analyze given descriptor to find filename or input stream or ...
+ utl::MediaDescriptor aDescriptor(lDescriptor);
+ OUString sURL = aDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL(), OUString());
+ OUString sReferer = aDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString());
+
+ if (
+ !sURL.isEmpty() &&
+ (avmedia::MediaWindow::isMediaURL(sURL, sReferer))
+ )
+ {
+ // If the file type is supported depends on the OS, so...
+ // I think we can the following ones:
+ // a) look for given extension of url to map our type decision HARD CODED!!!
+ // b) return preferred type every time... it's easy :-)
+ sTypeName = "wav_Wave_Audio_File";
+ aDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sTypeName;
+ aDescriptor >> lDescriptor;
+ }
+
+ // Return our decision.
+ return sTypeName;
+}
+
+/*-************************************************************************************************************
+ @short call back of sound player
+ @descr Our player call us back to give us some information.
+ We use this information to callback our might existing listener.
+
+ @seealso method dispatchWithNotification()
+ @return 0 every time... it doesn't matter for us.
+ @threadsafe yes
+*//*-*************************************************************************************************************/
+IMPL_LINK_NOARG(SoundHandler, implts_PlayerNotify, Timer *, void)
+{
+ // SAFE {
+ ::osl::ClearableMutexGuard aLock( GetMutex() );
+
+ if (m_xPlayer.is() && m_xPlayer->isPlaying() && m_xPlayer->getMediaTime() < m_xPlayer->getDuration())
+ {
+ m_aUpdateIdle.Start();
+ return;
+ }
+ m_xPlayer.clear();
+
+ // We use m_xSelfHold to let us die ... but we must live till real finishing of this method too!!!
+ // So we SHOULD use another "self-holder" temp. to provide that ...
+ css::uno::Reference< css::uno::XInterface > xOperationHold = m_xSelfHold;
+ m_xSelfHold.clear();
+
+ // notify might existing listener
+ // And forget this listener!
+ // Because the corresponding dispatch was finished.
+ if (m_xListener.is())
+ {
+ css::frame::DispatchResultEvent aEvent;
+ if (!m_bError)
+ aEvent.State = css::frame::DispatchResultState::SUCCESS;
+ else
+ aEvent.State = css::frame::DispatchResultState::FAILURE;
+ m_xListener->dispatchFinished(aEvent);
+ m_xListener.clear();
+ }
+
+ // } SAFE
+ //release aLock before end of method at which point xOperationHold goes out of scope and pThis dies
+ aLock.clear();
+}
+
+} // namespace framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_framework_SoundHandler_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new avmedia::SoundHandler);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/framework/soundhandler.hxx b/avmedia/source/framework/soundhandler.hxx
new file mode 100644
index 000000000..8a1dfde2e
--- /dev/null
+++ b/avmedia/source/framework/soundhandler.hxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/frame/XNotifyingDispatch.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/util/URL.hpp>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/weak.hxx>
+
+#include <vcl/timer.hxx>
+#include <vcl/idle.hxx>
+#include <tools/link.hxx>
+#include <toolkit/helper/mutexhelper.hxx>
+
+namespace avmedia{
+
+/*-************************************************************************************************************
+ @short handler to detect and play sounds ("wav" and "au" only!)
+ @descr Register this implementation as a content handler to detect and/or play wav- and au-sounds.
+ It doesn't depend from the target platform. But one instance of this class
+ can play one sound at the same time only. Means every new dispatch request will stop the
+ might still running one. So we support one operation/one URL/one listener at the same time
+ only.
+
+ @devstatus ready
+ @threadsafe yes
+*//*-*************************************************************************************************************/
+class SoundHandler : // interfaces
+ public css::lang::XTypeProvider
+ , public css::lang::XServiceInfo
+ , public css::frame::XNotifyingDispatch // => XDispatch
+ , public css::document::XExtendedFilterDetection
+ // baseclasses
+ // Order is necessary for right initialization!
+ , private MutexHelper
+ , public ::cppu::OWeakObject
+{
+ // public methods
+ public:
+
+ // constructor / destructor
+ SoundHandler();
+ virtual ~SoundHandler( ) override;
+
+ // XInterface, XTypeProvider, XServiceInfo
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() throw() override;
+ virtual void SAL_CALL release() throw() override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes () override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ /* interface XServiceInfo */
+ virtual OUString SAL_CALL getImplementationName ( ) override;
+ virtual sal_Bool SAL_CALL supportsService ( const OUString& sServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames ( ) override;
+
+ // XNotifyingDispatch
+ virtual void SAL_CALL dispatchWithNotification(const css::util::URL& aURL ,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
+ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch ( const css::util::URL& aURL ,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+ // not supported !
+ virtual void SAL_CALL addStatusListener ( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
+ const css::util::URL& /*aURL*/ ) override {};
+ virtual void SAL_CALL removeStatusListener ( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
+ const css::util::URL& /*aURL*/ ) override {};
+
+ // XExtendedFilterDetection
+ virtual OUString SAL_CALL detect ( css::uno::Sequence< css::beans::PropertyValue >& lDescriptor ) override;
+
+ // protected methods
+ protected:
+
+ // private methods
+ private:
+ DECL_LINK( implts_PlayerNotify, Timer*, void );
+
+ // variables
+ // (should be private everyway!)
+ private:
+
+ bool m_bError;
+ css::uno::Reference< css::uno::XInterface > m_xSelfHold ; // we must protect us against dying during async(!) dispatch() call!
+ css::uno::Reference< css::media::XPlayer > m_xPlayer ; // uses avmedia player to play sounds...
+
+ css::uno::Reference< css::frame::XDispatchResultListener > m_xListener ;
+ Idle m_aUpdateIdle;
+
+}; // class SoundHandler
+
+} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/avmediagstreamer.component b/avmedia/source/gstreamer/avmediagstreamer.component
new file mode 100644
index 000000000..252ac8990
--- /dev/null
+++ b/avmedia/source/gstreamer/avmediagstreamer.component
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+-->
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ prefix="avmediagst" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.media.Manager_GStreamer">
+ <service name="com.sun.star.comp.avmedia.Manager_GStreamer"/>
+ </implementation>
+</component>
diff --git a/avmedia/source/gstreamer/gstcommon.hxx b/avmedia/source/gstreamer/gstcommon.hxx
new file mode 100644
index 000000000..0e27907fb
--- /dev/null
+++ b/avmedia/source/gstreamer/gstcommon.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <gst/gst.h>
+
+#include <osl/mutex.hxx>
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/factory.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/media/XManager.hpp>
+
+#define WM_GRAPHNOTIFY (WM_USER + 567)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstframegrabber.cxx b/avmedia/source/gstreamer/gstframegrabber.cxx
new file mode 100644
index 000000000..7da1917a0
--- /dev/null
+++ b/avmedia/source/gstreamer/gstframegrabber.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "gstframegrabber.hxx"
+#include "gstplayer.hxx"
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include <gst/gstbuffer.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideosink.h>
+#include <o3tl/safeint.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/BitmapTools.hxx>
+
+#include <string>
+
+#define AVMEDIA_GST_FRAMEGRABBER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.FrameGrabber_GStreamer"
+#define AVMEDIA_GST_FRAMEGRABBER_SERVICENAME "com.sun.star.media.FrameGrabber_GStreamer"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::gstreamer {
+
+void FrameGrabber::disposePipeline()
+{
+ if( mpPipeline != nullptr )
+ {
+ gst_element_set_state( mpPipeline, GST_STATE_NULL );
+ g_object_unref( G_OBJECT( mpPipeline ) );
+ mpPipeline = nullptr;
+ }
+}
+
+FrameGrabber::FrameGrabber( const OUString &rURL ) :
+ FrameGrabber_BASE()
+{
+ gchar *pPipelineStr;
+ pPipelineStr = g_strdup_printf(
+ "uridecodebin uri=%s ! videoconvert ! videoscale ! appsink "
+ "name=sink caps=\"video/x-raw,format=RGB,pixel-aspect-ratio=1/1\"",
+ OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ GError *pError = nullptr;
+ mpPipeline = gst_parse_launch( pPipelineStr, &pError );
+ if( pError != nullptr) {
+ g_warning( "Failed to construct frame-grabber pipeline '%s'\n", pError->message );
+ g_error_free( pError );
+ disposePipeline();
+ }
+
+ if( mpPipeline ) {
+ // pre-roll
+ switch( gst_element_set_state( mpPipeline, GST_STATE_PAUSED ) ) {
+ case GST_STATE_CHANGE_FAILURE:
+ case GST_STATE_CHANGE_NO_PREROLL:
+ g_warning( "failure pre-rolling media" );
+ disposePipeline();
+ break;
+ default:
+ break;
+ }
+ }
+ if( mpPipeline &&
+ gst_element_get_state( mpPipeline, nullptr, nullptr, 5 * GST_SECOND ) == GST_STATE_CHANGE_FAILURE )
+ disposePipeline();
+}
+
+FrameGrabber::~FrameGrabber()
+{
+ disposePipeline();
+}
+
+FrameGrabber* FrameGrabber::create( const OUString &rURL )
+{
+ return new FrameGrabber( rURL );
+}
+
+uno::Reference< graphic::XGraphic > SAL_CALL FrameGrabber::grabFrame( double fMediaTime )
+{
+ uno::Reference< graphic::XGraphic > xRet;
+
+ if( !mpPipeline )
+ return xRet;
+
+ gint64 gst_position = llround( fMediaTime * GST_SECOND );
+ gst_element_seek_simple(
+ mpPipeline, GST_FORMAT_TIME,
+ GstSeekFlags(GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH),
+ gst_position );
+
+ GstElement *pSink = gst_bin_get_by_name( GST_BIN( mpPipeline ), "sink" );
+ if( !pSink )
+ return xRet;
+
+ GstBuffer *pBuf = nullptr;
+ GstCaps *pCaps = nullptr;
+
+ // synchronously fetch the frame
+ GstSample *pSample = nullptr;
+ g_signal_emit_by_name( pSink, "pull-preroll", &pSample, nullptr );
+
+ if( pSample )
+ {
+ pBuf = gst_sample_get_buffer( pSample );
+ pCaps = gst_sample_get_caps( pSample );
+ }
+
+ // get geometry
+ int nWidth = 0, nHeight = 0;
+ if( !pCaps )
+ g_warning( "could not get snapshot format\n" );
+ else
+ {
+ GstStructure *pStruct = gst_caps_get_structure( pCaps, 0 );
+
+ /* we need to get the final caps on the buffer to get the size */
+ if( !gst_structure_get_int( pStruct, "width", &nWidth ) ||
+ !gst_structure_get_int( pStruct, "height", &nHeight ) )
+ nWidth = nHeight = 0;
+ }
+
+ if( pBuf && nWidth > 0 && nHeight > 0 &&
+ // sanity check the size
+ gst_buffer_get_size( pBuf ) >= o3tl::make_unsigned( nWidth * nHeight * 3 )
+ )
+ {
+ sal_uInt8 *pData = nullptr;
+ GstMapInfo aMapInfo;
+ gst_buffer_map( pBuf, &aMapInfo, GST_MAP_READ );
+ pData = aMapInfo.data;
+
+ int nStride = GST_ROUND_UP_4( nWidth * 3 );
+ BitmapEx aBmp = vcl::bitmap::CreateFromData(pData, nWidth, nHeight, nStride, 24 );
+
+ gst_buffer_unmap( pBuf, &aMapInfo );
+ xRet = Graphic( aBmp ).GetXGraphic();
+ }
+
+ return xRet;
+}
+
+OUString SAL_CALL FrameGrabber::getImplementationName( )
+{
+ return AVMEDIA_GST_FRAMEGRABBER_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL FrameGrabber::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL FrameGrabber::getSupportedServiceNames()
+{
+ return { AVMEDIA_GST_FRAMEGRABBER_SERVICENAME };
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstframegrabber.hxx b/avmedia/source/gstreamer/gstframegrabber.hxx
new file mode 100644
index 000000000..03c4af65f
--- /dev/null
+++ b/avmedia/source/gstreamer/gstframegrabber.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "gstplayer.hxx"
+#include <com/sun/star/media/XFrameGrabber.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace avmedia::gstreamer {
+
+typedef ::cppu::WeakImplHelper< css::media::XFrameGrabber,
+ css::lang::XServiceInfo > FrameGrabber_BASE;
+
+
+class FrameGrabber : public FrameGrabber_BASE
+{
+ GstElement *mpPipeline;
+ void disposePipeline();
+public:
+ // noncopyable
+ FrameGrabber(const FrameGrabber&) = delete;
+ const FrameGrabber& operator=(const FrameGrabber&) =delete;
+
+ // static create method instead of public Ctor
+ static FrameGrabber* create( const OUString &rURL );
+
+ virtual ~FrameGrabber() override;
+
+ // XFrameGrabber
+ virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL grabFrame( double fMediaTime ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ explicit FrameGrabber( const OUString &aURL );
+};
+
+} // avmedia::gst
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstmanager.cxx b/avmedia/source/gstreamer/gstmanager.cxx
new file mode 100644
index 000000000..2b107e5c2
--- /dev/null
+++ b/avmedia/source/gstreamer/gstmanager.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include "gstmanager.hxx"
+#include "gstplayer.hxx"
+
+#include <tools/urlobj.hxx>
+
+#define AVMEDIA_GST_MANAGER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Manager_GStreamer"
+#define AVMEDIA_GST_MANAGER_SERVICENAME "com.sun.star.media.Manager"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::gstreamer {
+
+Manager::Manager()
+{
+}
+
+Manager::~Manager()
+{
+}
+
+uno::Reference< media::XPlayer > SAL_CALL Manager::createPlayer( const OUString& rURL )
+{
+ Player* pPlayer( new Player );
+ uno::Reference< media::XPlayer > xRet( pPlayer );
+ const INetURLObject aURL( rURL );
+
+ if( !pPlayer->create( aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ) )
+ xRet.clear();
+
+ return xRet;
+}
+
+OUString SAL_CALL Manager::getImplementationName( )
+{
+ return AVMEDIA_GST_MANAGER_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL Manager::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL Manager::getSupportedServiceNames( )
+{
+ return { AVMEDIA_GST_MANAGER_SERVICENAME };
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstmanager.hxx b/avmedia/source/gstreamer/gstmanager.hxx
new file mode 100644
index 000000000..21a5245dd
--- /dev/null
+++ b/avmedia/source/gstreamer/gstmanager.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "gstcommon.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/media/XManager.hpp>
+
+namespace avmedia::gstreamer {
+
+class Manager : public ::cppu::WeakImplHelper< css::media::XManager,
+ css::lang::XServiceInfo >
+{
+public:
+
+ explicit Manager();
+ virtual ~Manager() override;
+
+ // XManager
+ virtual css::uno::Reference< css::media::XPlayer > SAL_CALL createPlayer( const OUString& aURL ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+} // namespace avmedia::gstreamer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstplayer.cxx b/avmedia/source/gstreamer/gstplayer.cxx
new file mode 100644
index 000000000..9511be54b
--- /dev/null
+++ b/avmedia/source/gstreamer/gstplayer.cxx
@@ -0,0 +1,929 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstring>
+#include <map>
+#include <set>
+#include <vector>
+#include <math.h>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <sal/log.hxx>
+#include <rtl/string.hxx>
+#include <salhelper/thread.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/syschild.hxx>
+#include <vcl/sysdata.hxx>
+
+#include "gstplayer.hxx"
+#include "gstframegrabber.hxx"
+#include "gstwindow.hxx"
+
+#include <gst/video/videooverlay.h>
+#define AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_GStreamer"
+#define AVMEDIA_GST_PLAYER_SERVICENAME "com.sun.star.media.Player_GStreamer"
+
+#include <gst/pbutils/missing-plugins.h>
+#include <gst/pbutils/pbutils.h>
+
+#define AVVERSION "gst 1.0: "
+
+using namespace ::com::sun::star;
+
+namespace avmedia::gstreamer {
+
+namespace {
+
+class FlagGuard {
+public:
+ explicit FlagGuard(bool & flag): flag_(flag) { flag_ = true; }
+
+ ~FlagGuard() { flag_ = false; }
+
+private:
+ bool & flag_;
+};
+
+class MissingPluginInstallerThread: public salhelper::Thread {
+public:
+ MissingPluginInstallerThread(): Thread("MissingPluginInstaller") {}
+
+private:
+ void execute() override;
+};
+
+
+class MissingPluginInstaller {
+ friend class MissingPluginInstallerThread;
+
+public:
+ MissingPluginInstaller(): launchNewThread_(true), inCleanUp_(false) {}
+
+ ~MissingPluginInstaller();
+
+ void report(rtl::Reference<Player> const & source, GstMessage * message);
+
+ // Player::~Player calls Player::disposing calls
+ // MissingPluginInstaller::detach, so do not take Player by rtl::Reference
+ // here (which would bump its refcount back from 0 to 1):
+ void detach(Player const * source);
+
+private:
+ void processQueue();
+
+ DECL_STATIC_LINK(MissingPluginInstaller, launchUi, void*, void);
+
+ osl::Mutex mutex_;
+ std::set<OString> reported_;
+ std::map<OString, std::set<rtl::Reference<Player>>> queued_;
+ rtl::Reference<MissingPluginInstallerThread> currentThread_;
+ std::vector<OString> currentDetails_;
+ std::set<rtl::Reference<Player>> currentSources_;
+ bool launchNewThread_;
+ bool inCleanUp_;
+};
+
+
+MissingPluginInstaller::~MissingPluginInstaller() {
+ osl::MutexGuard g(mutex_);
+ SAL_WARN_IF(currentThread_.is(), "avmedia.gstreamer", "unjoined thread");
+ inCleanUp_ = true;
+}
+
+
+void MissingPluginInstaller::report(
+ rtl::Reference<Player> const & source, GstMessage * message)
+{
+ // assert(gst_is_missing_plugin_message(message));
+ gchar * det = gst_missing_plugin_message_get_installer_detail(message);
+ if (det == nullptr) {
+ SAL_WARN(
+ "avmedia.gstreamer",
+ "gst_missing_plugin_message_get_installer_detail failed");
+ return;
+ }
+ std::size_t len = std::strlen(det);
+ if (len > SAL_MAX_INT32) {
+ SAL_WARN("avmedia.gstreamer", "detail string too long");
+ g_free(det);
+ return;
+ }
+ OString detStr(det, len);
+ g_free(det);
+ rtl::Reference<MissingPluginInstallerThread> join;
+ rtl::Reference<MissingPluginInstallerThread> launch;
+ {
+ osl::MutexGuard g(mutex_);
+ if (reported_.find(detStr) != reported_.end()) {
+ return;
+ }
+ auto & i = queued_[detStr];
+ bool fresh = i.empty();
+ i.insert(source);
+ if (!(fresh && launchNewThread_)) {
+ return;
+ }
+ join = currentThread_;
+ currentThread_ = new MissingPluginInstallerThread;
+ {
+ FlagGuard f(inCleanUp_);
+ currentSources_.clear();
+ }
+ processQueue();
+ launchNewThread_ = false;
+ launch = currentThread_;
+ }
+ if (join.is()) {
+ join->join();
+ }
+ launch->acquire();
+ Application::PostUserEvent(
+ LINK(this, MissingPluginInstaller, launchUi), launch.get());
+}
+
+
+void eraseSource(std::set<rtl::Reference<Player>> & set, Player const * source)
+{
+ auto i = std::find_if(
+ set.begin(), set.end(),
+ [source](rtl::Reference<Player> const & el) {
+ return el.get() == source;
+ });
+ if (i != set.end()) {
+ set.erase(i);
+ }
+}
+
+
+void MissingPluginInstaller::detach(Player const * source) {
+ rtl::Reference<MissingPluginInstallerThread> join;
+ {
+ osl::MutexGuard g(mutex_);
+ if (inCleanUp_) {
+ // Guard against ~MissingPluginInstaller with erroneously un-joined
+ // currentThread_ (thus non-empty currentSources_) calling
+ // destructor of currentSources_, calling ~Player, calling here,
+ // which would use currentSources_ while it is already being
+ // destroyed:
+ return;
+ }
+ for (auto i = queued_.begin(); i != queued_.end();) {
+ eraseSource(i->second, source);
+ if (i->second.empty()) {
+ i = queued_.erase(i);
+ } else {
+ ++i;
+ }
+ }
+ if (currentThread_.is()) {
+ assert(!currentSources_.empty());
+ eraseSource(currentSources_, source);
+ if (currentSources_.empty()) {
+ join = currentThread_;
+ currentThread_.clear();
+ launchNewThread_ = true;
+ }
+ }
+ }
+ if (join.is()) {
+ // missing cancellability of gst_install_plugins_sync
+ join->join();
+ }
+}
+
+
+void MissingPluginInstaller::processQueue() {
+ assert(!queued_.empty());
+ assert(currentDetails_.empty());
+ for (const auto& rEntry : queued_) {
+ reported_.insert(rEntry.first);
+ currentDetails_.push_back(rEntry.first);
+ currentSources_.insert(rEntry.second.begin(), rEntry.second.end());
+ }
+ queued_.clear();
+}
+
+
+IMPL_STATIC_LINK(MissingPluginInstaller, launchUi, void *, p, void)
+{
+ MissingPluginInstallerThread* thread = static_cast<MissingPluginInstallerThread*>(p);
+ rtl::Reference<MissingPluginInstallerThread> ref(thread, SAL_NO_ACQUIRE);
+ gst_pb_utils_init();
+ // not thread safe; hopefully fine to consistently call from our event
+ // loop (which is the only reason to have this
+ // Application::PostUserEvent diversion, in case
+ // MissingPluginInstaller::report might be called from outside our event
+ // loop), and hopefully fine to call gst_is_missing_plugin_message and
+ // gst_missing_plugin_message_get_installer_detail before calling
+ // gst_pb_utils_init
+ ref->launch();
+}
+
+
+struct TheMissingPluginInstaller:
+ public rtl::Static<MissingPluginInstaller, TheMissingPluginInstaller>
+{};
+
+
+void MissingPluginInstallerThread::execute() {
+ MissingPluginInstaller & inst = TheMissingPluginInstaller::get();
+ for (;;) {
+ std::vector<OString> details;
+ {
+ osl::MutexGuard g(inst.mutex_);
+ assert(!inst.currentDetails_.empty());
+ details.swap(inst.currentDetails_);
+ }
+ std::vector<char *> args;
+ args.reserve(details.size());
+ for (auto const& i : details)
+ {
+ args.push_back(const_cast<char *>(i.getStr()));
+ }
+ args.push_back(nullptr);
+ gst_install_plugins_sync(args.data(), nullptr);
+ {
+ osl::MutexGuard g(inst.mutex_);
+ if (inst.queued_.empty() || inst.launchNewThread_) {
+ inst.launchNewThread_ = true;
+ break;
+ }
+ inst.processQueue();
+ }
+ }
+}
+
+} // end anonymous namespace
+
+
+Player::Player() :
+ GstPlayer_BASE( m_aMutex ),
+ mpPlaybin( nullptr ),
+ mpVolumeControl( nullptr ),
+ mbUseGtkSink( false ),
+ mbFakeVideo (false ),
+ mnUnmutedVolume( 0 ),
+ mbPlayPending ( false ),
+ mbMuted( false ),
+ mbLooping( false ),
+ mbInitialized( false ),
+ mpDisplay( nullptr ),
+ mnWindowID( 0 ),
+ mpXOverlay( nullptr ),
+ mnDuration( 0 ),
+ mnWidth( 0 ),
+ mnHeight( 0 ),
+ mnWatchID( 0 ),
+ mbWatchID( false )
+{
+ // Initialize GStreamer library
+ int argc = 1;
+ char name[] = "libreoffice";
+ char *arguments[] = { name };
+ char** argv = arguments;
+ GError* pError = nullptr;
+
+ mbInitialized = gst_init_check( &argc, &argv, &pError );
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " Player::Player" );
+
+ if (pError != nullptr)
+ {
+ // TODO: throw an exception?
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " Player::Player error '" << pError->message << "'" );
+ g_error_free (pError);
+ }
+}
+
+
+Player::~Player()
+{
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " Player::~Player" );
+ if( mbInitialized )
+ disposing();
+}
+
+
+void SAL_CALL Player::disposing()
+{
+ TheMissingPluginInstaller::get().detach(this);
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ stop();
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " Player::disposing" );
+
+ // Release the elements and pipeline
+ if( mbInitialized )
+ {
+ if( mpPlaybin )
+ {
+ gst_element_set_state( mpPlaybin, GST_STATE_NULL );
+ g_object_unref( G_OBJECT( mpPlaybin ) );
+
+ mpPlaybin = nullptr;
+ mpVolumeControl = nullptr;
+ }
+
+ if( mpXOverlay ) {
+ g_object_unref( G_OBJECT ( mpXOverlay ) );
+ mpXOverlay = nullptr;
+ }
+
+ }
+ if (mbWatchID)
+ {
+ g_source_remove(mnWatchID);
+ mbWatchID = false;
+ }
+}
+
+
+static gboolean pipeline_bus_callback( GstBus *, GstMessage *message, gpointer data )
+{
+ Player* pPlayer = static_cast<Player*>(data);
+
+ pPlayer->processMessage( message );
+
+ return true;
+}
+
+
+static GstBusSyncReply pipeline_bus_sync_handler( GstBus *, GstMessage * message, gpointer data )
+{
+ Player* pPlayer = static_cast<Player*>(data);
+
+ return pPlayer->processSyncMessage( message );
+}
+
+
+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;
+
+ gst_message_parse_state_changed (message, nullptr, &newstate, &pendingstate);
+
+ if (!mbUseGtkSink && newstate == GST_STATE_PAUSED &&
+ pendingstate == GST_STATE_VOID_PENDING && mpXOverlay)
+ {
+ gst_video_overlay_expose(mpXOverlay);
+ }
+
+ if (mbPlayPending)
+ mbPlayPending = ((newstate == GST_STATE_READY) || (newstate == GST_STATE_PAUSED));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+#define LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE "GstWaylandDisplayHandleContextType"
+
+static bool lcl_is_wayland_display_handle_need_context_message(GstMessage* msg)
+{
+ g_return_val_if_fail(GST_IS_MESSAGE(msg), false);
+
+ if (GST_MESSAGE_TYPE(msg) != GST_MESSAGE_NEED_CONTEXT)
+ return false;
+ const gchar *type = nullptr;
+ if (!gst_message_parse_context_type(msg, &type))
+ return false;
+ return !g_strcmp0(type, LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
+}
+
+static GstContext* lcl_wayland_display_handle_context_new(void* display)
+{
+ GstContext *context = gst_context_new(LCL_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE, true);
+ gst_structure_set (gst_context_writable_structure (context),
+ "handle", G_TYPE_POINTER, display, nullptr);
+ return context;
+}
+
+GstBusSyncReply Player::processSyncMessage( GstMessage *message )
+{
+#if OSL_DEBUG_LEVEL > 0
+ if ( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR )
+ {
+ GError* error;
+ gchar* error_debug;
+
+ gst_message_parse_error( message, &error, &error_debug );
+ SAL_WARN(
+ "avmedia.gstreamer",
+ "error: '" << error->message << "' debug: '"
+ << error_debug << "'");
+ }
+#endif
+
+ if (!mbUseGtkSink)
+ {
+ if (gst_is_video_overlay_prepare_window_handle_message (message) )
+ {
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " processSyncMessage prepare window id: " <<
+ GST_MESSAGE_TYPE_NAME( message ) << " " << static_cast<int>(mnWindowID) );
+ if( mpXOverlay )
+ g_object_unref( G_OBJECT ( mpXOverlay ) );
+ g_object_set( GST_MESSAGE_SRC( message ), "force-aspect-ratio", FALSE, nullptr );
+ mpXOverlay = GST_VIDEO_OVERLAY( GST_MESSAGE_SRC( message ) );
+ g_object_ref( G_OBJECT ( mpXOverlay ) );
+ if ( mnWindowID != 0 )
+ {
+ gst_video_overlay_set_window_handle( mpXOverlay, mnWindowID );
+ gst_video_overlay_handle_events(mpXOverlay, 0); // Let the parent window handle events.
+ if (maArea.Width > 0 && maArea.Height > 0)
+ gst_video_overlay_set_render_rectangle(mpXOverlay, maArea.X, maArea.Y, maArea.Width, maArea.Height);
+ }
+
+ return GST_BUS_DROP;
+ }
+ else if (lcl_is_wayland_display_handle_need_context_message(message))
+ {
+ GstContext *context = lcl_wayland_display_handle_context_new(mpDisplay);
+ gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context);
+
+ return GST_BUS_DROP;
+ }
+ }
+
+ if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ASYNC_DONE ) {
+ if( mnDuration == 0) {
+ gint64 gst_duration = 0;
+ if( gst_element_query_duration( mpPlaybin, GST_FORMAT_TIME, &gst_duration) )
+ mnDuration = gst_duration;
+ }
+ if( mnWidth == 0 ) {
+ GstPad *pad = nullptr;
+
+ g_signal_emit_by_name( mpPlaybin, "get-video-pad", 0, &pad );
+
+ if( pad ) {
+ int w = 0, h = 0;
+
+ GstCaps *caps = gst_pad_get_current_caps( pad );
+
+ if( gst_structure_get( gst_caps_get_structure( caps, 0 ),
+ "width", G_TYPE_INT, &w,
+ "height", G_TYPE_INT, &h,
+ nullptr ) ) {
+ mnWidth = w;
+ mnHeight = h;
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "queried size: " << mnWidth << "x" << mnHeight );
+
+ }
+ gst_caps_unref( caps );
+ g_object_unref( pad );
+ }
+
+ maSizeCondition.set();
+ }
+ } else if (gst_is_missing_plugin_message(message)) {
+ TheMissingPluginInstaller::get().report(this, message);
+ if( mnWidth == 0 ) {
+ // an error occurred, set condition so that OOo thread doesn't wait for us
+ maSizeCondition.set();
+ }
+ } 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
+ maSizeCondition.set();
+ }
+ }
+
+ return GST_BUS_PASS;
+}
+
+void Player::preparePlaybin( const OUString& rURL, GstElement *pSink )
+{
+ if (mpPlaybin != nullptr)
+ {
+ gst_element_set_state( mpPlaybin, GST_STATE_NULL );
+ mbPlayPending = false;
+ g_object_unref( mpPlaybin );
+ }
+
+ mpPlaybin = gst_element_factory_make( "playbin", nullptr );
+
+ //tdf#96989 on systems with flat-volumes setting the volume directly on the
+ //playbin to 100% results in setting the global volume to 100% of the
+ //maximum. We expect to set as % of the current volume.
+ mpVolumeControl = gst_element_factory_make( "volume", nullptr );
+ GstElement *pAudioSink = gst_element_factory_make( "autoaudiosink", nullptr );
+ GstElement* pAudioOutput = gst_bin_new("audio-output-bin");
+ assert(pAudioOutput);
+ if (pAudioSink)
+ gst_bin_add(GST_BIN(pAudioOutput), pAudioSink);
+ if (mpVolumeControl)
+ {
+ gst_bin_add(GST_BIN(pAudioOutput), mpVolumeControl);
+ if (pAudioSink)
+ gst_element_link(mpVolumeControl, pAudioSink);
+ GstPad *pPad = gst_element_get_static_pad(mpVolumeControl, "sink");
+ gst_element_add_pad(GST_ELEMENT(pAudioOutput), gst_ghost_pad_new("sink", pPad));
+ gst_object_unref(GST_OBJECT(pPad));
+ }
+ g_object_set(G_OBJECT(mpPlaybin), "audio-sink", pAudioOutput, nullptr);
+
+ if( pSink != nullptr ) // used for getting preferred size etc.
+ {
+ g_object_set( G_OBJECT( mpPlaybin ), "video-sink", pSink, nullptr );
+ mbFakeVideo = true;
+ }
+ else
+ mbFakeVideo = false;
+
+ OString ascURL = OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 );
+ g_object_set( G_OBJECT( mpPlaybin ), "uri", ascURL.getStr() , nullptr );
+
+ GstBus *pBus = gst_element_get_bus( mpPlaybin );
+ if (mbWatchID)
+ {
+ g_source_remove(mnWatchID);
+ mbWatchID = false;
+ }
+ mnWatchID = gst_bus_add_watch( pBus, pipeline_bus_callback, this );
+ mbWatchID = true;
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " set sync handler" );
+ gst_bus_set_sync_handler( pBus, pipeline_bus_sync_handler, this, nullptr );
+ g_object_unref( pBus );
+}
+
+
+bool Player::create( const OUString& rURL )
+{
+ bool bRet = false;
+
+ // create all the elements and link them
+
+ SAL_INFO( "avmedia.gstreamer", "create player, URL: '" << rURL << "'" );
+
+ if( mbInitialized && !rURL.isEmpty() )
+ {
+ // fakesink for pre-roll & sizing ...
+ preparePlaybin( rURL, gst_element_factory_make( "fakesink", nullptr ) );
+
+ gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
+ mbPlayPending = false;
+
+ bRet = true;
+ }
+
+ if( bRet )
+ maURL = rURL;
+ else
+ maURL.clear();
+
+ return bRet;
+}
+
+
+void SAL_CALL Player::start()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // set the pipeline state to READY and run the loop
+ if( mbInitialized && mpPlaybin != nullptr )
+ {
+ gst_element_set_state( mpPlaybin, GST_STATE_PLAYING );
+ mbPlayPending = true;
+ }
+}
+
+
+void SAL_CALL Player::stop()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // set the pipeline in PAUSED STATE
+ if( mpPlaybin )
+ gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
+
+ mbPlayPending = false;
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "stop " << mpPlaybin );
+}
+
+
+sal_Bool SAL_CALL Player::isPlaying()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ bool bRet = mbPlayPending;
+
+ // return whether the pipeline is in PLAYING STATE or not
+ if( !mbPlayPending && mbInitialized && mpPlaybin )
+ {
+ bRet = GST_STATE( mpPlaybin ) == GST_STATE_PLAYING;
+ }
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "isPlaying " << bRet );
+
+ return bRet;
+}
+
+
+double SAL_CALL Player::getDuration()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // slideshow checks for non-zero duration, so cheat here
+ double duration = 0.3;
+
+ if( mpPlaybin && mnDuration > 0 ) {
+ duration = mnDuration / GST_SECOND;
+ }
+
+ return duration;
+}
+
+
+void SAL_CALL Player::setMediaTime( double fTime )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if( !mpPlaybin )
+ return;
+
+ gint64 gst_position = llround (fTime * GST_SECOND);
+
+ 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 );
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "seek to: " << gst_position << " ns original: " << fTime << " s" );
+}
+
+
+double SAL_CALL Player::getMediaTime()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ double position = 0.0;
+
+ if( mpPlaybin ) {
+ // get current position in the stream
+ gint64 gst_position;
+ if( gst_element_query_position( mpPlaybin, GST_FORMAT_TIME, &gst_position ) )
+ position = gst_position / GST_SECOND;
+ }
+
+ return position;
+}
+
+
+void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ // TODO check how to do with GST
+ mbLooping = bSet;
+}
+
+
+sal_Bool SAL_CALL Player::isPlaybackLoop()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ // TODO check how to do with GST
+ return mbLooping;
+}
+
+
+void SAL_CALL Player::setMute( sal_Bool bSet )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "set mute: " << bSet << " muted: " << mbMuted << " unmuted volume: " << mnUnmutedVolume );
+
+ // change the volume to 0 or the unmuted volume
+ if (mpVolumeControl && mbMuted != bool(bSet))
+ {
+ double nVolume = mnUnmutedVolume;
+ if( bSet )
+ {
+ nVolume = 0.0;
+ }
+
+ g_object_set( G_OBJECT( mpVolumeControl ), "volume", nVolume, nullptr );
+
+ mbMuted = bSet;
+ }
+}
+
+
+sal_Bool SAL_CALL Player::isMute()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ return mbMuted;
+}
+
+
+void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ mnUnmutedVolume = pow( 10.0, nVolumeDB / 20.0 );
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "set volume: " << nVolumeDB << " gst volume: " << mnUnmutedVolume );
+
+ // change volume
+ if (mpVolumeControl && !mbMuted)
+ {
+ g_object_set( G_OBJECT( mpVolumeControl ), "volume", mnUnmutedVolume, nullptr );
+ }
+}
+
+
+sal_Int16 SAL_CALL Player::getVolumeDB()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ sal_Int16 nVolumeDB(0);
+
+ if (mpVolumeControl)
+ {
+ double nGstVolume = 0.0;
+
+ g_object_get( G_OBJECT( mpVolumeControl ), "volume", &nGstVolume, nullptr );
+
+ nVolumeDB = static_cast<sal_Int16>( 20.0*log10 ( nGstVolume ) );
+ }
+
+ return nVolumeDB;
+}
+
+
+awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ awt::Size aSize( 0, 0 );
+
+ if( maURL.isEmpty() )
+ {
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " Player::getPreferredPlayerWindowSize - empty URL => 0x0" );
+ return aSize;
+ }
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " pre-Player::getPreferredPlayerWindowSize, member " << mnWidth << "x" << mnHeight );
+
+ osl::Condition::Result aResult = maSizeCondition.wait( std::chrono::seconds(10) );
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION << this << " Player::getPreferredPlayerWindowSize after waitCondition " << aResult << ", member " << mnWidth << "x" << mnHeight );
+
+ if( mnWidth != 0 && mnHeight != 0 ) {
+ aSize.Width = mnWidth;
+ aSize.Height = mnHeight;
+ }
+
+ return aSize;
+}
+
+uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& rArguments )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ uno::Reference< ::media::XPlayerWindow > xRet;
+
+ if (rArguments.getLength() > 1)
+ rArguments[1] >>= maArea;
+
+ awt::Size aSize = getPreferredPlayerWindowSize();
+
+ if( mbFakeVideo )
+ preparePlaybin( maURL, nullptr );
+
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "Player::createPlayerWindow " << aSize.Width << "x" << aSize.Height << " length: " << rArguments.getLength() );
+
+ if( aSize.Width > 0 && aSize.Height > 0 )
+ {
+ if (rArguments.getLength() <= 2)
+ {
+ xRet = new ::avmedia::gstreamer::Window;
+ return xRet;
+ }
+
+ sal_IntPtr pIntPtr = 0;
+ rArguments[ 2 ] >>= pIntPtr;
+ SystemChildWindow *pParentWindow = reinterpret_cast< SystemChildWindow* >( pIntPtr );
+ if (!pParentWindow)
+ return nullptr;
+
+ const SystemEnvData* pEnvData = pParentWindow->GetSystemData();
+ if (!pEnvData)
+ return nullptr;
+
+ // tdf#124027: the position of embedded window is identical w/ the position
+ // of media object in all other vclplugs (kf5, gen), in gtk3 w/o gtksink it
+ // needs to be translated
+ if (pEnvData->toolkit == SystemEnvData::Toolkit::Gtk3)
+ {
+ Point aPoint = pParentWindow->GetPosPixel();
+ maArea.X = aPoint.getX();
+ maArea.Y = aPoint.getY();
+ }
+
+ mbUseGtkSink = false;
+
+ GstElement *pVideosink = static_cast<GstElement*>(pParentWindow->CreateGStreamerSink());
+ if (pVideosink)
+ {
+ if (pEnvData->toolkit == SystemEnvData::Toolkit::Gtk3)
+ mbUseGtkSink = true;
+ }
+ else
+ {
+ if (pEnvData->platform == SystemEnvData::Platform::Wayland)
+ pVideosink = gst_element_factory_make("waylandsink", "video-output");
+ else
+ pVideosink = gst_element_factory_make("autovideosink", "video-output");
+ if (!pVideosink)
+ return nullptr;
+ }
+
+ xRet = new ::avmedia::gstreamer::Window;
+
+ g_object_set(G_OBJECT(mpPlaybin), "video-sink", pVideosink, nullptr);
+ g_object_set(G_OBJECT(mpPlaybin), "force-aspect-ratio", FALSE, nullptr);
+
+ mnWindowID = pEnvData->aWindow;
+ mpDisplay = pEnvData->pDisplay;
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "set window id to " << static_cast<int>(mnWindowID) << " XOverlay " << mpXOverlay);
+ gst_element_set_state( mpPlaybin, GST_STATE_PAUSED );
+ if ( mpXOverlay != nullptr )
+ gst_video_overlay_set_window_handle( mpXOverlay, mnWindowID );
+ }
+
+ return xRet;
+}
+
+uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ FrameGrabber* pFrameGrabber = nullptr;
+ const awt::Size aPrefSize( getPreferredPlayerWindowSize() );
+
+ if( ( aPrefSize.Width > 0 ) && ( aPrefSize.Height > 0 ) )
+ pFrameGrabber = FrameGrabber::create( maURL );
+ SAL_INFO( "avmedia.gstreamer", AVVERSION "created FrameGrabber " << pFrameGrabber );
+
+ return pFrameGrabber;
+}
+
+
+OUString SAL_CALL Player::getImplementationName()
+{
+ return AVMEDIA_GST_PLAYER_IMPLEMENTATIONNAME;
+}
+
+
+sal_Bool SAL_CALL Player::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+uno::Sequence< OUString > SAL_CALL Player::getSupportedServiceNames()
+{
+ return { AVMEDIA_GST_PLAYER_SERVICENAME };
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstplayer.hxx b/avmedia/source/gstreamer/gstplayer.hxx
new file mode 100644
index 000000000..1b7c7f23b
--- /dev/null
+++ b/avmedia/source/gstreamer/gstplayer.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <osl/conditn.hxx>
+#include "gstcommon.hxx"
+
+#include <com/sun/star/media/XPlayer.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+typedef struct _GstVideoOverlay GstVideoOverlay;
+
+namespace avmedia::gstreamer {
+
+
+typedef ::cppu::WeakComponentImplHelper< css::media::XPlayer,
+ css::lang::XServiceInfo > GstPlayer_BASE;
+
+class Player final : public ::cppu::BaseMutex,
+ public GstPlayer_BASE
+{
+public:
+
+ explicit Player();
+ virtual ~Player() override;
+
+ void preparePlaybin( const OUString& rURL, GstElement *pSink );
+ bool create( const OUString& rURL );
+ void processMessage( GstMessage *message );
+ GstBusSyncReply processSyncMessage( GstMessage *message );
+
+ // XPlayer
+ virtual void SAL_CALL start( ) override;
+ virtual void SAL_CALL stop( ) override;
+ virtual sal_Bool SAL_CALL isPlaying( ) override;
+ virtual double SAL_CALL getDuration( ) override;
+ virtual void SAL_CALL setMediaTime( double fTime ) override;
+ virtual double SAL_CALL getMediaTime( ) override;
+ virtual void SAL_CALL setPlaybackLoop( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL isPlaybackLoop( ) override;
+ virtual void SAL_CALL setMute( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL isMute( ) override;
+ virtual void SAL_CALL setVolumeDB( sal_Int16 nVolumeDB ) override;
+ virtual sal_Int16 SAL_CALL getVolumeDB( ) override;
+ virtual css::awt::Size SAL_CALL getPreferredPlayerWindowSize( ) override;
+ virtual css::uno::Reference< css::media::XPlayerWindow > SAL_CALL createPlayerWindow( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+ virtual css::uno::Reference< css::media::XFrameGrabber > SAL_CALL createFrameGrabber( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() final override;
+
+private:
+ OUString maURL;
+
+ // Add elements and pipeline here
+ GstElement* mpPlaybin; // the playbin is also a pipeline
+ GstElement* mpVolumeControl; // the playbin is also a pipeline
+ bool mbUseGtkSink;
+ bool mbFakeVideo;
+
+ gdouble mnUnmutedVolume;
+ bool mbPlayPending;
+ bool mbMuted;
+ bool mbLooping;
+ bool mbInitialized;
+
+ void* mpDisplay;
+ long mnWindowID;
+ GstVideoOverlay* mpXOverlay;
+ gint64 mnDuration;
+ int mnWidth;
+ int mnHeight;
+
+ css::awt::Rectangle maArea; // Area of the player window.
+
+ guint mnWatchID;
+ bool mbWatchID;
+
+ osl::Condition maSizeCondition;
+};
+
+} // namespace avmedia::gstreamer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstuno.cxx b/avmedia/source/gstreamer/gstuno.cxx
new file mode 100644
index 000000000..2ca447d38
--- /dev/null
+++ b/avmedia/source/gstreamer/gstuno.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <mediamisc.hxx>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include "gstmanager.hxx"
+
+using namespace ::com::sun::star;
+
+
+// - factory methods -
+
+
+#define IMPL_NAME "com.sun.star.comp.media.Manager_GStreamer"
+#define SERVICE_NAME AVMEDIA_MANAGER_SERVICE_NAME // "com.sun.star.comp.avmedia.Manager_GStreamer"
+
+static uno::Reference< uno::XInterface > create_MediaPlayer( const uno::Reference< lang::XMultiServiceFactory >& )
+{
+ return uno::Reference< uno::XInterface >( *new ::avmedia::gstreamer::Manager );
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void* avmediagst_component_getFactory( const char* pImplName, void* pServiceManager, void* /*pRegistryKey*/ )
+{
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+ void* pRet = nullptr;
+
+ if( rtl_str_compare( pImplName, IMPL_NAME ) == 0 )
+ {
+ xFactory.set( ::cppu::createSingleFactory(
+ static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
+ IMPL_NAME, create_MediaPlayer, uno::Sequence< OUString > { SERVICE_NAME } ) );
+ }
+
+ if( xFactory.is() )
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstwindow.cxx b/avmedia/source/gstreamer/gstwindow.cxx
new file mode 100644
index 000000000..61f1b6a4c
--- /dev/null
+++ b/avmedia/source/gstreamer/gstwindow.cxx
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <com/sun/star/awt/SystemPointer.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include "gstwindow.hxx"
+#include "gstplayer.hxx"
+
+#define AVMEDIA_GST_WINDOW_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Window_GStreamer"
+#define AVMEDIA_GST_WINDOW_SERVICENAME "com.sun.star.media.Window_GStreamer"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::gstreamer {
+
+// Window
+
+
+Window::Window() :
+ meZoomLevel( media::ZoomLevel_NOT_AVAILABLE )
+{
+}
+
+Window::~Window()
+{
+}
+
+// XPlayerWindow
+
+
+void SAL_CALL Window::update( )
+{
+}
+
+sal_Bool SAL_CALL Window::setZoomLevel( media::ZoomLevel eZoomLevel )
+{
+ bool bRet = false;
+
+ if( meZoomLevel != media::ZoomLevel_NOT_AVAILABLE &&
+ eZoomLevel != media::ZoomLevel_NOT_AVAILABLE )
+ {
+ if( eZoomLevel != meZoomLevel )
+ {
+ meZoomLevel = eZoomLevel;
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+media::ZoomLevel SAL_CALL Window::getZoomLevel( )
+{
+ return meZoomLevel;
+}
+
+void SAL_CALL Window::setPointerType( sal_Int32 /*nPointerType*/ )
+{
+}
+
+// XWindow
+
+
+void SAL_CALL Window::setPosSize( sal_Int32 /*X*/, sal_Int32 /*Y*/, sal_Int32 /*Width*/, sal_Int32 /*Height*/, sal_Int16 /*Flags*/ )
+{
+}
+
+awt::Rectangle SAL_CALL Window::getPosSize()
+{
+ awt::Rectangle aRet;
+
+ aRet.X = aRet.Y = 0;
+ aRet.Width = 320;
+ aRet.Height = 240;
+
+ return aRet;
+}
+
+void SAL_CALL Window::setVisible( sal_Bool /*bVisible*/ )
+{
+}
+
+void SAL_CALL Window::setEnable( sal_Bool /*bEnable*/ )
+{
+}
+
+void SAL_CALL Window::setFocus( )
+{
+}
+
+void SAL_CALL Window::addWindowListener( const uno::Reference< awt::XWindowListener >& )
+{
+}
+
+void SAL_CALL Window::removeWindowListener( const uno::Reference< awt::XWindowListener >& )
+{
+}
+
+void SAL_CALL Window::addFocusListener( const uno::Reference< awt::XFocusListener >& )
+{
+}
+
+void SAL_CALL Window::removeFocusListener( const uno::Reference< awt::XFocusListener >& )
+{
+}
+
+void SAL_CALL Window::addKeyListener( const uno::Reference< awt::XKeyListener >& )
+{
+}
+
+void SAL_CALL Window::removeKeyListener( const uno::Reference< awt::XKeyListener >& )
+{
+}
+
+void SAL_CALL Window::addMouseListener( const uno::Reference< awt::XMouseListener >& )
+{
+}
+
+void SAL_CALL Window::removeMouseListener( const uno::Reference< awt::XMouseListener >& )
+{
+}
+
+void SAL_CALL Window::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
+{
+}
+
+void SAL_CALL Window::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
+{
+}
+
+void SAL_CALL Window::addPaintListener( const uno::Reference< awt::XPaintListener >& )
+{
+}
+
+void SAL_CALL Window::removePaintListener( const uno::Reference< awt::XPaintListener >& )
+{
+}
+
+// XComponent
+
+
+void SAL_CALL Window::dispose( )
+{
+}
+
+void SAL_CALL Window::addEventListener( const uno::Reference< lang::XEventListener >& )
+{
+}
+
+void SAL_CALL Window::removeEventListener( const uno::Reference< lang::XEventListener >& )
+{
+}
+
+// XServiceInfo
+
+
+OUString SAL_CALL Window::getImplementationName( )
+{
+ return AVMEDIA_GST_WINDOW_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL Window::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL Window::getSupportedServiceNames( )
+{
+ return { AVMEDIA_GST_WINDOW_SERVICENAME };
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/gstreamer/gstwindow.hxx b/avmedia/source/gstreamer/gstwindow.hxx
new file mode 100644
index 000000000..c9d633d54
--- /dev/null
+++ b/avmedia/source/gstreamer/gstwindow.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "gstcommon.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/interfacecontainer.h>
+
+#include <com/sun/star/media/XPlayerWindow.hpp>
+
+namespace avmedia::gstreamer {
+
+class Player;
+
+class Window : public ::cppu::WeakImplHelper< css::media::XPlayerWindow,
+ css::lang::XServiceInfo >
+{
+public:
+
+ explicit Window();
+ virtual ~Window() override;
+
+ // XPlayerWindow
+ virtual void SAL_CALL update( ) override;
+ virtual sal_Bool SAL_CALL setZoomLevel( css::media::ZoomLevel ZoomLevel ) override;
+ virtual css::media::ZoomLevel SAL_CALL getZoomLevel( ) override;
+ virtual void SAL_CALL setPointerType( sal_Int32 nPointerType ) override;
+
+ // XWindow
+ virtual void SAL_CALL setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) override;
+ virtual css::awt::Rectangle SAL_CALL getPosSize( ) override;
+ virtual void SAL_CALL setVisible( sal_Bool Visible ) override;
+ virtual void SAL_CALL setEnable( sal_Bool Enable ) override;
+ virtual void SAL_CALL setFocus( ) override;
+ virtual void SAL_CALL addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+
+ css::media::ZoomLevel meZoomLevel;
+};
+
+} // namespace avmedia::gstreamer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/inc/mediamisc.hxx b/avmedia/source/inc/mediamisc.hxx
new file mode 100644
index 000000000..504a136aa
--- /dev/null
+++ b/avmedia/source/inc/mediamisc.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <unotools/resmgr.hxx>
+
+#define AVMEDIA_MANAGER_SERVICE_PREFERRED "com.sun.star.comp.avmedia.Manager_VLC"
+#ifdef _WIN32
+#define AVMEDIA_MANAGER_SERVICE_NAME "com.sun.star.comp.avmedia.Manager_DirectX"
+#else
+#ifdef MACOSX
+#define AVMEDIA_MANAGER_SERVICE_NAME "com.sun.star.comp.avmedia.Manager_MacAVF"
+#else
+#define AVMEDIA_MANAGER_SERVICE_NAME "com.sun.star.comp.avmedia.Manager_GStreamer"
+#endif
+#endif
+
+#define AVMEDIA_OPENGL_MANAGER_SERVICE_NAME "com.sun.star.media.Manager_OpenGL"
+
+// Mime types
+#define AVMEDIA_MIMETYPE_COMMON "application/vnd.sun.star.media"
+
+inline OUString AvmResId(const char* pId)
+{
+ return Translate::get(pId, Translate::Create("avmedia"));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/avmediaMacAVF.component b/avmedia/source/macavf/avmediaMacAVF.component
new file mode 100644
index 000000000..376576ff5
--- /dev/null
+++ b/avmedia/source/macavf/avmediaMacAVF.component
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ prefix="avmediaMacAVF" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.avmedia.Manager_MacAVF">
+ <service name="com.sun.star.media.Manager_MacAVF"/>
+ </implementation>
+</component>
diff --git a/avmedia/source/macavf/framegrabber.hxx b/avmedia/source/macavf/framegrabber.hxx
new file mode 100644
index 000000000..0b199991e
--- /dev/null
+++ b/avmedia/source/macavf/framegrabber.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "macavfcommon.hxx"
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/media/XFrameGrabber.hpp>
+
+namespace avmedia::macavf {
+
+class FrameGrabber : public ::cppu::WeakImplHelper< css::media::XFrameGrabber,
+ css::lang::XServiceInfo >
+{
+public:
+
+ explicit FrameGrabber( const css::uno::Reference< css::lang::XMultiServiceFactory >& );
+ virtual ~FrameGrabber() override;
+
+ bool create( AVAsset* pMovie );
+
+ // XFrameGrabber
+ virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL grabFrame( double fMediaTime ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+
+ AVAssetImageGenerator* mpImageGen;
+};
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/framegrabber.mm b/avmedia/source/macavf/framegrabber.mm
new file mode 100644
index 000000000..711800103
--- /dev/null
+++ b/avmedia/source/macavf/framegrabber.mm
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "framegrabber.hxx"
+#include "player.hxx"
+
+#include <sal/log.hxx>
+#include <tools/stream.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <unotools/localfilehelper.hxx>
+
+using namespace ::com::sun::star;
+
+namespace avmedia::macavf {
+
+FrameGrabber::FrameGrabber( const uno::Reference< lang::XMultiServiceFactory >& /*rxMgr*/ )
+: mpImageGen( nullptr )
+{}
+
+
+FrameGrabber::~FrameGrabber()
+{
+ if( mpImageGen )
+ CFRelease( mpImageGen );
+}
+
+
+bool FrameGrabber::create( AVAsset* pMovie )
+{
+ if( [[pMovie tracksWithMediaType:AVMediaTypeVideo] count] == 0)
+ {
+ SAL_WARN("avmedia", "AVGrabber::create() found no video content!" );
+ return false;
+ }
+
+ mpImageGen = [AVAssetImageGenerator assetImageGeneratorWithAsset:pMovie];
+ CFRetain( mpImageGen );
+ return true;
+}
+
+
+uno::Reference< graphic::XGraphic > SAL_CALL FrameGrabber::grabFrame( double fMediaTime )
+{
+ uno::Reference< graphic::XGraphic > xRet;
+ if( !mpImageGen )
+ return xRet;
+
+ // get the requested image from the movie
+ CGImage* pCGImage = [mpImageGen copyCGImageAtTime:CMTimeMakeWithSeconds(fMediaTime,1000) actualTime:nullptr error:nullptr];
+
+ // convert the image to a TIFF-formatted byte-array
+ CFMutableDataRef pCFData = CFDataCreateMutable( kCFAllocatorDefault, 0 );
+ CGImageDestination* pCGImgDest = CGImageDestinationCreateWithData( pCFData, kUTTypeTIFF, 1, nullptr );
+ CGImageDestinationAddImage( pCGImgDest, pCGImage, nullptr );
+ CGImageDestinationFinalize( pCGImgDest );
+ CFRelease( pCGImgDest );
+ const long nBitmapLen = CFDataGetLength( pCFData );
+ UInt8 * pBitmapBytes = const_cast<UInt8 *>(CFDataGetBytePtr( pCFData ));
+
+ // convert the image into the return-value type which is a graphic::XGraphic
+ SvMemoryStream aMemStm( pBitmapBytes, nBitmapLen, StreamMode::READ | StreamMode::WRITE );
+ Graphic aGraphic;
+ if( GraphicConverter::Import( aMemStm, aGraphic, ConvertDataFormat::TIF ) == ERRCODE_NONE )
+ xRet = aGraphic.GetXGraphic();
+
+ // clean up resources
+ CFRelease( pCFData );
+ return xRet;
+}
+
+
+OUString SAL_CALL FrameGrabber::getImplementationName( )
+{
+ return AVMEDIA_MACAVF_FRAMEGRABBER_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL FrameGrabber::supportsService( const OUString& ServiceName )
+{
+ return ServiceName == AVMEDIA_MACAVF_FRAMEGRABBER_SERVICENAME;
+}
+
+uno::Sequence< OUString > SAL_CALL FrameGrabber::getSupportedServiceNames( )
+{
+ return { AVMEDIA_MACAVF_FRAMEGRABBER_SERVICENAME };
+}
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/macavfcommon.hxx b/avmedia/source/macavf/macavfcommon.hxx
new file mode 100644
index 000000000..699f495a0
--- /dev/null
+++ b/avmedia/source/macavf/macavfcommon.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#import <AVFoundation/AVFoundation.h>
+#include <postmac.h>
+
+#include <unordered_map>
+
+#include <osl/mutex.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/factory.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/media/XManager.hpp>
+
+
+#define AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Manager_MacAVF"
+#define AVMEDIA_MACAVF_MANAGER_SERVICENAME "com.sun.star.media.Manager_MacAVF"
+
+#define AVMEDIA_MACAVF_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_MacAVF"
+#define AVMEDIA_MACAVF_PLAYER_SERVICENAME "com.sun.star.media.Player_MacAVF"
+
+#define AVMEDIA_MACAVF_WINDOW_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Window_MacAVF"
+#define AVMEDIA_MACAVF_WINDOW_SERVICENAME "com.sun.star.media.Window_MacAVF"
+
+#define AVMEDIA_MACAVF_FRAMEGRABBER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.FrameGrabber_MacAVF"
+#define AVMEDIA_MACAVF_FRAMEGRABBER_SERVICENAME "com.sun.star.media.FrameGrabber_MacAVF"
+
+
+// MacAVObserver handles the notifications used in the AVFoundation framework
+
+namespace avmedia::macavf { class MacAVObserverHandler; }
+
+typedef std::unordered_map<NSObject*,avmedia::macavf::MacAVObserverHandler*> HandlersForObject;
+
+@interface MacAVObserverObject : NSObject
+{
+ HandlersForObject maHandlersForObject;
+}
+- (void)observeValueForKeyPath:(NSString*)pKeyPath ofObject:(id)pObject change:(NSDictionary*)pChangeDict context:(void*)pContext;
+- (void)onNotification:(NSNotification*)pNotification;
+@end
+
+namespace avmedia::macavf {
+
+class MacAVObserverHandler
+{
+private:
+ static MacAVObserverObject* mpMacAVObserverObject;
+public:
+ virtual ~MacAVObserverHandler() {}
+ static MacAVObserverObject* getObserver();
+ virtual bool handleObservation( NSString* pKeyPath ) = 0;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/macavfuno.mm b/avmedia/source/macavf/macavfuno.mm
new file mode 100644
index 000000000..dbee2e8ce
--- /dev/null
+++ b/avmedia/source/macavf/macavfuno.mm
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "macavfcommon.hxx"
+#include "manager.hxx"
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+using namespace ::com::sun::star;
+
+static uno::Reference< uno::XInterface > create_MediaPlayer( const uno::Reference< lang::XMultiServiceFactory >& rxFact )
+{
+ return uno::Reference< uno::XInterface >( *new ::avmedia::macavf::Manager( rxFact ) );
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void* avmediaMacAVF_component_getFactory( const char* pImplName, void* pServiceManager, void* /* pRegistryKey */ )
+{
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+ void* pRet = nullptr;
+
+ if( rtl_str_compare( pImplName, AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME ) == 0 )
+ {
+ const OUString aServiceName( AVMEDIA_MACAVF_MANAGER_SERVICENAME );
+
+ xFactory.set( ::cppu::createSingleFactory(
+ static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
+ AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME,
+ create_MediaPlayer, uno::Sequence< OUString >( &aServiceName, 1 ) ) );
+ }
+
+ if( xFactory.is() )
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/manager.hxx b/avmedia/source/macavf/manager.hxx
new file mode 100644
index 000000000..fbdcb61b3
--- /dev/null
+++ b/avmedia/source/macavf/manager.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "macavfcommon.hxx"
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/media/XManager.hpp>
+
+
+namespace avmedia::macavf {
+
+class Manager : public ::cppu::WeakImplHelper< css::media::XManager,
+ css::lang::XServiceInfo >
+{
+public:
+
+ Manager( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxMgr );
+ virtual ~Manager() override;
+
+ // XManager
+ virtual css::uno::Reference< css::media::XPlayer > SAL_CALL createPlayer( const OUString& aURL ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+private:
+
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+};
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/manager.mm b/avmedia/source/macavf/manager.mm
new file mode 100644
index 000000000..7f3036c86
--- /dev/null
+++ b/avmedia/source/macavf/manager.mm
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "manager.hxx"
+#include "player.hxx"
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+
+namespace avmedia::macavf {
+
+Manager::Manager( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
+ mxMgr( rxMgr )
+{
+}
+
+
+Manager::~Manager()
+{}
+
+
+uno::Reference< media::XPlayer > SAL_CALL Manager::createPlayer( const OUString& rURL )
+{
+ Player* pPlayer( new Player( mxMgr ) );
+ uno::Reference< media::XPlayer > xRet( pPlayer );
+ INetURLObject aURL( rURL );
+
+ if( !pPlayer->create( aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ) )
+ xRet.clear();
+
+ return xRet;
+}
+
+
+OUString SAL_CALL Manager::getImplementationName( )
+{
+ return AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME;
+}
+
+
+sal_Bool SAL_CALL Manager::supportsService( const OUString& ServiceName )
+{
+ return ServiceName == AVMEDIA_MACAVF_MANAGER_SERVICENAME;
+}
+
+
+uno::Sequence< OUString > SAL_CALL Manager::getSupportedServiceNames( )
+{
+ return { AVMEDIA_MACAVF_MANAGER_SERVICENAME };
+}
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/player.hxx b/avmedia/source/macavf/player.hxx
new file mode 100644
index 000000000..b9b49cc8c
--- /dev/null
+++ b/avmedia/source/macavf/player.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <osl/conditn.h>
+#include "macavfcommon.hxx"
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/media/XPlayer.hpp>
+
+namespace avmedia::macavf {
+
+class Player
+: public MacAVObserverHandler
+, public ::cppu::WeakImplHelper< css::media::XPlayer,
+ css::lang::XServiceInfo >
+{
+public:
+ explicit Player( const css::uno::Reference< css::lang::XMultiServiceFactory >& );
+ virtual ~Player() override;
+
+ bool create( const OUString& rURL );
+ bool create( AVAsset* );
+
+ // XPlayer
+ virtual void SAL_CALL start() override;
+ virtual void SAL_CALL stop() override;
+ virtual sal_Bool SAL_CALL isPlaying() override;
+ virtual double SAL_CALL getDuration() override;
+ virtual void SAL_CALL setMediaTime( double fTime ) override;
+ virtual double SAL_CALL getMediaTime() override;
+ /// @throws css::uno::RuntimeException
+ virtual void setStopTime( double fTime );
+ /// @throws css::uno::RuntimeException
+ virtual double getStopTime();
+ virtual void SAL_CALL setPlaybackLoop( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL isPlaybackLoop() override;
+ virtual void SAL_CALL setMute( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL isMute() override;
+ virtual void SAL_CALL setVolumeDB( sal_Int16 nVolumeDB ) override;
+ virtual sal_Int16 SAL_CALL getVolumeDB() override;
+ virtual css::awt::Size SAL_CALL getPreferredPlayerWindowSize( ) override;
+ virtual css::uno::Reference< css::media::XPlayerWindow > SAL_CALL createPlayerWindow( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+ virtual css::uno::Reference< css::media::XFrameGrabber > SAL_CALL createFrameGrabber( ) override;
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ AVPlayer* getAVPlayer() const { return mpPlayer; }
+ virtual bool handleObservation( NSString* pKeyPath ) override;
+
+private:
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+
+ AVPlayer* mpPlayer;
+
+ float mfUnmutedVolume;
+ double mfStopTime;
+
+ bool mbMuted;
+ bool mbLooping;
+};
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/player.mm b/avmedia/source/macavf/player.mm
new file mode 100644
index 000000000..dfe558524
--- /dev/null
+++ b/avmedia/source/macavf/player.mm
@@ -0,0 +1,364 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "player.hxx"
+#include "framegrabber.hxx"
+#include "window.hxx"
+
+#include <cmath> // for log10()
+
+using namespace ::com::sun::star;
+
+@implementation MacAVObserverObject
+
+- (void)observeValueForKeyPath:(NSString*)pKeyPath ofObject:(id)pObject change:(NSDictionary*)pChangeDict context:(void*)pContext
+{
+ (void) pObject;
+ (void) pChangeDict;
+ avmedia::macavf::MacAVObserverHandler* pHandler = static_cast<avmedia::macavf::MacAVObserverHandler*>(pContext);
+ pHandler->handleObservation( pKeyPath );
+}
+
+- (void)onNotification:(NSNotification*)pNotification
+{
+ NSString* pNoteName = [pNotification name];
+ HandlersForObject::iterator it = maHandlersForObject.find( [pNotification object]);
+ if( it != maHandlersForObject.end() )
+ (*it).second->handleObservation( pNoteName );
+}
+
+- (void)setHandlerForObject:(NSObject*)pObject handler:(avmedia::macavf::MacAVObserverHandler*)pHandler
+{
+ maHandlersForObject[ pObject] = pHandler;
+}
+
+- (void)removeHandlerForObject:(NSObject*)pObject
+{
+ maHandlersForObject.erase( pObject);
+}
+
+@end
+
+
+namespace avmedia::macavf {
+
+MacAVObserverObject* MacAVObserverHandler::mpMacAVObserverObject = nullptr;
+
+MacAVObserverObject* MacAVObserverHandler::getObserver()
+{
+ if( !mpMacAVObserverObject)
+ {
+ mpMacAVObserverObject = [MacAVObserverObject alloc];
+ [mpMacAVObserverObject retain];
+ }
+ return mpMacAVObserverObject;
+}
+
+
+Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr )
+: mxMgr( rxMgr )
+, mpPlayer( nullptr )
+, mfUnmutedVolume( 0 )
+, mfStopTime( DBL_MAX )
+, mbMuted( false )
+, mbLooping( false )
+{}
+
+
+Player::~Player()
+{
+ if( !mpPlayer )
+ return;
+ // remove the observers
+ [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
+ AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
+ [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
+ name:AVPlayerItemDidPlayToEndTimeNotification
+ object:pOldPlayerItem];
+ [getObserver() removeHandlerForObject:pOldPlayerItem];
+ // release the AVPlayer
+ CFRelease( mpPlayer );
+}
+
+
+bool Player::handleObservation( NSString* pKeyPath )
+{
+ if( [pKeyPath isEqualToString:AVPlayerItemDidPlayToEndTimeNotification])
+ {
+ if( mbLooping )
+ setMediaTime( 0.0);
+ }
+ return true;
+}
+
+
+bool Player::create( const OUString& rURL )
+{
+ // get the media asset
+ NSString* aNSStr = [NSString stringWithCharacters:reinterpret_cast<unichar const *>(rURL.getStr()) length:rURL.getLength()];
+ SAL_WNODEPRECATED_DECLARATIONS_PUSH
+ //TODO: 10.11 stringByAddingPercentEscapesUsingEncoding
+ NSURL* aNSURL = [NSURL URLWithString: [aNSStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ SAL_WNODEPRECATED_DECLARATIONS_POP
+ // get the matching AVPlayerItem
+ AVPlayerItem* pPlayerItem = [AVPlayerItem playerItemWithURL:aNSURL];
+
+ // create or update the AVPlayer with the new AVPlayerItem
+ if( !mpPlayer )
+ {
+ mpPlayer = [AVPlayer playerWithPlayerItem:pPlayerItem];
+ CFRetain( mpPlayer );
+ [mpPlayer setActionAtItemEnd:AVPlayerActionAtItemEndNone];
+ }
+ else
+ {
+ // remove the obsoleted observers
+ AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
+ [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
+ [getObserver() removeHandlerForObject:pOldPlayerItem];
+ [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
+ name:AVPlayerItemDidPlayToEndTimeNotification
+ object:pOldPlayerItem];
+ // replace the playeritem
+ [mpPlayer replaceCurrentItemWithPlayerItem:pPlayerItem];
+ }
+
+ // observe the status of the current player item
+ [mpPlayer addObserver:getObserver() forKeyPath:@"currentItem.status" options:0 context:this];
+
+ // observe playback-end needed for playback looping
+ [[NSNotificationCenter defaultCenter] addObserver:getObserver()
+ selector:@selector(onNotification:)
+ name:AVPlayerItemDidPlayToEndTimeNotification
+ object:pPlayerItem];
+ [getObserver() setHandlerForObject:pPlayerItem handler:this];
+
+ return true;
+}
+
+
+void SAL_CALL Player::start()
+{
+ if( !mpPlayer )
+ return;
+
+ [mpPlayer play];
+ // else // TODO: delay until it becomes ready
+}
+
+
+void SAL_CALL Player::stop()
+{
+ if( !mpPlayer )
+ return;
+ const bool bPlaying = isPlaying();
+ if( bPlaying )
+ [mpPlayer pause];
+}
+
+
+sal_Bool SAL_CALL Player::isPlaying()
+{
+ if( !mpPlayer )
+ return false;
+ const float fRate = [mpPlayer rate];
+ return (fRate != 0.0);
+}
+
+
+double SAL_CALL Player::getDuration()
+{
+ // slideshow checks for non-zero duration, so cheat here
+ double duration = 0.01;
+
+ if( mpPlayer )
+ {
+ AVPlayerItem* pItem = [mpPlayer currentItem];
+ if( [pItem status] == AVPlayerItemStatusReadyToPlay )
+ duration = CMTimeGetSeconds( [pItem duration] );
+ else // fall back to AVAsset's best guess
+ duration = CMTimeGetSeconds( [[pItem asset] duration] );
+ }
+
+ return duration;
+}
+
+
+void SAL_CALL Player::setMediaTime( double fTime )
+{
+ if( mpPlayer )
+ [mpPlayer seekToTime: CMTimeMakeWithSeconds(fTime,1000) ];
+}
+
+
+double SAL_CALL Player::getMediaTime()
+{
+ if( !mpPlayer )
+ return 0.0;
+
+ const double position = CMTimeGetSeconds( [mpPlayer currentTime] );
+ if( position >= mfStopTime )
+ if( isPlaying() )
+ stop();
+
+ return position;
+}
+
+
+void Player::setStopTime( double fTime )
+{
+ mfStopTime = fTime;
+}
+
+
+double Player::getStopTime()
+{
+ return mfStopTime;
+}
+
+
+void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
+{
+ mbLooping = bSet;
+}
+
+
+sal_Bool SAL_CALL Player::isPlaybackLoop()
+{
+ return mbLooping;
+}
+
+
+void SAL_CALL Player::setMute( sal_Bool bSet )
+{
+ if( !mpPlayer )
+ return;
+
+ mbMuted = bSet;
+ [mpPlayer setMuted:mbMuted];
+}
+
+
+sal_Bool SAL_CALL Player::isMute()
+{
+ return mbMuted;
+}
+
+
+void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
+{
+ // -40dB <-> AVPlayer volume 0.0
+ // 0dB <-> AVPlayer volume 1.0
+ mfUnmutedVolume = (nVolumeDB <= -40) ? 0.0 : pow( 10.0, nVolumeDB / 20.0 );
+
+ // change volume
+ if( !mbMuted && mpPlayer )
+ [mpPlayer setVolume:mfUnmutedVolume];
+}
+
+
+sal_Int16 SAL_CALL Player::getVolumeDB()
+{
+ if( !mpPlayer )
+ return 0;
+
+ // get the actual volume
+ const float fVolume = [mpPlayer volume];
+
+ // convert into Decibel value
+ // -40dB <-> AVPlayer volume 0.0
+ // 0dB <-> AVPlayer volume 1.0
+ const int nVolumeDB = (fVolume <= 0) ? -40 : lrint( 20.0*log10(fVolume));
+
+ return static_cast<sal_Int16>(nVolumeDB);
+}
+
+
+awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
+{
+ awt::Size aSize( 0, 0 ); // default size
+
+ AVAsset* pMovie = [[mpPlayer currentItem] asset];
+ NSArray* pVideoTracks = [pMovie tracksWithMediaType:AVMediaTypeVideo];
+ if ([pVideoTracks count] > 0)
+ {
+ AVAssetTrack* pFirstVideoTrack = static_cast<AVAssetTrack*>([pVideoTracks objectAtIndex:0]);
+ const CGSize aPrefSize = [pFirstVideoTrack naturalSize];
+ aSize = awt::Size( aPrefSize.width, aPrefSize.height );
+ }
+
+ return aSize;
+}
+
+
+uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& aArguments )
+{
+ // get the preferred window size
+ const awt::Size aSize( getPreferredPlayerWindowSize() );
+
+ // get the parent view
+ sal_IntPtr nNSViewPtr = 0;
+ aArguments[0] >>= nNSViewPtr;
+ NSView* pParentView = reinterpret_cast<NSView*>(nNSViewPtr);
+
+ // check the window parameters
+ uno::Reference< ::media::XPlayerWindow > xRet;
+ if( (aSize.Width <= 0) || (aSize.Height <= 0) || (pParentView == nullptr) )
+ return xRet;
+
+ // create the window
+ ::avmedia::macavf::Window* pWindow = new ::avmedia::macavf::Window( mxMgr, *this, pParentView );
+ xRet = pWindow;
+ return xRet;
+}
+
+
+uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
+{
+ uno::Reference< media::XFrameGrabber > xRet;
+
+ FrameGrabber* pGrabber = new FrameGrabber( mxMgr );
+ AVAsset* pMovie = [[mpPlayer currentItem] asset];
+ if( pGrabber->create( pMovie ) )
+ xRet = pGrabber;
+
+ return xRet;
+}
+
+
+OUString SAL_CALL Player::getImplementationName( )
+{
+ return AVMEDIA_MACAVF_PLAYER_IMPLEMENTATIONNAME;
+}
+
+
+sal_Bool SAL_CALL Player::supportsService( const OUString& ServiceName )
+{
+ return ServiceName == AVMEDIA_MACAVF_PLAYER_SERVICENAME;
+}
+
+
+uno::Sequence< OUString > SAL_CALL Player::getSupportedServiceNames( )
+{
+ return { AVMEDIA_MACAVF_PLAYER_SERVICENAME };
+}
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/window.hxx b/avmedia/source/macavf/window.hxx
new file mode 100644
index 000000000..c494b6def
--- /dev/null
+++ b/avmedia/source/macavf/window.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "macavfcommon.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/interfacecontainer.h>
+
+#include <com/sun/star/media/XPlayerWindow.hpp>
+
+
+@interface MyMediaView : NSView
+@property (nonatomic, readonly, strong) AVPlayer* player;
+@property (nonatomic, readonly, strong) AVPlayerLayer* playerLayer;
+@property (nonatomic, retain) NSURL* videoURL;
+- (void) play;
+@end
+
+namespace avmedia::macavf {
+
+class Player;
+
+class Window
+: public MacAVObserverHandler
+, public ::cppu::WeakImplHelper< css::media::XPlayerWindow,
+ css::lang::XServiceInfo >
+{
+public:
+
+ Window( const css::uno::Reference< css::lang::XMultiServiceFactory >& i_rxMgr,
+ Player& i_rPlayer,
+ NSView* i_pParentView
+ );
+ virtual ~Window() override;
+
+ void processGraphEvent();
+ void updatePointer();
+
+ // XPlayerWindow
+ virtual void SAL_CALL update( ) override;
+ virtual sal_Bool SAL_CALL setZoomLevel( css::media::ZoomLevel ZoomLevel ) override;
+ virtual css::media::ZoomLevel SAL_CALL getZoomLevel( ) override;
+ virtual void SAL_CALL setPointerType( sal_Int32 nPointerType ) override;
+
+ // XWindow
+ virtual void SAL_CALL setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) override;
+ virtual css::awt::Rectangle SAL_CALL getPosSize( ) override;
+ virtual void SAL_CALL setVisible( sal_Bool Visible ) override;
+ virtual void SAL_CALL setEnable( sal_Bool Enable ) override;
+ virtual void SAL_CALL setFocus( ) override;
+ virtual void SAL_CALL addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ virtual bool handleObservation( NSString* pKeyPath ) override;
+
+private:
+
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+
+ ::osl::Mutex maMutex;
+ ::cppu::OMultiTypeInterfaceContainerHelper maListeners;
+ css::media::ZoomLevel meZoomLevel;
+ Player& mrPlayer;
+ int mnPointerType;
+
+ NSView* mpView; // parent-view == movie-view
+ AVPlayerLayer* mpPlayerLayer;
+
+ void ImplLayoutVideoWindow();
+};
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/macavf/window.mm b/avmedia/source/macavf/window.mm
new file mode 100644
index 000000000..3c39a0725
--- /dev/null
+++ b/avmedia/source/macavf/window.mm
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+
+#include "window.hxx"
+#include "player.hxx"
+
+using namespace ::com::sun::star;
+
+
+namespace avmedia::macavf {
+
+Window::Window( const uno::Reference< lang::XMultiServiceFactory >& i_rxMgr, Player& i_rPlayer, NSView* i_pParentView )
+: mxMgr( i_rxMgr )
+, maListeners( maMutex )
+, meZoomLevel( media::ZoomLevel_NOT_AVAILABLE )
+, mrPlayer( i_rPlayer )
+, mnPointerType( awt::SystemPointer::ARROW )
+, mpView( i_pParentView )
+, mpPlayerLayer( nullptr )
+{
+ if( !mpView ) // sanity check
+ return;
+
+ // check the media asset for video content
+ AVPlayer* pAVPlayer = mrPlayer.getAVPlayer();
+ AVAsset* pMovie = [[pAVPlayer currentItem] asset];
+ const int nVideoCount = [pMovie tracksWithMediaType:AVMediaTypeVideo].count;
+ if( nVideoCount <= 0 )
+ return;
+
+ // setup the AVPlayerLayer
+ [pAVPlayer retain];
+ [pAVPlayer pause];
+ mpPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:pAVPlayer];
+ [mpPlayerLayer retain];
+ NSRect viewFrame = [mpView frame];
+ [mpPlayerLayer setFrame:CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.width, viewFrame.size.height)];
+ [mpPlayerLayer setHidden:YES];
+ [mpPlayerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
+ [mpPlayerLayer addObserver:getObserver() forKeyPath:@"readyForDisplay" options:0 context:this];
+
+ // setup the target view
+ [mpView setWantsLayer:YES];
+ [mpView.layer addSublayer:mpPlayerLayer];
+}
+
+
+Window::~Window()
+{
+ [mpPlayerLayer removeObserver:getObserver() forKeyPath:@"readyForDisplay"];
+ [mpPlayerLayer release];
+}
+
+
+bool Window::handleObservation( NSString* /*pKeyPath*/ )
+{
+ const bool bReadyForDisplay = [mpPlayerLayer isReadyForDisplay];
+ [mpPlayerLayer setHidden:!bReadyForDisplay];
+ return true;
+}
+
+// XPlayerWindow
+
+void SAL_CALL Window::update()
+{}
+
+
+sal_Bool SAL_CALL Window::setZoomLevel( media::ZoomLevel /* eZoomLevel */ )
+{
+ return false;
+}
+
+
+media::ZoomLevel SAL_CALL Window::getZoomLevel( )
+{
+ return meZoomLevel;
+}
+
+
+void SAL_CALL Window::setPointerType( sal_Int32 nPointerType )
+{
+ mnPointerType = nPointerType;
+}
+
+// XWindow
+
+void SAL_CALL Window::setPosSize( sal_Int32 /*X*/, sal_Int32 /*Y*/, sal_Int32 Width, sal_Int32 Height, sal_Int16 /* Flags */ )
+{
+ if( !mpView )
+ return;
+ NSRect aRect = [mpView frame];
+ // NOTE: if( (Flags & awt::PosSize::WIDTH) )
+ aRect.size.width = Width;
+ // NOTE: if( (Flags & awt::PosSize::HEIGHT) )
+ aRect.size.height = Height;
+
+ [mpView setFrameSize: aRect.size];
+ NSRect viewFrame = [mpView frame];
+ [mpPlayerLayer setFrame:CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.width, viewFrame.size.height)];
+}
+
+
+awt::Rectangle SAL_CALL Window::getPosSize()
+{
+ awt::Rectangle aRet;
+
+ NSRect aRect = [mpView frame];
+ aRet.X = aRet.Y = 0;
+ aRet.Width = aRect.size.width;
+ aRet.Height = aRect.size.height;
+
+ return aRet;
+}
+
+
+void SAL_CALL Window::setVisible( sal_Bool /*bVisible*/ )
+{
+}
+
+
+void SAL_CALL Window::setEnable( sal_Bool /*bEnable*/ )
+{
+}
+
+
+void SAL_CALL Window::setFocus()
+{
+}
+
+
+void SAL_CALL Window::addWindowListener( const uno::Reference< awt::XWindowListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::removeWindowListener( const uno::Reference< awt::XWindowListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::addFocusListener( const uno::Reference< awt::XFocusListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::removeFocusListener( const uno::Reference< awt::XFocusListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::addKeyListener( const uno::Reference< awt::XKeyListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::removeKeyListener( const uno::Reference< awt::XKeyListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::addMouseListener( const uno::Reference< awt::XMouseListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::removeMouseListener( const uno::Reference< awt::XMouseListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::addPaintListener( const uno::Reference< awt::XPaintListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::removePaintListener( const uno::Reference< awt::XPaintListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+// XComponent
+
+void SAL_CALL Window::dispose( )
+{
+}
+
+
+void SAL_CALL Window::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+
+void SAL_CALL Window::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+// XServiceInfo
+
+OUString SAL_CALL Window::getImplementationName( )
+{
+ return AVMEDIA_MACAVF_WINDOW_IMPLEMENTATIONNAME;
+}
+
+
+sal_Bool SAL_CALL Window::supportsService( const OUString& ServiceName )
+{
+ return ServiceName == AVMEDIA_MACAVF_WINDOW_SERVICENAME;
+}
+
+
+uno::Sequence< OUString > SAL_CALL Window::getSupportedServiceNames( )
+{
+ return { AVMEDIA_MACAVF_WINDOW_SERVICENAME };
+}
+
+} // namespace avmedia::macavf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediaevent_impl.cxx b/avmedia/source/viewer/mediaevent_impl.cxx
new file mode 100644
index 000000000..9fbaceea1
--- /dev/null
+++ b/avmedia/source/viewer/mediaevent_impl.cxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "mediaevent_impl.hxx"
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+
+using namespace ::com::sun::star;
+
+namespace avmedia::priv {
+
+MediaEventListenersImpl::MediaEventListenersImpl( vcl::Window& rEventWindow ) :
+ mpNotifyWindow( &rEventWindow )
+{
+}
+
+
+MediaEventListenersImpl::~MediaEventListenersImpl()
+{
+}
+
+
+void MediaEventListenersImpl::cleanUp()
+{
+ Application::RemoveMouseAndKeyEvents( reinterpret_cast< vcl::Window* >( mpNotifyWindow.get() ) );
+ mpNotifyWindow = nullptr;
+}
+
+
+void SAL_CALL MediaEventListenersImpl::disposing( const css::lang::EventObject& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::keyPressed( const css::awt::KeyEvent& e )
+{
+ const ::osl::MutexGuard aGuard( maMutex );
+ const SolarMutexGuard aAppGuard;
+
+ if( mpNotifyWindow )
+ {
+ vcl::KeyCode aVCLKeyCode( e.KeyCode,
+ ( ( e.Modifiers & 1 ) ? KEY_SHIFT : 0 ) |
+ ( ( e.Modifiers & 2 ) ? KEY_MOD1 : 0 ) |
+ ( ( e.Modifiers & 4 ) ? KEY_MOD2 : 0 ) );
+ KeyEvent aVCLKeyEvt( e.KeyChar, aVCLKeyCode );
+
+ Application::PostKeyEvent( VclEventId::WindowKeyInput, reinterpret_cast< vcl::Window* >( mpNotifyWindow.get() ), &aVCLKeyEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::keyReleased( const css::awt::KeyEvent& e )
+{
+ const ::osl::MutexGuard aGuard( maMutex );
+ const SolarMutexGuard aAppGuard;
+
+ if( mpNotifyWindow )
+ {
+ vcl::KeyCode aVCLKeyCode( e.KeyCode,
+ ( ( e.Modifiers & 1 ) ? KEY_SHIFT : 0 ) |
+ ( ( e.Modifiers & 2 ) ? KEY_MOD1 : 0 ) |
+ ( ( e.Modifiers & 4 ) ? KEY_MOD2 : 0 ) );
+ KeyEvent aVCLKeyEvt( e.KeyChar, aVCLKeyCode );
+ Application::PostKeyEvent( VclEventId::WindowKeyUp, reinterpret_cast< vcl::Window* >( mpNotifyWindow.get() ), &aVCLKeyEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mousePressed( const css::awt::MouseEvent& e )
+{
+ const ::osl::MutexGuard aGuard( maMutex );
+ const SolarMutexGuard aAppGuard;
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ),
+ sal::static_int_cast< sal_uInt16 >(e.ClickCount),
+ MouseEventModifiers::NONE,
+ ( ( e.Buttons & 1 ) ? MOUSE_LEFT : 0 ) |
+ ( ( e.Buttons & 2 ) ? MOUSE_RIGHT : 0 ) |
+ ( ( e.Buttons & 4 ) ? MOUSE_MIDDLE : 0 ),
+ e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseButtonDown, reinterpret_cast< vcl::Window* >( mpNotifyWindow.get() ), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseReleased( const css::awt::MouseEvent& e )
+{
+ const ::osl::MutexGuard aGuard( maMutex );
+ const SolarMutexGuard aAppGuard;
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ),
+ sal::static_int_cast< sal_uInt16 >(e.ClickCount),
+ MouseEventModifiers::NONE,
+ ( ( e.Buttons & 1 ) ? MOUSE_LEFT : 0 ) |
+ ( ( e.Buttons & 2 ) ? MOUSE_RIGHT : 0 ) |
+ ( ( e.Buttons & 4 ) ? MOUSE_MIDDLE : 0 ),
+ e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseButtonUp, reinterpret_cast< vcl::Window* >( mpNotifyWindow.get() ), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseEntered( const css::awt::MouseEvent& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseExited( const css::awt::MouseEvent& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseDragged( const css::awt::MouseEvent& e )
+{
+ const ::osl::MutexGuard aGuard( maMutex );
+ const SolarMutexGuard aAppGuard;
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ), 0, MouseEventModifiers::NONE, e.Buttons, e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseMove, reinterpret_cast< vcl::Window* >( mpNotifyWindow.get() ), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseMoved( const css::awt::MouseEvent& e )
+{
+ const ::osl::MutexGuard aGuard( maMutex );
+ const SolarMutexGuard aAppGuard;
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ), 0, MouseEventModifiers::NONE, e.Buttons, e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseMove, reinterpret_cast< vcl::Window* >( mpNotifyWindow.get() ), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::focusGained( const css::awt::FocusEvent& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::focusLost( const css::awt::FocusEvent& )
+{
+}
+
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediaevent_impl.hxx b/avmedia/source/viewer/mediaevent_impl.hxx
new file mode 100644
index 000000000..9c864ecff
--- /dev/null
+++ b/avmedia/source/viewer/mediaevent_impl.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <avmedia/mediawindow.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/awt/XKeyListener.hpp>
+#include <com/sun/star/awt/XMouseListener.hpp>
+#include <com/sun/star/awt/XMouseMotionListener.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <vcl/vclptr.hxx>
+
+namespace avmedia
+{
+ namespace priv
+ {
+
+ // - MediaEventListenersImpl -
+
+ class MediaEventListenersImpl : public ::cppu::WeakImplHelper< css::awt::XKeyListener,
+ css::awt::XMouseListener,
+ css::awt::XMouseMotionListener,
+ css::awt::XFocusListener >
+ {
+ public:
+
+ explicit MediaEventListenersImpl( vcl::Window& rNotifyWindow );
+ virtual ~MediaEventListenersImpl() override;
+
+ void cleanUp();
+
+ protected:
+
+ // XKeyListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ virtual void SAL_CALL keyPressed( const css::awt::KeyEvent& e ) override;
+ virtual void SAL_CALL keyReleased( const css::awt::KeyEvent& e ) override;
+
+ // XMouseListener
+ virtual void SAL_CALL mousePressed( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseReleased( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseEntered( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseExited( const css::awt::MouseEvent& e ) override;
+
+ // XMouseMotionListener
+ virtual void SAL_CALL mouseDragged( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseMoved( const css::awt::MouseEvent& e ) override;
+
+ // XFocusListener
+ virtual void SAL_CALL focusGained( const css::awt::FocusEvent& e ) override;
+ virtual void SAL_CALL focusLost( const css::awt::FocusEvent& e ) override;
+
+ private:
+
+ VclPtr<vcl::Window> mpNotifyWindow;
+ mutable ::osl::Mutex maMutex;
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediawindow.cxx b/avmedia/source/viewer/mediawindow.cxx
new file mode 100644
index 000000000..e823c2e8d
--- /dev/null
+++ b/avmedia/source/viewer/mediawindow.cxx
@@ -0,0 +1,404 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <avmedia/mediawindow.hxx>
+#include "mediawindow_impl.hxx"
+#include <mediamisc.hxx>
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <tools/urlobj.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <memory>
+#include <sal/log.hxx>
+
+#define AVMEDIA_FRAMEGRABBER_DEFAULTFRAME_MEDIATIME 3.0
+
+using namespace ::com::sun::star;
+
+namespace avmedia {
+
+MediaWindow::MediaWindow( vcl::Window* parent, bool bInternalMediaControl ) :
+ mpImpl( VclPtr<priv::MediaWindowImpl>::Create( parent, this, bInternalMediaControl ) )
+{
+ mpImpl->Show();
+}
+
+
+MediaWindow::~MediaWindow()
+{
+ mpImpl.disposeAndClear();
+}
+
+
+void MediaWindow::setURL( const OUString& rURL, const OUString& rReferer )
+{
+ mpImpl->setURL( rURL, OUString(), rReferer );
+}
+
+
+const OUString& MediaWindow::getURL() const
+{
+ return mpImpl->getURL();
+}
+
+
+bool MediaWindow::isValid() const
+{
+ return mpImpl->isValid();
+}
+
+
+void MediaWindow::MouseMove( const MouseEvent& )
+{
+}
+
+
+void MediaWindow::MouseButtonDown( const MouseEvent& )
+{
+}
+
+
+void MediaWindow::MouseButtonUp( const MouseEvent& )
+{
+}
+
+
+void MediaWindow::KeyInput( const KeyEvent& )
+{
+}
+
+
+void MediaWindow::KeyUp( const KeyEvent& )
+{
+}
+
+void MediaWindow::Command( const CommandEvent& )
+{
+}
+
+
+sal_Int8 MediaWindow::AcceptDrop( const AcceptDropEvent& )
+{
+ return 0;
+}
+
+
+sal_Int8 MediaWindow::ExecuteDrop( const ExecuteDropEvent& )
+{
+ return 0;
+}
+
+
+void MediaWindow::StartDrag( sal_Int8, const Point& )
+{
+}
+
+
+Size MediaWindow::getPreferredSize() const
+{
+ return mpImpl->getPreferredSize();
+}
+
+
+void MediaWindow::setPosSize( const tools::Rectangle& rNewRect )
+{
+ mpImpl->setPosSize( rNewRect );
+}
+
+
+void MediaWindow::setPointer( PointerStyle nPointer )
+{
+ mpImpl->setPointer( nPointer );
+}
+
+
+bool MediaWindow::start()
+{
+ return mpImpl->start();
+}
+
+
+void MediaWindow::updateMediaItem( MediaItem& rItem ) const
+{
+ mpImpl->updateMediaItem( rItem );
+}
+
+
+void MediaWindow::executeMediaItem( const MediaItem& rItem )
+{
+ mpImpl->executeMediaItem( rItem );
+}
+
+
+void MediaWindow::show()
+{
+ mpImpl->Show();
+}
+
+
+void MediaWindow::hide()
+{
+ mpImpl->Hide();
+}
+
+
+vcl::Window* MediaWindow::getWindow() const
+{
+ return mpImpl.get();
+}
+
+
+FilterNameVector MediaWindow::getMediaFilters()
+{
+ return {{"Advanced Audio Coding", "aac"},
+ {"AIF Audio", "aif;aiff"},
+ {"Advanced Systems Format", "asf;wma;wmv"},
+ {"AU Audio", "au"},
+ {"AC3 Audio", "ac3"},
+ {"AVI", "avi"},
+ {"CD Audio", "cda"},
+ {"Digital Video", "dv"},
+ {"FLAC Audio", "flac"},
+ {"Flash Video", "flv"},
+ {"Matroska Media", "mkv"},
+ {"MIDI Audio", "mid;midi"},
+ {"MPEG Audio", "mp2;mp3;mpa;m4a"},
+ {"MPEG Video", "mpg;mpeg;mpv;mp4;m4v"},
+ {"Ogg Audio", "ogg;oga;opus"},
+ {"Ogg Video", "ogv;ogx"},
+ {"Real Audio", "ra"},
+ {"Real Media", "rm"},
+ {"RMI MIDI Audio", "rmi"},
+ {"SND (SouND) Audio", "snd"},
+ {"Quicktime Video", "mov"},
+ {"Vivo Video", "viv"},
+ {"WAVE Audio", "wav"},
+ {"WebM Video", "webm"},
+ {"Windows Media Audio", "wma"},
+ {"Windows Media Video", "wmv"}};
+}
+
+
+bool MediaWindow::executeMediaURLDialog(weld::Window* pParent, OUString& rURL, bool *const o_pbLink)
+{
+ ::sfx2::FileDialogHelper aDlg(o_pbLink != nullptr
+ ? ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW
+ : ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, pParent);
+ static const char aWildcard[] = "*.";
+ FilterNameVector aFilters = getMediaFilters();
+ static const char aSeparator[] = ";";
+ OUStringBuffer aAllTypes;
+
+ aDlg.SetTitle( AvmResId( o_pbLink != nullptr
+ ? AVMEDIA_STR_INSERTMEDIA_DLG : AVMEDIA_STR_OPENMEDIA_DLG ) );
+
+ for( FilterNameVector::size_type i = 0; i < aFilters.size(); ++i )
+ {
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ if( !aAllTypes.isEmpty() )
+ aAllTypes.append(aSeparator);
+
+ aAllTypes.append(aWildcard).append(aFilters[ i ].second.getToken( 0, ';', nIndex ));
+ }
+ }
+
+ // add filter for all media types
+ aDlg.AddFilter( AvmResId( AVMEDIA_STR_ALL_MEDIAFILES ), aAllTypes.makeStringAndClear() );
+
+ for( FilterNameVector::size_type i = 0; i < aFilters.size(); ++i )
+ {
+ OUStringBuffer aTypes;
+
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ if( !aTypes.isEmpty() )
+ aTypes.append(aSeparator);
+
+ aTypes.append(aWildcard).append(aFilters[ i ].second.getToken( 0, ';', nIndex ));
+ }
+
+ // add single filters
+ aDlg.AddFilter( aFilters[ i ].first, aTypes.makeStringAndClear() );
+ }
+
+ // add filter for all types
+ aDlg.AddFilter( AvmResId( AVMEDIA_STR_ALL_FILES ), "*.*" );
+
+ uno::Reference<ui::dialogs::XFilePicker3> const xFP(aDlg.GetFilePicker());
+ uno::Reference<ui::dialogs::XFilePickerControlAccess> const xCtrlAcc(xFP,
+ uno::UNO_QUERY_THROW);
+ if (o_pbLink != nullptr)
+ {
+ // for video link should be the default
+ xCtrlAcc->setValue(
+ ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK, 0,
+ uno::Any(true) );
+ // disabled for now: TODO: preview?
+ xCtrlAcc->enableControl(
+ ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW,
+ false);
+ }
+
+ if( aDlg.Execute() == ERRCODE_NONE )
+ {
+ const INetURLObject aURL( aDlg.GetPath() );
+ rURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+
+ if (o_pbLink != nullptr)
+ {
+ uno::Any const any = xCtrlAcc->getValue(
+ ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK, 0);
+ if (!(any >>= *o_pbLink))
+ {
+ SAL_WARN("avmedia", "invalid link property");
+ *o_pbLink = true;
+ }
+ }
+ }
+ else if( !rURL.isEmpty() )
+ rURL.clear();
+
+ return !rURL.isEmpty();
+}
+
+void MediaWindow::executeFormatErrorBox(weld::Window* pParent)
+{
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Warning, VclButtonsType::Ok, AvmResId(AVMEDIA_STR_ERR_URL)));
+ xBox->run();
+}
+
+bool MediaWindow::isMediaURL( const OUString& rURL, const OUString& rReferer, bool bDeep, Size* pPreferredSizePixel )
+{
+ const INetURLObject aURL( rURL );
+
+ if( aURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ if( bDeep || pPreferredSizePixel )
+ {
+ try
+ {
+ uno::Reference< media::XPlayer > xPlayer( priv::MediaWindowImpl::createPlayer(
+ aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ),
+ rReferer, nullptr ) );
+
+ if( xPlayer.is() )
+ {
+ if( pPreferredSizePixel )
+ {
+ const awt::Size aAwtSize( xPlayer->getPreferredPlayerWindowSize() );
+
+ pPreferredSizePixel->setWidth( aAwtSize.Width );
+ pPreferredSizePixel->setHeight( aAwtSize.Height );
+ }
+
+ return true;
+ }
+ }
+ catch( ... )
+ {
+ }
+ }
+ else
+ {
+ FilterNameVector aFilters = getMediaFilters();
+ const OUString aExt( aURL.getExtension() );
+
+ for( FilterNameVector::size_type i = 0; i < aFilters.size(); ++i )
+ {
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ if( aExt.equalsIgnoreAsciiCase( aFilters[ i ].second.getToken( 0, ';', nIndex ) ) )
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+
+uno::Reference< media::XPlayer > MediaWindow::createPlayer( const OUString& rURL, const OUString& rReferer, const OUString* pMimeType )
+{
+ return priv::MediaWindowImpl::createPlayer( rURL, rReferer, pMimeType );
+}
+
+
+uno::Reference< graphic::XGraphic > MediaWindow::grabFrame( const OUString& rURL,
+ const OUString& rReferer,
+ const OUString& sMimeType )
+{
+ uno::Reference< media::XPlayer > xPlayer( createPlayer( rURL, rReferer, &sMimeType ) );
+ uno::Reference< graphic::XGraphic > xRet;
+ std::unique_ptr< Graphic > xGraphic;
+
+ if( xPlayer.is() )
+ {
+ uno::Reference< media::XFrameGrabber > xGrabber( xPlayer->createFrameGrabber() );
+
+ if( xGrabber.is() )
+ {
+ double fMediaTime = AVMEDIA_FRAMEGRABBER_DEFAULTFRAME_MEDIATIME;
+
+ if( fMediaTime >= xPlayer->getDuration() )
+ fMediaTime = ( xPlayer->getDuration() * 0.5 );
+
+ xRet = xGrabber->grabFrame( fMediaTime );
+ }
+
+ if( !xRet.is() )
+ {
+ awt::Size aPrefSize( xPlayer->getPreferredPlayerWindowSize() );
+
+ if( !aPrefSize.Width && !aPrefSize.Height )
+ {
+ const BitmapEx aBmpEx(AVMEDIA_BMP_AUDIOLOGO);
+ xGraphic.reset( new Graphic( aBmpEx ) );
+ }
+ }
+ }
+
+ if (!xRet.is() && !xGraphic)
+ {
+ const BitmapEx aBmpEx(AVMEDIA_BMP_EMPTYLOGO);
+ xGraphic.reset( new Graphic( aBmpEx ) );
+ }
+
+ if (xGraphic)
+ xRet = xGraphic->GetXGraphic();
+
+ return xRet;
+}
+
+
+} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediawindow_impl.cxx b/avmedia/source/viewer/mediawindow_impl.cxx
new file mode 100644
index 000000000..98f867e4e
--- /dev/null
+++ b/avmedia/source/viewer/mediawindow_impl.cxx
@@ -0,0 +1,671 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <iostream>
+#include "mediawindow_impl.hxx"
+#include "mediaevent_impl.hxx"
+#include <mediamisc.hxx>
+#include <bitmaps.hlst>
+#include <helpids.h>
+
+#include <algorithm>
+
+#include <sal/log.hxx>
+#include <comphelper/processfactory.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <unotools/securityoptions.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ptrstyle.hxx>
+
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/media/XManager.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+using namespace ::com::sun::star;
+
+namespace avmedia::priv {
+
+MediaWindowControl::MediaWindowControl(vcl::Window* pParent)
+ : MediaControl(pParent, MEDIACONTROLSTYLE_MULTILINE)
+{
+}
+
+void MediaWindowControl::update()
+{
+ MediaItem aItem;
+
+ static_cast< MediaWindowImpl* >( GetParent() )->updateMediaItem( aItem );
+ setState(aItem);
+}
+
+void MediaWindowControl::execute(const MediaItem& rItem)
+{
+ static_cast<MediaWindowImpl*>(GetParent())->executeMediaItem(rItem);
+}
+
+MediaChildWindow::MediaChildWindow(vcl::Window* pParent)
+ : SystemChildWindow(pParent, WB_CLIPCHILDREN)
+{
+}
+
+void MediaChildWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ SystemChildWindow::MouseMove( rMEvt );
+ GetParent()->MouseMove( aTransformedEvent );
+}
+
+void MediaChildWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ SystemChildWindow::MouseButtonDown( rMEvt );
+ GetParent()->MouseButtonDown( aTransformedEvent );
+}
+
+void MediaChildWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ SystemChildWindow::MouseButtonUp( rMEvt );
+ GetParent()->MouseButtonUp( aTransformedEvent );
+}
+
+void MediaChildWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ SystemChildWindow::KeyInput( rKEvt );
+ GetParent()->KeyInput( rKEvt );
+}
+
+void MediaChildWindow::KeyUp( const KeyEvent& rKEvt )
+{
+ SystemChildWindow::KeyUp( rKEvt );
+ GetParent()->KeyUp( rKEvt );
+}
+
+void MediaChildWindow::Command( const CommandEvent& rCEvt )
+{
+ const CommandEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rCEvt.GetMousePosPixel() ) ),
+ rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData() );
+
+ SystemChildWindow::Command( rCEvt );
+ GetParent()->Command( aTransformedEvent );
+}
+
+MediaWindowImpl::MediaWindowImpl(vcl::Window* pParent, MediaWindow* pMediaWindow, bool bInternalMediaControl)
+ : Control(pParent)
+ , DropTargetHelper(this)
+ , DragSourceHelper(this)
+ , mpMediaWindow(pMediaWindow)
+ , mpMediaWindowControl(bInternalMediaControl ? VclPtr<MediaWindowControl>::Create(this) : nullptr)
+{
+ if (mpMediaWindowControl)
+ {
+ mpMediaWindowControl->SetSizePixel(mpMediaWindowControl->GetOptimalSize());
+ mpMediaWindowControl->Show();
+ }
+}
+
+MediaWindowImpl::~MediaWindowImpl()
+{
+ disposeOnce();
+}
+
+void MediaWindowImpl::dispose()
+{
+ if (mxEvents.is())
+ mxEvents->cleanUp();
+
+ if (mxPlayerWindow.is())
+ {
+ auto pEventsIf = static_cast<cppu::OWeakObject*>(mxEvents.get());
+ mxPlayerWindow->removeKeyListener( uno::Reference< awt::XKeyListener >( pEventsIf, uno::UNO_QUERY ) );
+ mxPlayerWindow->removeMouseListener( uno::Reference< awt::XMouseListener >( pEventsIf, uno::UNO_QUERY ) );
+ mxPlayerWindow->removeMouseMotionListener( uno::Reference< awt::XMouseMotionListener >( pEventsIf, uno::UNO_QUERY ) );
+ mxPlayerWindow->dispose();
+ mxPlayerWindow.clear();
+ }
+
+ uno::Reference< lang::XComponent > xComponent( mxPlayer, uno::UNO_QUERY );
+ if (xComponent.is()) // this stops the player
+ xComponent->dispose();
+
+ mxPlayer.clear();
+
+ mpMediaWindow = nullptr;
+
+ mpEmptyBmpEx.reset();
+ mpAudioBmpEx.reset();
+ mpMediaWindowControl.disposeAndClear();
+ mpChildWindow.disposeAndClear();
+
+ Control::dispose();
+}
+
+uno::Reference<media::XPlayer> MediaWindowImpl::createPlayer(const OUString& rURL, const OUString& rReferer, const OUString* pMimeType)
+{
+ uno::Reference<media::XPlayer> xPlayer;
+
+ if( rURL.isEmpty() )
+ return xPlayer;
+
+ if (SvtSecurityOptions().isUntrustedReferer(rReferer))
+ {
+ return xPlayer;
+ }
+
+ if (!pMimeType || *pMimeType == AVMEDIA_MIMETYPE_COMMON)
+ {
+ uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+
+ static OUStringLiteral aServiceManagers[] =
+ {
+ AVMEDIA_MANAGER_SERVICE_PREFERRED,
+ AVMEDIA_MANAGER_SERVICE_NAME,
+ };
+
+ for (const auto& rServiceName : aServiceManagers)
+ {
+ xPlayer = createPlayer(rURL, rServiceName, xContext);
+ if (xPlayer)
+ break;
+ }
+ }
+
+ return xPlayer;
+}
+
+uno::Reference< media::XPlayer > MediaWindowImpl::createPlayer(
+ const OUString& rURL, const OUString& rManagerServName,
+ const uno::Reference< uno::XComponentContext >& xContext)
+{
+ uno::Reference< media::XPlayer > xPlayer;
+ try
+ {
+ uno::Reference< media::XManager > xManager (
+ xContext->getServiceManager()->createInstanceWithContext(rManagerServName, xContext),
+ uno::UNO_QUERY );
+ if( xManager.is() )
+ xPlayer = xManager->createPlayer( rURL );
+ else
+ SAL_INFO( "avmedia", "failed to create media player service " << rManagerServName );
+ } catch ( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION( "avmedia", "couldn't create media player " << rManagerServName);
+ }
+ return xPlayer;
+}
+
+void MediaWindowImpl::setURL( const OUString& rURL,
+ OUString const& rTempURL, OUString const& rReferer)
+{
+ maReferer = rReferer;
+ if( rURL == getURL() )
+ return;
+
+ if( mxPlayer.is() )
+ mxPlayer->stop();
+
+ if( mxPlayerWindow.is() )
+ {
+ mxPlayerWindow->setVisible( false );
+ mxPlayerWindow.clear();
+ }
+
+ mxPlayer.clear();
+ mTempFileURL.clear();
+
+ if (!rTempURL.isEmpty())
+ {
+ maFileURL = rURL;
+ mTempFileURL = rTempURL;
+ }
+ else
+ {
+ INetURLObject aURL( rURL );
+
+ if (aURL.GetProtocol() != INetProtocol::NotValid)
+ maFileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
+ else
+ maFileURL = rURL;
+ }
+
+ mxPlayer = createPlayer((!mTempFileURL.isEmpty()) ? mTempFileURL : maFileURL, rReferer, &m_sMimeType );
+ onURLChanged();
+}
+
+const OUString& MediaWindowImpl::getURL() const
+{
+ return maFileURL;
+}
+
+bool MediaWindowImpl::isValid() const
+{
+ return mxPlayer.is();
+}
+
+Size MediaWindowImpl::getPreferredSize() const
+{
+ Size aRet(480, 360);
+
+ if( mxPlayer.is() )
+ {
+ awt::Size aPrefSize( mxPlayer->getPreferredPlayerWindowSize() );
+
+ aRet.setWidth( aPrefSize.Width );
+ aRet.setHeight( aPrefSize.Height );
+ }
+
+ return aRet;
+}
+
+bool MediaWindowImpl::start()
+{
+ return mxPlayer.is() && ( mxPlayer->start(), true );
+}
+
+void MediaWindowImpl::updateMediaItem( MediaItem& rItem ) const
+{
+ if( isPlaying() )
+ rItem.setState( MediaState::Play );
+ else
+ rItem.setState( ( getMediaTime() == 0.0 ) ? MediaState::Stop : MediaState::Pause );
+
+ rItem.setDuration( getDuration() );
+ rItem.setTime( getMediaTime() );
+ rItem.setLoop( mxPlayer.is() && mxPlayer->isPlaybackLoop() );
+ rItem.setMute( mxPlayer.is() && mxPlayer->isMute() );
+ rItem.setVolumeDB( mxPlayer.is() ? mxPlayer->getVolumeDB() : 0 );
+ rItem.setZoom( mxPlayerWindow.is() ? mxPlayerWindow->getZoomLevel() : media::ZoomLevel_NOT_AVAILABLE );
+ rItem.setURL( getURL(), mTempFileURL, maReferer );
+}
+
+void MediaWindowImpl::executeMediaItem( const MediaItem& rItem )
+{
+ const AVMediaSetMask nMaskSet = rItem.getMaskSet();
+
+ // set URL first
+ if (nMaskSet & AVMediaSetMask::URL)
+ {
+ m_sMimeType = rItem.getMimeType();
+ setURL(rItem.getURL(), rItem.getTempURL(), rItem.getReferer());
+ }
+
+ // set different states next
+ if (nMaskSet & AVMediaSetMask::TIME)
+ setMediaTime(std::min(rItem.getTime(), getDuration()));
+
+ if (nMaskSet & AVMediaSetMask::LOOP && mxPlayer.is() )
+ mxPlayer->setPlaybackLoop( rItem.isLoop() );
+
+ if (nMaskSet & AVMediaSetMask::MUTE && mxPlayer.is() )
+ mxPlayer->setMute( rItem.isMute() );
+
+ if (nMaskSet & AVMediaSetMask::VOLUMEDB && mxPlayer.is() )
+ mxPlayer->setVolumeDB( rItem.getVolumeDB() );
+
+ if (nMaskSet & AVMediaSetMask::ZOOM && mxPlayerWindow.is() )
+ mxPlayerWindow->setZoomLevel( rItem.getZoom() );
+
+ // set play state at last
+ if (!(nMaskSet & AVMediaSetMask::STATE))
+ return;
+
+ switch (rItem.getState())
+ {
+ case MediaState::Play:
+ {
+ if (!isPlaying())
+ start();
+ }
+ break;
+
+ case MediaState::Pause:
+ {
+ if (isPlaying())
+ stop();
+ }
+ break;
+
+ case MediaState::Stop:
+ {
+ if (isPlaying())
+ {
+ setMediaTime( 0.0 );
+ stop();
+ setMediaTime( 0.0 );
+ }
+ }
+ break;
+ }
+}
+
+void MediaWindowImpl::stop()
+{
+ if( mxPlayer.is() )
+ mxPlayer->stop();
+}
+
+bool MediaWindowImpl::isPlaying() const
+{
+ return( mxPlayer.is() && mxPlayer->isPlaying() );
+}
+
+double MediaWindowImpl::getDuration() const
+{
+ return( mxPlayer.is() ? mxPlayer->getDuration() : 0.0 );
+}
+
+void MediaWindowImpl::setMediaTime( double fTime )
+{
+ if( mxPlayer.is() )
+ mxPlayer->setMediaTime( fTime );
+}
+
+double MediaWindowImpl::getMediaTime() const
+{
+ return( mxPlayer.is() ? mxPlayer->getMediaTime() : 0.0 );
+}
+
+void MediaWindowImpl::stopPlayingInternal(bool bStop)
+{
+ if (isPlaying())
+ {
+ bStop ? mxPlayer->stop() : mxPlayer->start();
+ }
+}
+
+void MediaWindowImpl::onURLChanged()
+{
+ if (m_sMimeType == AVMEDIA_MIMETYPE_COMMON)
+ {
+ mpChildWindow.disposeAndClear();
+ mpChildWindow.reset(VclPtr<MediaChildWindow>::Create(this));
+ }
+ if (!mpChildWindow)
+ return;
+ mpChildWindow->SetHelpId(HID_AVMEDIA_PLAYERWINDOW);
+ mxEvents = new MediaEventListenersImpl(*mpChildWindow);
+
+ if (mxPlayer.is())
+ {
+ Resize();
+ uno::Sequence<uno::Any> aArgs( 3 );
+ uno::Reference<media::XPlayerWindow> xPlayerWindow;
+ const Point aPoint;
+ const Size aSize(mpChildWindow->GetSizePixel());
+
+ aArgs[0] <<= mpChildWindow->GetParentWindowHandle();
+ aArgs[1] <<= awt::Rectangle(aPoint.X(), aPoint.Y(), aSize.Width(), aSize.Height());
+ aArgs[2] <<= reinterpret_cast<sal_IntPtr>(mpChildWindow.get());
+
+ try
+ {
+ xPlayerWindow = mxPlayer->createPlayerWindow( aArgs );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ // happens eg, on MacOSX where Java frames cannot be created from X11 window handles
+ }
+
+ mxPlayerWindow = xPlayerWindow;
+
+ if( xPlayerWindow.is() )
+ {
+ auto pEventsIf = static_cast<cppu::OWeakObject*>(mxEvents.get());
+ xPlayerWindow->addKeyListener( uno::Reference< awt::XKeyListener >( pEventsIf, uno::UNO_QUERY ) );
+ xPlayerWindow->addMouseListener( uno::Reference< awt::XMouseListener >( pEventsIf, uno::UNO_QUERY ) );
+ xPlayerWindow->addMouseMotionListener( uno::Reference< awt::XMouseMotionListener >( pEventsIf, uno::UNO_QUERY ) );
+ xPlayerWindow->addFocusListener( uno::Reference< awt::XFocusListener >( pEventsIf, uno::UNO_QUERY ) );
+ }
+ }
+ else
+ mxPlayerWindow.clear();
+
+ if( mxPlayerWindow.is() )
+ mpChildWindow->Show();
+ else
+ mpChildWindow->Hide();
+
+ if( mpMediaWindowControl )
+ {
+ MediaItem aItem;
+
+ updateMediaItem( aItem );
+ mpMediaWindowControl->setState( aItem );
+ }
+}
+
+void MediaWindowImpl::setPosSize(const tools::Rectangle& rRect)
+{
+ SetPosSizePixel(rRect.TopLeft(), rRect.GetSize());
+}
+
+void MediaWindowImpl::setPointer(PointerStyle aPointer)
+{
+ SetPointer(aPointer);
+
+ if (mpChildWindow)
+ mpChildWindow->SetPointer(aPointer);
+
+ if (!mxPlayerWindow.is())
+ return;
+
+ long nPointer;
+
+ switch (aPointer)
+ {
+ case PointerStyle::Cross:
+ nPointer = awt::SystemPointer::CROSS;
+ break;
+ case PointerStyle::Hand:
+ nPointer = awt::SystemPointer::HAND;
+ break;
+ case PointerStyle::Move:
+ nPointer = awt::SystemPointer::MOVE;
+ break;
+ case PointerStyle::Wait:
+ nPointer = awt::SystemPointer::WAIT;
+ break;
+ default:
+ nPointer = awt::SystemPointer::ARROW;
+ break;
+ }
+
+ mxPlayerWindow->setPointerType(nPointer);
+}
+
+void MediaWindowImpl::Resize()
+{
+ const Size aCurSize(GetOutputSizePixel());
+ const sal_Int32 nOffset(mpMediaWindowControl ? AVMEDIA_CONTROLOFFSET : 0);
+
+ Size aPlayerWindowSize(aCurSize.Width() - (nOffset << 1),
+ aCurSize.Height() - (nOffset << 1));
+
+ if (mpMediaWindowControl)
+ {
+ const sal_Int32 nControlHeight = mpMediaWindowControl->GetSizePixel().Height();
+ const sal_Int32 nControlY = std::max(aCurSize.Height() - nControlHeight - nOffset, 0L);
+
+ aPlayerWindowSize.setHeight( nControlY - (nOffset << 1) );
+ mpMediaWindowControl->SetPosSizePixel(Point(nOffset, nControlY ), Size(aCurSize.Width() - (nOffset << 1), nControlHeight));
+ }
+ if (mpChildWindow)
+ mpChildWindow->SetPosSizePixel(Point(0, 0), aPlayerWindowSize);
+
+ if (mxPlayerWindow.is())
+ mxPlayerWindow->setPosSize(0, 0, aPlayerWindowSize.Width(), aPlayerWindowSize.Height(), 0);
+}
+
+void MediaWindowImpl::StateChanged(StateChangedType eType)
+{
+ if (!mxPlayerWindow.is())
+ return;
+
+ // stop playing when going disabled or hidden
+ switch (eType)
+ {
+ case StateChangedType::Visible:
+ {
+ stopPlayingInternal(!IsVisible());
+ mxPlayerWindow->setVisible(IsVisible());
+ }
+ break;
+
+ case StateChangedType::Enable:
+ {
+ stopPlayingInternal(!IsEnabled());
+ mxPlayerWindow->setEnable(IsEnabled());
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MediaWindowImpl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ if (mxPlayerWindow.is())
+ mxPlayerWindow->update();
+
+ BitmapEx* pLogo = nullptr;
+
+ if (!mxPlayer.is())
+ {
+ if (!mpEmptyBmpEx)
+ mpEmptyBmpEx.reset(new BitmapEx(AVMEDIA_BMP_EMPTYLOGO));
+
+ pLogo = mpEmptyBmpEx.get();
+ }
+ else if (!mxPlayerWindow.is())
+ {
+ if (!mpAudioBmpEx)
+ mpAudioBmpEx.reset(new BitmapEx(AVMEDIA_BMP_AUDIOLOGO));
+
+ pLogo = mpAudioBmpEx.get();
+ }
+
+ if (!mpChildWindow)
+ return;
+
+ const Point aBasePos(mpChildWindow->GetPosPixel());
+ const tools::Rectangle aVideoRect(aBasePos, mpChildWindow->GetSizePixel());
+
+ if (!(pLogo && !pLogo->IsEmpty() && !aVideoRect.IsEmpty()))
+ return;
+
+ Size aLogoSize(pLogo->GetSizePixel());
+ const Color aBackgroundColor(67, 67, 67);
+
+ rRenderContext.SetLineColor(aBackgroundColor);
+ rRenderContext.SetFillColor(aBackgroundColor);
+ rRenderContext.DrawRect(aVideoRect);
+
+ if ((aLogoSize.Width() > aVideoRect.GetWidth() || aLogoSize.Height() > aVideoRect.GetHeight() ) &&
+ (aLogoSize.Height() > 0))
+ {
+ const double fLogoWH = double(aLogoSize.Width()) / aLogoSize.Height();
+
+ if (fLogoWH < (double(aVideoRect.GetWidth()) / aVideoRect.GetHeight()))
+ {
+ aLogoSize.setWidth( long(aVideoRect.GetHeight() * fLogoWH) );
+ aLogoSize.setHeight( aVideoRect.GetHeight() );
+ }
+ else
+ {
+ aLogoSize.setWidth( aVideoRect.GetWidth() );
+ aLogoSize.setHeight( long(aVideoRect.GetWidth() / fLogoWH) );
+ }
+ }
+
+ Point aPoint(aBasePos.X() + ((aVideoRect.GetWidth() - aLogoSize.Width()) >> 1),
+ aBasePos.Y() + ((aVideoRect.GetHeight() - aLogoSize.Height()) >> 1));
+
+ rRenderContext.DrawBitmapEx(aPoint, aLogoSize, *pLogo);
+}
+
+void MediaWindowImpl::GetFocus()
+{
+}
+
+void MediaWindowImpl::MouseMove(const MouseEvent& rMEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->MouseMove(rMEvt);
+}
+
+void MediaWindowImpl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->MouseButtonDown(rMEvt);
+}
+
+void MediaWindowImpl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->MouseButtonUp(rMEvt);
+}
+
+void MediaWindowImpl::KeyInput(const KeyEvent& rKEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->KeyInput(rKEvt);
+}
+
+void MediaWindowImpl::KeyUp(const KeyEvent& rKEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->KeyUp(rKEvt);
+}
+
+void MediaWindowImpl::Command(const CommandEvent& rCEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->Command(rCEvt);
+}
+
+sal_Int8 MediaWindowImpl::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ return (mpMediaWindow ? mpMediaWindow->AcceptDrop(rEvt) : 0);
+}
+
+sal_Int8 MediaWindowImpl::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ return (mpMediaWindow ? mpMediaWindow->ExecuteDrop(rEvt) : 0);
+}
+
+void MediaWindowImpl::StartDrag(sal_Int8 nAction, const Point& rPosPixel)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->StartDrag(nAction, rPosPixel);
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediawindow_impl.hxx b/avmedia/source/viewer/mediawindow_impl.hxx
new file mode 100644
index 000000000..8bceebb08
--- /dev/null
+++ b/avmedia/source/viewer/mediawindow_impl.hxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <vcl/syschild.hxx>
+
+#include <mediacontrol.hxx>
+
+namespace com::sun::star::media {
+ class XPlayer;
+ class XPlayerWindow;
+}
+
+namespace com::sun::star::uno {
+ class XComponentContext;
+}
+
+class BitmapEx;
+
+namespace avmedia
+{
+
+class MediaWindow;
+
+namespace priv
+{
+
+class MediaWindowControl : public MediaControl
+{
+public:
+
+ explicit MediaWindowControl( vcl::Window* pParent );
+
+protected:
+
+ void update() override;
+ void execute( const MediaItem& rItem ) override;
+};
+
+class MediaChildWindow : public SystemChildWindow
+{
+public:
+
+ explicit MediaChildWindow( vcl::Window* pParent );
+
+protected:
+
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void KeyUp( const KeyEvent& rKEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+};
+
+class MediaEventListenersImpl;
+
+class MediaWindowImpl : public Control, public DropTargetHelper, public DragSourceHelper
+{
+public:
+ MediaWindowImpl(vcl::Window* parent, MediaWindow* pMediaWindow, bool bInternalMediaControl);
+ virtual ~MediaWindowImpl() override;
+
+ virtual void dispose() override;
+
+ static css::uno::Reference<css::media::XPlayer> createPlayer(const OUString& rURL, const OUString& rReferer, const OUString* pMimeType);
+
+ void setURL(const OUString& rURL, OUString const& rTempURL, OUString const& rReferer);
+
+ const OUString& getURL() const;
+
+ bool isValid() const;
+
+ Size getPreferredSize() const;
+
+ bool start();
+
+ void updateMediaItem( MediaItem& rItem ) const;
+ void executeMediaItem( const MediaItem& rItem );
+
+ void setPosSize( const tools::Rectangle& rRect );
+
+ void setPointer( PointerStyle nPointer );
+
+private:
+
+ // Window
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void KeyUp( const KeyEvent& rKEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void Resize() override;
+ virtual void StateChanged( StateChangedType ) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override; // const
+ virtual void GetFocus() override;
+
+ // DropTargetHelper
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ // DragSourceHelper
+ virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
+
+ void stop();
+
+ bool isPlaying() const;
+
+ double getDuration() const;
+
+ void setMediaTime( double fTime );
+ double getMediaTime() const;
+
+ void stopPlayingInternal( bool );
+
+ void onURLChanged();
+
+ static css::uno::Reference<css::media::XPlayer> createPlayer(const OUString& rURL, const OUString& rManagerServName,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext);
+
+ OUString maFileURL;
+ OUString mTempFileURL;
+ OUString maReferer;
+ OUString m_sMimeType;
+ css::uno::Reference<css::media::XPlayer> mxPlayer;
+ css::uno::Reference<css::media::XPlayerWindow> mxPlayerWindow;
+ MediaWindow* mpMediaWindow;
+
+ rtl::Reference<MediaEventListenersImpl> mxEvents;
+ VclPtr<MediaChildWindow> mpChildWindow;
+ VclPtr<MediaWindowControl> mpMediaWindowControl;
+ std::unique_ptr<BitmapEx> mpEmptyBmpEx;
+ std::unique_ptr<BitmapEx> mpAudioBmpEx;
+};
+
+}} // end namespace avmedia::priv
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/avmediavlc.component b/avmedia/source/vlc/avmediavlc.component
new file mode 100644
index 000000000..cbdba1d03
--- /dev/null
+++ b/avmedia/source/vlc/avmediavlc.component
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+-->
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ prefix="avmediavlc" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.media.Manager_VLC">
+ <service name="com.sun.star.comp.avmedia.Manager_VLC"/>
+ </implementation>
+</component>
diff --git a/avmedia/source/vlc/inc/wrapper/Common.hxx b/avmedia/source/vlc/inc/wrapper/Common.hxx
new file mode 100644
index 000000000..c9b7f9682
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/Common.hxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+ class Common
+ {
+ public:
+ static bool LoadSymbols();
+ static const char* Version();
+ static const char* LastErrorMessage();
+ };
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/inc/wrapper/EventHandler.hxx b/avmedia/source/vlc/inc/wrapper/EventHandler.hxx
new file mode 100644
index 000000000..955c83478
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/EventHandler.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <functional>
+#include <salhelper/thread.hxx>
+#include <wrapper/ThreadsafeQueue.hxx>
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+ class EventHandler : public ::osl::Thread
+ {
+ public:
+ EventHandler(const EventHandler&) = delete;
+ const EventHandler& operator=(const EventHandler&) = delete;
+
+ EventHandler();
+ void stop();
+
+ protected:
+ virtual void SAL_CALL run() override;
+
+ public:
+ typedef std::function< void() > TCallback;
+ ThreadsafeQueue< TCallback > mCallbackQueue;
+ };
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/inc/wrapper/EventManager.hxx b/avmedia/source/vlc/inc/wrapper/EventManager.hxx
new file mode 100644
index 000000000..9a8515483
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/EventManager.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <functional>
+#include <wrapper/Player.hxx>
+
+struct libvlc_event_manager_t;
+struct libvlc_event_t;
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+ class EventHandler;
+ class EventManager
+ {
+
+ public:
+ EventManager(const EventManager&) = delete;
+ const EventManager& operator=(const EventManager&) = delete;
+
+ static bool LoadSymbols();
+ typedef std::function<void()> Callback;
+
+ EventManager( Player& player, EventHandler& eh );
+
+ void onPaused( const Callback& callback = Callback() );
+ void onEndReached( const Callback& callback = Callback() );
+
+ private:
+ EventHandler& mEventHandler;
+ typedef std::function< void() > TCallback;
+ libvlc_event_manager_t *mManager;
+ TCallback mOnPaused;
+ TCallback mOnEndReached;
+
+ void registerSignal( int signal, const Callback& callback );
+
+ static void Handler( const libvlc_event_t *event, void *pData );
+ };
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/inc/wrapper/Instance.hxx b/avmedia/source/vlc/inc/wrapper/Instance.hxx
new file mode 100644
index 000000000..7e4ba7741
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/Instance.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+struct libvlc_instance_t;
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+ class Instance
+ {
+ public:
+ static bool LoadSymbols();
+ Instance( int argc, const char * const argv[] );
+ Instance( const Instance& other );
+ Instance& operator=( const Instance& other );
+ ~Instance();
+
+ operator libvlc_instance_t*()
+ {
+ return mInstance;
+ }
+
+ private:
+ libvlc_instance_t *mInstance;
+ };
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/inc/wrapper/Media.hxx b/avmedia/source/vlc/inc/wrapper/Media.hxx
new file mode 100644
index 000000000..288bb0d43
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/Media.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+struct libvlc_media_t;
+
+namespace rtl { class OUString; }
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+ class Instance;
+ class Media
+ {
+ public:
+ static bool LoadSymbols();
+ Media( const rtl::OUString& url, Instance& instance );
+ Media( const Media& other );
+ Media& operator=( const Media& other );
+
+ int getDuration() const;
+
+ ~Media();
+
+ operator libvlc_media_t*()
+ {
+ return mMedia;
+ }
+
+ private:
+ libvlc_media_t *mMedia;
+ };
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/inc/wrapper/Player.hxx b/avmedia/source/vlc/inc/wrapper/Player.hxx
new file mode 100644
index 000000000..a41e01b10
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/Player.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+#if defined UNX
+# include <stdint.h>
+#endif
+
+struct libvlc_media_player_t;
+
+namespace rtl
+{
+ class OUString;
+}
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+ class Media;
+ class Player
+ {
+ public:
+ static bool LoadSymbols();
+ explicit Player( Media& media );
+ Player( const Player& other );
+ Player& operator=( const Player& other );
+ ~Player();
+
+ bool play();
+ void pause();
+ void stop();
+ void setTime( int time );
+ int getTime() const;
+ bool isPlaying() const;
+
+ void setVolume( int volume );
+ int getVolume() const;
+
+ void setMute( bool mute);
+ bool getMute() const;
+
+ void setWindow( intptr_t id );
+
+ void takeSnapshot(const rtl::OUString& file);
+
+ bool hasVout() const;
+
+ void setScale( float factor );
+ void setVideoSize( unsigned width, unsigned height );
+
+ operator libvlc_media_player_t*()
+ {
+ return mPlayer;
+ }
+
+ void setMouseHandling(bool flag);
+ private:
+ libvlc_media_player_t *mPlayer;
+ };
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/inc/wrapper/ThreadsafeQueue.hxx b/avmedia/source/vlc/inc/wrapper/ThreadsafeQueue.hxx
new file mode 100644
index 000000000..f8eb480dd
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/ThreadsafeQueue.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+#pragma once
+#include <queue>
+#include <iostream>
+#include <osl/mutex.hxx>
+#include <osl/conditn.hxx>
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+template<class T>
+class ThreadsafeQueue
+{
+public:
+ ThreadsafeQueue(const ThreadsafeQueue&) = delete;
+ const ThreadsafeQueue& operator=(const ThreadsafeQueue&) = delete;
+
+ ThreadsafeQueue();
+
+ void push( const T& data );
+ void pop( T& data );
+
+private:
+ std::queue< T > mQueue;
+ mutable ::osl::Mutex mMutex;
+ ::osl::Condition mCondition;
+};
+
+template<class T>
+ThreadsafeQueue<T>::ThreadsafeQueue()
+{
+}
+
+template<class T>
+void ThreadsafeQueue<T>::push( const T& data )
+{
+ ::osl::MutexGuard guard( mMutex );
+ mQueue.push( data );
+ mMutex.release();
+ mCondition.set();
+}
+
+template<class T>
+void ThreadsafeQueue<T>::pop( T& data )
+{
+ mCondition.wait();
+ ::osl::MutexGuard guard( mMutex );
+ while ( mQueue.empty() )
+ {
+ mMutex.release();
+ mCondition.wait();
+ mMutex.acquire();
+ }
+ data = mQueue.front();
+ mQueue.pop();
+}
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/inc/wrapper/Wrapper.hxx b/avmedia/source/vlc/inc/wrapper/Wrapper.hxx
new file mode 100644
index 000000000..c381ea8db
--- /dev/null
+++ b/avmedia/source/vlc/inc/wrapper/Wrapper.hxx
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <wrapper/Common.hxx>
+#include <wrapper/EventHandler.hxx>
+#include <wrapper/EventManager.hxx>
+#include <wrapper/Instance.hxx>
+#include <wrapper/Media.hxx>
+#include <wrapper/Player.hxx>
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlccommon.hxx b/avmedia/source/vlc/vlccommon.hxx
new file mode 100644
index 000000000..13719516b
--- /dev/null
+++ b/avmedia/source/vlc/vlccommon.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <osl/mutex.hxx>
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/factory.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/media/XManager.hpp>
+#include <com/sun/star/media/XPlayerWindow.hpp>
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcframegrabber.cxx b/avmedia/source/vlc/vlcframegrabber.cxx
new file mode 100644
index 000000000..034de4511
--- /dev/null
+++ b/avmedia/source/vlc/vlcframegrabber.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <chrono>
+#include <iostream>
+#include <osl/conditn.hxx>
+#include <osl/file.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/bitmapaccess.hxx>
+#include <vcl/pngread.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <tools/stream.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sal/log.hxx>
+
+#include "vlcframegrabber.hxx"
+#include "vlcplayer.hxx"
+#include <wrapper/Player.hxx>
+#include <wrapper/EventManager.hxx>
+
+using namespace ::com::sun::star;
+
+namespace avmedia::vlc {
+
+namespace
+{
+ const OUString AVMEDIA_VLC_GRABBER_IMPLEMENTATIONNAME = "com.sun.star.comp.avmedia.VLCFrameGrabber_VLC";
+ const OUString AVMEDIA_VLC_GRABBER_SERVICENAME = "com.sun.star.media.VLCFrameGrabber_VLC";
+ const int MSEC_IN_SEC = 1000;
+
+ const char * const VLC_ARGS[] = {
+ "-Vdummy",
+ "--demux",
+ "ffmpeg",
+ "--snapshot-format=png",
+ "--ffmpeg-threads", /* Is deprecated in 2.1.0 */
+ "--verbose=-1",
+ "--no-audio"
+ };
+}
+
+VLCFrameGrabber::VLCFrameGrabber( wrapper::EventHandler& eh, const OUString& url )
+ : FrameGrabber_BASE()
+ , mInstance( SAL_N_ELEMENTS(VLC_ARGS), VLC_ARGS )
+ , mMedia( url, mInstance )
+ , mPlayer( mMedia )
+ , mEventHandler( eh )
+{
+}
+
+::uno::Reference< css::graphic::XGraphic > SAL_CALL VLCFrameGrabber::grabFrame( double fMediaTime )
+{
+ osl::Condition condition;
+
+ const OUString& fileName = utl::TempFile::CreateTempName();
+ {
+ wrapper::EventManager manager( mPlayer, mEventHandler );
+ manager.onPaused([&condition](){ condition.set(); });
+
+ if ( !mPlayer.play() )
+ {
+ SAL_WARN("avmedia", "Couldn't play when trying to grab frame");
+ return ::uno::Reference< css::graphic::XGraphic >();
+ }
+
+ mPlayer.setTime( std::max(fMediaTime, 0.0) * MSEC_IN_SEC );
+ mPlayer.pause();
+
+ condition.wait(std::chrono::seconds(2));
+
+ if ( !mPlayer.hasVout() )
+ {
+ SAL_WARN("avmedia", "Couldn't grab frame");
+ manager.onPaused();
+ return ::uno::Reference< css::graphic::XGraphic >();
+ }
+
+ mPlayer.takeSnapshot( fileName );
+ mPlayer.stop();
+
+ manager.onPaused();
+ }
+
+ OUString url;
+ osl::FileBase::getFileURLFromSystemPath( fileName, url );
+ std::unique_ptr<SvStream> stream( utl::UcbStreamHelper::CreateStream( url,
+ StreamMode::STD_READ ) );
+
+ vcl::PNGReader reader( *stream );
+
+ const BitmapEx& bitmap = reader.Read();
+
+ return Graphic( bitmap ).GetXGraphic();
+}
+
+OUString SAL_CALL VLCFrameGrabber::getImplementationName()
+{
+ return AVMEDIA_VLC_GRABBER_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL VLCFrameGrabber::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+::uno::Sequence< OUString > SAL_CALL VLCFrameGrabber::getSupportedServiceNames()
+{
+ return { AVMEDIA_VLC_GRABBER_SERVICENAME };
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcframegrabber.hxx b/avmedia/source/vlc/vlcframegrabber.hxx
new file mode 100644
index 000000000..77684d6b9
--- /dev/null
+++ b/avmedia/source/vlc/vlcframegrabber.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/media/XFrameGrabber.hpp>
+#include <cppuhelper/implbase.hxx>
+#include "vlccommon.hxx"
+#include <wrapper/Wrapper.hxx>
+
+namespace avmedia {
+namespace vlc {
+
+typedef ::cppu::WeakImplHelper< css::media::XFrameGrabber,
+ css::lang::XServiceInfo > FrameGrabber_BASE;
+
+class VLCFrameGrabber : public FrameGrabber_BASE
+{
+ wrapper::Instance mInstance;
+ wrapper::Media mMedia;
+ wrapper::Player mPlayer;
+ wrapper::EventHandler& mEventHandler;
+public:
+ VLCFrameGrabber( wrapper::EventHandler& eh, const OUString& url );
+
+ css::uno::Reference< css::graphic::XGraphic > SAL_CALL grabFrame( double fMediaTime ) override;
+
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService( const OUString& serviceName ) override;
+ css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcmanager.cxx b/avmedia/source/vlc/vlcmanager.cxx
new file mode 100644
index 000000000..60c02b259
--- /dev/null
+++ b/avmedia/source/vlc/vlcmanager.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <sal/log.hxx>
+#include "vlcmanager.hxx"
+#include "vlcplayer.hxx"
+#include <wrapper/Instance.hxx>
+#include <wrapper/EventManager.hxx>
+#include <wrapper/Media.hxx>
+#include <wrapper/Player.hxx>
+#include <wrapper/Common.hxx>
+
+using namespace ::com::sun::star;
+
+namespace avmedia::vlc {
+
+namespace
+{
+ const OUString VLC_IMPLEMENTATION_NAME = "com.sun.star.comp.avmedia.Manager_VLC";
+ const OUString VLC_SERVICENAME = "com.sun.star.media.Manager_VLC";
+
+ const char * const VLC_ARGS[] = {
+ "--demux",
+ "ffmpeg",
+ "--no-mouse-events",
+ "--verbose=-1"
+ };
+}
+
+Manager::Manager()
+ : mEventHandler()
+{
+ using namespace wrapper;
+ static bool success = Instance::LoadSymbols() && EventManager::LoadSymbols()
+ && Media::LoadSymbols() && Player::LoadSymbols()
+ && Common::LoadSymbols();
+
+ m_is_vlc_found = success;
+ if (m_is_vlc_found)
+ {
+ mInstance.reset(new Instance( SAL_N_ELEMENTS(VLC_ARGS), VLC_ARGS ));
+ //Check VLC version
+ std::vector<std::string> verComponents;
+ const std::string str(Common::Version());
+
+ boost::split(verComponents,
+ str,
+ boost::is_any_of(". "));
+ if (verComponents.size() < 3
+ || boost::lexical_cast<int>(verComponents[0]) < 2
+ || (boost::lexical_cast<int>(verComponents[1]) == 0
+ && boost::lexical_cast<int>(verComponents[2]) < 8))
+ {
+ SAL_WARN("avmedia", "VLC version '" << str << "' is too old");
+ m_is_vlc_found = false;
+ }
+ else
+ SAL_INFO("avmedia", "VLC version '" << str << "' is acceptable");
+ }
+ else
+ SAL_WARN("avmedia", "Cannot load symbols");
+
+ if (m_is_vlc_found)
+ {
+ mEventHandler.create();
+ }
+}
+
+Manager::~Manager()
+{
+ mEventHandler.stop();
+}
+
+uno::Reference< media::XPlayer > SAL_CALL Manager::createPlayer( const OUString& rURL )
+{
+ if ( !m_is_vlc_found )
+ throw uno::RuntimeException("VLC not found", nullptr);
+
+ if ( !rURL.isEmpty() )
+ {
+ if (mURL == rURL)
+ return mPlayer;
+
+ mURL = rURL;
+ }
+ else
+ return mPlayer;
+
+ VLCPlayer* pPlayer( new VLCPlayer( mURL,
+ *mInstance,
+ mEventHandler /*, mxMgr */ ) );
+ mPlayer.set( pPlayer );
+
+ return mPlayer;
+}
+
+OUString SAL_CALL Manager::getImplementationName()
+{
+ return VLC_IMPLEMENTATION_NAME;
+}
+
+sal_Bool SAL_CALL Manager::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+uno::Sequence< OUString > SAL_CALL Manager::getSupportedServiceNames()
+{
+ return { VLC_SERVICENAME };
+}
+
+} // end namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcmanager.hxx b/avmedia/source/vlc/vlcmanager.hxx
new file mode 100644
index 000000000..3615ab17d
--- /dev/null
+++ b/avmedia/source/vlc/vlcmanager.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+#include <com/sun/star/media/XManager.hpp>
+#include "vlccommon.hxx"
+#include <wrapper/Wrapper.hxx>
+#include <memory>
+#include <cppuhelper/implbase.hxx>
+
+namespace avmedia {
+namespace vlc {
+
+class Manager : public ::cppu::WeakImplHelper< css::media::XManager,
+ css::lang::XServiceInfo >
+{
+ std::unique_ptr<wrapper::Instance> mInstance;
+ wrapper::EventHandler mEventHandler;
+public:
+ explicit Manager();
+ virtual ~Manager() override;
+
+ css::uno::Reference< css::media::XPlayer > SAL_CALL createPlayer( const OUString& aURL ) override;
+
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService( const OUString& serviceName ) override;
+ css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+private:
+ css::uno::Reference< css::media::XPlayer > mPlayer;
+ OUString mURL;
+ bool m_is_vlc_found;
+};
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcplayer.cxx b/avmedia/source/vlc/vlcplayer.cxx
new file mode 100644
index 000000000..bd2cc92ba
--- /dev/null
+++ b/avmedia/source/vlc/vlcplayer.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <vcl/syschild.hxx>
+#include <vcl/sysdata.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include "vlcplayer.hxx"
+#include "vlcwindow.hxx"
+#include "vlcframegrabber.hxx"
+#include <wrapper/Instance.hxx>
+
+using namespace ::com::sun::star;
+
+namespace avmedia::vlc {
+
+namespace
+{
+ const OUString AVMEDIA_VLC_PLAYER_IMPLEMENTATIONNAME = "com.sun.star.comp.avmedia.Player_VLC";
+ const OUString AVMEDIA_VLC_PLAYER_SERVICENAME = "com.sun.star.media.Player_VLC";
+
+ const int MS_IN_SEC = 1000; // Millisec in sec
+}
+
+VLCPlayer::VLCPlayer( const OUString& url,
+ wrapper::Instance& instance,
+ wrapper::EventHandler& eh )
+ : VLC_Base( m_aMutex )
+ , mEventHandler( eh )
+ , mMedia( url, instance )
+ , mPlayer( mMedia )
+ , mEventManager( mPlayer, mEventHandler )
+ , mUrl( url )
+ , mPlaybackLoop( false )
+ , mPrevWinID( 0 )
+{
+ mPlayer.setMouseHandling( false );
+}
+
+void SAL_CALL VLCPlayer::start()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (!mPlayer.play())
+ {
+ // TODO: Error
+ }
+}
+
+void SAL_CALL VLCPlayer::stop()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ mPlayer.pause();
+}
+
+sal_Bool SAL_CALL VLCPlayer::isPlaying()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return mPlayer.isPlaying();
+}
+
+double SAL_CALL VLCPlayer::getDuration()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return static_cast<double>( mMedia.getDuration() ) / MS_IN_SEC;
+}
+
+void SAL_CALL VLCPlayer::setMediaTime( double fTime )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( fTime < 0.00000001 && !mPlayer.isPlaying() )
+ {
+ mPlayer.stop();
+ }
+
+ mPlayer.setTime( fTime * MS_IN_SEC );
+}
+
+double SAL_CALL VLCPlayer::getMediaTime()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return static_cast<double>( mPlayer.getTime() ) / MS_IN_SEC;
+}
+
+void VLCPlayer::replay()
+{
+ setPlaybackLoop( false );
+ stop();
+ setMediaTime( 0 );
+ start();
+}
+
+void SAL_CALL VLCPlayer::setPlaybackLoop( sal_Bool bSet )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ mPlaybackLoop = bSet;
+
+ if ( bSet )
+ mEventManager.onEndReached([this](){ this->replay(); });
+ else
+ mEventManager.onEndReached();
+}
+
+sal_Bool SAL_CALL VLCPlayer::isPlaybackLoop()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return mPlaybackLoop;
+}
+
+void SAL_CALL VLCPlayer::setVolumeDB( ::sal_Int16 nDB )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ mPlayer.setVolume( static_cast<sal_Int16>( ( nDB + 40 ) * 10.0 / 4 ) );
+}
+
+::sal_Int16 SAL_CALL VLCPlayer::getVolumeDB()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return static_cast<sal_Int16>( mPlayer.getVolume() / 10.0 * 4 - 40 );
+}
+
+void SAL_CALL VLCPlayer::setMute( sal_Bool bSet )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ mPlayer.setMute( bSet );
+}
+
+sal_Bool SAL_CALL VLCPlayer::isMute()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return mPlayer.getMute();
+}
+
+css::awt::Size SAL_CALL VLCPlayer::getPreferredPlayerWindowSize()
+{
+ return css::awt::Size( 480, 360 );
+}
+
+namespace
+{
+ // TODO: Move this function to the common space for avoiding duplication with
+ // gstreamer/gstwindow::createPlayerWindow functionality
+ intptr_t GetWindowID( const uno::Sequence< uno::Any >& arguments )
+ {
+ if (arguments.getLength() <= 2)
+ return -1;
+
+ sal_IntPtr pIntPtr = 0;
+
+ arguments[ 2 ] >>= pIntPtr;
+
+ SystemChildWindow *pParentWindow = reinterpret_cast< SystemChildWindow* >( pIntPtr );
+
+ const SystemEnvData* pEnvData = pParentWindow ? pParentWindow->GetSystemData() : nullptr;
+
+ if (pEnvData == nullptr)
+ return -1;
+
+#if defined MACOSX
+ const intptr_t id = reinterpret_cast<intptr_t>( pEnvData->mpNSView );
+#elif defined _WIN32
+ const intptr_t id = reinterpret_cast<intptr_t>( pEnvData->hWnd );
+#else
+ const intptr_t id = static_cast<intptr_t>( pEnvData->aWindow );
+#endif
+
+ return id;
+ }
+}
+
+void VLCPlayer::setWindowID( const intptr_t windowID )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mPlayer.stop();
+ mPlayer.setWindow( windowID );
+}
+
+void VLCPlayer::setVideoSize( unsigned width, unsigned height )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mPlayer.setVideoSize( width, height );
+}
+
+uno::Reference< css::media::XPlayerWindow > SAL_CALL VLCPlayer::createPlayerWindow( const uno::Sequence< uno::Any >& aArguments )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ const intptr_t winID = GetWindowID( aArguments );
+ VLCWindow * window;
+ if ( mPrevWinID == 0 )
+ {
+ mPrevWinID = winID;
+ window = new VLCWindow( *this, 0 );
+ }
+ else
+ window = new VLCWindow( *this, mPrevWinID );
+
+ if ( winID != -1 )
+ {
+ setWindowID( winID );
+ }
+
+ return css::uno::Reference< css::media::XPlayerWindow >( window );
+}
+
+uno::Reference< css::media::XFrameGrabber > SAL_CALL VLCPlayer::createFrameGrabber()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( !mrFrameGrabber.is() )
+ {
+ VLCFrameGrabber *frameGrabber = new VLCFrameGrabber( mEventHandler, mUrl );
+ mrFrameGrabber.set( frameGrabber );
+ }
+
+ return mrFrameGrabber;
+}
+
+OUString SAL_CALL VLCPlayer::getImplementationName()
+{
+ return AVMEDIA_VLC_PLAYER_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL VLCPlayer::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+::uno::Sequence< OUString > SAL_CALL VLCPlayer::getSupportedServiceNames()
+{
+ return { AVMEDIA_VLC_PLAYER_SERVICENAME };
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcplayer.hxx b/avmedia/source/vlc/vlcplayer.hxx
new file mode 100644
index 000000000..4c3c03d0b
--- /dev/null
+++ b/avmedia/source/vlc/vlcplayer.hxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "vlccommon.hxx"
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <cppuhelper/basemutex.hxx>
+
+#include <wrapper/Instance.hxx>
+#include <wrapper/Media.hxx>
+#include <wrapper/Player.hxx>
+#include <wrapper/EventManager.hxx>
+
+namespace avmedia {
+namespace vlc {
+
+typedef ::cppu::WeakComponentImplHelper< css::media::XPlayer,
+ css::lang::XServiceInfo > VLC_Base;
+
+class VLCPlayer : public ::cppu::BaseMutex,
+ public VLC_Base
+{
+ wrapper::EventHandler& mEventHandler;
+
+ wrapper::Media mMedia;
+ wrapper::Player mPlayer;
+ wrapper::EventManager mEventManager;
+ const OUString mUrl;
+ bool mPlaybackLoop;
+ css::uno::Reference< css::media::XFrameGrabber > mrFrameGrabber;
+ intptr_t mPrevWinID;
+public:
+ VLCPlayer( const OUString& url,
+ wrapper::Instance& instance,
+ wrapper::EventHandler& eh );
+
+ void setVideoSize( unsigned width, unsigned height );
+
+ void setWindowID( const intptr_t windowID );
+
+ void SAL_CALL start() override;
+ void SAL_CALL stop() override;
+ sal_Bool SAL_CALL isPlaying() override;
+ double SAL_CALL getDuration() override;
+ void SAL_CALL setMediaTime( double fTime ) override;
+ double SAL_CALL getMediaTime() override;
+ void SAL_CALL setPlaybackLoop( sal_Bool bSet ) override;
+ sal_Bool SAL_CALL isPlaybackLoop() override;
+ void SAL_CALL setVolumeDB( ::sal_Int16 nDB ) override;
+ ::sal_Int16 SAL_CALL getVolumeDB() override;
+ void SAL_CALL setMute( sal_Bool bSet ) override;
+ sal_Bool SAL_CALL isMute() override;
+ css::awt::Size SAL_CALL getPreferredPlayerWindowSize() override;
+ css::uno::Reference< css::media::XPlayerWindow > SAL_CALL createPlayerWindow( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+ css::uno::Reference< css::media::XFrameGrabber > SAL_CALL createFrameGrabber() override;
+
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService( const OUString& serviceName ) override;
+ css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+private:
+ void replay();
+};
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcuno.cxx b/avmedia/source/vlc/vlcuno.cxx
new file mode 100644
index 000000000..dba992eb9
--- /dev/null
+++ b/avmedia/source/vlc/vlcuno.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <comphelper/processfactory.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <sal/log.hxx>
+
+#include "vlccommon.hxx"
+#include "vlcmanager.hxx"
+
+using namespace ::com::sun::star;
+
+#define IMPL_NAME "com.sun.star.comp.media.Manager_VLC"
+#define SERVICE_NAME "com.sun.star.comp.avmedia.Manager_VLC"
+
+static uno::Reference< uno::XInterface > create_MediaPlayer( const uno::Reference< lang::XMultiServiceFactory >& /*rxFact*/ )
+{
+ SAL_INFO("avmedia", "create VLC Media player !");
+
+ // Experimental for now - code is neither elegant nor well tested.
+ uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+ if (!xContext.is() || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext))
+ return nullptr;
+
+ static uno::Reference< uno::XInterface > manager( *new ::avmedia::vlc::Manager );
+ return manager;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void* avmediavlc_component_getFactory( const char* pImplName, void* pServiceManager, void* /*pRegistryKey*/ )
+{
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+ void* pRet = nullptr;
+
+ // Experimental for now - code is neither elegant nor well tested.
+ uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+ if (!xContext.is() || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext))
+ return nullptr;
+
+ SAL_INFO("avmedia", "Create VLC Media component: " << pImplName);
+ if( rtl_str_compare( pImplName, IMPL_NAME ) == 0 )
+ {
+ const OUString aServiceName( SERVICE_NAME );
+ xFactory.set( ::cppu::createSingleFactory(
+ static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
+ IMPL_NAME, create_MediaPlayer, uno::Sequence< OUString >( &aServiceName, 1 ) ) );
+ }
+
+ if( xFactory.is() )
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcwindow.cxx b/avmedia/source/vlc/vlcwindow.cxx
new file mode 100644
index 000000000..1cd0e1306
--- /dev/null
+++ b/avmedia/source/vlc/vlcwindow.cxx
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <iostream>
+#include <cppuhelper/supportsservice.hxx>
+#include "vlcwindow.hxx"
+#include "vlcplayer.hxx"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::vlc {
+
+namespace
+{
+ const OUString AVMEDIA_VLC_WINDOW_IMPLEMENTATIONNAME = "com.sun.star.comp.avmedia.Window_VLC";
+ const OUString AVMEDIA_VLC_WINDOW_SERVICENAME = "com.sun.star.media.Window_VLC";
+}
+
+VLCWindow::VLCWindow( VLCPlayer& player, const intptr_t prevWinID )
+ : mPlayer( player )
+ , mPrevWinID( prevWinID )
+ , meZoomLevel( media::ZoomLevel_ORIGINAL )
+{
+}
+
+VLCWindow::~VLCWindow()
+{
+ if ( mPrevWinID != 0 )
+ mPlayer.setWindowID( mPrevWinID );
+}
+
+void SAL_CALL VLCWindow::update()
+{
+}
+
+sal_Bool SAL_CALL VLCWindow::setZoomLevel( css::media::ZoomLevel eZoomLevel )
+{
+ bool bRet = false;
+
+ if( media::ZoomLevel_NOT_AVAILABLE != meZoomLevel &&
+ media::ZoomLevel_NOT_AVAILABLE != eZoomLevel )
+ {
+ if( eZoomLevel != meZoomLevel )
+ {
+ meZoomLevel = eZoomLevel;
+ }
+
+ switch ( eZoomLevel )
+ {
+ case media::ZoomLevel_ORIGINAL:
+ case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT:
+ mPlayer.setVideoSize( mSize.Width, mSize.Height );
+ break;
+ case media::ZoomLevel_ZOOM_1_TO_2:
+ mPlayer.setVideoSize( mSize.Width / 2, mSize.Height / 2 );
+ break;
+ case media::ZoomLevel_ZOOM_2_TO_1:
+ mPlayer.setVideoSize( mSize.Width * 2, mSize.Height * 2 );
+ break;
+ default:
+ break;
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+css::media::ZoomLevel SAL_CALL VLCWindow::getZoomLevel()
+{
+ return meZoomLevel;
+}
+
+void SAL_CALL VLCWindow::setPointerType( ::sal_Int32 )
+{
+}
+
+OUString SAL_CALL VLCWindow::getImplementationName()
+{
+ return AVMEDIA_VLC_WINDOW_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL VLCWindow::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+uno::Sequence< OUString > SAL_CALL VLCWindow::getSupportedServiceNames()
+{
+ return { AVMEDIA_VLC_WINDOW_SERVICENAME };
+}
+
+void SAL_CALL VLCWindow::dispose()
+{
+}
+
+void SAL_CALL VLCWindow::addEventListener( const uno::Reference< lang::XEventListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::removeEventListener( const uno::Reference< lang::XEventListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 /* Flags */ )
+{
+ mSize.X = X;
+ mSize.Y = Y;
+ mSize.Width = Width;
+ mSize.Height = Height;
+}
+
+awt::Rectangle SAL_CALL VLCWindow::getPosSize()
+{
+ return mSize;
+}
+
+void SAL_CALL VLCWindow::setVisible( sal_Bool )
+{
+}
+
+void SAL_CALL VLCWindow::setEnable( sal_Bool )
+{
+}
+
+void SAL_CALL VLCWindow::setFocus()
+{
+}
+
+void SAL_CALL VLCWindow::addWindowListener( const uno::Reference< awt::XWindowListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::removeWindowListener( const uno::Reference< awt::XWindowListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::addFocusListener( const uno::Reference< awt::XFocusListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::removeFocusListener( const uno::Reference< awt::XFocusListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::addKeyListener( const uno::Reference< awt::XKeyListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::removeKeyListener( const uno::Reference< awt::XKeyListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::addMouseListener( const uno::Reference< awt::XMouseListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::removeMouseListener( const uno::Reference< awt::XMouseListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::addPaintListener( const uno::Reference< awt::XPaintListener >& )
+{
+}
+
+void SAL_CALL VLCWindow::removePaintListener( const uno::Reference< awt::XPaintListener >& )
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/vlcwindow.hxx b/avmedia/source/vlc/vlcwindow.hxx
new file mode 100644
index 000000000..e70c8e80f
--- /dev/null
+++ b/avmedia/source/vlc/vlcwindow.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+#pragma once
+
+#include "vlccommon.hxx"
+#include <cppuhelper/implbase.hxx>
+
+namespace avmedia {
+namespace vlc {
+class VLCPlayer;
+
+class VLCWindow : public ::cppu::WeakImplHelper< css::media::XPlayerWindow,
+ css::lang::XServiceInfo >
+{
+ VLCPlayer& mPlayer;
+ const intptr_t mPrevWinID;
+ css::media::ZoomLevel meZoomLevel;
+ css::awt::Rectangle mSize;
+public:
+ VLCWindow( VLCPlayer& player, const intptr_t prevWinID );
+ virtual ~VLCWindow() override;
+
+ void SAL_CALL update() override;
+ sal_Bool SAL_CALL setZoomLevel( css::media::ZoomLevel ZoomLevel ) override;
+ css::media::ZoomLevel SAL_CALL getZoomLevel() override;
+ void SAL_CALL setPointerType( ::sal_Int32 SystemPointerType ) override;
+
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService( const OUString& serviceName ) override;
+ css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ void SAL_CALL dispose() override;
+ void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ void SAL_CALL setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) override;
+ css::awt::Rectangle SAL_CALL getPosSize() override;
+ void SAL_CALL setVisible( sal_Bool Visible ) override;
+ void SAL_CALL setEnable( sal_Bool Enable ) override;
+ void SAL_CALL setFocus() override;
+ void SAL_CALL addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ void SAL_CALL removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ void SAL_CALL addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ void SAL_CALL removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ void SAL_CALL addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ void SAL_CALL removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+};
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/Common.cxx b/avmedia/source/vlc/wrapper/Common.cxx
new file mode 100644
index 000000000..4ee3a2977
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/Common.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include <wrapper/Common.hxx>
+#include "SymbolLoader.hxx"
+
+namespace
+{
+ const char AVMEDIA_NO_ERROR[] = "No error";
+
+ const char* ( *libvlc_get_version ) ();
+ char * ( * libvlc_errmsg ) ();
+}
+
+namespace avmedia::vlc::wrapper
+{
+bool Common::LoadSymbols()
+{
+ static ApiMap const VLC_COMMON_API[] =
+ {
+ SYM_MAP( libvlc_get_version ),
+ SYM_MAP( libvlc_errmsg )
+ };
+
+ return InitApiMap( VLC_COMMON_API );
+}
+
+const char* Common::Version()
+{
+ return libvlc_get_version();
+}
+
+const char* Common::LastErrorMessage()
+{
+ const char *errorMsg = libvlc_errmsg();
+ return errorMsg == nullptr ? AVMEDIA_NO_ERROR : errorMsg;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/EventHandler.cxx b/avmedia/source/vlc/wrapper/EventHandler.cxx
new file mode 100644
index 000000000..a2a0db16e
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/EventHandler.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <wrapper/EventHandler.hxx>
+
+namespace avmedia::vlc::wrapper
+{
+EventHandler::EventHandler()
+ : ::osl::Thread()
+{
+}
+
+void EventHandler::stop()
+{
+ mCallbackQueue.push(TCallback());
+ join();
+}
+
+void EventHandler::run()
+{
+ osl_setThreadName("VLC EventHandler");
+
+ TCallback callback;
+ do
+ {
+ mCallbackQueue.pop( callback );
+
+ if ( !callback )
+ return;
+
+ callback();
+ } while ( true );
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/EventManager.cxx b/avmedia/source/vlc/wrapper/EventManager.cxx
new file mode 100644
index 000000000..27e56603e
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/EventManager.cxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <wrapper/EventManager.hxx>
+#include "SymbolLoader.hxx"
+#include <wrapper/EventHandler.hxx>
+#include "Types.hxx"
+
+namespace
+{
+ libvlc_event_manager_t* ( *libvlc_media_player_event_manager ) ( libvlc_media_player_t *p_mi );
+ int ( *libvlc_event_attach ) ( libvlc_event_manager_t *p_event_manager,
+ libvlc_event_type_t i_event_type,
+ libvlc_callback_t f_callback,
+ void *user_data );
+ void ( *libvlc_event_detach ) ( libvlc_event_manager_t *p_event_manager,
+ libvlc_event_type_t i_event_type,
+ libvlc_callback_t f_callback,
+ void *p_user_data );
+}
+
+namespace avmedia::vlc::wrapper
+{
+void EventManager::Handler( const libvlc_event_t *event, void *pData )
+{
+ EventManager *instance = static_cast<EventManager*>( pData );
+ switch ( event->type )
+ {
+ case libvlc_MediaPlayerPaused:
+ instance->mEventHandler.mCallbackQueue.push( instance->mOnPaused );
+ break;
+ case libvlc_MediaPlayerEndReached:
+ instance->mEventHandler.mCallbackQueue.push( instance->mOnEndReached );
+ break;
+ }
+}
+
+bool EventManager::LoadSymbols()
+{
+ static ApiMap const VLC_EVENT_MANAGER_API[] =
+ {
+ SYM_MAP( libvlc_media_player_event_manager ),
+ SYM_MAP( libvlc_event_attach ),
+ SYM_MAP( libvlc_event_detach )
+ };
+
+ return InitApiMap( VLC_EVENT_MANAGER_API );
+}
+
+EventManager::EventManager( Player& player, EventHandler& eh )
+ : mEventHandler( eh )
+ , mManager( libvlc_media_player_event_manager( player ) )
+{
+
+}
+
+void EventManager::registerSignal( int signal, const Callback& callback )
+{
+ if ( !callback )
+ libvlc_event_detach( mManager, signal, Handler, this );
+ else
+ libvlc_event_attach( mManager, signal, Handler, this );
+}
+
+void EventManager::onPaused( const EventManager::Callback& callback )
+{
+ mOnPaused = callback;
+ registerSignal( libvlc_MediaPlayerPaused, callback );
+}
+
+void EventManager::onEndReached( const Callback& callback )
+{
+ mOnEndReached = callback;
+ registerSignal( libvlc_MediaPlayerEndReached, callback );
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/Instance.cxx b/avmedia/source/vlc/wrapper/Instance.cxx
new file mode 100644
index 000000000..1226cb7ea
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/Instance.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <wrapper/Instance.hxx>
+#include "SymbolLoader.hxx"
+
+namespace
+{
+ libvlc_instance_t* ( *libvlc_new ) ( int argc, const char * const *argv );
+ void ( *libvlc_release ) ( libvlc_instance_t *p_instance );
+ void ( *libvlc_retain ) ( libvlc_instance_t *p_instance );
+}
+
+namespace avmedia::vlc::wrapper
+{
+ bool Instance::LoadSymbols()
+ {
+ static ApiMap const VLC_INSTANCE_API[] =
+ {
+ SYM_MAP( libvlc_new ),
+ SYM_MAP( libvlc_release ),
+ SYM_MAP( libvlc_retain )
+ };
+
+ return InitApiMap( VLC_INSTANCE_API );
+ }
+
+ Instance::Instance( int argc, const char * const argv[] )
+ : mInstance( libvlc_new( argc, argv ) )
+ {
+ if ( mInstance == nullptr)
+ {
+ //TODO: error
+ }
+ }
+
+ Instance::Instance( const Instance& other )
+ {
+ operator=( other );
+ }
+
+ Instance& Instance::operator=( const Instance& other )
+ {
+ libvlc_release( mInstance );
+ mInstance = other.mInstance;
+ libvlc_retain( mInstance );
+ return *this;
+ }
+
+ Instance::~Instance()
+ {
+ libvlc_release( mInstance );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/Media.cxx b/avmedia/source/vlc/wrapper/Media.cxx
new file mode 100644
index 000000000..f09aecd76
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/Media.cxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <rtl/ustring.h>
+#include <wrapper/Media.hxx>
+#include "SymbolLoader.hxx"
+#include <wrapper/Instance.hxx>
+#include "Types.hxx"
+#include <wrapper/Common.hxx>
+#include <sal/log.hxx>
+
+struct libvlc_instance_t;
+
+namespace avmedia::vlc::wrapper
+{
+namespace
+{
+ libvlc_media_t* ( *libvlc_media_new_path ) ( libvlc_instance_t *p_instance, const char *path );
+ libvlc_media_t* ( *libvlc_media_new_location ) (libvlc_instance_t *p_instance, const char *psz_mrl);
+ void ( *libvlc_media_release ) ( libvlc_media_t *p_md );
+ void ( *libvlc_media_retain ) ( libvlc_media_t *p_md );
+ libvlc_time_t ( *libvlc_media_get_duration ) ( libvlc_media_t *p_md );
+ void ( *libvlc_media_parse ) ( libvlc_media_t *p_md );
+ int ( *libvlc_media_is_parsed ) ( libvlc_media_t *p_md );
+ char* ( *libvlc_media_get_mrl )(libvlc_media_t *p_md);
+
+
+ libvlc_media_t* InitMedia( const OUString& url, Instance& instance )
+ {
+ OString dest;
+ url.convertToString(&dest, RTL_TEXTENCODING_UTF8, 0);
+
+ return libvlc_media_new_location(instance, dest.getStr());
+ }
+}
+
+bool Media::LoadSymbols()
+{
+ static ApiMap const VLC_MEDIA_API[] =
+ {
+ SYM_MAP( libvlc_media_new_path ),
+ SYM_MAP( libvlc_media_release ),
+ SYM_MAP( libvlc_media_retain ),
+ SYM_MAP( libvlc_media_get_duration ),
+ SYM_MAP( libvlc_media_parse ),
+ SYM_MAP( libvlc_media_is_parsed ),
+ SYM_MAP( libvlc_media_get_mrl ),
+ SYM_MAP( libvlc_media_new_location )
+ };
+
+ return InitApiMap( VLC_MEDIA_API );
+}
+
+Media::Media( const OUString& url, Instance& instance )
+ : mMedia( InitMedia( url, instance ) )
+{
+ if (mMedia == nullptr)
+ {
+ // TODO: Error
+ }
+}
+
+Media::Media( const Media& other )
+{
+ operator=( other );
+}
+
+Media& Media::operator=( const Media& other )
+{
+ libvlc_media_release( mMedia );
+ mMedia = other.mMedia;
+
+ libvlc_media_retain( mMedia );
+ return *this;
+}
+
+int Media::getDuration() const
+{
+ if ( !libvlc_media_is_parsed( mMedia ) )
+ libvlc_media_parse( mMedia );
+
+ const int duration = libvlc_media_get_duration( mMedia );
+ if (duration == -1)
+ {
+ SAL_WARN("avmedia", Common::LastErrorMessage());
+ return 0;
+ }
+ else if (duration == 0)
+ {
+ // A duration must be greater than 0
+ return 1;
+ }
+
+ return duration;
+}
+
+Media::~Media()
+{
+ libvlc_media_release( mMedia );
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/Player.cxx b/avmedia/source/vlc/wrapper/Player.cxx
new file mode 100644
index 000000000..27e63a21a
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/Player.cxx
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <rtl/ustring.h>
+#include "Types.hxx"
+#include <wrapper/Player.hxx>
+#include <wrapper/Media.hxx>
+#include "SymbolLoader.hxx"
+#include <wrapper/Common.hxx>
+
+struct libvlc_media_t;
+
+namespace { extern "C" {
+ void ( *libvlc_media_player_retain ) ( libvlc_media_player_t *p_mi );
+ libvlc_media_player_t * ( *libvlc_media_player_new_from_media ) ( libvlc_media_t *p_md );
+ void ( *libvlc_media_player_release ) ( libvlc_media_player_t *p_mi );
+ int ( *libvlc_media_player_play ) ( libvlc_media_player_t *p_mi );
+ void ( *libvlc_media_player_pause ) ( libvlc_media_player_t *p_mi );
+ int ( *libvlc_media_player_is_playing ) ( libvlc_media_player_t *p_mi );
+ void ( *libvlc_media_player_stop ) ( libvlc_media_player_t *p_mi );
+ void ( *libvlc_media_player_set_time ) ( libvlc_media_player_t *p_mi, libvlc_time_t i_time );
+ libvlc_time_t ( *libvlc_media_player_get_time ) ( libvlc_media_player_t *p_mi );
+ float ( *libvlc_media_player_get_rate )( libvlc_media_player_t *p_mi );
+ int ( *libvlc_audio_set_volume ) ( libvlc_media_player_t *p_mi, int i_volume );
+ int ( *libvlc_audio_get_volume ) ( libvlc_media_player_t *p_mi );
+ int ( *libvlc_audio_get_mute ) ( libvlc_media_player_t *p_mi );
+ void ( *libvlc_audio_set_mute ) ( libvlc_media_player_t *p_mi, int status );
+ int ( *libvlc_video_take_snapshot ) ( libvlc_media_player_t *p_mi,
+ unsigned num,
+ const char *psz_filepath,
+ unsigned int i_width,
+ unsigned int i_height );
+#if defined MACOSX
+ void ( *libvlc_media_player_set_nsobject ) ( libvlc_media_player_t *p_mi, void *drawable );
+#elif defined UNX
+ void ( *libvlc_media_player_set_xwindow ) ( libvlc_media_player_t *p_mi, uint32_t drawable );
+#elif defined _WIN32
+ void ( *libvlc_media_player_set_hwnd ) ( libvlc_media_player_t *p_mi, void *drawable );
+#else
+#error unknown OS
+#endif
+ unsigned ( *libvlc_media_player_has_vout ) ( libvlc_media_player_t *p_mi );
+ void ( *libvlc_video_set_mouse_input ) ( libvlc_media_player_t *p_mi, unsigned on );
+ void ( *libvlc_video_set_scale ) ( libvlc_media_player_t *p_mi, float f_factor );
+ int ( *libvlc_video_get_size ) ( libvlc_media_player_t *p_mi, unsigned num,
+ unsigned *px, unsigned *py );
+ int ( *libvlc_video_get_track_count ) ( libvlc_media_player_t *p_mi );
+ int ( *libvlc_video_set_track ) ( libvlc_media_player_t *p_mi, int i_track );
+ libvlc_track_description_t* ( *libvlc_video_get_track_description ) ( libvlc_media_player_t *p_mi );
+
+ int ( *libvlc_audio_get_track ) ( libvlc_media_player_t *p_mi );
+ libvlc_track_description_t * ( *libvlc_audio_get_track_description ) (libvlc_media_player_t *p_mi );
+ int ( *libvlc_audio_set_track ) (libvlc_media_player_t *p_mi, int i_track);
+} }
+
+namespace avmedia::vlc::wrapper
+{
+ bool Player::LoadSymbols()
+ {
+ static ApiMap const VLC_PLAYER_API[] =
+ {
+ SYM_MAP( libvlc_media_player_new_from_media ),
+ SYM_MAP( libvlc_media_player_release ),
+ SYM_MAP( libvlc_media_player_play ),
+ SYM_MAP( libvlc_media_player_pause ),
+ SYM_MAP( libvlc_media_player_is_playing ),
+ SYM_MAP( libvlc_media_player_stop ),
+ SYM_MAP( libvlc_media_player_set_time ),
+ SYM_MAP( libvlc_media_player_get_time ),
+ SYM_MAP( libvlc_media_player_get_rate ),
+ SYM_MAP( libvlc_audio_set_volume ),
+ SYM_MAP( libvlc_audio_get_volume ),
+ SYM_MAP( libvlc_audio_set_mute ),
+ SYM_MAP( libvlc_audio_get_mute ),
+ SYM_MAP( libvlc_video_take_snapshot ),
+#if defined MACOSX
+ SYM_MAP( libvlc_media_player_set_nsobject ),
+#elif defined UNX
+ SYM_MAP( libvlc_media_player_set_xwindow ),
+#elif defined _WIN32
+ SYM_MAP( libvlc_media_player_set_hwnd ),
+#endif
+ SYM_MAP( libvlc_media_player_has_vout ),
+ SYM_MAP( libvlc_video_set_mouse_input ),
+ SYM_MAP( libvlc_media_player_retain ),
+ SYM_MAP( libvlc_video_set_scale ),
+ SYM_MAP( libvlc_video_get_size ),
+ SYM_MAP( libvlc_video_get_track_count ),
+ SYM_MAP( libvlc_video_set_track ),
+ SYM_MAP( libvlc_video_get_track_description ),
+ SYM_MAP( libvlc_audio_get_track ),
+ SYM_MAP( libvlc_audio_get_track_description ),
+ SYM_MAP( libvlc_audio_set_track )
+ };
+
+ return InitApiMap( VLC_PLAYER_API );
+ }
+
+ Player::Player( Media& media )
+ : mPlayer( libvlc_media_player_new_from_media( media ) )
+ {
+ }
+
+ Player::Player( const Player& other )
+ {
+ operator=( other );
+ }
+
+ Player& Player::operator=( const Player& other )
+ {
+ libvlc_media_player_release( mPlayer );
+ mPlayer = other.mPlayer;
+ libvlc_media_player_retain( mPlayer );
+ return *this;
+ }
+
+ Player::~Player()
+ {
+ libvlc_media_player_release( mPlayer );
+ }
+
+ bool Player::play()
+ {
+ const bool status = ( libvlc_media_player_play( mPlayer ) == 0 );
+ if ( libvlc_video_get_track_count( mPlayer ) > 0 )
+ {
+ const libvlc_track_description_t *description = libvlc_video_get_track_description( mPlayer );
+
+ for ( ; description->p_next != nullptr; description = description->p_next );
+
+ libvlc_video_set_track( mPlayer, description->i_id );
+ }
+
+ if ( libvlc_audio_get_track( mPlayer ) > 0 )
+ {
+ const libvlc_track_description_t *description = libvlc_audio_get_track_description( mPlayer );
+
+ for ( ; description->p_next != nullptr; description = description->p_next );
+
+ libvlc_audio_set_track( mPlayer, description->i_id );
+ }
+
+ return status;
+ }
+
+ void Player::pause()
+ {
+ libvlc_media_player_pause( mPlayer );
+ }
+
+ void Player::stop()
+ {
+ libvlc_media_player_stop( mPlayer );
+ }
+
+ void Player::setTime( int time )
+ {
+ libvlc_media_player_set_time( mPlayer, time );
+ }
+
+ int Player::getTime() const
+ {
+ const int time = libvlc_media_player_get_time( mPlayer );
+
+ return ( time == -1 ? 0 : time );
+ }
+
+ void Player::setScale( float factor )
+ {
+ libvlc_video_set_scale( mPlayer, factor );
+ }
+
+ void Player::setMouseHandling(bool flag)
+ {
+ libvlc_video_set_mouse_input( mPlayer, flag );
+ }
+
+ bool Player::isPlaying() const
+ {
+ return libvlc_media_player_is_playing( mPlayer ) == 1;
+ }
+
+ void Player::setVolume( int volume )
+ {
+ libvlc_audio_set_volume( mPlayer, volume );
+ }
+
+ int Player::getVolume() const
+ {
+ return libvlc_audio_get_volume( mPlayer );
+ }
+
+ void Player::setMute( bool mute)
+ {
+ libvlc_audio_set_mute( mPlayer, mute );
+ }
+
+ bool Player::getMute() const
+ {
+ return libvlc_audio_get_mute( mPlayer );
+ }
+
+ void Player::setVideoSize( unsigned width, unsigned )
+ {
+ unsigned currentWidth, currentHeight;
+ libvlc_video_get_size( mPlayer, 0, &currentWidth, &currentHeight );
+ if ( currentWidth != 0 )
+ setScale( static_cast<float>( width ) / currentWidth );
+ }
+
+ void Player::setWindow( intptr_t id )
+ {
+#if defined MACOSX
+ libvlc_media_player_set_nsobject( mPlayer, reinterpret_cast<void*>( id ) );
+#elif defined UNX
+ libvlc_media_player_set_xwindow( mPlayer, static_cast<uint32_t>(id) );
+#elif defined _WIN32
+ libvlc_media_player_set_hwnd( mPlayer, reinterpret_cast<void*>( id ) );
+#endif
+ }
+
+ void Player::takeSnapshot( const OUString& file )
+ {
+ OString dest;
+ file.convertToString( &dest, RTL_TEXTENCODING_UTF8, 0 );
+ libvlc_video_take_snapshot( mPlayer, 0, dest.getStr(), 480, 360 );
+ }
+
+ bool Player::hasVout() const
+ {
+ return libvlc_media_player_has_vout( mPlayer );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/SymbolLoader.hxx b/avmedia/source/vlc/wrapper/SymbolLoader.hxx
new file mode 100644
index 000000000..64789b326
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/SymbolLoader.hxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+#if defined(_WIN32)
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+# include <windows.h>
+# include <winreg.h>
+#endif
+#include <osl/module.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+
+#define SYM_MAP(a) { #a, reinterpret_cast<SymbolFunc *>(&a) }
+
+namespace avmedia
+{
+namespace vlc
+{
+namespace wrapper
+{
+typedef void (*SymbolFunc) (void);
+
+struct ApiMap
+{
+ OUStringLiteral symName;
+ SymbolFunc *refValue;
+};
+
+#if defined( LINUX )
+ const char LibName[] = "libvlc.so.5";
+#elif defined( MACOSX )
+ const char LibName[] = "/Applications/VLC.app/Contents/MacOS/lib/libvlc.dylib";
+#elif defined( _WIN32 )
+ const char LibName[] = "libvlc.dll";
+
+ inline OUString GetVLCPath()
+ {
+ HKEY hKey;
+ sal_Unicode arCurrent[MAX_PATH];
+ DWORD dwType, dwCurrentSize = sizeof( arCurrent );
+
+ //TODO: This one will work only with LibreOffice 32-bit + VLC 32-bit on Win x86_64.
+ const LONG errorCore = ::RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Wow6432Node\\VideoLAN\\VLC", 0, KEY_READ | KEY_WOW64_64KEY, &hKey );
+ if ( errorCore == ERROR_SUCCESS )
+ {
+ if ( ::RegQueryValueExW( hKey, L"InstallDir", nullptr, &dwType, reinterpret_cast<LPBYTE>(arCurrent), &dwCurrentSize ) == ERROR_SUCCESS &&
+ dwType == REG_SZ )
+ {
+ ::RegCloseKey( hKey );
+ dwCurrentSize -= 2;
+ dwCurrentSize /= 2;
+
+ return OUString( arCurrent, dwCurrentSize ) + "\\";
+ }
+
+ ::RegCloseKey( hKey );
+ }
+
+ return OUString();
+ }
+#endif
+
+ template<size_t N>
+ bool tryLink( oslModule &aModule, const ApiMap ( &pMap )[N] )
+ {
+ for (size_t i = 0; i < N; ++i)
+ {
+ SymbolFunc aMethod = reinterpret_cast<SymbolFunc>(osl_getFunctionSymbol
+ ( aModule, OUString( pMap[ i ].symName ).pData ));
+ if ( !aMethod )
+ {
+ SAL_WARN("avmedia", "Cannot load method " << pMap[ i ].symName);
+ *pMap[ i ].refValue = nullptr;
+ return false;
+ }
+ else
+ *pMap[ i ].refValue = aMethod;
+ }
+
+ return true;
+ }
+
+ template<size_t N>
+ bool InitApiMap( const ApiMap ( &pMap )[N] )
+ {
+#if defined( LINUX ) || defined( MACOSX )
+ OUString const fullPath(LibName);
+#elif defined( _WIN32 )
+ OUString const fullPath(GetVLCPath() + LibName);
+#endif
+ SAL_INFO("avmedia", fullPath);
+
+ oslModule aModule = osl_loadModule( fullPath.pData,
+ SAL_LOADMODULE_DEFAULT );
+
+
+ if( aModule == nullptr)
+ {
+ SAL_WARN("avmedia", "Cannot load libvlc");
+ return false;
+ }
+
+ if (tryLink( aModule, pMap ))
+ {
+ return true;
+ }
+
+ SAL_WARN("avmedia", "Cannot load libvlc");
+ osl_unloadModule( aModule );
+
+ return false;
+ }
+}
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/vlc/wrapper/Types.hxx b/avmedia/source/vlc/wrapper/Types.hxx
new file mode 100644
index 000000000..c66a88bdc
--- /dev/null
+++ b/avmedia/source/vlc/wrapper/Types.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* Typedefs and structures that represent the libvlc API / ABI */
+
+#pragma once
+
+#include <sal/config.h>
+
+#if defined(_WIN32)
+ typedef __int64 libvlc_time_t;
+#else
+#include <stdint.h>
+ typedef int64_t libvlc_time_t;
+#endif
+
+extern "C" {
+
+// basic callback / event types we use
+typedef int libvlc_event_type_t;
+typedef struct libvlc_event_manager_t libvlc_event_manager_t;
+typedef void ( *libvlc_callback_t ) ( const struct libvlc_event_t *, void * );
+
+// the enumeration values we use cf. libvlc_events.h
+#define libvlc_MediaPlayerPaused 0x105
+#define libvlc_MediaPlayerEndReached 0x109
+
+// event structure pieces we use
+struct libvlc_event_t
+{
+ int type; // event type
+ void *p_obj; // object emitting that event
+
+ union // so far we don't need this.
+ {
+ struct {
+ const char *dummy1;
+ const char *dummy2;
+ } padding;
+ } u;
+};
+
+struct libvlc_track_description_t
+{
+ int i_id;
+ char *psz_name;
+ libvlc_track_description_t *p_next;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/avmediawin.component b/avmedia/source/win/avmediawin.component
new file mode 100644
index 000000000..3874439f4
--- /dev/null
+++ b/avmedia/source/win/avmediawin.component
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ prefix="avmediawin" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.avmedia.Manager_DirectX">
+ <service name="com.sun.star.media.Manager_DirectX"/>
+ </implementation>
+</component>
diff --git a/avmedia/source/win/framegrabber.cxx b/avmedia/source/win/framegrabber.cxx
new file mode 100644
index 000000000..21b5dede6
--- /dev/null
+++ b/avmedia/source/win/framegrabber.cxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <prewin.h>
+#include <postwin.h>
+#include <objbase.h>
+#include <strmif.h>
+#include <Amvideo.h>
+#include "interface.hxx"
+#include <uuids.h>
+
+#include "framegrabber.hxx"
+#include "player.hxx"
+
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/file.hxx>
+#include <tools/stream.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/dibtools.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+
+#define AVMEDIA_WIN_FRAMEGRABBER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.FrameGrabber_DirectX"
+#define AVMEDIA_WIN_FRAMEGRABBER_SERVICENAME "com.sun.star.media.FrameGrabber_DirectX"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::win {
+
+
+FrameGrabber::FrameGrabber( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
+ mxMgr( rxMgr )
+{
+ ::CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED );
+}
+
+
+FrameGrabber::~FrameGrabber()
+{
+ ::CoUninitialize();
+}
+
+namespace {
+
+IMediaDet* implCreateMediaDet( const OUString& rURL )
+{
+ IMediaDet* pDet = nullptr;
+
+ if( SUCCEEDED( CoCreateInstance( CLSID_MediaDet, nullptr, CLSCTX_INPROC_SERVER, IID_IMediaDet, reinterpret_cast<void**>(&pDet) ) ) )
+ {
+ OUString aLocalStr;
+
+ if( osl::FileBase::getSystemPathFromFileURL( rURL, aLocalStr )
+ == osl::FileBase::E_None )
+ {
+ BSTR bstrFilename = SysAllocString(o3tl::toW(aLocalStr.getStr()));
+ if( !SUCCEEDED( pDet->put_Filename( bstrFilename ) ) )
+ {
+ // Shouldn't we free this string unconditionally, not only in case of failure?
+ // I cannot find information why do we pass a newly allocated BSTR to the put_Filename
+ // and if it frees the string internally
+ SysFreeString(bstrFilename);
+ pDet->Release();
+ pDet = nullptr;
+ }
+ }
+ }
+
+ return pDet;
+}
+
+}
+
+bool FrameGrabber::create( const OUString& rURL )
+{
+ // just check if a MediaDet interface can be created with the given URL
+ IMediaDet* pDet = implCreateMediaDet( rURL );
+
+ if( pDet )
+ {
+ maURL = rURL;
+ pDet->Release();
+ pDet = nullptr;
+ }
+ else
+ maURL.clear();
+
+ return !maURL.isEmpty();
+}
+
+
+uno::Reference< graphic::XGraphic > SAL_CALL FrameGrabber::grabFrame( double fMediaTime )
+{
+ uno::Reference< graphic::XGraphic > xRet;
+ IMediaDet* pDet = implCreateMediaDet( maURL );
+
+ if( pDet )
+ {
+ double fLength;
+ long nStreamCount;
+ bool bFound = false;
+
+ if( SUCCEEDED( pDet->get_OutputStreams( &nStreamCount ) ) )
+ {
+ for( long n = 0; ( n < nStreamCount ) && !bFound; ++n )
+ {
+ GUID aMajorType;
+
+ if( SUCCEEDED( pDet->put_CurrentStream( n ) ) &&
+ SUCCEEDED( pDet->get_StreamType( &aMajorType ) ) &&
+ ( aMajorType == MEDIATYPE_Video ) )
+ {
+ bFound = true;
+ }
+ }
+ }
+
+ if( bFound &&
+ ( S_OK == pDet->get_StreamLength( &fLength ) ) &&
+ ( fLength > 0.0 ) && ( fMediaTime >= 0.0 ) && ( fMediaTime <= fLength ) )
+ {
+ AM_MEDIA_TYPE aMediaType;
+ long nWidth = 0, nHeight = 0, nSize = 0;
+
+ if( SUCCEEDED( pDet->get_StreamMediaType( &aMediaType ) ) )
+ {
+ if( ( aMediaType.formattype == FORMAT_VideoInfo ) &&
+ ( aMediaType.cbFormat >= sizeof( VIDEOINFOHEADER ) ) )
+ {
+ VIDEOINFOHEADER* pVih = reinterpret_cast< VIDEOINFOHEADER* >( aMediaType.pbFormat );
+
+ nWidth = pVih->bmiHeader.biWidth;
+ nHeight = pVih->bmiHeader.biHeight;
+
+ if( nHeight < 0 )
+ nHeight *= -1;
+ }
+
+ if( aMediaType.cbFormat != 0 )
+ {
+ ::CoTaskMemFree( aMediaType.pbFormat );
+ aMediaType.cbFormat = 0;
+ aMediaType.pbFormat = nullptr;
+ }
+
+ if( aMediaType.pUnk != nullptr )
+ {
+ aMediaType.pUnk->Release();
+ aMediaType.pUnk = nullptr;
+ }
+ }
+
+ if( ( nWidth > 0 ) && ( nHeight > 0 ) &&
+ SUCCEEDED( pDet->GetBitmapBits( 0, &nSize, nullptr, nWidth, nHeight ) ) &&
+ ( nSize > 0 ) )
+ {
+ auto pBuffer = std::make_unique<char[]>(nSize);
+
+ try
+ {
+ if( SUCCEEDED( pDet->GetBitmapBits( fMediaTime, nullptr, pBuffer.get(), nWidth, nHeight ) ) )
+ {
+ SvMemoryStream aMemStm( pBuffer.get(), nSize, StreamMode::READ | StreamMode::WRITE );
+ Bitmap aBmp;
+
+ if( ReadDIB(aBmp, aMemStm, false ) && !aBmp.IsEmpty() )
+ {
+ const Graphic aGraphic( aBmp );
+ xRet = aGraphic.GetXGraphic();
+ }
+ }
+ }
+ catch( ... )
+ {
+ }
+ }
+ }
+
+ pDet->Release();
+ }
+
+ return xRet;
+}
+
+
+OUString SAL_CALL FrameGrabber::getImplementationName( )
+{
+ return AVMEDIA_WIN_FRAMEGRABBER_IMPLEMENTATIONNAME;
+}
+
+
+sal_Bool SAL_CALL FrameGrabber::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+uno::Sequence< OUString > SAL_CALL FrameGrabber::getSupportedServiceNames( )
+{
+ return { AVMEDIA_WIN_FRAMEGRABBER_SERVICENAME };
+}
+
+} // namespace avmedia::win
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/framegrabber.hxx b/avmedia/source/win/framegrabber.hxx
new file mode 100644
index 000000000..aa5b8945e
--- /dev/null
+++ b/avmedia/source/win/framegrabber.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "wincommon.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/media/XFrameGrabber.hpp>
+
+struct IMediaDet;
+
+namespace avmedia::win {
+
+class FrameGrabber : public ::cppu::WeakImplHelper< css::media::XFrameGrabber,
+ css::lang::XServiceInfo >
+{
+public:
+
+ explicit FrameGrabber( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxMgr );
+ ~FrameGrabber() override;
+
+ bool create( const OUString& rURL );
+
+ // XFrameGrabber
+ virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL grabFrame( double fMediaTime ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+ OUString maURL;
+};
+
+} // namespace avmedia::win
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/interface.hxx b/avmedia/source/win/interface.hxx
new file mode 100644
index 000000000..a52c6ab1f
--- /dev/null
+++ b/avmedia/source/win/interface.hxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+extern "C" const CLSID CLSID_MediaDet;
+extern "C" const IID IID_IMediaDet;
+struct ISampleGrabber;
+
+struct
+__declspec(uuid("65BD0710-24D2-4ff7-9324-ED2E5D3ABAFA")) __declspec(novtable)
+IMediaDet : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall get_Filter(
+ IUnknown **pVal) = 0;
+ virtual HRESULT __stdcall put_Filter(
+ IUnknown *newVal) = 0;
+ virtual HRESULT __stdcall get_OutputStreams(
+ long *pVal) = 0;
+ virtual HRESULT __stdcall get_CurrentStream(
+ long *pVal) = 0;
+ virtual HRESULT __stdcall put_CurrentStream(
+ long newVal) = 0;
+ virtual HRESULT __stdcall get_StreamType(
+ GUID *pVal) = 0;
+ virtual HRESULT __stdcall get_StreamTypeB(
+ BSTR *pVal) = 0;
+ virtual HRESULT __stdcall get_StreamLength(
+ double *pVal) = 0;
+ virtual HRESULT __stdcall get_Filename(
+ BSTR *pVal) = 0;
+ virtual HRESULT __stdcall put_Filename(
+ BSTR newVal) = 0;
+ virtual HRESULT __stdcall GetBitmapBits(
+ double StreamTime,
+ long *pBufferSize,
+ char *pBuffer,
+ long Width,
+ long Height) = 0;
+ virtual HRESULT __stdcall WriteBitmapBits(
+ double StreamTime,
+ long Width,
+ long Height,
+ BSTR Filename) = 0;
+ virtual HRESULT __stdcall get_StreamMediaType(
+ AM_MEDIA_TYPE *pVal) = 0;
+ virtual HRESULT __stdcall GetSampleGrabber(
+ ISampleGrabber **ppVal) = 0;
+ virtual HRESULT __stdcall get_FrameRate(
+ double *pVal) = 0;
+ virtual HRESULT __stdcall EnterBitmapGrabMode(
+ double SeekTime) = 0;
+
+protected:
+ ~IMediaDet() {}
+};
+
+extern "C" const IID IID_ISampleGrabberCB;
+struct
+__declspec(uuid("0579154A-2B53-4994-B0D0-E773148EFF85")) __declspec(novtable)
+ISampleGrabberCB : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall SampleCB(
+ double SampleTime,
+ IMediaSample *pSample) = 0;
+ virtual HRESULT __stdcall BufferCB(
+ double SampleTime,
+ BYTE *pBuffer,
+ long BufferLen) = 0;
+
+protected:
+ ~ISampleGrabberCB() {}
+};
+
+extern "C" const IID IID_ISampleGrabber;
+struct
+__declspec(uuid("6B652FFF-11FE-4fce-92AD-0266B5D7C78F")) __declspec(novtable)
+ISampleGrabber : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall SetOneShot(
+ BOOL OneShot) = 0;
+ virtual HRESULT __stdcall SetMediaType(
+ const AM_MEDIA_TYPE *pType) = 0;
+ virtual HRESULT __stdcall GetConnectedMediaType(
+ AM_MEDIA_TYPE *pType) = 0;
+ virtual HRESULT __stdcall SetBufferSamples(
+ BOOL BufferThem) = 0;
+ virtual HRESULT __stdcall GetCurrentBuffer(
+ long *pBufferSize,
+ long *pBuffer) = 0;
+ virtual HRESULT __stdcall GetCurrentSample(
+ IMediaSample **ppSample) = 0;
+ virtual HRESULT __stdcall SetCallback(
+ ISampleGrabberCB *pCallback,
+ long WhichMethodToCallback) = 0;
+
+protected:
+ ~ISampleGrabber() {}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/manager.cxx b/avmedia/source/win/manager.cxx
new file mode 100644
index 000000000..3615850a7
--- /dev/null
+++ b/avmedia/source/win/manager.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "manager.hxx"
+#include "player.hxx"
+
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/urlobj.hxx>
+
+#define AVMEDIA_WIN_MANAGER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Manager_DirectX"
+#define AVMEDIA_WIN_MANAGER_SERVICENAME "com.sun.star.media.Manager"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::win {
+
+Manager::Manager( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
+ mxMgr( rxMgr )
+{
+}
+
+
+Manager::~Manager()
+{
+}
+
+
+uno::Reference< media::XPlayer > SAL_CALL Manager::createPlayer( const OUString& rURL )
+{
+ Player* pPlayer( new Player( mxMgr ) );
+ uno::Reference< media::XPlayer > xRet( pPlayer );
+ const INetURLObject aURL( rURL );
+
+ if( !pPlayer->create( aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ) )
+ xRet.clear();
+
+ return xRet;
+}
+
+
+OUString SAL_CALL Manager::getImplementationName( )
+{
+ return AVMEDIA_WIN_MANAGER_IMPLEMENTATIONNAME;
+}
+
+
+sal_Bool SAL_CALL Manager::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+uno::Sequence< OUString > SAL_CALL Manager::getSupportedServiceNames( )
+{
+ return { AVMEDIA_WIN_MANAGER_SERVICENAME };
+}
+
+} // namespace avmedia::win
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/manager.hxx b/avmedia/source/win/manager.hxx
new file mode 100644
index 000000000..77d1ce6ef
--- /dev/null
+++ b/avmedia/source/win/manager.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "wincommon.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/media/XManager.hpp>
+
+
+namespace avmedia::win {
+
+class Manager : public ::cppu::WeakImplHelper< css::media::XManager,
+ css::lang::XServiceInfo >
+{
+public:
+
+ explicit Manager( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxMgr );
+ ~Manager() override;
+
+ // XManager
+ virtual css::uno::Reference< css::media::XPlayer > SAL_CALL createPlayer( const OUString& aURL ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+private:
+
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+};
+
+} // namespace avmedia::win
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/player.cxx b/avmedia/source/win/player.cxx
new file mode 100644
index 000000000..8e08d9e53
--- /dev/null
+++ b/avmedia/source/win/player.cxx
@@ -0,0 +1,463 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <objbase.h>
+#include <strmif.h>
+#include <control.h>
+#include <uuids.h>
+#include <evcode.h>
+
+#include "player.hxx"
+#include "framegrabber.hxx"
+#include "window.hxx"
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <osl/file.hxx>
+
+#define AVMEDIA_WIN_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_DirectX"
+#define AVMEDIA_WIN_PLAYER_SERVICENAME "com.sun.star.media.Player_DirectX"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::win {
+
+static LRESULT CALLBACK MediaPlayerWndProc_2( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
+{
+ Player* pPlayer = reinterpret_cast<Player*>(::GetWindowLongPtrW( hWnd, 0 ));
+ bool bProcessed = true;
+
+ if( pPlayer )
+ {
+ switch( nMsg )
+ {
+ case WM_GRAPHNOTIFY:
+ pPlayer->processEvent();
+ break;
+ default:
+ bProcessed = false;
+ break;
+ }
+ }
+ else
+ bProcessed = false;
+
+ return( bProcessed ? 0 : DefWindowProcW( hWnd, nMsg, nPar1, nPar2 ) );
+}
+
+
+Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) :
+ Player_BASE(m_aMutex),
+ mxMgr( rxMgr ),
+ mpGB( nullptr ),
+ mpOMF( nullptr ),
+ mpMC( nullptr ),
+ mpME( nullptr ),
+ mpMS( nullptr ),
+ mpMP( nullptr ),
+ mpBA( nullptr ),
+ mpBV( nullptr ),
+ mpVW( nullptr ),
+ mpEV( nullptr ),
+ mnUnmutedVolume( 0 ),
+ mnFrameWnd( nullptr ),
+ mbMuted( false ),
+ mbLooping( false ),
+ mbAddWindow( true )
+{
+ ::CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED );
+}
+
+
+Player::~Player()
+{
+ if( mnFrameWnd )
+ ::DestroyWindow( mnFrameWnd );
+
+ ::CoUninitialize();
+}
+
+
+void SAL_CALL Player::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ stop();
+ if( mpBA )
+ mpBA->Release();
+
+ if( mpBV )
+ mpBV->Release();
+
+ if( mpVW )
+ mpVW->Release();
+
+ if( mpMP )
+ mpMP->Release();
+
+ if( mpMS )
+ mpMS->Release();
+
+ if( mpME )
+ {
+ mpME->SetNotifyWindow( 0, WM_GRAPHNOTIFY, 0);
+ mpME->Release();
+ }
+
+ if( mpMC )
+ mpMC->Release();
+
+ if( mpEV )
+ mpEV->Release();
+
+ if( mpOMF )
+ mpOMF->Release();
+
+ if( mpGB )
+ mpGB->Release();
+}
+
+
+bool Player::create( const OUString& rURL )
+{
+ HRESULT hR;
+ bool bRet = false;
+
+ if( SUCCEEDED( hR = CoCreateInstance( CLSID_FilterGraph, nullptr, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, reinterpret_cast<void**>(&mpGB) ) ) )
+ {
+ // Don't use the overlay mixer on Windows Vista
+ // It disables the desktop composition as soon as RenderFile is called
+ // also causes some other problems: video rendering is not reliable
+
+ // tdf#128057: IGraphBuilder::RenderFile seems to fail to handle file URIs properly when
+ // they contain encoded characters like "%23"; so pass system path in that case instead.
+ OUString aFile(rURL);
+ if (aFile.startsWithIgnoreAsciiCase("file:"))
+ osl::FileBase::getSystemPathFromFileURL(rURL, aFile);
+
+ if( SUCCEEDED( hR = mpGB->RenderFile( o3tl::toW(aFile.getStr()), nullptr ) ) &&
+ SUCCEEDED( hR = mpGB->QueryInterface( IID_IMediaControl, reinterpret_cast<void**>(&mpMC) ) ) &&
+ SUCCEEDED( hR = mpGB->QueryInterface( IID_IMediaEventEx, reinterpret_cast<void**>(&mpME) ) ) &&
+ SUCCEEDED( hR = mpGB->QueryInterface( IID_IMediaSeeking, reinterpret_cast<void**>(&mpMS) ) ) &&
+ SUCCEEDED( hR = mpGB->QueryInterface( IID_IMediaPosition, reinterpret_cast<void**>(&mpMP) ) ) )
+ {
+ // Video interfaces
+ mpGB->QueryInterface( IID_IVideoWindow, reinterpret_cast<void**>(&mpVW) );
+ mpGB->QueryInterface( IID_IBasicVideo, reinterpret_cast<void**>(&mpBV) );
+
+ // Audio interface
+ mpGB->QueryInterface( IID_IBasicAudio, reinterpret_cast<void**>(&mpBA) );
+
+ if( mpBA )
+ mpBA->put_Volume( mnUnmutedVolume );
+
+ bRet = true;
+ }
+ }
+
+ if( bRet )
+ maURL = rURL;
+ else
+ maURL.clear();
+
+ return bRet;
+}
+
+
+const IVideoWindow* Player::getVideoWindow() const
+{
+ return mpVW;
+}
+
+
+void Player::setNotifyWnd( HWND nNotifyWnd )
+{
+ mbAddWindow = false;
+ if( mpME )
+ mpME->SetNotifyWindow( reinterpret_cast<OAHWND>(nNotifyWnd), WM_GRAPHNOTIFY, reinterpret_cast< LONG_PTR>( this ) );
+}
+
+
+long Player::processEvent()
+{
+ long nCode;
+ LONG_PTR nParam1, nParam2;
+
+ while( mpME && SUCCEEDED( mpME->GetEvent( &nCode, &nParam1, &nParam2, 0 ) ) )
+ {
+ if( EC_COMPLETE == nCode )
+ {
+ if( mbLooping )
+ {
+ setMediaTime( 0.0 );
+ start();
+ }
+ else
+ {
+ setMediaTime( getDuration() );
+ stop();
+ }
+ }
+
+ mpME->FreeEventParams( nCode, nParam1, nParam2 );
+ }
+
+ return 0;
+}
+
+
+void SAL_CALL Player::start( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if( mpMC )
+ {
+ if ( mbAddWindow )
+ {
+ static WNDCLASSW* mpWndClass = nullptr;
+ if ( !mpWndClass )
+ {
+ mpWndClass = new WNDCLASSW;
+
+ memset( mpWndClass, 0, sizeof( *mpWndClass ) );
+ mpWndClass->hInstance = GetModuleHandleW( nullptr );
+ mpWndClass->cbWndExtra = sizeof( DWORD );
+ mpWndClass->lpfnWndProc = MediaPlayerWndProc_2;
+ mpWndClass->lpszClassName = L"com_sun_star_media_Sound_Player";
+ mpWndClass->hbrBackground = static_cast<HBRUSH>(::GetStockObject( BLACK_BRUSH ));
+ mpWndClass->hCursor = ::LoadCursor( nullptr, IDC_ARROW );
+
+ RegisterClassW( mpWndClass );
+ }
+ if ( !mnFrameWnd )
+ {
+ mnFrameWnd = CreateWindowW( mpWndClass->lpszClassName, nullptr,
+ 0,
+ 0, 0, 0, 0,
+ nullptr, nullptr, mpWndClass->hInstance, nullptr );
+ if ( mnFrameWnd )
+ {
+ ::ShowWindow(mnFrameWnd, SW_HIDE);
+ SetWindowLongPtrW( mnFrameWnd, 0, reinterpret_cast<LONG_PTR>(this) );
+ // mpVW->put_Owner( (OAHWND) mnFrameWnd );
+ setNotifyWnd( mnFrameWnd );
+ }
+ }
+ }
+
+ mpMC->Run();
+ }
+}
+
+
+void SAL_CALL Player::stop( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if( mpMC )
+ mpMC->Stop();
+}
+
+
+sal_Bool SAL_CALL Player::isPlaying()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OAFilterState eFilterState;
+ bool bRet = false;
+
+ if( mpMC && SUCCEEDED( mpMC->GetState( 10, &eFilterState ) ) )
+ bRet = ( State_Running == eFilterState );
+
+ return bRet;
+}
+
+
+double SAL_CALL Player::getDuration( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ REFTIME aRefTime( 0.0 );
+
+ if( mpMP )
+ mpMP->get_Duration( &aRefTime );
+
+ return aRefTime;
+}
+
+
+void SAL_CALL Player::setMediaTime( double fTime )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if( mpMP )
+ {
+ const bool bPlaying = isPlaying();
+
+ mpMP->put_CurrentPosition( fTime );
+
+ if( !bPlaying && mpMC )
+ mpMC->StopWhenReady();
+ }
+}
+
+
+double SAL_CALL Player::getMediaTime( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ REFTIME aRefTime( 0.0 );
+
+ if( mpMP )
+ mpMP->get_CurrentPosition( &aRefTime );
+
+ return aRefTime;
+}
+
+
+void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ mbLooping = bSet;
+}
+
+
+sal_Bool SAL_CALL Player::isPlaybackLoop( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ return mbLooping;
+}
+
+
+void SAL_CALL Player::setMute( sal_Bool bSet )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if (mpBA && (mbMuted != static_cast<bool>(bSet)))
+ {
+ mbMuted = bSet;
+ mpBA->put_Volume( mbMuted ? -10000 : mnUnmutedVolume );
+ }
+}
+
+
+sal_Bool SAL_CALL Player::isMute( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ return mbMuted;
+}
+
+
+void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ mnUnmutedVolume = static_cast< long >( nVolumeDB ) * 100;
+
+ if( !mbMuted && mpBA )
+ mpBA->put_Volume( mnUnmutedVolume );
+}
+
+
+sal_Int16 SAL_CALL Player::getVolumeDB( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ return static_cast< sal_Int16 >( mnUnmutedVolume / 100 );
+}
+
+
+awt::Size SAL_CALL Player::getPreferredPlayerWindowSize( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ awt::Size aSize( 0, 0 );
+
+ if( mpBV )
+ {
+ long nWidth = 0, nHeight = 0;
+
+ mpBV->GetVideoSize( &nWidth, &nHeight );
+ aSize.Width = nWidth;
+ aSize.Height = nHeight;
+ }
+
+ return aSize;
+}
+
+
+uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& aArguments )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ uno::Reference< ::media::XPlayerWindow > xRet;
+ awt::Size aSize( getPreferredPlayerWindowSize() );
+
+ if( mpVW && aSize.Width > 0 && aSize.Height > 0 )
+ {
+ ::avmedia::win::Window* pWindow = new ::avmedia::win::Window( mxMgr, *this );
+
+ xRet = pWindow;
+
+ if( !pWindow->create( aArguments ) )
+ xRet.clear();
+ }
+
+ return xRet;
+}
+
+
+uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber( )
+{
+ uno::Reference< media::XFrameGrabber > xRet;
+
+ if( !maURL.isEmpty() )
+ {
+ FrameGrabber* pGrabber = new FrameGrabber( mxMgr );
+
+ xRet = pGrabber;
+
+ if( !pGrabber->create( maURL ) )
+ xRet.clear();
+ }
+
+ return xRet;
+}
+
+
+OUString SAL_CALL Player::getImplementationName( )
+{
+ return AVMEDIA_WIN_PLAYER_IMPLEMENTATIONNAME;
+}
+
+
+sal_Bool SAL_CALL Player::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+uno::Sequence< OUString > SAL_CALL Player::getSupportedServiceNames( )
+{
+ return { AVMEDIA_WIN_PLAYER_SERVICENAME };
+}
+
+} // namespace avmedia::win
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/player.hxx b/avmedia/source/win/player.hxx
new file mode 100644
index 000000000..370851368
--- /dev/null
+++ b/avmedia/source/win/player.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <WinDef.h>
+
+#include "wincommon.hxx"
+
+#include <com/sun/star/media/XPlayer.hpp>
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+struct IGraphBuilder;
+struct IBaseFilter;
+struct IMediaControl;
+struct IMediaEventEx;
+struct IMediaSeeking;
+struct IMediaPosition;
+struct IBasicAudio;
+struct IBasicVideo;
+struct IVideoWindow;
+struct IDDrawExclModeVideo;
+struct IDirectDraw;
+struct IDirectDrawSurface;
+
+namespace avmedia::win {
+
+typedef ::cppu::WeakComponentImplHelper< css::media::XPlayer,
+ css::lang::XServiceInfo > Player_BASE;
+
+
+class Player : public cppu::BaseMutex,
+ public Player_BASE
+{
+public:
+
+ explicit Player( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxMgr );
+ ~Player() override;
+
+ bool create( const OUString& rURL );
+
+ void setNotifyWnd( HWND nNotifyWnd );
+ long processEvent();
+
+ const IVideoWindow* getVideoWindow() const;
+
+ // XPlayer
+ virtual void SAL_CALL start( ) override;
+ virtual void SAL_CALL stop( ) override;
+ virtual sal_Bool SAL_CALL isPlaying( ) override;
+ virtual double SAL_CALL getDuration( ) override;
+ virtual void SAL_CALL setMediaTime( double fTime ) override;
+ virtual double SAL_CALL getMediaTime( ) override;
+ virtual void SAL_CALL setPlaybackLoop( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL isPlaybackLoop( ) override;
+ virtual void SAL_CALL setMute( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL isMute( ) override;
+ virtual void SAL_CALL setVolumeDB( sal_Int16 nVolumeDB ) override;
+ virtual sal_Int16 SAL_CALL getVolumeDB( ) override;
+ virtual css::awt::Size SAL_CALL getPreferredPlayerWindowSize( ) override;
+ virtual css::uno::Reference< css::media::XPlayerWindow > SAL_CALL createPlayerWindow( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+ virtual css::uno::Reference< css::media::XFrameGrabber > SAL_CALL createFrameGrabber( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+private:
+
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+
+ OUString maURL;
+ IGraphBuilder* mpGB;
+ IBaseFilter* mpOMF;
+ IMediaControl* mpMC;
+ IMediaEventEx* mpME;
+ IMediaSeeking* mpMS;
+ IMediaPosition* mpMP;
+ IBasicAudio* mpBA;
+ IBasicVideo* mpBV;
+ IVideoWindow* mpVW;
+ IDDrawExclModeVideo* mpEV;
+ long mnUnmutedVolume;
+ HWND mnFrameWnd;
+ bool mbMuted;
+ bool mbLooping;
+ bool mbAddWindow;
+
+ void ImplLayoutVideoWindow();
+};
+
+} // namespace avmedia::win
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/wincommon.hxx b/avmedia/source/win/wincommon.hxx
new file mode 100644
index 000000000..f0277e169
--- /dev/null
+++ b/avmedia/source/win/wincommon.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#ifndef INCLUDED_AVMEDIA_SOURCE_WIN_WINCOMMON_HXX
+#define INCLUDED_AVMEDIA_SOURCE_WIN_WINCOMMON_HXX
+
+#include <osl/mutex.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/stream.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/factory.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/media/XManager.hpp>
+
+#define WM_GRAPHNOTIFY (WM_USER + 567)
+
+#endif // INCLUDED_AVMEDIA_SOURCE_WIN_WINCOMMON_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/window.cxx b/avmedia/source/win/window.cxx
new file mode 100644
index 000000000..995ddd92c
--- /dev/null
+++ b/avmedia/source/win/window.cxx
@@ -0,0 +1,495 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <objbase.h>
+#include <strmif.h>
+#include <control.h>
+#include <dshow.h>
+
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+#include "window.hxx"
+#include "player.hxx"
+
+#define AVMEDIA_WIN_WINDOW_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Window_DirectX"
+#define AVMEDIA_WIN_WINDOW_SERVICENAME "com.sun.star.media.Window_DirectX"
+
+using namespace ::com::sun::star;
+
+namespace avmedia::win {
+
+static LRESULT CALLBACK MediaPlayerWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
+{
+ Window* pWindow = reinterpret_cast<Window*>(GetWindowLongPtrW( hWnd, 0 ));
+ bool bProcessed = true;
+
+ if( pWindow )
+ {
+ switch( nMsg )
+ {
+ case WM_SETCURSOR:
+ pWindow->updatePointer();
+ break;
+
+ case WM_GRAPHNOTIFY:
+ pWindow->processGraphEvent();
+ break;
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ PostMessage(pWindow->getParentWnd(), nMsg, nPar1, nPar2);
+ break;
+
+ case WM_SETFOCUS:
+ {
+ const awt::FocusEvent aUNOEvt;
+ pWindow->fireSetFocusEvent( aUNOEvt );
+ }
+ break;
+
+ default:
+ bProcessed = false;
+ break;
+ }
+ }
+ else
+ bProcessed = false;
+
+ return( bProcessed ? 0 : DefWindowProcW( hWnd, nMsg, nPar1, nPar2 ) );
+}
+
+static WNDCLASSW* lcl_getWndClass()
+{
+ WNDCLASSW* s_pWndClass = new WNDCLASSW;
+
+ memset( s_pWndClass, 0, sizeof( *s_pWndClass ) );
+ s_pWndClass->hInstance = GetModuleHandleW( nullptr );
+ s_pWndClass->cbWndExtra = sizeof( DWORD_PTR );
+ s_pWndClass->lpfnWndProc = MediaPlayerWndProc;
+ s_pWndClass->lpszClassName = L"com_sun_star_media_PlayerWnd";
+ s_pWndClass->hbrBackground = static_cast<HBRUSH>(::GetStockObject( BLACK_BRUSH ));
+ s_pWndClass->hCursor = ::LoadCursor( nullptr, IDC_ARROW );
+
+ RegisterClassW( s_pWndClass );
+
+ return s_pWndClass;
+}
+
+Window::Window( const uno::Reference< lang::XMultiServiceFactory >& rxMgr, Player& rPlayer ) :
+ mxMgr( rxMgr ),
+ maListeners( maMutex ),
+ meZoomLevel( media::ZoomLevel_NOT_AVAILABLE ),
+ mrPlayer( rPlayer ),
+ mnFrameWnd( nullptr ),
+ mnParentWnd( nullptr ),
+ mnPointerType( awt::SystemPointer::ARROW )
+{
+}
+
+Window::~Window()
+{
+ if( mnFrameWnd )
+ ::DestroyWindow( mnFrameWnd );
+}
+
+void Window::ImplLayoutVideoWindow()
+{
+ if( media::ZoomLevel_NOT_AVAILABLE != meZoomLevel )
+ {
+ awt::Size aPrefSize( mrPlayer.getPreferredPlayerWindowSize() );
+ awt::Rectangle aRect = getPosSize();
+ int nW = aRect.Width, nH = aRect.Height;
+ int nVideoW = nW, nVideoH = nH;
+ int nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ bool bDone = false, bZoom = false;
+
+ if( media::ZoomLevel_ORIGINAL == meZoomLevel )
+ {
+ bZoom = true;
+ }
+ else if( media::ZoomLevel_ZOOM_1_TO_4 == meZoomLevel )
+ {
+ aPrefSize.Width >>= 2;
+ aPrefSize.Height >>= 2;
+ bZoom = true;
+ }
+ else if( media::ZoomLevel_ZOOM_1_TO_2 == meZoomLevel )
+ {
+ aPrefSize.Width >>= 1;
+ aPrefSize.Height >>= 1;
+ bZoom = true;
+ }
+ else if( media::ZoomLevel_ZOOM_2_TO_1 == meZoomLevel )
+ {
+ aPrefSize.Width <<= 1;
+ aPrefSize.Height <<= 1;
+ bZoom = true;
+ }
+ else if( media::ZoomLevel_ZOOM_4_TO_1 == meZoomLevel )
+ {
+ aPrefSize.Width <<= 2;
+ aPrefSize.Height <<= 2;
+ bZoom = true;
+ }
+ else if( media::ZoomLevel_FIT_TO_WINDOW == meZoomLevel )
+ {
+ nWidth = nVideoW;
+ nHeight = nVideoH;
+ bDone = true;
+ }
+
+ if( bZoom )
+ {
+ if( ( aPrefSize.Width <= nVideoW ) && ( aPrefSize.Height <= nVideoH ) )
+ {
+ nX = ( nVideoW - aPrefSize.Width ) >> 1;
+ nY = ( nVideoH - aPrefSize.Height ) >> 1;
+ nWidth = aPrefSize.Width;
+ nHeight = aPrefSize.Height;
+ bDone = true;
+ }
+ }
+
+ if( !bDone )
+ {
+ if( aPrefSize.Width > 0 && aPrefSize.Height > 0 && nVideoW > 0 && nVideoH > 0 )
+ {
+ double fPrefWH = static_cast<double>(aPrefSize.Width) / aPrefSize.Height;
+
+ if( fPrefWH < ( static_cast<double>(nVideoW) / nVideoH ) )
+ nVideoW = static_cast<int>( nVideoH * fPrefWH );
+ else
+ nVideoH = static_cast<int>( nVideoW / fPrefWH );
+
+ nX = ( nW - nVideoW ) >> 1;
+ nY = ( nH - nVideoH ) >> 1;
+ nWidth = nVideoW;
+ nHeight = nVideoH;
+ }
+ else
+ nX = nY = nWidth = nHeight = 0;
+ }
+
+ IVideoWindow* pVideoWindow = const_cast< IVideoWindow* >( mrPlayer.getVideoWindow() );
+
+ if( pVideoWindow )
+ pVideoWindow->SetWindowPosition( nX, nY, nWidth, nHeight );
+ }
+}
+
+bool Window::create( const uno::Sequence< uno::Any >& rArguments )
+{
+ IVideoWindow* pVideoWindow = const_cast< IVideoWindow* >( mrPlayer.getVideoWindow() );
+ static WNDCLASSW* mpWndClass = lcl_getWndClass();
+
+ if( !mnFrameWnd && pVideoWindow && mpWndClass )
+ {
+ awt::Rectangle aRect;
+ sal_IntPtr nWnd;
+
+ rArguments[ 0 ] >>= nWnd;
+ rArguments[ 1 ] >>= aRect;
+
+ mnParentWnd = reinterpret_cast<HWND>(nWnd);
+
+ mnFrameWnd = CreateWindowW( mpWndClass->lpszClassName, nullptr,
+ WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ aRect.X, aRect.Y, aRect.Width, aRect.Height,
+ mnParentWnd, nullptr, mpWndClass->hInstance, nullptr );
+
+ if( mnFrameWnd )
+ {
+ SetWindowLongPtrW( mnFrameWnd, 0, reinterpret_cast<LONG_PTR>(this) );
+
+ pVideoWindow->put_Owner( reinterpret_cast<OAHWND>(mnFrameWnd) );
+ pVideoWindow->put_MessageDrain( reinterpret_cast<OAHWND>(mnFrameWnd) );
+ pVideoWindow->put_WindowStyle( WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
+
+ mrPlayer.setNotifyWnd( mnFrameWnd );
+
+ meZoomLevel = media::ZoomLevel_FIT_TO_WINDOW;
+ ImplLayoutVideoWindow();
+ }
+ }
+
+ return( mnFrameWnd != nullptr );
+}
+
+void Window::processGraphEvent()
+{
+ mrPlayer.processEvent();
+}
+
+void Window::updatePointer()
+{
+ LPCTSTR pCursorName;
+
+ switch( mnPointerType )
+ {
+ case awt::SystemPointer::CROSS: pCursorName = IDC_CROSS; break;
+ case awt::SystemPointer::MOVE: pCursorName = IDC_SIZEALL; break;
+ case awt::SystemPointer::WAIT: pCursorName = IDC_WAIT; break;
+
+ default:
+ pCursorName = IDC_ARROW;
+ break;
+ }
+
+ SetCursor( LoadCursor( nullptr, pCursorName ) );
+}
+
+void SAL_CALL Window::update( )
+{
+ ::RedrawWindow( mnFrameWnd, nullptr, nullptr, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE );
+}
+
+sal_Bool SAL_CALL Window::setZoomLevel( media::ZoomLevel eZoomLevel )
+{
+ bool bRet = false;
+
+ if( media::ZoomLevel_NOT_AVAILABLE != meZoomLevel &&
+ media::ZoomLevel_NOT_AVAILABLE != eZoomLevel )
+ {
+ if( eZoomLevel != meZoomLevel )
+ {
+ meZoomLevel = eZoomLevel;
+ ImplLayoutVideoWindow();
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+media::ZoomLevel SAL_CALL Window::getZoomLevel( )
+{
+ return meZoomLevel;
+}
+
+void SAL_CALL Window::setPointerType( sal_Int32 nPointerType )
+{
+ mnPointerType = nPointerType;
+}
+
+void SAL_CALL Window::setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 )
+{
+ if( mnFrameWnd )
+ {
+ ::SetWindowPos( mnFrameWnd, HWND_TOP, X, Y, Width, Height, 0 );
+ ImplLayoutVideoWindow();
+ }
+}
+
+awt::Rectangle SAL_CALL Window::getPosSize()
+{
+ awt::Rectangle aRet;
+
+ if( mnFrameWnd )
+ {
+ ::RECT aWndRect;
+
+ if( ::GetClientRect( mnFrameWnd, &aWndRect ) )
+ {
+ aRet.X = aWndRect.left;
+ aRet.Y = aWndRect.top;
+ aRet.Width = aWndRect.right - aWndRect.left + 1;
+ aRet.Height = aWndRect.bottom - aWndRect.top + 1;
+ }
+ }
+
+ return aRet;
+}
+
+void SAL_CALL Window::setVisible( sal_Bool bVisible )
+{
+ if( mnFrameWnd )
+ {
+ IVideoWindow* pVideoWindow = const_cast< IVideoWindow* >( mrPlayer.getVideoWindow() );
+
+ if( pVideoWindow )
+ pVideoWindow->put_Visible( bVisible ? OATRUE : OAFALSE );
+
+ ::ShowWindow( mnFrameWnd, bVisible ? SW_SHOW : SW_HIDE );
+ }
+}
+
+void SAL_CALL Window::setEnable( sal_Bool bEnable )
+{
+ if( mnFrameWnd )
+ ::EnableWindow( mnFrameWnd, bEnable );
+}
+
+void SAL_CALL Window::setFocus( )
+{
+ if( mnFrameWnd )
+ ::SetFocus( mnFrameWnd );
+}
+
+void SAL_CALL Window::addWindowListener( const uno::Reference< awt::XWindowListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::removeWindowListener( const uno::Reference< awt::XWindowListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::addFocusListener( const uno::Reference< awt::XFocusListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::removeFocusListener( const uno::Reference< awt::XFocusListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::addKeyListener( const uno::Reference< awt::XKeyListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::removeKeyListener( const uno::Reference< awt::XKeyListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::addMouseListener( const uno::Reference< awt::XMouseListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::removeMouseListener( const uno::Reference< awt::XMouseListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::addPaintListener( const uno::Reference< awt::XPaintListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::removePaintListener( const uno::Reference< awt::XPaintListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::dispose( )
+{
+}
+
+void SAL_CALL Window::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void SAL_CALL Window::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+void Window::fireMousePressedEvent( const css::awt::MouseEvent& rEvt )
+{
+ ::cppu::OInterfaceContainerHelper* pContainer = maListeners.getContainer( cppu::UnoType<awt::XMouseListener>::get());
+
+ if( pContainer )
+ {
+ ::cppu::OInterfaceIteratorHelper aIter( *pContainer );
+
+ while( aIter.hasMoreElements() )
+ uno::Reference< awt::XMouseListener >( aIter.next(), uno::UNO_QUERY_THROW )->mousePressed( rEvt );
+ }
+}
+
+void Window::fireMouseReleasedEvent( const css::awt::MouseEvent& rEvt )
+{
+ ::cppu::OInterfaceContainerHelper* pContainer = maListeners.getContainer( cppu::UnoType<awt::XMouseListener>::get());
+
+ if( pContainer )
+ {
+ ::cppu::OInterfaceIteratorHelper aIter( *pContainer );
+
+ while( aIter.hasMoreElements() )
+ uno::Reference< awt::XMouseListener >( aIter.next(), uno::UNO_QUERY_THROW )->mouseReleased( rEvt );
+ }
+}
+
+void Window::fireMouseMovedEvent( const css::awt::MouseEvent& rEvt )
+{
+ ::cppu::OInterfaceContainerHelper* pContainer = maListeners.getContainer( cppu::UnoType<awt::XMouseMotionListener>::get());
+
+ if( pContainer )
+ {
+ ::cppu::OInterfaceIteratorHelper aIter( *pContainer );
+
+ while( aIter.hasMoreElements() )
+ uno::Reference< awt::XMouseMotionListener >( aIter.next(), uno::UNO_QUERY_THROW )->mouseMoved( rEvt );
+ }
+}
+
+void Window::fireSetFocusEvent( const css::awt::FocusEvent& rEvt )
+{
+ ::cppu::OInterfaceContainerHelper* pContainer = maListeners.getContainer( cppu::UnoType<awt::XFocusListener>::get());
+
+ if( pContainer )
+ {
+ ::cppu::OInterfaceIteratorHelper aIter( *pContainer );
+
+ while( aIter.hasMoreElements() )
+ uno::Reference< awt::XFocusListener >( aIter.next(), uno::UNO_QUERY_THROW )->focusGained( rEvt );
+ }
+}
+
+OUString SAL_CALL Window::getImplementationName( )
+{
+ return AVMEDIA_WIN_WINDOW_IMPLEMENTATIONNAME;
+}
+
+sal_Bool SAL_CALL Window::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL Window::getSupportedServiceNames( )
+{
+ return { AVMEDIA_WIN_WINDOW_SERVICENAME };
+}
+
+} // namespace avmedia::win
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/window.hxx b/avmedia/source/win/window.hxx
new file mode 100644
index 000000000..a947c1717
--- /dev/null
+++ b/avmedia/source/win/window.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <WinDef.h>
+
+#include "wincommon.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/interfacecontainer.h>
+
+#include <com/sun/star/media/XPlayerWindow.hpp>
+
+struct IVideoWindow;
+
+namespace avmedia::win {
+
+class Player;
+
+
+class Window : public ::cppu::WeakImplHelper< css::media::XPlayerWindow,
+ css::lang::XServiceInfo >
+{
+public:
+
+ Window( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxMgr,
+ Player& rPlayer );
+ ~Window() override;
+
+ bool create( const css::uno::Sequence< css::uno::Any >& aArguments );
+ void processGraphEvent();
+ void updatePointer();
+
+ // XPlayerWindow
+ virtual void SAL_CALL update( ) override;
+ virtual sal_Bool SAL_CALL setZoomLevel( css::media::ZoomLevel ZoomLevel ) override;
+ virtual css::media::ZoomLevel SAL_CALL getZoomLevel( ) override;
+ virtual void SAL_CALL setPointerType( sal_Int32 nPointerType ) override;
+
+ // XWindow
+ virtual void SAL_CALL setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) override;
+ virtual css::awt::Rectangle SAL_CALL getPosSize( ) override;
+ virtual void SAL_CALL setVisible( sal_Bool Visible ) override;
+ virtual void SAL_CALL setEnable( sal_Bool Enable ) override;
+ virtual void SAL_CALL setFocus( ) override;
+ virtual void SAL_CALL addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+public:
+
+ void fireMousePressedEvent( const css::awt::MouseEvent& rEvt );
+ void fireMouseReleasedEvent( const css::awt::MouseEvent& rEvt );
+ void fireMouseMovedEvent( const css::awt::MouseEvent& rEvt );
+ void fireKeyPressedEvent( const css::awt::KeyEvent& rEvt );
+ void fireKeyReleasedEvent( const css::awt::KeyEvent& rEvt );
+ void fireSetFocusEvent( const css::awt::FocusEvent& rEvt );
+ HWND getParentWnd() const { return mnParentWnd; }
+
+private:
+
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr;
+
+ ::osl::Mutex maMutex;
+ ::cppu::OMultiTypeInterfaceContainerHelper maListeners;
+ css::media::ZoomLevel meZoomLevel;
+ Player& mrPlayer;
+ HWND mnFrameWnd;
+ HWND mnParentWnd;
+ int mnPointerType;
+
+ void ImplLayoutVideoWindow();
+};
+
+} // namespace avmedia::win
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/win/winuno.cxx b/avmedia/source/win/winuno.cxx
new file mode 100644
index 000000000..90b1f3e40
--- /dev/null
+++ b/avmedia/source/win/winuno.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "wincommon.hxx"
+#include "manager.hxx"
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+using namespace ::com::sun::star;
+
+
+// - factory methods -
+
+
+static uno::Reference< uno::XInterface > create_MediaPlayer( const uno::Reference< lang::XMultiServiceFactory >& rxFact )
+{
+ return uno::Reference< uno::XInterface >( *new ::avmedia::win::Manager( rxFact ) );
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void* avmediawin_component_getFactory( const char* pImplName, void* pServiceManager, void* )
+{
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+ void* pRet = nullptr;
+
+ if( rtl_str_compare( pImplName, "com.sun.star.comp.avmedia.Manager_DirectX" ) == 0 )
+ {
+ const OUString aServiceName( "com.sun.star.media.Manager_DirectX" );
+
+ xFactory.set( ::cppu::createSingleFactory(
+ static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
+ "com.sun.star.comp.avmedia.Manager_DirectX",
+ create_MediaPlayer, uno::Sequence< OUString >( &aServiceName, 1 ) ) );
+ }
+
+ if( xFactory.is() )
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */