avmedia/Library_avmediawin.mk                     |    8 
 avmedia/source/win/framegrabber.cxx               |  211 ++++---
 avmedia/source/win/framegrabber.hxx               |    8 
 avmedia/source/win/player.cxx                     |  634 +++++++++++++++-------
 avmedia/source/win/player.hxx                     |   89 ++-
 avmedia/source/win/wincommon.hxx                  |    2 
 avmedia/source/win/window.cxx                     |   96 +--
 avmedia/source/win/window.hxx                     |    5 
 slideshow/source/engine/shapes/viewmediashape.cxx |    8 
 svx/uiconfig/ui/medialine.ui                      |   11 
 svx/uiconfig/ui/mediawindow.ui                    |   10 
 11 files changed, 732 insertions(+), 350 deletions(-)

New commits:
commit 65d72f816afc92a062cf6ad14c1bb4fb0a5829df
Author:     Balazs Varga <[email protected]>
AuthorDate: Fri Jul 4 12:54:04 2025 +0200
Commit:     Balazs Varga <[email protected]>
CommitDate: Wed Jul 23 20:34:23 2025 +0200

    tdf#62408 tdf#159292 Impress: Introduce Microsoft Media Foundation APIs
    
    on Windows to support playback of common codecs.
    
    Managing video playback with MFPlay:
    
https://learn.microsoft.com/en-us/windows/win32/medfound/getting-started-with-mfplay
    
    Using MFCreateSourceReaderFromURL for getting media informations.
    
    Supported video/audio file formats (without any additional codec) should be 
the same
    as in PowerPoint:
    
https://support.microsoft.com/en-us/office/video-and-audio-file-formats-supported-in-powerpoint-d8b12450-26db-4c7b-a5c1-593d3418fb59
    
    Change-Id: I6a32f3619b6985753122a17b863e09b3a12ecc0e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187384
    Tested-by: Jenkins
    Reviewed-by: Balazs Varga <[email protected]>

