qtmobility/plugins/multimedia/directshow/player/directshowplayerservice.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 11 06b8e2af4411
--- a/qtmobility/plugins/multimedia/directshow/player/directshowplayerservice.cpp	Fri Apr 16 15:51:22 2010 +0300
+++ b/qtmobility/plugins/multimedia/directshow/player/directshowplayerservice.cpp	Mon May 03 13:18:40 2010 +0300
@@ -49,15 +49,14 @@
 #include "directshowvideorenderercontrol.h"
 #include "vmr9videowindowcontrol.h"
 
-#include <qmediacontent.h>
+#include "../../src/multimedia/qmediacontent.h"
 
 #include <QtCore/qcoreapplication.h>
 #include <QtCore/qdatetime.h>
 #include <QtCore/qthread.h>
 #include <QtCore/qvarlengtharray.h>
 
-#include <uuids.h>
-
+Q_GLOBAL_STATIC(DirectShowEventLoop, qt_directShowEventLoop)
 
 class DirectShowPlayerServiceThread : public QThread
 {
@@ -77,12 +76,13 @@
 DirectShowPlayerService::DirectShowPlayerService(QObject *parent)
     : QMediaService(parent)
     , m_playerControl(0)
-    , m_audioEndpointControl(0)
     , m_metaDataControl(0)
     , m_videoOutputControl(0)
     , m_videoRendererControl(0)
     , m_videoWindowControl(0)
+    , m_audioEndpointControl(0)
     , m_taskThread(0)
+    , m_loop(qt_directShowEventLoop())
     , m_pendingTasks(0)
     , m_executingTask(0)
     , m_executedTasks(0)
@@ -105,7 +105,7 @@
     m_metaDataControl = new DirectShowMetaDataControl(this);
     m_videoOutputControl = new DirectShowVideoOutputControl; 
     m_audioEndpointControl = new DirectShowAudioEndpointControl(this);
-    m_videoRendererControl = new DirectShowVideoRendererControl(&m_loop);
+    m_videoRendererControl = new DirectShowVideoRendererControl(m_loop);
     m_videoWindowControl = new Vmr9VideoWindowControl;
 
     m_taskThread = new DirectShowPlayerServiceThread(this);
@@ -178,6 +178,9 @@
 
     m_resources = media.resources();
     m_stream = stream;
+    m_error = QMediaPlayer::NoError;
+    m_errorString = QString();
+    m_position = 0;
     m_duration = 0;
     m_streamTypes = 0;
     m_executedTasks = 0;
@@ -191,10 +194,17 @@
         m_graphStatus = NoMedia;
 
         m_url.clear();
+    } else if (stream && (!stream->isReadable() || stream->isSequential())) {
+        m_pendingTasks = 0;
+        m_graphStatus = InvalidMedia;
+        m_error = QMediaPlayer::ResourceError;
     } else {
+        // {36b73882-c2c8-11cf-8b46-00805f6cef60}
+        static const GUID iid_IFilterGraph2 = {
+            0x36b73882, 0xc2c8, 0x11cf, {0x8b, 0x46, 0x00, 0x80, 0x5f, 0x6c, 0xef, 0x60} };
         m_graphStatus = Loading;
 
-        m_graph = com_new<IFilterGraph2>(CLSID_FilterGraph);
+        m_graph = com_new<IFilterGraph2>(CLSID_FilterGraph, iid_IFilterGraph2);
 
         if (stream)
             m_pendingTasks = SetStreamSource;
@@ -204,8 +214,10 @@
         ::SetEvent(m_taskHandle);
     }
 
+    m_playerControl->updateError(m_error, m_errorString);
     m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
     m_playerControl->updateState(QMediaPlayer::StoppedState);
+    m_playerControl->updatePosition(m_position);
     updateStatus();
 }
 
@@ -218,15 +230,22 @@
 
     HRESULT hr = E_FAIL;
 
