WMF: Recreate the MFMediaSession when loading a new media.
authorYoann Lopes <yoann.lopes@digia.com>
Thu, 6 Dec 2012 15:00:06 +0000 (16:00 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 7 Dec 2012 12:06:16 +0000 (13:06 +0100)
MFMediaSession doesn't seem to handle correctly the change of media
source, causing the playback not to work afterwards.
A single MFMediaSession was created and used for every loaded media, we
now create a new one whenever we load a new media (releasing the old one
beforehand).

Task-number: QTBUG-26819

Change-Id: Id99c9dd54e161823d9580933e063f16240806529
Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
Reviewed-by: Jason Barron <jason@cutehacks.com>
src/plugins/wmf/player/evr9videowindowcontrol.cpp
src/plugins/wmf/player/evr9videowindowcontrol.h
src/plugins/wmf/player/mfaudioendpointcontrol.cpp
src/plugins/wmf/player/mfaudioendpointcontrol.h
src/plugins/wmf/player/mfplayersession.cpp
src/plugins/wmf/player/mfplayersession.h
src/plugins/wmf/player/mfvideorenderercontrol.cpp
src/plugins/wmf/player/mfvideorenderercontrol.h

index 0a50114..7f1c713 100644 (file)
@@ -57,27 +57,17 @@ Evr9VideoWindowControl::Evr9VideoWindowControl(QObject *parent)
     , m_currentActivate(0)
     , m_evrSink(0)
     , m_displayControl(0)
+    , m_processor(0)
 {
-    if (FAILED(MFCreateVideoRendererActivate(0, &m_currentActivate))) {
-        qWarning() << "Failed to create evr video renderer activate!";
-        return;
-    }
-    if (FAILED(m_currentActivate->ActivateObject(IID_IMFMediaSink, (LPVOID*)(&m_evrSink)))) {
-        qWarning() << "Failed to activate evr media sink!";
-        return;
-    }
-    if (FAILED(MFGetService(m_evrSink, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_displayControl)))) {
-        qWarning() << "Failed to get display control from evr media sink!";
-        return;
-    }
-    if (FAILED(MFGetService(m_evrSink,  MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_processor)))) {
-        qWarning() << "Failed to get video processor from evr media sink!";
-        return;
-    }
 }
 
 Evr9VideoWindowControl::~Evr9VideoWindowControl()
 {
+   clear();
+}
+
+void Evr9VideoWindowControl::clear()
+{
     if (m_processor)
         m_processor->Release();
     if (m_displayControl)
@@ -88,8 +78,12 @@ Evr9VideoWindowControl::~Evr9VideoWindowControl()
         m_currentActivate->ShutdownObject();
         m_currentActivate->Release();
     }
-}
 
+    m_processor = NULL;
+    m_displayControl = NULL;
+    m_evrSink = NULL;
+    m_currentActivate = NULL;
+}
 
 WId Evr9VideoWindowControl::winId() const
 {
@@ -307,8 +301,32 @@ void Evr9VideoWindowControl::setSaturation(int saturation)
     emit saturationChanged(saturation);
 }
 
-IMFActivate* Evr9VideoWindowControl::currentActivate() const
+IMFActivate* Evr9VideoWindowControl::createActivate()
 {
+    clear();
+
+    if (FAILED(MFCreateVideoRendererActivate(0, &m_currentActivate))) {
+        qWarning() << "Failed to create evr video renderer activate!";
+        return 0;
+    }
+    if (FAILED(m_currentActivate->ActivateObject(IID_IMFMediaSink, (LPVOID*)(&m_evrSink)))) {
+        qWarning() << "Failed to activate evr media sink!";
+        return 0;
+    }
+    if (FAILED(MFGetService(m_evrSink, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_displayControl)))) {
+        qWarning() << "Failed to get display control from evr media sink!";
+        return 0;
+    }
+    if (FAILED(MFGetService(m_evrSink,  MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_processor)))) {
+        qWarning() << "Failed to get video processor from evr media sink!";
+        return 0;
+    }
+
+    setWinId(m_windowId);
+    setDisplayRect(m_displayRect);
+    setAspectRatioMode(m_aspectRatioMode);
+    m_dirtyValues = DXVA2_ProcAmp_Brightness | DXVA2_ProcAmp_Contrast | DXVA2_ProcAmp_Hue | DXVA2_ProcAmp_Saturation;
+
     return m_currentActivate;
 }
 