diff --git a/avmedia/Library_avmediawin.mk b/avmedia/Library_avmediawin.mk
index 318e28265530..b34c0eda7f51 100644
--- a/avmedia/Library_avmediawin.mk
+++ b/avmedia/Library_avmediawin.mk
@@ -28,6 +28,7 @@ $(eval $(call gb_Library_use_libraries,avmediawin,\
        tl \
        utl \
        vcl \
+       avmedia \
 ))
 
 $(eval $(call gb_Library_use_system_win32_libs,avmediawin,\
@@ -35,6 +36,13 @@ $(eval $(call gb_Library_use_system_win32_libs,avmediawin,\
        ole32 \
        oleaut32 \
        strmiids \
+       propsys \
+       shlwapi \
+       mf \
+       mfuuid \
+       mfplat \
+       mfplay \
+       mfreadwrite \
 ))
 
 $(eval $(call gb_Library_add_exception_objects,avmediawin,\
diff --git a/avmedia/source/win/framegrabber.cxx 
b/avmedia/source/win/framegrabber.cxx
index 84e9d1b187e8..62b771c076e4 100644
--- a/avmedia/source/win/framegrabber.cxx
+++ b/avmedia/source/win/framegrabber.cxx
@@ -21,14 +21,16 @@
 
 #include <memory>
 
-#include <prewin.h>
-#include <postwin.h>
 #include <objbase.h>
 #include <strmif.h>
-#include <Amvideo.h>
 #include "interface.hxx"
 #include <uuids.h>
 
+// Media Foundation headers
+#include <mfapi.h>
+#include <mfidl.h>
+#include <mfreadwrite.h>
+
 #include "framegrabber.hxx"
 #include "player.hxx"
 
@@ -37,147 +39,166 @@
 #include <tools/stream.hxx>
 #include <vcl/graph.hxx>
 #include <vcl/dibtools.hxx>
+#include <vcl/BitmapTools.hxx>
 #include <o3tl/char16_t2wchar_t.hxx>
 #include <systools/win32/oleauto.hxx>
 
 constexpr OUStringLiteral AVMEDIA_WIN_FRAMEGRABBER_IMPLEMENTATIONNAME = 
u"com.sun.star.comp.avmedia.FrameGrabber_DirectX";
 constexpr OUString AVMEDIA_WIN_FRAMEGRABBER_SERVICENAME = 
u"com.sun.star.media.FrameGrabber_DirectX"_ustr;
+constexpr LONGLONG SEEK_TOLERANCE = 10000000;
+constexpr LONGLONG MAX_FRAMES_TO_SKIP = 10;
 
 using namespace ::com::sun::star;
 
 namespace avmedia::win {
 
 
-FrameGrabber::FrameGrabber()
+FrameGrabber::FrameGrabber( const OUString& rURL, UINT32 nFrameWidth, UINT32 
nFrameHeight )
     : sal::systools::CoInitializeGuard(COINIT_APARTMENTTHREADED, false,
                                        
sal::systools::CoInitializeGuard::WhenFailed::NoThrow)
 {
+    maURL = rURL;
+    mnFrameWidth = nFrameWidth;
+    mnFrameHeight = nFrameHeight;
 }
 
-
 FrameGrabber::~FrameGrabber() = default;
 
-namespace {
-
-sal::systools::COMReference<IMediaDet> implCreateMediaDet( const OUString& 
rURL )
+uno::Reference< graphic::XGraphic > SAL_CALL FrameGrabber::grabFrame( double 
fMediaTime )
 {
-    sal::systools::COMReference<IMediaDet> pDet;
+    uno::Reference< graphic::XGraphic > xRet;
 
-    if( SUCCEEDED(pDet.CoCreateInstance(CLSID_MediaDet, nullptr, 
CLSCTX_INPROC_SERVER)) )
+    if (mnFrameWidth && mnFrameHeight &&
+        SUCCEEDED(MFStartup(MF_VERSION)))
     {
-        OUString aLocalStr;
-
-        if( osl::FileBase::getSystemPathFromFileURL( rURL, aLocalStr )
-            == osl::FileBase::E_None )
+        HRESULT hr = S_OK;
+        IMFAttributes* pAttributes = nullptr;
+
+        // Configure the source reader to perform video processing.
+        //
+        // This includes:
+        //   - YUV to RGB-32
+        //   - Software deinterlace
+        if (SUCCEEDED(MFCreateAttributes(&pAttributes, 1)))
         {
-            if( !SUCCEEDED( pDet->put_Filename(sal::systools::BStr(aLocalStr)) 
) )
-                pDet.clear();
+            hr = 
pAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE);
         }
-    }
-
-    return pDet;
-}
-
-}
 
-bool FrameGrabber::create( const OUString& rURL )
-{
-    // just check if a MediaDet interface can be created with the given URL
-    if (implCreateMediaDet(rURL))
-        maURL = rURL;
-    else
-        maURL.clear();
+        // Create the source reader from the URL.
+        IMFSourceReader* pReader = nullptr; // Create the source reader.
+        if (SUCCEEDED(hr) && 
SUCCEEDED(MFCreateSourceReaderFromURL(o3tl::toW(maURL.getStr()), pAttributes, 
&pReader)))
+        {
+            IMFMediaType* pType = nullptr;
 
-    return !maURL.isEmpty();
-}
+            // Configure the source reader to give us progressive RGB32 frames.
+            // The source reader will load the decoder if needed.
+            if (SUCCEEDED(MFCreateMediaType(&pType)))
+                hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
 
+            if (SUCCEEDED(hr))
+                hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
 
-uno::Reference< graphic::XGraphic > SAL_CALL FrameGrabber::grabFrame( double 
fMediaTime )
-{
-    uno::Reference< graphic::XGraphic > xRet;
-    if (sal::systools::COMReference<IMediaDet> pDet = 
implCreateMediaDet(maURL))
-    {
-        double  fLength;
-        long    nStreamCount;
-        bool    bFound = false;
-
-        if( SUCCEEDED( pDet->get_OutputStreams( &nStreamCount ) ) )
-        {
-            for( long n = 0; ( n < nStreamCount ) && !bFound; ++n )
+            if (SUCCEEDED(hr))
             {
-                GUID aMajorType;
-
-                if( SUCCEEDED( pDet->put_CurrentStream( n ) )  &&
-                    SUCCEEDED( pDet->get_StreamType( &aMajorType ) ) &&
-                    ( aMajorType == MEDIATYPE_Video ) )
-                {
-                    bFound = true;
-                }
+                hr = pReader->SetCurrentMediaType(
+                    (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
+                    nullptr,
+                    pType
+                );
             }
-        }
-
-        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;
-            long            nSize = 0;
 
-            if( SUCCEEDED( pDet->get_StreamMediaType( &aMediaType ) ) )
+            // Ensure the stream is selected.
+            if (SUCCEEDED(hr))
             {
-                if( ( aMediaType.formattype == FORMAT_VideoInfo ) &&
-                    ( aMediaType.cbFormat >= sizeof( VIDEOINFOHEADER ) ) )
-                {
-                    VIDEOINFOHEADER* pVih = reinterpret_cast< VIDEOINFOHEADER* 
>( aMediaType.pbFormat );
+                hr = pReader->SetStreamSelection(
+                    (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
+                    TRUE
+                );
+            }
 
-                    nWidth = pVih->bmiHeader.biWidth;
-                    nHeight = pVih->bmiHeader.biHeight;
+            SafeRelease(&pType);
 
-                    if( nHeight < 0 )
-                        nHeight *= -1;
-                }
+            if (SUCCEEDED(hr) && fMediaTime > 0.0)
+            {
+                PROPVARIANT var;
+                PropVariantInit(&var);
 
-                if( aMediaType.cbFormat != 0 )
-                {
-                    ::CoTaskMemFree( aMediaType.pbFormat );
-                    aMediaType.cbFormat = 0;
-                    aMediaType.pbFormat = nullptr;
-                }
+                var.vt = VT_I8;
+                var.hVal.QuadPart = fMediaTime;
 
-                if( aMediaType.pUnk != nullptr )
-                {
-                    aMediaType.pUnk->Release();
-                    aMediaType.pUnk = nullptr;
-                }
+                hr = pReader->SetCurrentPosition(GUID_NULL, var);
             }
 
-            if( ( nWidth > 0 ) && ( nHeight > 0 ) &&
-                SUCCEEDED( pDet->GetBitmapBits( 0, &nSize, nullptr, nWidth, 
nHeight ) ) &&
-                ( nSize > 0  ) )
-            {
-                auto pBuffer = std::make_unique<char[]>(nSize);
+            IMFSample* pSampleTmp = nullptr;
 
-                try
+            if (SUCCEEDED(hr))
+            {
+                DWORD dwFlags = 0;
+                DWORD cSkipped = 0; // Number of skipped frames
+                while (true)
                 {
-                    if( SUCCEEDED( pDet->GetBitmapBits( fMediaTime, nullptr, 
pBuffer.get(), nWidth, nHeight ) ) )
+                    hr = pReader->ReadSample(
+                        (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
+                        0,
+                        nullptr,
+                        &dwFlags,
+                        nullptr,
+                        &pSampleTmp
+                    );
+
+                    if (FAILED(hr) || (dwFlags & 
MF_SOURCE_READERF_ENDOFSTREAM))
+                        break;
+
+                    if (pSampleTmp == nullptr)
+                        continue;
+
+                    LONGLONG hnsTimeStamp = 0;
+                    if (SUCCEEDED(pSampleTmp->GetSampleTime(&hnsTimeStamp)))
                     {
-                        SvMemoryStream  aMemStm( pBuffer.get(), nSize, 
StreamMode::READ | StreamMode::WRITE );
-                        Bitmap          aBmp;
+                        // Keep going until we get a frame that is within 
tolerance of the
+                        // desired seek position, or until we skip 
MAX_FRAMES_TO_SKIP frames.
 
-                        if( ReadDIB(aBmp, aMemStm, false ) && !aBmp.IsEmpty() )
+                        // During this process, we might reach the end of the 
file, so we
+                        // always cache the last sample that we got (pSample).
+
+                        if ((cSkipped < MAX_FRAMES_TO_SKIP) &&
+                            (hnsTimeStamp + SEEK_TOLERANCE < fMediaTime))
                         {
-                            BitmapEx aBitmapEx(aBmp);
-                            Graphic aGraphic(aBitmapEx);
-                            xRet = aGraphic.GetXGraphic();
+                            SafeRelease(&pSampleTmp);
+
+                            ++cSkipped;
+                            continue;
                         }
                     }
+
+                    fMediaTime = hnsTimeStamp;
+                    break;
                 }
-                catch( ... )
+            }
+
+            // We got a sample. Hold onto it.
+            IMFMediaBuffer* pBuffer = nullptr;
+            BYTE* pBitmapData = nullptr;  // Bitmap data
+            DWORD cbBitmapData = 0;       // Size of data, in bytes
+            if (pSampleTmp && 
SUCCEEDED(pSampleTmp->ConvertToContiguousBuffer(&pBuffer)))
+            {
+                if (SUCCEEDED(pBuffer->Lock(&pBitmapData, nullptr, 
&cbBitmapData)) && cbBitmapData)
                 {
+                    BitmapEx aBitmapEx = 
vcl::bitmap::CreateFromData(pBitmapData, mnFrameWidth, mnFrameHeight, 
mnFrameWidth * 4, /*nBitsPerPixel*/32, true);
+                    Graphic aGraphic(aBitmapEx);
+                    xRet = aGraphic.GetXGraphic();
                 }
+                pBuffer->Unlock();
             }
+
+            SafeRelease(&pBuffer);
+            SafeRelease(&pSampleTmp);
         }
+
+        SafeRelease(&pAttributes);
+        SafeRelease(&pReader);
+        // Shut down Media Foundation.
+        MFShutdown();
     }
 
     return xRet;
diff --git a/avmedia/source/win/framegrabber.hxx 
b/avmedia/source/win/framegrabber.hxx
index d1ca48e84230..3971d3f98e78 100644
--- a/avmedia/source/win/framegrabber.hxx
+++ b/avmedia/source/win/framegrabber.hxx
@@ -34,11 +34,9 @@ class FrameGrabber : public ::cppu::WeakImplHelper< 
css::media::XFrameGrabber,
                      public sal::systools::CoInitializeGuard
 {
 public:
-    explicit FrameGrabber();
+    explicit FrameGrabber( const OUString& rURL, UINT32 nFrameWidth, UINT32 
nFrameHeight );
     ~FrameGrabber() override;
 
-    bool    create( const OUString& rURL );
-
     // XFrameGrabber
     virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL grabFrame( 
double fMediaTime ) override;
 
@@ -48,7 +46,9 @@ public:
     virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames(  
) override;
 
 private:
-    OUString                                                  maURL;
+    OUString                maURL;
+    UINT32                  mnFrameWidth;
+    UINT32                  mnFrameHeight;
 };
 
 } // namespace avmedia::win
diff --git a/avmedia/source/win/player.cxx b/avmedia/source/win/player.cxx
index b52ac8171dfc..39330ab70829 100644
--- a/avmedia/source/win/player.cxx
+++ b/avmedia/source/win/player.cxx
@@ -18,10 +18,17 @@
  */
 
 #include <objbase.h>
-#include <strmif.h>
-#include <control.h>
 #include <uuids.h>
 #include <evcode.h>
+#include <propvarutil.h>
+#include <propkey.h>
+// Media Foundation headers
+#include <mfapi.h>
+#include <mfidl.h>
+#include <mfreadwrite.h>
+
+#include <avmedia/mediaitem.hxx>
+#include <avmedia/mediawindow.hxx>
 
 #include "player.hxx"
 #include "framegrabber.hxx"
@@ -33,255 +40,510 @@
 
 constexpr OUStringLiteral AVMEDIA_WIN_PLAYER_IMPLEMENTATIONNAME = 
u"com.sun.star.comp.avmedia.Player_DirectX";
 constexpr OUString AVMEDIA_WIN_PLAYER_SERVICENAME = 
u"com.sun.star.media.Player_DirectX"_ustr;
+constexpr float AVMEDIA_DB_RANGE = 40.0;
 
 using namespace ::com::sun::star;
 
 namespace avmedia::win {
 
-static LRESULT CALLBACK MediaPlayerWndProc_2( HWND hWnd,UINT nMsg, WPARAM 
nPar1, LPARAM nPar2 )
+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 ) );
+    return 0;
 }
 
-
 Player::Player() :
     Player_BASE(m_aMutex),
     sal::systools::CoInitializeGuard(COINIT_APARTMENTTHREADED, false,
                                      
sal::systools::CoInitializeGuard::WhenFailed::NoThrow),
-    mnUnmutedVolume( 0 ),
+    m_cRef( 1 ),
+    mnUnmutedVolume( 1 ),
     mnFrameWnd( nullptr ),
     mbMuted( false ),
     mbLooping( false ),
-    mbAddWindow( true )
+    mbAutoPlayBack( false ),
+    mnFrameWidth( 0 ),
+    mnFrameHeight( 0 ),
+    g_pPlayer( nullptr ),
+    g_bHasVideo( false ),
+    g_bHasAudio( false ),
+    m_state( Closed )
 {
 }
 
-
 Player::~Player()
 {
     if( mnFrameWnd )
         ::DestroyWindow( mnFrameWnd );
+
+    if (g_pPlayer)
+        g_pPlayer->Shutdown();
+    SafeRelease(&g_pPlayer);
 }
 
+//***************************** IUnknown methods 
*****************************//
 
-void SAL_CALL Player::disposing()
+
+//------------------------------------------------------------------------------
+//  AddRef
+//------------------------------------------------------------------------------
+
+ULONG Player::AddRef()
 {
-    ::osl::MutexGuard aGuard(m_aMutex);
-    stop();
-    if( mpME )
-        mpME->SetNotifyWindow( 0, WM_GRAPHNOTIFY, 0);
+    return InterlockedIncrement(&m_cRef);
 }
 
+//------------------------------------------------------------------------------
+//  Release
+//------------------------------------------------------------------------------
 
-bool Player::create( const OUString& rURL )
+ULONG Player::Release()
 {
-    bool    bRet = false;
+    ULONG uCount = InterlockedDecrement(&m_cRef);
+    if (uCount == 0)
+    {
+        delete this;
+    }
+    return uCount;
+}
 
-    if( SUCCEEDED(mpGB.CoCreateInstance(CLSID_FilterGraph, nullptr, 
CLSCTX_INPROC_SERVER)) )
+//------------------------------------------------------------------------------
+//  QueryInterface
+//------------------------------------------------------------------------------
+
+STDMETHODIMP Player::QueryInterface(REFIID riid, void** ppv)
+{
+    static const QITAB qit[] =
     {
-        // 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( mpGB->RenderFile( o3tl::toW(aFile.getStr()), nullptr ) 
) &&
-            mpMC.set(mpGB, sal::systools::COM_QUERY) &&
-            mpME.set(mpGB, sal::systools::COM_QUERY) &&
-            mpMP.set(mpGB, sal::systools::COM_QUERY) )
-        {
-            // Video interfaces
-            mpVW.set(mpGB, sal::systools::COM_QUERY);
-            mpBV.set(mpGB, sal::systools::COM_QUERY);
+        QITABENT(Player, IMFPMediaPlayerCallback),
+        { 0 },
+    };
+    return QISearch(this, qit, riid, ppv);
+}
 
-            // Audio interface
-            mpBA.set(mpGB, sal::systools::COM_QUERY);
+//********************* IMFPMediaPlayerCallback methods 
**********************//
 
-            if( mpBA )
-                mpBA->put_Volume( mnUnmutedVolume );
+//-----------------------------------------------------------------------------
+// OnMediaPlayerEvent
+//
+// Notifies the object of an MFPlay event.
+//-----------------------------------------------------------------------------
 
-            bRet = true;
-        }
+void Player::OnMediaPlayerEvent(MFP_EVENT_HEADER* pEventHeader)
+{
+    if (FAILED(pEventHeader->hrEvent))
+    {
+        SAL_WARN("avmedia.win",
+            "Player::OnMediaPlayerEvent failed with error code: " << 
pEventHeader->hrEvent);
+
+        ::avmedia::MediaWindow::executeFormatErrorBox(nullptr);
+
+        return;
+    }
+
+    switch (pEventHeader->eEventType)
+    {
+    case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
+        OnMediaItemCreated(MFP_GET_MEDIAITEM_CREATED_EVENT(pEventHeader));
+        break;
+
+    case MFP_EVENT_TYPE_MEDIAITEM_SET:
+        OnMediaItemSet(MFP_GET_MEDIAITEM_SET_EVENT(pEventHeader));
+        break;
+
+    case MFP_EVENT_TYPE_POSITION_SET:
+        OnMediaPosSet(MFP_GET_POSITION_SET_EVENT(pEventHeader));
+        break;
+
+    case MFP_EVENT_TYPE_PLAYBACK_ENDED:
+        OnMediaItemEnded(MFP_GET_PLAYBACK_ENDED_EVENT(pEventHeader));
+        break;
     }
+}
+
+void SAL_CALL Player::disposing()
+{
+    ::osl::MutexGuard aGuard(m_aMutex);
+    OnClose(mnFrameWnd);
+}
 
-    if( bRet )
+bool Player::create( const OUString& rURL )
+{
+    bool bRet = !rURL.isEmpty();
+    if (bRet)
+    {
         maURL = rURL;
+        // Initialize the Media Foundation platform.
+        HRESULT hr = MFStartup(MF_VERSION);
+        if (SUCCEEDED(hr))
+        {
+            // Create the source reader.
+            IMFSourceReader* pReader;
+            hr = MFCreateSourceReaderFromURL(o3tl::toW(maURL.getStr()), 
nullptr, &pReader);
+            if (SUCCEEDED(hr))
+            {
+                IMFMediaType* pType = nullptr;
+                DWORD dwMediaTypeIndex = 0;
+                if 
(SUCCEEDED(pReader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
 dwMediaTypeIndex, &pType)))
+                {
+                    MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &mnFrameWidth, 
&mnFrameHeight);
+                    SafeRelease(&pType);
+                }
+                SafeRelease(&pReader);
+            }
+            // Shut down Media Foundation.
+            MFShutdown();
+        }
+        bRet = SUCCEEDED(hr);
+    }
     else
         maURL.clear();
 
     return bRet;
 }
 
+void Player::setNotifyWnd( HWND nNotifyWnd )
+{
+    mnFrameWnd = nNotifyWnd;
+}
 
-const IVideoWindow* Player::getVideoWindow() const
+//-------------------------------------------------------------------
+// OnClose
+//
+// Handles the WM_CLOSE message.
+//-------------------------------------------------------------------
+void Player::OnClose(HWND /*hwnd*/)
 {
-    return mpVW;
+    if (g_pPlayer)
+        g_pPlayer->Shutdown();
+    SafeRelease(&g_pPlayer);
+
+    PostQuitMessage(0);
 }
 
+//-------------------------------------------------------------------
+// OnPaint
+//
+// Handles the WM_PAINT message.
+//-------------------------------------------------------------------
+void Player::OnPaint(HWND hwnd)
+{
+    PAINTSTRUCT ps;
+    HDC hdc = 0;
 
-void Player::setNotifyWnd( HWND nNotifyWnd )
+    hdc = BeginPaint(hwnd, &ps);
+
+    if (g_pPlayer && g_bHasVideo)
+    {
+        // Playback has started and there is video.
+
+        // Do not draw the window background, because the video
+        // frame fills the entire client area.
+
+        g_pPlayer->UpdateVideo();
+    }
+    else
+    {
+        // There is no video stream, or playback has not started.
+        // Paint the entire client area.
+
+        FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
+    }
+
+    EndPaint(hwnd, &ps);
+}
+
+//-------------------------------------------------------------------
+// OnSize
+//
+// Handles the WM_SIZE message.
+//-------------------------------------------------------------------
+void Player::OnSize(HWND /*hwnd*/, UINT state, int /*cx*/, int /*cy*/)
+{
+    if (state == SIZE_RESTORED)
+    {
+        if (g_pPlayer)
+        {
+            // Resize the video.
+            g_pPlayer->UpdateVideo();
+        }
+    }
+}
+
+//-------------------------------------------------------------------
+// OnMediaItemCreated
+//
+// Called when the IMFPMediaPlayer::CreateMediaItemFromURL method
+// completes.
+//-------------------------------------------------------------------
+void Player::OnMediaItemCreated(MFP_MEDIAITEM_CREATED_EVENT* pEvent)
+{
+    if (g_pPlayer)
+    {
+        BOOL bHasVideoOrAudio = FALSE, bIsSelected = FALSE;
+
+        // Check if the media item contains video or audio.
+        HRESULT hr = pEvent->pMediaItem->HasVideo(&bHasVideoOrAudio, 
&bIsSelected);
+        if (SUCCEEDED(hr))
+            g_bHasVideo = bHasVideoOrAudio && bIsSelected;
+
+        hr = pEvent->pMediaItem->HasAudio(&bHasVideoOrAudio, &bIsSelected);
+        if (SUCCEEDED(hr))
+            g_bHasAudio = bHasVideoOrAudio && bIsSelected;
+
+        if (SUCCEEDED(hr) && (g_bHasVideo || g_bHasAudio))
+        {
+            // Set the media item on the player. This method completes 
asynchronously.
+            hr = g_pPlayer->SetMediaItem(pEvent->pMediaItem);
+        }
+
+        if (FAILED(hr) || (!g_bHasVideo && !g_bHasAudio))
+        {
+            SAL_WARN("avmedia.win",
+                "Player::OnMediaItemCreated failed with error code: " << hr);
+
+            ::avmedia::MediaWindow::executeFormatErrorBox(nullptr);
+            m_state = Closed;
+        }
+    }
+}
+
+//-------------------------------------------------------------------
+// OnMediaItemSet
+//
+// Called when the IMFPMediaPlayer::SetMediaItem method completes.
+//-------------------------------------------------------------------
+void Player::OnMediaItemSet(MFP_MEDIAITEM_SET_EVENT* /*pEvent*/)
+{
+    HRESULT hr = S_OK;
+
+    if (mbAutoPlayBack)
+    {
+        hr = g_pPlayer->Play();
+        if (SUCCEEDED(hr))
+            m_state = Started;
+    }
+
+    if (FAILED(hr))
+    {
+        SAL_WARN("avmedia.win",
+            "Player::OnMediaItemSet failed with error code: " << hr);
+
+        ::avmedia::MediaWindow::executeFormatErrorBox(nullptr);
+    }
+}
+
+void Player::OnMediaPosSet(MFP_POSITION_SET_EVENT* /*pEvent*/)
 {
-    mbAddWindow = false;
-    if( mpME )
-        mpME->SetNotifyWindow( reinterpret_cast<OAHWND>(nNotifyWnd), 
WM_GRAPHNOTIFY, reinterpret_cast< LONG_PTR>( this ) );
+    // TODO: Handle position set event if needed with update of MediaPlayer UI.
+    // void MediaWindowControl::update() should be called
 }
 
+void Player::OnMediaItemEnded(MFP_PLAYBACK_ENDED_EVENT* /*pEvent*/)
+{
+    if( mbLooping )
+        start();
+    else
+        m_state = Stopped;
+}
 
-void Player::processEvent()
+HRESULT Player::InitializeWindow(bool bAddSoundWindow)
 {
-    long nCode;
-    LONG_PTR nParam1, nParam2;
+    HRESULT hr = S_OK;
+    SafeRelease(&g_pPlayer);
 
-    while( mpME && SUCCEEDED( mpME->GetEvent( &nCode, &nParam1, &nParam2, 0 ) 
) )
+    if (bAddSoundWindow)
     {
-        if( EC_COMPLETE == nCode )
+        static WNDCLASSW* mpWndClass = nullptr;
+        if ( !mpWndClass )
         {
-            if( mbLooping )
-            {
-                setMediaTime( 0.0 );
-                start();
-            }
-            else
+            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 )
             {
-                setMediaTime( getDuration() );
-                stop();
+                ::ShowWindow(mnFrameWnd, SW_HIDE);
+                SetWindowLongPtrW( mnFrameWnd, 0, 
reinterpret_cast<LONG_PTR>(this) );
             }
         }
-
-        mpME->FreeEventParams( nCode, nParam1, nParam2 );
     }
-}
 
+    // Create the MFPlayer object.
+    hr = MFPCreateMediaPlayer(
+        nullptr,
+        FALSE,          // Start playback automatically?
+        0,              // Flags
+        this,           // Callback pointer
+        mnFrameWnd,     // Video window
+        &g_pPlayer
+    );
+
+    // Create a new media item for this URL.
+    // The CreateMediaItemFromURL method completes asynchronously. When it 
does,
+    // MFPlay sends an MFP_EVENT_TYPE_MEDIAITEM_CREATED event.
+    if (SUCCEEDED(hr))
+        hr = g_pPlayer->CreateMediaItemFromURL(o3tl::toW(maURL.getStr()), 
FALSE, 0, nullptr);
+
+    if (SUCCEEDED(hr))
+        m_state = Stopped;
+
+    return hr;
+}
 
 void SAL_CALL Player::start(  )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