-#ifndef QT_NO_WMSDK
     if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) {
-        if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(CLSID_WMAsfReader)) {
+        static const GUID clsid_WMAsfReader = {
+            0x187463a0, 0x5bb7, 0x11d3, {0xac, 0xbe, 0x00, 0x80, 0xc7, 0x5e, 0x24, 0x6e} };
+
+        // {56a868a6-0ad4-11ce-b03a-0020af0ba770}
+        static const GUID iid_IFileSourceFilter = {
+            0x56a868a6, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} };
+
+        if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(
+                clsid_WMAsfReader, iid_IFileSourceFilter)) {
             locker->unlock();
-            hr = fileSource->Load(url.toString().utf16(), 0);
+            hr = fileSource->Load(reinterpret_cast<const OLECHAR *>(url.toString().utf16()), 0);
             locker->relock();
 
             if (SUCCEEDED(hr)) {
-                source = com_cast<IBaseFilter>(fileSource);
+                source = com_cast<IBaseFilter>(fileSource, IID_IBaseFilter);
 
                 if (!SUCCEEDED(hr = m_graph->AddFilter(source, L"Source")) && source) {
                     source->Release();
@@ -236,16 +255,21 @@
 
             fileSource->Release();
         }
+    } else if (url.scheme() == QLatin1String("qrc")) {
+        DirectShowRcSource *rcSource = new DirectShowRcSource(m_loop);
+
+        if (rcSource->open(url) && SUCCEEDED(hr = m_graph->AddFilter(rcSource, L"Source")))
+            source = rcSource;
+        else
+            rcSource->Release();
     }
 
     if (!SUCCEEDED(hr)) {
-#endif
         locker->unlock();
-        hr = m_graph->AddSourceFilter(url.toString().utf16(), L"Source", &source);
+        hr = m_graph->AddSourceFilter(
+                reinterpret_cast<const OLECHAR *>(url.toString().utf16()), L"Source", &source);
         locker->relock();
-#ifndef QT_NO_WMSDK
     }
-#endif
 
     if (SUCCEEDED(hr)) {
         m_executedTasks = SetSource;
@@ -269,14 +293,17 @@
         switch (hr) {
         case VFW_E_UNKNOWN_FILE_TYPE:
             m_error = QMediaPlayer::FormatError;
+            m_errorString = QString();
             break;
         case E_OUTOFMEMORY:
         case VFW_E_CANNOT_LOAD_SOURCE_FILTER:
         case VFW_E_NOT_FOUND:
             m_error = QMediaPlayer::ResourceError;
+            m_errorString = QString();
         default:
             m_error = QMediaPlayer::ResourceError;
-            qWarning("DirectShowPlayerService::doSetUrlSource: Unresolved error code %x", hr);
+            m_errorString = QString();
+            qWarning("DirectShowPlayerService::doSetUrlSource: Unresolved error code %x", uint(hr));
             break;
         }
 
@@ -286,7 +313,8 @@
 
 void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker)
 {
-    IBaseFilter *source = new DirectShowIOSource(m_stream, &m_loop);
+    DirectShowIOSource *source = new DirectShowIOSource(m_loop);
+    source->setDevice(m_stream);
 
     if (SUCCEEDED(m_graph->AddFilter(source, L"Source"))) {
         m_executedTasks = SetSource;
@@ -308,6 +336,7 @@
         m_graphStatus = InvalidMedia;
 
         m_error = QMediaPlayer::ResourceError;
+        m_errorString = QString();
 
         QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
     }
@@ -315,6 +344,13 @@
 
 void DirectShowPlayerService::doRender(QMutexLocker *locker)
 {
+    m_pendingTasks |= m_executedTasks & (Play | Pause);
+
+    if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
+        control->Stop();
+        control->Release();
+    }
+
     if (m_pendingTasks & SetAudioOutput) {
         m_graph->AddFilter(m_audioOutput, L"AudioOutput");
 
@@ -354,14 +390,14 @@
                     IPin *peer = 0;
                     if (pin->ConnectedTo(&peer) == S_OK) {
                         PIN_INFO peerInfo;
-                        if (peer->QueryPinInfo(&peerInfo) == S_OK)
+                        if (SUCCEEDED(peer->QueryPinInfo(&peerInfo)))
                             filters.append(peerInfo.pFilter);
                         peer->Release();
                     } else {
                         locker->unlock();
                         HRESULT hr;
                         if (SUCCEEDED(hr = graph->RenderEx(
-                                pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, 0))) {
+                                pin, /*AM_RENDEREX_RENDERTOEXISTINGRENDERERS*/ 1, 0))) {
                             rendered = true;
                         } else if (renderHr == S_OK || renderHr == VFW_E_NO_DECOMPRESSOR){
                             renderHr = hr;
@@ -370,13 +406,15 @@
                     }
                 }
             }