index d64447f..ea4bae5 100644 (file)
@@ -85,10 +85,12 @@ public:
     int saturation() const;
     void setSaturation(int saturation);
 
-    IMFActivate* currentActivate() const;
+    IMFActivate* createActivate();
 
-private:
     void setProcAmpValues();
+
+private:
+    void clear();
     DXVA2_Fixed32 scaleProcAmpValue(DWORD prop, int value) const;
 
     WId m_windowId;
index 6d421fd..7639f4f 100644 (file)
@@ -46,17 +46,23 @@ MFAudioEndpointControl::MFAudioEndpointControl(QObject *parent)
     : QAudioOutputSelectorControl(parent)
     , m_currentActivate(0)
 {
-    updateEndpoints();
-    setActiveOutput(m_defaultEndpoint);
 }
 
 MFAudioEndpointControl::~MFAudioEndpointControl()
 {
+    clear();
+}
+
+void MFAudioEndpointControl::clear()
+{
+    m_activeEndpoint.clear();
+
     foreach (LPWSTR wstrID, m_devices)
          CoTaskMemFree(wstrID);
 
     if (m_currentActivate)
         m_currentActivate->Release();
+    m_currentActivate = NULL;
 }
 
 QList<QString> MFAudioEndpointControl::availableOutputs() const
@@ -119,8 +125,13 @@ void MFAudioEndpointControl::setActiveOutput(const QString &name)
     m_activeEndpoint = name;
 }
 
-IMFActivate*  MFAudioEndpointControl::currentActivate() const
+IMFActivate*  MFAudioEndpointControl::createActivate()
 {
+    clear();
+
+    updateEndpoints();
+    setActiveOutput(m_defaultEndpoint);
+
     return m_currentActivate;
 }
 
index 1e7fc58..53c6657 100644 (file)
@@ -68,9 +68,10 @@ public:
 
     void setActiveOutput(const QString& name);
 
-    IMFActivate* currentActivate() const;
+    IMFActivate* createActivate();
 
 private:
+    void clear();
     void updateEndpoints();
 
     QString m_defaultEndpoint;
index 1509586..7b35af4 100644 (file)
@@ -411,6 +411,7 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
     , m_volumeControl(0)
     , m_netsourceStatistics(0)
     , m_hCloseEvent(0)
+    , m_closing(false)
     , m_pendingRate(1)
     , m_volume(1)
     , m_muted(false)
@@ -422,10 +423,6 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
     , m_audioSampleGrabberNode(0)
     , m_videoProbeMFT(0)
 {
-    m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    m_sourceResolver = new SourceResolver();
-    QObject::connect(m_sourceResolver, SIGNAL(mediaSourceReady()), this, SLOT(handleMediaSourceReady()));
-    QObject::connect(m_sourceResolver, SIGNAL(error(long)), this, SLOT(handleSourceError(long)));
     QObject::connect(this, SIGNAL(sessionEvent(IMFMediaEvent *)), this, SLOT(handleSessionEvent(IMFMediaEvent *)));
 
     m_pendingState = NoPending;
@@ -438,20 +435,23 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
     m_request.prevCmd = CmdNone;
     m_request.rate = 1.0f;
 
-    createSession();
-    PropVariantInit(&m_varStart);
-    m_varStart.vt = VT_I8;
-    m_varStart.uhVal.QuadPart = 0;
-
     m_audioSampleGrabber = new AudioSampleGrabberCallback;
     m_videoProbeMFT = new MFTransform;
 }
 
 void MFPlayerSession::close()
 {
+#ifdef DEBUG_MEDIAFOUNDATION
+    qDebug() << "close";
+#endif
+
     clear();
+    if (!m_session)
+        return;
+
     HRESULT hr = S_OK;
     if (m_session) {
+        m_closing = true;
         hr = m_session->Close();
         if (SUCCEEDED(hr)) {
             DWORD dwWaitResult = WaitForSingleObject(m_hCloseEvent, 100);
@@ -459,6 +459,7 @@ void MFPlayerSession::close()
                 qWarning() << "session close time out!";
             }
         }
+         m_closing = false;
     }
 
     if (SUCCEEDED(hr)) {
@@ -475,7 +476,9 @@ void MFPlayerSession::close()
     if (m_session)
         m_session->Release();
     m_session = 0;
-    CloseHandle(m_hCloseEvent);
+    if (m_hCloseEvent)
+        CloseHandle(m_hCloseEvent);
+    m_hCloseEvent = 0;
 }
 
 void MFPlayerSession::addProbe(MFAudioProbeControl *probe)