-    if( mpMC )
+    if( g_pPlayer )
     {
-        if ( mbAddWindow )
+        HRESULT hr = S_OK;
+        if (g_bHasVideo || g_bHasAudio)
         {
-            static WNDCLASSW* mpWndClass = nullptr;
-            if ( !mpWndClass )
+            MFP_MEDIAPLAYER_STATE state = MFP_MEDIAPLAYER_STATE_EMPTY;
+            hr = g_pPlayer->GetState(&state);
+            if (SUCCEEDED(hr))
             {
-                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 )
+                if (state == MFP_MEDIAPLAYER_STATE_PAUSED || state == 
MFP_MEDIAPLAYER_STATE_STOPPED)
                 {
-                    ::ShowWindow(mnFrameWnd, SW_HIDE);
-                    SetWindowLongPtrW( mnFrameWnd, 0, 
reinterpret_cast<LONG_PTR>(this) );
-                    // mpVW->put_Owner( (OAHWND) mnFrameWnd );
-                    setNotifyWnd( mnFrameWnd );
+                    hr = g_pPlayer->Play();
+                    if (SUCCEEDED(hr))
+                        m_state = Started;
                 }
             }
         }
 
-        mpMC->Run();
+        if (FAILED(hr))
+        {
+            SAL_WARN("avmedia.win",
+                "Player::start failed with error code: " << hr);
+
+            ::avmedia::MediaWindow::executeFormatErrorBox(nullptr);
+        }
     }
 }
 