+
+            pins->Release();
+
             if (outputs == 0)
                 rendered = true;
         }
         filter->Release();
     }
 
-
     if (m_audioOutput && !isConnected(m_audioOutput, PINDIR_INPUT)) {
         graph->RemoveFilter(m_audioOutput);
 
@@ -402,16 +440,19 @@
 
             if (!m_audioOutput && !m_videoOutput) {
                 m_error = QMediaPlayer::ResourceError;
+                m_errorString = QString();
             } else {
                 switch (renderHr) {
                 case VFW_E_UNSUPPORTED_AUDIO:
                 case VFW_E_UNSUPPORTED_VIDEO:
                 case VFW_E_UNSUPPORTED_STREAM:
                     m_error = QMediaPlayer::FormatError;
+                    m_errorString = QString();
                 default:
                     m_error = QMediaPlayer::ResourceError;
+                    m_errorString = QString();
                     qWarning("DirectShowPlayerService::doRender: Unresolved error code %x",
-                             renderHr);
+                             uint(renderHr));
                 }
             }
 
@@ -421,17 +462,17 @@
         m_executedTasks |= Render;
     }
 
-    m_loop.wake();
+    m_loop->wake();
 }
 
 void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker)
 {
     if (m_graphStatus != Loaded) {
-        if (IMediaEvent *event = com_cast<IMediaEvent>(m_graph)) {
+        if (IMediaEvent *event = com_cast<IMediaEvent>(m_graph, IID_IMediaEvent)) {
             event->GetEventHandle(reinterpret_cast<OAEVENT *>(&m_eventHandle));
             event->Release();
         }
-        if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+        if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
             LONGLONG duration = 0;
             seeking->GetDuration(&duration);
             m_duration = duration / 10;
@@ -461,7 +502,12 @@
 {
     if (m_graph) {
         if (m_executingTask != 0) {
-            if (IAMOpenProgress *progress = com_cast<IAMOpenProgress>(m_graph)) {
+            // {8E1C39A1-DE53-11cf-AA63-0080C744528D}
+            static const GUID iid_IAMOpenProgress = {
+                0x8E1C39A1, 0xDE53, 0x11cf, {0xAA, 0x63, 0x00, 0x80, 0xC7, 0x44, 0x52, 0x8D} };
+
+            if (IAMOpenProgress *progress = com_cast<IAMOpenProgress>(
+                    m_graph, iid_IAMOpenProgress)) {
                 progress->AbortOperation();
                 progress->Release();
             }
@@ -472,7 +518,7 @@
 
         ::SetEvent(m_taskHandle);
 
-        m_loop.wait(&m_mutex);
+        m_loop->wait(&m_mutex);
     }
 }
 
@@ -480,7 +526,7 @@
 {
     Q_UNUSED(locker);
 
-    if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+    if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
         control->Stop();
         control->Release();
     }
@@ -495,7 +541,7 @@
     m_graph->Release();
     m_graph = 0;
 
-    m_loop.wake();
+    m_loop->wake();
 }
 
 int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const
@@ -595,23 +641,21 @@
 
 void DirectShowPlayerService::doPlay(QMutexLocker *locker)
 {
-    if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+    if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
         locker->unlock();
         HRESULT hr = control->Run();
         locker->relock();
 
         control->Release();
 
-        if (SUCCEEDED(hr))
-            m_executedTasks |= Play;
-
         if (SUCCEEDED(hr)) {
             m_executedTasks |= Play;
 
             QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange)));
         } else {
             m_error = QMediaPlayer::ResourceError;
-            qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", hr);
+            m_errorString = QString();
+            qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", uint(hr));
 
             QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
         }
@@ -639,7 +683,7 @@
 
 void DirectShowPlayerService::doPause(QMutexLocker *locker)
 {
-    if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+    if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
         locker->unlock();
         HRESULT hr = control->Pause();
         locker->relock();
@@ -647,12 +691,24 @@
         control->Release();
 
         if (SUCCEEDED(hr)) {
+            if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
+                LONGLONG position = 0;
+
+                seeking->GetCurrentPosition(&position);
+                seeking->Release();
+
+                m_position = position / 10;
+            } else {
+                m_position = 0;
+            }
+
             m_executedTasks |= Pause;
 
             QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange)));
         } else {
             m_error = QMediaPlayer::ResourceError;
-            qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", hr);
+            m_errorString = QString();
+            qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", uint(hr));
 
             QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
         }