@@ -522,6 +525,7 @@ void MFPlayerSession::load(const QMediaContent &media, QIODevice *stream)
         changeStatus(QMediaPlayer::InvalidMedia);
         emit error(QMediaPlayer::ResourceError, tr("Invalid stream source."), true);
     } else {
+        createSession();
         changeStatus(QMediaPlayer::LoadingMedia);
         m_sourceResolver->load(resources, stream);
     }
@@ -638,6 +642,7 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat
                             break;
                         }
                     }
+                    outputNode->Release();
                 }
                 sourceNode->Release();
             }
@@ -703,14 +708,14 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(IMFStreamDescriptor *streamDesc,
             IMFActivate *activate = NULL;
             if (MFMediaType_Audio == guidMajorType) {
                 mediaType = Audio;
-                activate = m_playerService->audioEndpointControl()->currentActivate();
+                activate = m_playerService->audioEndpointControl()->createActivate();
             } else if (MFMediaType_Video == guidMajorType) {
                 mediaType = Video;
                 if (m_playerService->videoRendererControl()) {
-                    activate = m_playerService->videoRendererControl()->currentActivate();
+                    activate = m_playerService->videoRendererControl()->createActivate();
 #ifndef Q_WS_SIMULATOR
                 } else if (m_playerService->videoWindowControl()) {
-                    activate = m_playerService->videoWindowControl()->currentActivate();
+                    activate = m_playerService->videoWindowControl()->createActivate();
 #endif
                 } else {
                     qWarning() << "no videoWindowControl or videoRendererControl, unable to add output node for video data";
@@ -1136,6 +1141,7 @@ void MFPlayerSession::pause()
     } else {
         if (m_state.command == CmdPause)
             return;
+
         if (SUCCEEDED(m_session->Pause())) {
             m_state.setCommand(CmdPause);
             m_pendingState = CmdPending;
@@ -1163,6 +1169,14 @@ QMediaPlayer::MediaStatus MFPlayerSession::status() const
 
 void MFPlayerSession::createSession()
 {
+    close();
+
+    m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    m_sourceResolver = new SourceResolver();
+    QObject::connect(m_sourceResolver, SIGNAL(mediaSourceReady()), this, SLOT(handleMediaSourceReady()));
+    QObject::connect(m_sourceResolver, SIGNAL(error(long)), this, SLOT(handleSourceError(long)));
+
     Q_ASSERT(m_session == NULL);
     HRESULT hr = MFCreateMediaSession(NULL, &m_session);
     if (FAILED(hr)) {
@@ -1176,6 +1190,10 @@ void MFPlayerSession::createSession()
         changeStatus(QMediaPlayer::UnknownMediaStatus);
         emit error(QMediaPlayer::ResourceError, tr("Unable to pull session events."), false);
     }
+
+    PropVariantInit(&m_varStart);
+    m_varStart.vt = VT_I8;
+    m_varStart.hVal.QuadPart = 0;
 }
 
 qint64 MFPlayerSession::position()
@@ -1511,7 +1529,8 @@ HRESULT MFPlayerSession::Invoke(IMFAsyncResult *pResult)
         }
     }
 
-    emit sessionEvent(pEvent);
+    if (!m_closing)
+        emit sessionEvent(pEvent);
     return S_OK;
 }
 
@@ -1569,6 +1588,13 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
     case MESessionStarted:
         if (!m_scrubbing)
             updatePendingCommands(CmdStart);
+#ifndef Q_WS_SIMULATOR
+        // playback started, we can now set again the procAmpValues if they have been
+        // changed previously (these are lost when loading a new media)
+        if (m_playerService->videoWindowControl()) {
+            m_playerService->videoWindowControl()->setProcAmpValues();
+        }
+#endif
         break;
     case MESessionStopped:
         if (m_status != QMediaPlayer::EndOfMedia) {
@@ -1659,9 +1685,16 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
                 m_volumeControl->SetMasterVolume(m_volume);
                 m_volumeControl->SetMute(m_muted);
             }
+
             DWORD dwCharacteristics = 0;
             m_sourceResolver->mediaSource()->GetCharacteristics(&dwCharacteristics);
             emit seekableUpdate(MFMEDIASOURCE_CAN_SEEK & dwCharacteristics);
+
+            // Topology is resolved and successfuly set, this happens only after loading a new media.
+            // Make sure we always start the media from the beginning
+            m_varStart.vt = VT_I8;
+            m_varStart.hVal.QuadPart = 0;
+
             changeStatus(QMediaPlayer::LoadedMedia);
         }
         break;