-
 void SAL_CALL Player::stop(  )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
-    if( mpMC )
-        mpMC->Stop();
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio))
+    {
+        HRESULT hr = S_OK;
+        if (getMediaTime())
+        {
+            hr = g_pPlayer->Pause();
+            if (SUCCEEDED(hr))
+                m_state = Paused;
+        }
+        else
+        {
+            hr = g_pPlayer->Stop();
+            if (SUCCEEDED(hr))
+                m_state = Stopped;
+        }
+    }
 }
 
-
 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 );
+    bool bRet = false;
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio))
+    {
+        MFP_MEDIAPLAYER_STATE state = MFP_MEDIAPLAYER_STATE_EMPTY;
+        HRESULT hr = g_pPlayer->GetState(&state);
+        if (SUCCEEDED(hr))
+        {
+            bRet = (state == MFP_MEDIAPLAYER_STATE_PLAYING && m_state == 
Started);
+        }
+        else
+        {
+            SAL_WARN("avmedia.win",
+                "Player::isPlaying failed with error code: " << hr);
+        }
+    }
 
     return bRet;
 }
 
-
 double SAL_CALL Player::getDuration(  )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
 
     REFTIME aRefTime( 0.0 );
-
-    if( mpMP  )
-        mpMP->get_Duration( &aRefTime );
-
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio))
+    {
+        PROPVARIANT var;
+        HRESULT hr = g_pPlayer->GetDuration(MFP_POSITIONTYPE_100NS, &var);
+        if (SUCCEEDED(hr))
+        {
+            hr = PropVariantToDouble(var, &aRefTime);
+            aRefTime = aRefTime / (1000.0 * 10.0) / 1000.0; // Convert from 
100-nanosecond units to seconds
+            PropVariantClear(&var);
+        }
+    }
     return aRefTime;
 }
 