@@ -665,23 +721,43 @@
 
     m_pendingTasks &= ~(Play | Pause | Seek);
 
-    if (m_executedTasks & Render) {
-        if (m_executingTask & (Play | Pause | Seek)) {
-            m_pendingTasks |= Stop;
+    if ((m_executingTask | m_executedTasks) & (Play | Pause | Seek)) {
+        m_pendingTasks |= Stop;
+
+        ::SetEvent(m_taskHandle);
+
+        m_loop->wait(&m_mutex);
+    }
 
-            m_loop.wait(&m_mutex);
+}
+
+void DirectShowPlayerService::doStop(QMutexLocker *locker)
+{
+    if (m_executedTasks & (Play | Pause)) {
+        if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
+            control->Stop();
+            control->Release();
         }
 
-        if (m_executedTasks & (Play | Pause)) {
-            if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
-                control->Stop();
-                control->Release();
-            }
-            m_executedTasks &= ~(Play | Pause);
+        if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
+            LONGLONG position = 0;
+
+            seeking->GetCurrentPosition(&position);
+            seeking->Release();
+
+            m_position = position / 10;
+        } else {
+            m_position = 0;
         }
+
+        m_executedTasks &= ~(Play | Pause);
+        
+        QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange)));
     }
 
     m_executedTasks |= Stop;
+
+    m_loop->wake();
 }
 
 void DirectShowPlayerService::setRate(qreal rate)
@@ -698,7 +774,7 @@
 
 void DirectShowPlayerService::doSetRate(QMutexLocker *locker)
 {
-    if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+    if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
         // Cache current values as we can't query IMediaSeeking during a seek due to the
         // possibility of a deadlock when flushing the VideoSurfaceFilter.
         LONGLONG currentPosition = 0;
@@ -736,13 +812,15 @@
     if (m_graphStatus == Loaded) {
         if (m_executingTask == Seek || m_executingTask == SetRate) {
             return m_position;
-        } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+        } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
             LONGLONG position = 0;
 
             seeking->GetCurrentPosition(&position);
             seeking->Release();
 
-            return position / 10;
+            const_cast<qint64 &>(m_position) = position / 10;
+
+            return m_position;
         }
     }
     return 0;
@@ -755,7 +833,7 @@
     if (m_graphStatus == Loaded) {
         if (m_executingTask == Seek || m_executingTask == SetRate) {
             return m_playbackRange;
-        } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+        } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
             LONGLONG minimum = 0;
             LONGLONG maximum = 0;
 
@@ -783,7 +861,7 @@
 
 void DirectShowPlayerService::doSeek(QMutexLocker *locker)
 {
-    if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+    if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
         LONGLONG seekPosition = LONGLONG(m_position) * 10;
 
         // Cache current values as we can't query IMediaSeeking during a seek due to the
@@ -803,8 +881,15 @@
                 &seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning);
         locker->relock();
 
+        seeking->GetCurrentPosition(&currentPosition);
+        m_position = currentPosition / 10;
+
         seeking->Release();
+    } else {
+        m_position = 0;
     }
+
+    QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange)));
 }
 
 int DirectShowPlayerService::bufferStatus() const
@@ -812,7 +897,8 @@
 #ifndef QT_NO_WMSDK
     QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
 
-    if (IWMReaderAdvanced2 *reader = com_cast<IWMReaderAdvanced2>(m_source)) {
+    if (IWMReaderAdvanced2 *reader = com_cast<IWMReaderAdvanced2>(
+            m_source, IID_IWMReaderAdvanced2)) {
         DWORD percentage = 0;
 
         reader->GetBufferProgress(&percentage, 0);
@@ -838,7 +924,7 @@
 
                 ::SetEvent(m_taskHandle);
 
-                m_loop.wait(&m_mutex);
+                m_loop->wait(&m_mutex);
             }
             m_audioOutput->Release();
         } 
@@ -849,15 +935,15 @@
             m_audioOutput->AddRef();
 
             m_pendingTasks |= SetAudioOutput;