index b050ad0..b8b6f08 100644 (file)
@@ -178,6 +178,7 @@ private:
 
     SourceResolver  *m_sourceResolver;
     HANDLE           m_hCloseEvent;
+    bool m_closing;
 
     enum MediaType
     {
index 8d47b1a..c3c5c1a 100644 (file)
@@ -2130,17 +2130,23 @@ namespace
 MFVideoRendererControl::MFVideoRendererControl(QObject *parent)
     : QVideoRendererControl(parent)
     , m_surface(0)
+    , m_currentActivate(0)
     , m_callback(0)
 {
-    m_currentActivate = new VideoRendererActivate(this);
 }
 
 MFVideoRendererControl::~MFVideoRendererControl()
 {
+    clear();
+}
+
+void MFVideoRendererControl::clear()
+{
     if (m_currentActivate) {
         m_currentActivate->ShutdownObject();
         m_currentActivate->Release();
     }
+    m_currentActivate = NULL;
 }
 
 QAbstractVideoSurface *MFVideoRendererControl::surface() const
@@ -2150,9 +2156,6 @@ QAbstractVideoSurface *MFVideoRendererControl::surface() const
 
 void MFVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
 {
-    if (m_surface == surface)
-        return;
-
     if (m_surface)
         disconnect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged()));
     m_surface = surface;
@@ -2160,11 +2163,16 @@ void MFVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
     if (m_surface) {
         connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged()));
     }
-    static_cast<VideoRendererActivate*>(m_currentActivate)->setSurface(m_surface);
+
+    if (m_currentActivate)
+        static_cast<VideoRendererActivate*>(m_currentActivate)->setSurface(m_surface);
 }
 
 void MFVideoRendererControl::customEvent(QEvent *event)
 {
+    if (!m_currentActivate)
+        return;
+
     if (event->type() == MediaStream::PresentSurface) {
         MFTIME targetTime = static_cast<MediaStream::PresentEvent*>(event)->targetTime();
         MFTIME currentTime = static_cast<VideoRendererActivate*>(m_currentActivate)->getTime();
@@ -2185,16 +2193,26 @@ void MFVideoRendererControl::customEvent(QEvent *event)
 
 void MFVideoRendererControl::supportedFormatsChanged()
 {
-    static_cast<VideoRendererActivate*>(m_currentActivate)->supportedFormatsChanged();
+    if (m_currentActivate)
+        static_cast<VideoRendererActivate*>(m_currentActivate)->supportedFormatsChanged();
 }
 
 void MFVideoRendererControl::present()
 {
-    static_cast<VideoRendererActivate*>(m_currentActivate)->present();
+    if (m_currentActivate)
+        static_cast<VideoRendererActivate*>(m_currentActivate)->present();
 }
 
-IMFActivate* MFVideoRendererControl::currentActivate() const
+IMFActivate* MFVideoRendererControl::createActivate()
 {
+    clear();
+
+    m_currentActivate = new VideoRendererActivate(this);
+    if (m_surface) {
+        setSurface(m_surface);
+        supportedFormatsChanged();
+    }
+
     return m_currentActivate;
 }
 
index 25adcf2..ba04e73 100644 (file)
@@ -58,7 +58,7 @@ public:
     QAbstractVideoSurface *surface() const;
     void setSurface(QAbstractVideoSurface *surface);
 
-    IMFActivate* currentActivate() const;
+    IMFActivate* createActivate();
 
 protected:
     void customEvent(QEvent *event);
@@ -68,6 +68,8 @@ private Q_SLOTS:
     void present();
 
 private:
+    void clear();
+
     QAbstractVideoSurface *m_surface;
     IMFActivate *m_currentActivate;
     IMFSampleGrabberSinkCallback *m_callback;