-
 void SAL_CALL Player::setMediaTime( double fTime )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
 
-    if( mpMP  )
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio))
     {
-        const bool bPlaying = isPlaying();
-
-        mpMP->put_CurrentPosition( fTime );
-
-        if( !bPlaying && mpMC )
-            mpMC->StopWhenReady();
+        PROPVARIANT var;
+        PropVariantInit(&var);
+        var.vt = VT_I8; // PROPVARIANT type has to be VT_I8.
+        var.hVal.QuadPart = static_cast<MFTIME>(fTime * 1000.0 * (1000.0 * 
10.0)); // Convert from seconds to 100-nanosecond units
+        HRESULT hr = g_pPlayer->SetPosition(MFP_POSITIONTYPE_100NS, &var);
+        if (FAILED(hr))
+        {
+            SAL_WARN("avmedia.win",
+                     "Player::setMediaTime: setMediaTime failed with error 
code: " << hr);
+        }
+        PropVariantClear(&var);
+        // on resetting back to zero the reported timestamp doesn't seem to get
+        // updated in a reasonable time, so on zero just force an update of 
timestamp to 0.
+        // Same as in 
/core/avmedia/source/gtk/gtkplayer.cxx:GtkPlayer::setMediaTime(double fTime)
+        // With UpdateVideo() it can help on video streams, but doesn't help 
on audio streams. TODO!
+        if (fTime == 0.0)
+            g_pPlayer->UpdateVideo();
     }
 }
 
-
 double SAL_CALL Player::getMediaTime(  )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
 
     REFTIME aRefTime( 0.0 );
-
-    if( mpMP  )
-        mpMP->get_CurrentPosition( &aRefTime );
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio))
+    {
+        PROPVARIANT var;
+        HRESULT hr = g_pPlayer->GetPosition(MFP_POSITIONTYPE_100NS, &var);
+        if (SUCCEEDED(hr))
+        {
+            hr = PropVariantToDouble(var, &aRefTime);
+            aRefTime = aRefTime / (1000.0 * 10.0) / 1000.0; // Convert from 
100-nanosecond units to seconds
+            PropVariantClear(&var);
+        }
+    }
 
     return aRefTime;
 }
 
-
 void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
@@ -289,7 +551,6 @@ void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
     mbLooping = bSet;
 }
 
-
 sal_Bool SAL_CALL Player::isPlaybackLoop(  )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
@@ -297,116 +558,143 @@ sal_Bool SAL_CALL Player::isPlaybackLoop(  )
     return mbLooping;
 }
 
-
 void SAL_CALL Player::setMute( sal_Bool bSet )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
 
-    if (mpBA && (mbMuted != static_cast<bool>(bSet)))
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio) &&
+        (mbMuted != static_cast<BOOL>(bSet)))
     {
         mbMuted = bSet;
-        mpBA->put_Volume( mbMuted ? -10000 : mnUnmutedVolume );
+        HRESULT hr = g_pPlayer->SetMute(bSet);
+        if (FAILED(hr))
+        {
+            SAL_WARN("avmedia.win",
+                     "Player::setMute: setMute failed with error code: " << 
hr);
+        }
     }
 }
 
-
 sal_Bool SAL_CALL Player::isMute(  )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
 
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio))
+    {
+        HRESULT hr = g_pPlayer->GetMute(&mbMuted);
+        if (FAILED(hr))
+        {
+            SAL_WARN("avmedia.win",
+                     "Player::isMute: getMute failed with error code: " << hr);
+            mbMuted = false; // Reset to default if error occurs
+        }
+    }
     return mbMuted;
 }
 
-
 void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
 
-    mnUnmutedVolume = static_cast< long >( nVolumeDB ) * 100;
+    mnUnmutedVolume = static_cast< float >( (nVolumeDB / AVMEDIA_DB_RANGE) + 
1.0 );
 
-    if( !mbMuted && mpBA )
-        mpBA->put_Volume( mnUnmutedVolume );
+    if ( g_pPlayer && (g_bHasVideo || g_bHasAudio))
+    {
+        HRESULT hr = g_pPlayer->SetVolume(mnUnmutedVolume);
+        if (FAILED(hr))
+        {
+            SAL_WARN("avmedia.win",
+                     "Player::setVolumeDB: setVolumeDB failed with error code: 
" << hr);
+        }
+    }
 }
 
-
 sal_Int16 SAL_CALL Player::getVolumeDB(  )
 {
     ::osl::MutexGuard aGuard(m_aMutex);
 
-    return static_cast< sal_Int16 >( mnUnmutedVolume / 100 );
+    if (g_pPlayer && (g_bHasVideo || g_bHasAudio))
+    {
+        HRESULT hr = g_pPlayer->GetVolume(&mnUnmutedVolume);
+        if (FAILED(hr))
+        {
+            SAL_WARN("avmedia.win",
+                "Player::getVolumeDB: getVolumeDB failed with error code: " << 
hr);
+            mnUnmutedVolume = 1; // Reset to default if error occurs
+        }
+    }
+    return static_cast< sal_Int16 >( (mnUnmutedVolume - 1.0) * 
AVMEDIA_DB_RANGE);
 }
 