+
+            if (m_executedTasks & SetSource) {
+                m_pendingTasks |= Render;
+
+                ::SetEvent(m_taskHandle);
+            }
         } else {
             m_pendingTasks &= ~ SetAudioOutput;
         }
-
-        if (m_executedTasks & SetSource) {
-            m_pendingTasks |= Render;
-
-            ::SetEvent(m_taskHandle);
-        }
     } else {
         if (m_audioOutput)
             m_audioOutput->Release();
@@ -875,16 +961,33 @@
 {
     m_pendingTasks |= m_executedTasks & (Play | Pause);
 
-    if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+    if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
         control->Stop();
         control->Release();
     }
 
-    m_graph->RemoveFilter(m_audioOutput);
+    IBaseFilter *decoder = getConnected(m_audioOutput, PINDIR_INPUT);
+    if (!decoder) {
+        decoder = m_audioOutput;
+        decoder->AddRef();
+    }
+
+    // {DCFBDCF6-0DC2-45f5-9AB2-7C330EA09C29}
+    static const GUID iid_IFilterChain = {
+        0xDCFBDCF6, 0x0DC2, 0x45f5, {0x9A, 0xB2, 0x7C, 0x33, 0x0E, 0xA0, 0x9C, 0x29} };
+
+    if (IFilterChain *chain = com_cast<IFilterChain>(m_graph, iid_IFilterChain)) {
+        chain->RemoveChain(decoder, m_audioOutput);
+        chain->Release();
+    } else {
+        m_graph->RemoveFilter(m_audioOutput);
+    }
+
+    decoder->Release();
 
     m_executedTasks &= ~SetAudioOutput;
 
-    m_loop.wake();
+    m_loop->wake();
 }
 
 void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter)
@@ -898,7 +1001,7 @@
 
                 ::SetEvent(m_taskHandle);
 
-                m_loop.wait(&m_mutex);
+                m_loop->wait(&m_mutex);
             }
             m_videoOutput->Release();
         }
@@ -909,14 +1012,12 @@
             m_videoOutput->AddRef();
 
             m_pendingTasks |= SetVideoOutput;
-        } else {
-            m_pendingTasks &= ~ SetVideoOutput;
-        }
 
-        if (m_executedTasks & SetSource) {
-            m_pendingTasks |= Render;
+            if (m_executedTasks & SetSource) {
+                m_pendingTasks |= Render;
 
-            ::SetEvent(m_taskHandle);
+                ::SetEvent(m_taskHandle);
+            }
         }
     } else {
         if (m_videoOutput)
@@ -933,16 +1034,40 @@
 {
     m_pendingTasks |= m_executedTasks & (Play | Pause);
 
-    if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+    if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
         control->Stop();
         control->Release();
     }
 
-    m_graph->RemoveFilter(m_videoOutput);
+    IBaseFilter *intermediate = 0;
+    if (!SUCCEEDED(m_graph->FindFilterByName(L"Color Space Converter", &intermediate))) {
+        intermediate = m_videoOutput;
+        intermediate->AddRef();
+    }
+
+    IBaseFilter *decoder = getConnected(intermediate, PINDIR_INPUT);
+    if (!decoder) {
+        decoder = intermediate;
+        decoder->AddRef();
+    }
+
+    // {DCFBDCF6-0DC2-45f5-9AB2-7C330EA09C29}
+    static const GUID iid_IFilterChain = {
+        0xDCFBDCF6, 0x0DC2, 0x45f5, {0x9A, 0xB2, 0x7C, 0x33, 0x0E, 0xA0, 0x9C, 0x29} };
+
+    if (IFilterChain *chain = com_cast<IFilterChain>(m_graph, iid_IFilterChain)) {
+        chain->RemoveChain(decoder, m_videoOutput);
+        chain->Release();
+    } else {
+        m_graph->RemoveFilter(m_videoOutput);
+    }
+
+    intermediate->Release();
+    decoder->Release();
 
     m_executedTasks &= ~SetVideoOutput;
 
-    m_loop.wake();
+    m_loop->wake();
 }
 
 void DirectShowPlayerService::customEvent(QEvent *event)
@@ -955,18 +1080,14 @@
 
         updateStatus();
     } else if (event->type() == QEvent::Type(Error)) {
-        QMediaPlayer::Error error;
-        {
-            QMutexLocker locker(&m_mutex);
-            error = m_error;
+        QMutexLocker locker(&m_mutex);
 
-            if (error != QMediaPlayer::NoError) {
-                m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
-                m_playerControl->updateState(QMediaPlayer::StoppedState);
-                updateStatus();
-            }
+        if (m_error != QMediaPlayer::NoError) {
+            m_playerControl->updateError(m_error, m_errorString);
+            m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+            m_playerControl->updateState(QMediaPlayer::StoppedState);
+            updateStatus();
         }
-        m_playerControl->error(error, QString());
     } else if (event->type() == QEvent::Type(RateChange)) {
         QMutexLocker locker(&m_mutex);
 
@@ -975,6 +1096,7 @@
         QMutexLocker locker(&m_mutex);
 
         updateStatus();
+        m_playerControl->updatePosition(m_position);
     } else if (event->type() == QEvent::Type(DurationChange)) {
         QMutexLocker locker(&m_mutex);
 
@@ -985,7 +1107,12 @@
         if (m_atEnd) {
             m_playerControl->updateState(QMediaPlayer::StoppedState);
             m_playerControl->updateStatus(QMediaPlayer::EndOfMedia);
+            m_playerControl->updatePosition(m_position);
         }
+    } else if (event->type() == QEvent::Type(PositionChange)) {
+        QMutexLocker locker(&m_mutex);
+
+        m_playerControl->updatePosition(m_position);
     } else {
         QMediaService::customEvent(event);
     }
@@ -1011,7 +1138,7 @@
 
 void DirectShowPlayerService::graphEvent(QMutexLocker *locker)
 {
-    if (IMediaEvent *event = com_cast<IMediaEvent>(m_graph)) {
+    if (IMediaEvent *event = com_cast<IMediaEvent>(m_graph, IID_IMediaEvent)) {
         long eventCode;
         LONG_PTR param1;
         LONG_PTR param2;
@@ -1030,10 +1157,19 @@
                 m_buffering = false;
                 m_atEnd = true;
 
+                if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
+                    LONGLONG position = 0;
+
+                    seeking->GetCurrentPosition(&position);
+                    seeking->Release();
+
+                    m_position = position / 10;
+                }
+
                 QCoreApplication::postEvent(this, new QEvent(QEvent::Type(EndOfMedia)));
                 break;
             case EC_LENGTH_CHANGED:
-                if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+                if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
                     LONGLONG duration = 0;
                     seeking->GetDuration(&duration);
                     m_duration = duration / 10;
@@ -1107,6 +1243,38 @@
     return connected;
 }
 
+IBaseFilter *DirectShowPlayerService::getConnected(
+        IBaseFilter *filter, PIN_DIRECTION direction) const
+{
+    IBaseFilter *connected = 0;
+
+    IEnumPins *pins = 0;
+
+    if (SUCCEEDED(filter->EnumPins(&pins))) {
+        for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+            PIN_DIRECTION dir;
+            if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) {
+                IPin *peer = 0;
+                if (SUCCEEDED(pin->ConnectedTo(&peer))) {
+                    PIN_INFO info;
+
+                    if (SUCCEEDED(peer->QueryPinInfo(&info))) {
+                        if (connected) {
+                            qWarning("DirectShowPlayerService::getConnected: "
+                                "Multiple connected filters");
+                            connected->Release();
+                        }
+                        connected = info.pFilter;
+                    }
+                    peer->Release();
+                }
+            }
+        }
+        pins->Release();
+    }
+    return connected;
+}
+
 void DirectShowPlayerService::run()
 {
     QMutexLocker locker(&m_mutex);
@@ -1171,15 +1339,16 @@
             m_executingTask = FinalizeLoad;
 
             doFinalizeLoad(&locker);
+        } else if (m_pendingTasks & Stop) {
+            m_pendingTasks ^= Stop;
+            m_executingTask = Stop;
+
+            doStop(&locker);
         } else if (m_pendingTasks & SetRate) {
             m_pendingTasks ^= SetRate;
             m_executingTask = SetRate;
 
             doSetRate(&locker);
-        } else if (m_pendingTasks & Stop) {
-            m_pendingTasks ^= Stop;
-
-            m_loop.wake();
         } else if (m_pendingTasks & Pause) {
             m_pendingTasks ^= Pause;
             m_executingTask = Pause;