-
 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;
+    return awt::Size(mnFrameWidth, mnFrameHeight);
 }
 
-
 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() );
+    awt::Size aSize(getPreferredPlayerWindowSize());
 
-    if( mpVW && aSize.Width > 0 && aSize.Height > 0 )
+    if( aSize.Width > 0 && aSize.Height > 0 )
     {
         rtl::Reference<::avmedia::win::Window> pWindow = new 
::avmedia::win::Window( *this );
 
         xRet = pWindow;
 
-        if( !pWindow->create( aArguments ) )
+        if (!pWindow->create( aArguments ) )
             xRet.clear();
     }
+    else
+    {
+        if (SUCCEEDED(InitializeWindow(true)))
+        {
+            sal_IntPtr pIntPtr = 0;
+            if ((aArguments.getLength() >= 4) && (aArguments[3] >>= pIntPtr) 
&& pIntPtr)
+            {
+                auto pItem = reinterpret_cast<const 
avmedia::MediaItem*>(pIntPtr);
+                if (pItem->getState() == avmedia::MediaState::Play)
+                {
+                    setAutoPlayBack(true);
+                }
+            }
+        }
+        else
+        {
+            ::avmedia::MediaWindow::executeFormatErrorBox(nullptr);
+        }
+    }
 
     return xRet;
 }
 
-
 uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber(  )
 {
     uno::Reference< media::XFrameGrabber > xRet;
 
     if( !maURL.isEmpty() )
     {
-        rtl::Reference<FrameGrabber> pGrabber = new FrameGrabber();
-
+        rtl::Reference<FrameGrabber> pGrabber = new FrameGrabber(maURL, 
mnFrameWidth, mnFrameHeight);
         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 };
diff --git a/avmedia/source/win/player.hxx b/avmedia/source/win/player.hxx
index 1563d549a85e..04675217881f 100644
--- a/avmedia/source/win/player.hxx
+++ b/avmedia/source/win/player.hxx
@@ -23,6 +23,10 @@
 
 #include <WinDef.h>
 
+// Media Foundation headers
+#include <mfplay.h>
+#include <mferror.h>
+
 #include "wincommon.hxx"
 
 #include <com/sun/star/media/XPlayer.hpp>
@@ -31,26 +35,31 @@
 #include <cppuhelper/basemutex.hxx>
 #include <systools/win32/comtools.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 {
 
+enum PlayerState
+{
+    Closed = 0,     // No session.
+    Started,        // Session is playing a file.
+    Paused,         // Session is paused.
+    Stopped         // Session is stopped (ready to play).
+};
+
+template <class T> void SafeRelease(T **ppT)
+{
+    if (*ppT)
+    {
+        (*ppT)->Release();
+        *ppT = nullptr;
+    }
+}
+
 typedef ::cppu::WeakComponentImplHelper< css::media::XPlayer,
                                          css::lang::XServiceInfo > Player_BASE;
 
-
-class Player : public cppu::BaseMutex,
+class Player : public IMFPMediaPlayerCallback,
+               public cppu::BaseMutex,
                public Player_BASE,
                public sal::systools::CoInitializeGuard
 {
@@ -59,12 +68,32 @@ public:
     explicit Player();
     ~Player() override;
 
-    bool                create( const OUString& rURL );
-
-    void                setNotifyWnd( HWND nNotifyWnd );
-    void                processEvent();
-
-    const IVideoWindow* getVideoWindow() const;
+    bool    create( const OUString& rURL );
+    HRESULT InitializeWindow( bool bAddSoundWindow );
+    void    setNotifyWnd( HWND nNotifyWnd );
+    HWND*   getNotifyWnd() { return &mnFrameWnd; }
+    void    setAutoPlayBack(bool bVal) { mbAutoPlayBack = bVal; }
+    const UINT32  GetVideoWidth() const { return mnFrameWidth; }
+    const UINT32  GetVideoHeight() const { return mnFrameHeight; }
+
+    // IUnknown methods
+    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
+    STDMETHODIMP_(ULONG) AddRef();
+    STDMETHODIMP_(ULONG) Release();
+
+    // IMFPMediaPlayerCallback methods
+    void STDMETHODCALLTYPE OnMediaPlayerEvent(MFP_EVENT_HEADER* pEventHeader);
+
+    // Window message handlers
+    void    OnClose(HWND hwnd);
+    void    OnPaint(HWND hwnd);
+    void    OnSize(HWND hwnd, UINT state, int cx, int cy);
+
+    // MFPlay event handler functions.
+    void    OnMediaItemCreated(MFP_MEDIAITEM_CREATED_EVENT* pEvent);
+    void    OnMediaItemSet(MFP_MEDIAITEM_SET_EVENT* pEvent);
+    void    OnMediaPosSet(MFP_POSITION_SET_EVENT* pEvent);
+    void    OnMediaItemEnded(MFP_PLAYBACK_ENDED_EVENT* pEvent);
 
     // XPlayer
     virtual void SAL_CALL start(  ) override;
@@ -93,19 +122,19 @@ public:
 
 private:
 
+    long                    m_cRef;          // Reference count.
     OUString                maURL;
-    sal::systools::COMReference<IGraphBuilder>          mpGB;
-    sal::systools::COMReference<IMediaControl>          mpMC;
-    sal::systools::COMReference<IMediaEventEx>          mpME;
-    sal::systools::COMReference<IMediaPosition>         mpMP;
-    sal::systools::COMReference<IBasicAudio>            mpBA;
-    sal::systools::COMReference<IBasicVideo>            mpBV;
-    sal::systools::COMReference<IVideoWindow>           mpVW;
-    long                    mnUnmutedVolume;
+    float                   mnUnmutedVolume;
     HWND                    mnFrameWnd;
-    bool                    mbMuted;
+    BOOL                    mbMuted;
     bool                    mbLooping;
-    bool                    mbAddWindow;
+    bool                    mbAutoPlayBack;
+    UINT32                  mnFrameWidth;
+    UINT32                  mnFrameHeight;
+    IMFPMediaPlayer*        g_pPlayer;      // The MFPlay player object.
+    BOOL                    g_bHasVideo;
+    BOOL                    g_bHasAudio;
+    PlayerState             m_state;
 };
 
 } // namespace avmedia::win
diff --git a/avmedia/source/win/wincommon.hxx b/avmedia/source/win/wincommon.hxx
index 5572f6c3e63d..ec0d0004b41d 100644
--- a/avmedia/source/win/wincommon.hxx
+++ b/avmedia/source/win/wincommon.hxx
@@ -36,6 +36,4 @@
 #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/win/window.cxx b/avmedia/source/win/window.cxx
index 8cf3fee74d3d..4c3100bea864 100644
--- a/avmedia/source/win/window.cxx
+++ b/avmedia/source/win/window.cxx
@@ -18,12 +18,12 @@
  */
 
 #include <objbase.h>
-#include <strmif.h>
-#include <control.h>
 #include <dshow.h>
 
 #include <com/sun/star/awt/SystemPointer.hpp>
 #include <cppuhelper/supportsservice.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <avmedia/mediawindow.hxx>
 
 #include "window.hxx"
 #include "player.hxx"
@@ -35,7 +35,7 @@ using namespace ::com::sun::star;
 
 namespace avmedia::win {
 
-static LRESULT CALLBACK MediaPlayerWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, 
LPARAM nPar2 )
+static LRESULT CALLBACK MediaPlayerWndProc( HWND hWnd, UINT nMsg, WPARAM 
wParam, LPARAM lParam)
 {
     Window* pWindow = reinterpret_cast<Window*>(GetWindowLongPtrW( hWnd, 0 ));
     bool    bProcessed = true;
@@ -44,14 +44,14 @@ static LRESULT CALLBACK MediaPlayerWndProc( HWND hWnd,UINT 
nMsg, WPARAM nPar1, L
     {
         switch( nMsg )
         {
+            HANDLE_MSG(hWnd, WM_CLOSE, pWindow->getPlayer().OnClose);
+            HANDLE_MSG(hWnd, WM_PAINT, pWindow->getPlayer().OnPaint);
+            HANDLE_MSG(hWnd, WM_SIZE, pWindow->getPlayer().OnSize);
+
             case WM_SETCURSOR:
                 pWindow->updatePointer();
             break;
 
-            case WM_GRAPHNOTIFY:
-                pWindow->processGraphEvent();
-            break;
-
             case WM_MOUSEMOVE:
             case WM_LBUTTONDOWN:
             case WM_MBUTTONDOWN:
@@ -59,7 +59,7 @@ static LRESULT CALLBACK MediaPlayerWndProc( HWND hWnd,UINT 
nMsg, WPARAM nPar1, L
             case WM_LBUTTONUP:
             case WM_MBUTTONUP:
             case WM_RBUTTONUP:
-                PostMessage(pWindow->getParentWnd(), nMsg, nPar1, nPar2);
+                PostMessage(pWindow->getParentWnd(), nMsg, wParam, lParam);
             break;
 
             case WM_SETFOCUS:
@@ -77,7 +77,7 @@ static LRESULT CALLBACK MediaPlayerWndProc( HWND hWnd,UINT 
nMsg, WPARAM nPar1, L
     else
         bProcessed = false;
 
-    return( bProcessed ? 0 : DefWindowProcW( hWnd, nMsg, nPar1, nPar2 ) );
+    return( bProcessed ? 0 : DefWindowProcW( hWnd, nMsg, wParam, lParam ) );
 }
 
 static WNDCLASSW* lcl_getWndClass()
@@ -112,12 +112,32 @@ Window::~Window()
         ::DestroyWindow( mnFrameWnd );
 }
 
+const css::awt::Rectangle Window::getParentPosSize() const
+{
+    awt::Rectangle aRet;
+
+    if (mnParentWnd)
+    {
+        ::RECT  aWndRect;
+
+        if (::GetClientRect(mnParentWnd, &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 Window::ImplLayoutVideoWindow()
 {
     if( media::ZoomLevel_NOT_AVAILABLE != meZoomLevel )
     {
         awt::Size           aPrefSize( mrPlayer.getPreferredPlayerWindowSize() 
);
-        awt::Rectangle      aRect = getPosSize();
+        awt::Rectangle      aRect = getParentPosSize();
         int                 nW = aRect.Width, nH = aRect.Height;
         int                 nVideoW = nW, nVideoH = nH;
         int                 nX = 0, nY = 0, nWidth = 0, nHeight = 0;
@@ -190,19 +210,16 @@ void Window::ImplLayoutVideoWindow()
                 nX = nY = nWidth = nHeight = 0;
         }
 
-        IVideoWindow* pVideoWindow = const_cast< IVideoWindow* >( 
mrPlayer.getVideoWindow() );
-
-        if( pVideoWindow )
-            pVideoWindow->SetWindowPosition( nX, nY, nWidth, nHeight );
+        if (mnFrameWnd && mrPlayer.GetVideoWidth() && 
mrPlayer.GetVideoHeight() )
+            SetWindowPos( mnFrameWnd, HWND_TOP, nX, nY, nWidth, nHeight, 0 );
     }
 }
 
 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 )
+    if( !mnFrameWnd && mpWndClass )
     {
         awt::Rectangle  aRect;
         sal_IntPtr       nWnd;
@@ -213,32 +230,38 @@ bool Window::create( const uno::Sequence< uno::Any >& 
rArguments )
         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 );
+            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();
+            mrPlayer.setNotifyWnd(mnFrameWnd);
+            if (SUCCEEDED(mrPlayer.InitializeWindow(false)))
+            {
+                sal_IntPtr pIntPtr = 0;
+                if ((rArguments.getLength() >= 4) && (rArguments[3] >>= 
pIntPtr) && pIntPtr)
+                {
+                    auto pItem = reinterpret_cast<const 
avmedia::MediaItem*>(pIntPtr);
+                    if (pItem->getState() == avmedia::MediaState::Play)
+                    {
+                        mrPlayer.setAutoPlayBack(true);
+                    }
+                }
+                meZoomLevel = media::ZoomLevel_FIT_TO_WINDOW;
+                ImplLayoutVideoWindow();
+            }
+            else
+            {
+                ::avmedia::MediaWindow::executeFormatErrorBox(nullptr);
+            }
         }
     }
 
     return( mnFrameWnd != nullptr );
 }
 
-void Window::processGraphEvent()
-{
-    mrPlayer.processEvent();
-}
 
 void Window::updatePointer()
 {
@@ -323,15 +346,8 @@ awt::Rectangle SAL_CALL Window::getPosSize()
 
 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 );
-
+    if( mnFrameWnd && mrPlayer.GetVideoWidth() && mrPlayer.GetVideoHeight() )
         ::ShowWindow( mnFrameWnd, bVisible ? SW_SHOW : SW_HIDE );
-    }
 }
 
 void SAL_CALL Window::setEnable( sal_Bool bEnable )
diff --git a/avmedia/source/win/window.hxx b/avmedia/source/win/window.hxx
index 0ab691ffbb82..7c6316ef473e 100644
--- a/avmedia/source/win/window.hxx
+++ b/avmedia/source/win/window.hxx
@@ -30,8 +30,6 @@
 
 #include <com/sun/star/media/XPlayerWindow.hpp>
 
-struct IVideoWindow;
-
 namespace avmedia::win {
 
 class Player;
@@ -46,7 +44,6 @@ public:
             ~Window() override;
 
     bool    create( const css::uno::Sequence< css::uno::Any >& aArguments );
-    void    processGraphEvent();
     void    updatePointer();
 
     // XPlayerWindow
@@ -93,6 +90,7 @@ public:
     void fireKeyReleasedEvent( const css::awt::KeyEvent& rEvt );
     void fireSetFocusEvent( const css::awt::FocusEvent& rEvt );
     HWND getParentWnd() const { return mnParentWnd; }
+    Player& getPlayer() const { return mrPlayer; }
 
 private:
 
@@ -110,6 +108,7 @@ private:
     HWND                                        mnParentWnd;
     int                                         mnPointerType;
 
+    const css::awt::Rectangle                   getParentPosSize() const;
     void                                        ImplLayoutVideoWindow();
 };
 
diff --git a/slideshow/source/engine/shapes/viewmediashape.cxx 
b/slideshow/source/engine/shapes/viewmediashape.cxx
index ec19f11b66f8..dbdb172fc40f 100644
--- a/slideshow/source/engine/shapes/viewmediashape.cxx
+++ b/slideshow/source/engine/shapes/viewmediashape.cxx
@@ -464,12 +464,16 @@ namespace slideshow::internal
 
                             SdrObject* pObj = 
SdrObject::getSdrObjectFromXShape(mxShape);
                             auto pMediaObj = dynamic_cast<SdrMediaObj*>(pObj);
-                            const avmedia::MediaItem* pMediaItem = nullptr;
+                            avmedia::MediaItem* pMediaItem = nullptr;
                             if (pMediaObj)
                             {
-                                pMediaItem = &pMediaObj->getMediaProperties();
+                                pMediaItem = 
pMediaObj->getMediaProperties().Clone();
                             }
 
+                            // TODO In slideshow we cannot play/pause/stop the 
video
+                            if (pMediaItem)
+                                
pMediaItem->setState(avmedia::MediaState::Play);
+
                             uno::Sequence< uno::Any >   aArgs{
                                 uno::Any(nParentWindowHandle),
                                 uno::Any(aAWTRect),
diff --git a/svx/uiconfig/ui/medialine.ui b/svx/uiconfig/ui/medialine.ui
index 4c90cae1d213..c83b1834069b 100644
--- a/svx/uiconfig/ui/medialine.ui
+++ b/svx/uiconfig/ui/medialine.ui
@@ -31,6 +31,7 @@
             <property name="show-arrow">False</property>
             <child>
               <object class="GtkToolButton" id="open">
+                <property name="can-focus">False</property>
                 <property name="no-show-all">True</property>
                 <property name="label" translatable="yes" 
context="medialine|toolbutton_open">Open</property>
                 <property name="use-underline">True</property>
@@ -43,6 +44,7 @@
             </child>
             <child>
               <object class="GtkToolButton" id="apply">
+                <property name="can-focus">False</property>
                 <property name="no-show-all">True</property>
                 <property name="label" translatable="yes" 
context="medialine|toolbutton_apply">Apply</property>
                 <property name="use-underline">True</property>
@@ -66,6 +68,7 @@
             <child>
               <object class="GtkToggleToolButton" id="play">
                 <property name="visible">True</property>
+                <property name="can-focus">False</property>
                 <property name="label" translatable="yes" 
context="medialine|toolbutton_play">Play</property>
                 <property name="use-underline">True</property>
                 <property name="icon-name">avmedia/res/av02049.png</property>
@@ -78,6 +81,7 @@
             <child>
               <object class="GtkToggleToolButton" id="pause">
                 <property name="visible">True</property>
+                <property name="can-focus">False</property>
                 <property name="label" translatable="yes" 
context="medialine|toolbutton_pause">Pause</property>
                 <property name="use-underline">True</property>
                 <property name="icon-name">avmedia/res/av02050.png</property>
@@ -90,6 +94,7 @@
             <child>
               <object class="GtkToggleToolButton" id="stop">
                 <property name="visible">True</property>
+                <property name="can-focus">False</property>
                 <property name="label" translatable="yes" 
context="medialine|toolbutton_stop">Stop</property>
                 <property name="use-underline">True</property>
                 <property name="icon-name">avmedia/res/av02051.png</property>
@@ -112,6 +117,7 @@
             <child>
               <object class="GtkToggleToolButton" id="loop">
                 <property name="visible">True</property>
+                <property name="can-focus">False</property>
                 <property name="label" translatable="yes" 
context="medialine|toolbutton_loop">Repeat</property>
                 <property name="use-underline">True</property>
                 <property name="icon-name">avmedia/res/av02052.png</property>
@@ -196,6 +202,7 @@
             <child>
               <object class="GtkToggleToolButton" id="mute">
                 <property name="visible">True</property>
+                <property name="can-focus">False</property>
                 <property name="label" translatable="yes" 
context="medialine|toolbutton_mute">Mute</property>
                 <property name="use-underline">True</property>
                 <property name="icon-name">avmedia/res/av02054.png</property>
@@ -211,11 +218,13 @@
                 <property name="can-focus">True</property>
                 <child>
                   <object class="GtkScale" id="volumeslider">
-                    <property name="width-request">50</property>
+                    <property name="width-request">150</property>
                     <property name="visible">True</property>
                     <property name="can-focus">True</property>
                     <property name="opacity">0.9882352941176471</property>
+                    <property name="valign">center</property>
                     <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
                     <property name="adjustment">adjustment2</property>
                     <property name="draw-value">False</property>
                   </object>
diff --git a/svx/uiconfig/ui/mediawindow.ui b/svx/uiconfig/ui/mediawindow.ui
index 327c52356d21..8f9757fa96b5 100644
--- a/svx/uiconfig/ui/mediawindow.ui
+++ b/svx/uiconfig/ui/mediawindow.ui
@@ -97,6 +97,7 @@
                 <child>
                   <object class="GtkToolButton" id="open">
                     <property name="visible">True</property>
+                    <property name="can-focus">False</property>
                     <property name="label" translatable="yes" 
context="mediawindow|toolbutton_open">Open</property>
                     <property name="use-underline">True</property>
                     <property 
name="icon-name">avmedia/res/av02048.png</property>
@@ -109,6 +110,7 @@
                 <child>
                   <object class="GtkToolButton" id="apply">
                     <property name="visible">True</property>
+                    <property name="can-focus">False</property>
                     <property name="label" translatable="yes" 
context="mediawindow|toolbutton_apply">Apply</property>
                     <property name="use-underline">True</property>
                     <property 
name="icon-name">avmedia/res/av02053.png</property>
@@ -131,6 +133,7 @@
                 <child>
                   <object class="GtkToggleToolButton" id="play">
                     <property name="visible">True</property>
+                    <property name="can-focus">False</property>
                     <property name="label" translatable="yes" 
context="mediawindow|toolbutton_play">Play</property>
                     <property name="use-underline">True</property>
                     <property 
name="icon-name">avmedia/res/av02049.png</property>
@@ -143,6 +146,7 @@
                 <child>
                   <object class="GtkToggleToolButton" id="pause">
                     <property name="visible">True</property>
+                    <property name="can-focus">False</property>
                     <property name="label" translatable="yes" 
context="mediawindow|toolbutton_pause">Pause</property>
                     <property name="use-underline">True</property>
                     <property 
name="icon-name">avmedia/res/av02050.png</property>
@@ -155,6 +159,7 @@
                 <child>
                   <object class="GtkToggleToolButton" id="stop">
                     <property name="visible">True</property>
+                    <property name="can-focus">False</property>
                     <property name="label" translatable="yes" 
context="mediawindow|toolbutton_stop">Stop</property>
                     <property name="use-underline">True</property>
                     <property 
name="icon-name">avmedia/res/av02051.png</property>
@@ -177,6 +182,7 @@
                 <child>
                   <object class="GtkToggleToolButton" id="loop">
                     <property name="visible">True</property>
+                    <property name="can-focus">False</property>
                     <property name="label" translatable="yes" 
context="mediawindow|toolbutton_loop">Repeat</property>
                     <property name="use-underline">True</property>
                     <property 
name="icon-name">avmedia/res/av02052.png</property>
@@ -206,6 +212,7 @@
                     <child>
                       <object class="GtkToggleToolButton" id="mute">
                         <property name="visible">True</property>
+                        <property name="can-focus">False</property>
                         <property name="label" translatable="yes" 
context="mediawindow|toolbutton_mute">Mute</property>
                         <property name="use-underline">True</property>
                         <property 
name="icon-name">avmedia/res/av02054.png</property>
@@ -224,10 +231,13 @@
                 </child>
                 <child>
                   <object class="GtkScale" id="volumeslider">
+                    <property name="width-request">150</property>
                     <property name="visible">True</property>
                     <property name="can-focus">True</property>
                     <property name="opacity">0.9882352941176471</property>
+                    <property name="valign">center</property>
                     <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
                     <property name="adjustment">adjustment2</property>
                     <property name="draw-value">False</property>
                   </object>

Reply via email to