diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..175fec1d532dc0b6a01e41b02f2567c207d75487
--- /dev/null
+++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtabstractvideorenderercontrol.h"
+
+#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/QGlobalStatic>
+#include <QtCore/QMetaMethod>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLTexture>
+#include <QtMultimedia/QAbstractVideoBuffer>
+#include <QtMultimedia/QAbstractVideoSurface>
+#include <QtMultimedia/QVideoSurfaceFormat>
+
+#define EGL_EGLEXT_PROTOTYPES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <d3d11.h>
+#include <mfapi.h>
+#include <wrl.h>
+
+using namespace Microsoft::WRL;
+
+QT_USE_NAMESPACE
+
+#define BREAK_IF_FAILED(msg) RETURN_IF_FAILED(msg, break)
+#define CONTINUE_IF_FAILED(msg) RETURN_IF_FAILED(msg, continue)
+
+// Global D3D device to be shared between video surfaces
+struct QWinRTVideoRendererControlGlobal
+{
+    QWinRTVideoRendererControlGlobal()
+    {
+        HRESULT hr;
+
+        D3D_FEATURE_LEVEL featureLevels[] =
+        {
+            D3D_FEATURE_LEVEL_11_1,
+            D3D_FEATURE_LEVEL_11_0,
+            D3D_FEATURE_LEVEL_10_1,
+            D3D_FEATURE_LEVEL_10_0,
+            D3D_FEATURE_LEVEL_9_3,
+            D3D_FEATURE_LEVEL_9_2,
+            D3D_FEATURE_LEVEL_9_1
+        };
+
+        UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
+#ifdef _DEBUG
+        flags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+        hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags,
+                               featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION,
+                               &device, &featureLevel, &context);
+        if (FAILED(hr))
+            qErrnoWarning(hr, "Failed to create D3D device");
+
+        if (!device || FAILED(hr)) {
+            hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, flags,
+                                   featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION,
+                                   &device, &featureLevel, &context);
+            if (FAILED(hr)) {
+                qErrnoWarning(hr, "Failed to create software D3D device");
+                return;
+            }
+        }
+
+        ComPtr<ID3D10Multithread> multithread;
+        hr = device.As(&multithread);
+        Q_ASSERT_SUCCEEDED(hr);
+        hr = multithread->SetMultithreadProtected(true);
+        Q_ASSERT_SUCCEEDED(hr);
+
+        ComPtr<IDXGIDevice> dxgiDevice;
+        hr = device.As(&dxgiDevice);
+        Q_ASSERT_SUCCEEDED(hr);
+        ComPtr<IDXGIAdapter> adapter;
+        hr = dxgiDevice->GetAdapter(&adapter);
+        Q_ASSERT_SUCCEEDED(hr);
+        hr = adapter->EnumOutputs(0, &output);
+        Q_ASSERT_SUCCEEDED(hr);
+    }
+
+    ComPtr<ID3D11Device> device;
+    ComPtr<ID3D11DeviceContext> context;
+    D3D_FEATURE_LEVEL featureLevel;
+    ComPtr<IDXGIOutput> output;
+};
+Q_GLOBAL_STATIC(QWinRTVideoRendererControlGlobal, g)
+
+class QWinRTVideoBuffer : public QAbstractVideoBuffer, public QOpenGLTexture
+{
+public:
+    QWinRTVideoBuffer()
+        : QAbstractVideoBuffer(QAbstractVideoBuffer::GLTextureHandle)
+        , QOpenGLTexture(QOpenGLTexture::Target2D)
+    {
+    }
+
+    void addRef()
+    {
+        refCount.ref();
+    }
+
+    void release() Q_DECL_OVERRIDE
+    {
+        if (!refCount.deref())
+            delete this;
+    }
+
+    MapMode mapMode() const Q_DECL_OVERRIDE
+    {
+        return NotMapped;
+    }
+
+    uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) Q_DECL_OVERRIDE
+    {
+        Q_UNUSED(mode);
+        Q_UNUSED(numBytes);
+        Q_UNUSED(bytesPerLine);
+        return 0;
+    }
+
+    void unmap() Q_DECL_OVERRIDE
+    {
+    }
+
+    QVariant handle() const Q_DECL_OVERRIDE
+    {
+        return QVariant::fromValue(textureId());
+    }
+
+private:
+    QAtomicInt refCount;
+};
+
+enum DirtyState {
+    NotDirty,     // All resources have been created
+    TextureDirty, // The shared D3D texture needs to be recreated
+    SurfaceDirty  // The shared EGL surface needs to be recreated
+};
+
+class QWinRTAbstractVideoRendererControlPrivate
+{
+public:
+    QAbstractVideoSurface *surface;
+    QVideoSurfaceFormat format;
+
+    DirtyState dirtyState;
+
+    HANDLE shareHandle;
+    ComPtr<ID3D11Texture2D> texture;
+
+    EGLDisplay eglDisplay;
+    EGLConfig eglConfig;
+    EGLSurface eglSurface;
+
+    QWinRTVideoBuffer *videoBuffer;
+
+    QThread renderThread;
+    bool active;
+};
+
+ID3D11Device *QWinRTAbstractVideoRendererControl::d3dDevice()
+{
+    return g->device.Get();
+}
+
+// This is required so that subclasses can stop the render thread before deletion
+void QWinRTAbstractVideoRendererControl::shutdown()
+{
+    Q_D(QWinRTAbstractVideoRendererControl);
+    if (d->renderThread.isRunning()) {
+        d->renderThread.requestInterruption();
+        d->renderThread.wait();
+    }
+}
+
+QWinRTAbstractVideoRendererControl::QWinRTAbstractVideoRendererControl(const QSize &size, QObject *parent)
+    : QVideoRendererControl(parent), d_ptr(new QWinRTAbstractVideoRendererControlPrivate)
+{
+    Q_D(QWinRTAbstractVideoRendererControl);
+
+    d->surface = Q_NULLPTR;
+    d->format = QVideoSurfaceFormat(size, QVideoFrame::Format_BGRA32,
+                                    QAbstractVideoBuffer::GLTextureHandle);
+    d->dirtyState = TextureDirty;
+    d->shareHandle = 0;
+    d->eglDisplay = EGL_NO_DISPLAY;
+    d->eglConfig = 0;
+    d->eglSurface = EGL_NO_SURFACE;
+    d->active = false;
+
+    d->videoBuffer = new QWinRTVideoBuffer;
+
+    connect(&d->renderThread, &QThread::started,
+            this, &QWinRTAbstractVideoRendererControl::syncAndRender,
+            Qt::DirectConnection);
+}
+
+QWinRTAbstractVideoRendererControl::~QWinRTAbstractVideoRendererControl()
+{
+    shutdown();
+}
+
+QAbstractVideoSurface *QWinRTAbstractVideoRendererControl::surface() const
+{
+    Q_D(const QWinRTAbstractVideoRendererControl);
+    return d->surface;
+}
+
+void QWinRTAbstractVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+    Q_D(QWinRTAbstractVideoRendererControl);
+    d->surface = surface;
+}
+
+void QWinRTAbstractVideoRendererControl::syncAndRender()
+{
+    Q_D(QWinRTAbstractVideoRendererControl);
+
+    QThread *currentThread = QThread::currentThread();
+    const QMetaMethod present = staticMetaObject.method(staticMetaObject.indexOfMethod("present()"));
+    forever {
+        if (currentThread->isInterruptionRequested())
+            break;
+
+        HRESULT hr;
+        if (d->dirtyState == TextureDirty) {
+            CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, d->format.frameWidth(), d->format.frameHeight(), 1, 1);
+            desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
+            desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+            hr = g->device->CreateTexture2D(&desc, NULL, d->texture.ReleaseAndGetAddressOf());
+            BREAK_IF_FAILED("Failed to get create video texture");
+            ComPtr<IDXGIResource> resource;
+            hr = d->texture.As(&resource);
+            BREAK_IF_FAILED("Failed to cast texture to resource");
+            hr = resource->GetSharedHandle(&d->shareHandle);
+            BREAK_IF_FAILED("Failed to get texture share handle");
+            d->dirtyState = SurfaceDirty;
+        }
+
+        hr = g->output->WaitForVBlank();
+        CONTINUE_IF_FAILED("Failed to wait for vertical blank");
+
+        if (!render(d->texture.Get()))
+            continue;
+
+        // Queue to the control's thread for presentation
+        present.invoke(this, Qt::QueuedConnection);
+        currentThread->eventDispatcher()->processEvents(QEventLoop::AllEvents);
+    }
+
+    // All done, exit render loop
+    currentThread->quit();
+}
+
+QSize QWinRTAbstractVideoRendererControl::size() const
+{
+    Q_D(const QWinRTAbstractVideoRendererControl);
+    return d->format.frameSize();
+}
+
+void QWinRTAbstractVideoRendererControl::setSize(const QSize &size)
+{
+    Q_D(QWinRTAbstractVideoRendererControl);
+
+    if (d->format.frameSize() == size)
+        return;
+
+    d->format.setFrameSize(size);
+    d->dirtyState = TextureDirty;
+}
+
+void QWinRTAbstractVideoRendererControl::setActive(bool active)
+{
+    Q_D(QWinRTAbstractVideoRendererControl);
+
+    if (d->active == active)
+        return;
+
+    d->active = active;
+    if (d->active) {
+        if (!d->surface)
+            return;
+
+        if (!d->surface->isActive())
+            d->surface->start(d->format);
+
+        d->renderThread.start();
+        return;
+    }
+
+    d->renderThread.requestInterruption();
+}
+
+void QWinRTAbstractVideoRendererControl::present()
+{
+    Q_D(QWinRTAbstractVideoRendererControl);
+
+    if (d->dirtyState == SurfaceDirty) {
+        if (!QOpenGLContext::currentContext()) {
+            qWarning("A valid OpenGL context is required for binding the video texture.");
+            return;
+        }
+
+        if (d->eglDisplay == EGL_NO_DISPLAY)
+            d->eglDisplay = eglGetCurrentDisplay();
+
+        if (d->eglDisplay == EGL_NO_DISPLAY) {
+            qWarning("Failed to get the current EGL display for video presentation: 0x%x", eglGetError());
+            return;
+        }
+
+        EGLint configAttributes[] = {
+            EGL_RED_SIZE, 8,
+            EGL_GREEN_SIZE, 8,
+            EGL_BLUE_SIZE, 8,
+            EGL_ALPHA_SIZE, 8,
+            EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
+            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+            EGL_NONE
+        };
+        EGLint configCount;
+        if (!eglChooseConfig(d->eglDisplay, configAttributes, &d->eglConfig, 1, &configCount)) {
+            qWarning("Failed to create the texture EGL configuration for video presentation: 0x%x", eglGetError());
+            return;
+        }
+
+        if (d->eglSurface != EGL_NO_SURFACE)
+            eglDestroySurface(d->eglDisplay, d->eglSurface);
+
+        EGLint bufferAttributes[] = {
+            EGL_WIDTH, d->format.frameWidth(),
+            EGL_HEIGHT, d->format.frameHeight(),
+            EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+            EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+            EGL_NONE
+        };
+        d->eglSurface = eglCreatePbufferFromClientBuffer(d->eglDisplay,
+                                                         EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
+                                                         d->shareHandle, d->eglConfig, bufferAttributes);
+        if (d->eglSurface == EGL_NO_SURFACE) {
+            qWarning("Failed to create the EGL configuration for video presentation: 0x%x", eglGetError());
+            return;
+        }
+
+        d->videoBuffer->setFormat(QOpenGLTexture::RGBAFormat);
+        d->videoBuffer->setSize(d->format.frameWidth(), d->format.frameHeight());
+        if (!d->videoBuffer->isCreated())
+            d->videoBuffer->create();
+
+        // bind the pbuffer surface to the texture
+        d->videoBuffer->bind();
+        eglBindTexImage(d->eglDisplay, d->eglSurface, EGL_BACK_BUFFER);
+        static_cast<QOpenGLTexture *>(d->videoBuffer)->release();
+
+        d->dirtyState = NotDirty;
+    }
+
+    // Present the frame
+    d->videoBuffer->addRef();
+    QVideoFrame frame(d->videoBuffer, d->format.frameSize(), d->format.pixelFormat());
+    d->surface->present(frame);
+}
diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..86a7b15f9f697a098b62316109dfea2d07cdc0ef
--- /dev/null
+++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTABSTRACTVIDEORENDERERCONTROL_H
+#define QWINRTABSTRACTVIDEORENDERERCONTROL_H
+
+#include <QtMultimedia/QVideoRendererControl>
+
+struct ID3D11Device;
+struct ID3D11Texture2D;
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTAbstractVideoRendererControlPrivate;
+class QWinRTAbstractVideoRendererControl : public QVideoRendererControl
+{
+    Q_OBJECT
+public:
+    explicit QWinRTAbstractVideoRendererControl(const QSize &size, QObject *parent = 0);
+    ~QWinRTAbstractVideoRendererControl();
+
+    QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
+    void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
+
+    QSize size() const;
+    void setSize(const QSize &size);
+
+    void setActive(bool active);
+
+    virtual bool render(ID3D11Texture2D *texture) = 0;
+
+    static ID3D11Device *d3dDevice();
+
+protected:
+    void shutdown();
+
+private slots:
+    void syncAndRender();
+
+private:
+    Q_INVOKABLE void present();
+
+    QScopedPointer<QWinRTAbstractVideoRendererControlPrivate> d_ptr;
+    Q_DECLARE_PRIVATE(QWinRTAbstractVideoRendererControl)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTABSTRACTVIDEORENDERERCONTROL_H
diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..66c0bd56805f2cf2e125093aac75807c22006aad
--- /dev/null
+++ b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp
@@ -0,0 +1,899 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtmediaplayercontrol.h"
+#include "qwinrtplayerrenderercontrol.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFile>
+#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/QSize>
+#include <QtCore/QTimerEvent>
+#include <QtCore/QUrl>
+#include <QtMultimedia/QMediaPlaylist>
+#include <QtConcurrent/QtConcurrentRun>
+
+#include <dxgi.h>
+#include <oleauto.h>
+#include <mfapi.h>
+#include <mfmediaengine.h>
+
+#include <comdef.h>
+#include <wrl.h>
+using namespace Microsoft::WRL;
+
+QT_USE_NAMESPACE
+
+#define QT_WINRT_MEDIAPLAYER_STREAM_ID "__qtmultimedia_winrt_player_stream"
+
+class MediaEngineNotify;
+class MediaEngineSources;
+class MediaEngineByteStream;
+class QWinRTMediaPlayerControlPrivate
+{
+public:
+    QMediaPlayer::State state;
+    QMediaPlayer::MediaStatus mediaStatus;
+    qint64 duration;
+    qint64 position;
+    qreal playbackRate;
+    int volume;
+    bool muted;
+    int bufferStatus;
+    bool seekable;
+    bool hasVideo;
+    bool hasAudio;
+
+    QMediaContent media;
+    QScopedPointer<QIODevice, QWinRTMediaPlayerControlPrivate> stream;
+    QWinRTPlayerRendererControl *videoRenderer;
+
+    ComPtr<MediaEngineNotify> notifier;
+    ComPtr<MediaEngineSources> sources;
+    ComPtr<MediaEngineByteStream> streamProvider;
+    ComPtr<IMFAttributes> configuration;
+    ComPtr<IMFMediaEngineEx> engine;
+
+    quint32 resetToken;
+    ComPtr<IMFDXGIDeviceManager> manager;
+
+    // Automatically delete streams created by the player
+    static inline void cleanup(QIODevice *device)
+    {
+        if (device && device->property(QT_WINRT_MEDIAPLAYER_STREAM_ID).toBool())
+            device->deleteLater();
+    }
+
+    // Allows for deferred cleanup of the engine, which tends to block on shutdown
+    static void cleanup(QWinRTMediaPlayerControlPrivate *d);
+    static void shutdown(QWinRTMediaPlayerControlPrivate *d);
+};
+
+class MediaEngineNotify : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IMFMediaEngineNotify>
+{
+public:
+    MediaEngineNotify(QWinRTMediaPlayerControl *q_ptr, QWinRTMediaPlayerControlPrivate *d_ptr)
+        : q(q_ptr), d(d_ptr)
+    {
+    }
+
+    HRESULT __stdcall EventNotify(DWORD event, DWORD_PTR param1, DWORD param2)
+    {
+        QMediaPlayer::State newState = d->state;
+        QMediaPlayer::MediaStatus newStatus = d->mediaStatus;
+
+        switch (event) {
+        // Media change events
+        case MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA: {
+            const bool hasAudio = d->engine->HasAudio();
+            if (d->hasAudio != hasAudio) {
+                d->hasAudio = hasAudio;
+                emit q->audioAvailableChanged(d->hasAudio);
+            }
+
+            const bool hasVideo = d->engine->HasVideo();
+            if (d->hasVideo != hasVideo) {
+                d->hasVideo = hasVideo;
+                emit q->audioAvailableChanged(d->hasAudio);
+            }
+
+            if (hasVideo) {
+                HRESULT hr;
+                DWORD width, height;
+                hr = d->engine->GetNativeVideoSize(&width, &height);
+                if (FAILED(hr))
+                    break;
+                d->videoRenderer->setSize(QSize(width, height));
+            }
+
+            newStatus = QMediaPlayer::LoadedMedia;
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_LOADSTART:
+        case MF_MEDIA_ENGINE_EVENT_PROGRESS: {
+            newStatus = QMediaPlayer::LoadingMedia;
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_CANPLAY:
+            d->bufferStatus = 100; // Fired when buffering is not used
+            newStatus = d->state == QMediaPlayer::StoppedState ? QMediaPlayer::LoadedMedia
+                                                               : QMediaPlayer::BufferedMedia;
+            break;
+        case MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED:
+        case MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED: {
+            PROPVARIANT stat;
+            HRESULT hr = d->engine->GetStatistics(MF_MEDIA_ENGINE_STATISTIC_BUFFER_PROGRESS, &stat);
+            if (SUCCEEDED(hr)) {
+                d->bufferStatus = stat.lVal;
+                PropVariantClear(&stat);
+            }
+            newStatus = d->state == QMediaPlayer::StoppedState ? QMediaPlayer::LoadedMedia
+                    : (d->bufferStatus == 100 ? QMediaPlayer::BufferedMedia : QMediaPlayer::BufferingMedia);
+            break;
+        }
+        //case MF_MEDIA_ENGINE_EVENT_SUSPEND: ???
+        //case MF_MEDIA_ENGINE_EVENT_ABORT: ???
+        case MF_MEDIA_ENGINE_EVENT_EMPTIED: {
+            newState = QMediaPlayer::StoppedState;
+            break;
+        }
+        // Transport controls
+        case MF_MEDIA_ENGINE_EVENT_PLAY: {
+            // If the media is already loaded, the playing event may not occur after stop
+            if (d->mediaStatus != QMediaPlayer::LoadedMedia)
+                break;
+            // fall through
+        }
+        case MF_MEDIA_ENGINE_EVENT_PLAYING: {
+            newState = QMediaPlayer::PlayingState;
+            newStatus = d->bufferStatus < 100 ? QMediaPlayer::BufferingMedia
+                                              : QMediaPlayer::BufferedMedia;
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_PAUSE: {
+            newState = QMediaPlayer::PausedState;
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_STALLED: {
+            newStatus = QMediaPlayer::StalledMedia;
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_WAITING: {
+            newStatus = QMediaPlayer::StalledMedia;
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_ENDED: {
+            newState = QMediaPlayer::StoppedState;
+            newStatus = QMediaPlayer::EndOfMedia;
+            break;
+        }
+        // Media attributes
+        case MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE: {
+            double duration = d->engine->GetDuration() * 1000;
+            if (!qFuzzyCompare(d->duration, duration)) {
+                d->duration = duration;
+                emit q->durationChanged(d->duration);
+            }
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_TIMEUPDATE: {
+            double position = d->engine->GetCurrentTime() * 1000;
+            if (!qFuzzyCompare(d->position, position)) {
+                d->position = position;
+                emit q->positionChanged(d->position);
+            }
+            // Stopped state: paused at beginning
+            if (qFuzzyIsNull(position) && d->state == QMediaPlayer::PausedState)
+                newState = QMediaPlayer::StoppedState;
+            break;
+        }
+        case MF_MEDIA_ENGINE_EVENT_RATECHANGE: {
+            double playbackRate = d->engine->GetPlaybackRate();
+            if (!qFuzzyCompare(d->playbackRate, playbackRate)) {
+                d->playbackRate = playbackRate;
+                emit q->playbackRateChanged(d->playbackRate);
+            }
+            break;
+        }
+        // Error handling
+        case MF_MEDIA_ENGINE_EVENT_ERROR: {
+            newState = QMediaPlayer::StoppedState;
+            newStatus = QMediaPlayer::InvalidMedia;
+            switch (param1) {
+            default:
+            case MF_MEDIA_ENGINE_ERR_NOERROR:
+                newStatus = QMediaPlayer::UnknownMediaStatus;
+                emit q->error(QMediaPlayer::ResourceError, qt_error_string(param2));
+                break;
+            case MF_MEDIA_ENGINE_ERR_ABORTED:
+                if (d->mediaStatus == QMediaPlayer::StalledMedia || d->mediaStatus == QMediaPlayer::BufferingMedia)
+                    d->mediaStatus = QMediaPlayer::LoadedMedia;
+                emit q->error(QMediaPlayer::ResourceError, QStringLiteral("The process of fetching the media resource was stopped at the user's request."));
+                break;
+            case MF_MEDIA_ENGINE_ERR_NETWORK:
+                if (d->mediaStatus == QMediaPlayer::StalledMedia || d->mediaStatus == QMediaPlayer::BufferingMedia)
+                    d->mediaStatus = QMediaPlayer::LoadedMedia;
+                emit q->error(QMediaPlayer::NetworkError, QStringLiteral("A network error occurred while fetching the media resource."));
+                break;
+            case MF_MEDIA_ENGINE_ERR_DECODE:
+                emit q->error(QMediaPlayer::FormatError, QStringLiteral("An error occurred while decoding the media resource."));
+                break;
+            case MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED:
+                emit q->error(QMediaPlayer::FormatError, QStringLiteral("The media resource is not supported."));
+                break;
+            case MF_MEDIA_ENGINE_ERR_ENCRYPTED:
+                emit q->error(QMediaPlayer::FormatError, QStringLiteral("An error occurred while encrypting the media resource."));
+                break;
+            }
+            break;
+        }
+        default:
+            break;
+        }
+
+        if (d->state != newState) {
+            d->state = newState;
+            emit q->stateChanged(d->state);
+        }
+
+        if (d->videoRenderer)
+            d->videoRenderer->setActive(d->state == QMediaPlayer::PlayingState);
+
+        if (d->mediaStatus != newStatus) {
+            d->mediaStatus = newStatus;
+            emit q->mediaStatusChanged(d->mediaStatus);
+        }
+
+        return S_OK;
+    }
+
+private:
+    QWinRTMediaPlayerControl *q;
+    QWinRTMediaPlayerControlPrivate *d;
+};
+
+class MediaEngineSources : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IMFMediaEngineSrcElements>
+{
+public:
+    MediaEngineSources(QWinRTMediaPlayerControlPrivate *d_ptr)
+        : d(d_ptr)
+    {
+    }
+
+    DWORD __stdcall GetLength()
+    {
+        return d->media.resources().length();
+    }
+
+    HRESULT __stdcall GetURL(DWORD index, BSTR *url)
+    {
+        const QString resourceUrl = d->media.resources().value(index).url().toString();
+        *url = SysAllocString((const OLECHAR *)resourceUrl.utf16());
+        return S_OK;
+    }
+
+    HRESULT __stdcall GetType(DWORD index, BSTR *type)
+    {
+        const QString resourceType = d->media.resources().value(index).mimeType();
+        *type = SysAllocString((const OLECHAR *)resourceType.utf16());
+        return S_OK;
+    }
+
+    HRESULT __stdcall GetMedia(DWORD index, BSTR *media)
+    {
+        Q_UNUSED(index);
+        *media = NULL;
+        return S_OK;
+    }
+
+    HRESULT __stdcall AddElement(BSTR url, BSTR type, BSTR media)
+    {
+        Q_UNUSED(url);
+        Q_UNUSED(type);
+        Q_UNUSED(media);
+        return E_NOTIMPL;
+    }
+
+    HRESULT __stdcall RemoveAllElements()
+    {
+        return E_NOTIMPL;
+    }
+
+private:
+    QWinRTMediaPlayerControlPrivate *d;
+};
+
+class MediaEngineReadResult : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IUnknown>
+{
+public:
+    MediaEngineReadResult(BYTE *bytes, ULONG maxLength)
+        : bytes(bytes), maxLength(maxLength) { }
+
+    void read(QIODevice *device)
+    {
+        bytesRead = device->read(reinterpret_cast<char *>(bytes), maxLength);
+    }
+
+    BYTE *bytes;
+    ULONG maxLength;
+    ULONG bytesRead;
+};
+
+class MediaEngineByteStream : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IMFByteStream>
+{
+public:
+    MediaEngineByteStream(QWinRTMediaPlayerControl *q_ptr, QWinRTMediaPlayerControlPrivate *d_ptr)
+        : q(q_ptr), d(d_ptr)
+    {
+    }
+
+    HRESULT __stdcall GetCapabilities(DWORD *capabilities)
+    {
+        *capabilities |= MFBYTESTREAM_IS_READABLE;
+        if (!d->stream->isSequential())
+            *capabilities |= MFBYTESTREAM_IS_SEEKABLE;
+        return S_OK;
+    }
+
+    HRESULT __stdcall GetLength(QWORD *length)
+    {
+        *length = QWORD(d->stream->size());
+        return S_OK;
+    }
+
+    HRESULT __stdcall SetLength(QWORD length)
+    {
+        Q_UNUSED(length);
+        return E_NOTIMPL;
+    }
+
+    HRESULT __stdcall GetCurrentPosition(QWORD *position)
+    {
+        *position = QWORD(d->stream->pos());
+        return S_OK;
+    }
+
+    HRESULT __stdcall SetCurrentPosition(QWORD position)
+    {
+        qint64 pos(position);
+        if (pos >= d->stream->size())
+            return E_INVALIDARG;
+
+        const bool ok = d->stream->seek(pos);
+        return ok ? S_OK : S_FALSE;
+    }
+
+    HRESULT __stdcall IsEndOfStream(BOOL *endOfStream)
+    {
+        *endOfStream = d->stream->atEnd() ? TRUE : FALSE;
+        return S_OK;
+    }
+
+    HRESULT __stdcall Read(BYTE *bytes, ULONG maxlen, ULONG *bytesRead)
+    {
+        *bytesRead = d->stream->read(reinterpret_cast<char *>(bytes), maxlen);
+        return S_OK;
+    }
+
+    HRESULT __stdcall BeginRead(BYTE *bytes, ULONG maxLength, IMFAsyncCallback *callback, IUnknown *state)
+    {
+        ComPtr<MediaEngineReadResult> readResult = Make<MediaEngineReadResult>(bytes, maxLength);
+        HRESULT hr;
+        hr = MFCreateAsyncResult(readResult.Get(), callback, state, &asyncResult);
+        RETURN_HR_IF_FAILED("Failed to create read callback result");
+        QMetaObject::invokeMethod(q, "finishRead", Qt::QueuedConnection);
+        return S_OK;
+    }
+
+    HRESULT __stdcall EndRead(IMFAsyncResult *result, ULONG *bytesRead)
+    {
+        HRESULT hr;
+        ComPtr<MediaEngineReadResult> readResult;
+        hr = result->GetObject(&readResult);
+        RETURN_HR_IF_FAILED("Failed to get read result");
+
+        *bytesRead = readResult->bytesRead;
+        return S_OK;
+    }
+
+    HRESULT __stdcall Write(const BYTE *bytes, ULONG maxlen, ULONG *bytesWritten)
+    {
+        Q_UNUSED(bytes);
+        Q_UNUSED(maxlen);
+        Q_UNUSED(bytesWritten);
+        return E_NOTIMPL;
+    }
+
+    HRESULT __stdcall BeginWrite(const BYTE *bytes, ULONG maxlen, IMFAsyncCallback *callback, IUnknown *state)
+    {
+        Q_UNUSED(bytes);
+        Q_UNUSED(maxlen);
+        Q_UNUSED(callback);
+        Q_UNUSED(state);
+        return E_NOTIMPL;
+    }
+
+    HRESULT __stdcall EndWrite(IMFAsyncResult *result, ULONG *bytesWritten)
+    {
+        Q_UNUSED(result);
+        Q_UNUSED(bytesWritten);
+        return E_NOTIMPL;
+    }
+
+    HRESULT __stdcall Seek(MFBYTESTREAM_SEEK_ORIGIN origin, LONGLONG offset, DWORD flags, QWORD *position)
+    {
+        Q_UNUSED(flags);
+
+        qint64 pos = offset;
+        if (origin == msoCurrent)
+            pos += d->stream->pos();
+
+        const bool ok = d->stream->seek(pos);
+        *position = QWORD(d->stream->pos());
+
+        return ok ? S_OK : E_FAIL;
+    }
+
+    HRESULT __stdcall Flush()
+    {
+        return E_NOTIMPL;
+    }
+
+    HRESULT __stdcall Close()
+    {
+        if (asyncResult)
+            finishRead();
+
+        if (d->stream->property(QT_WINRT_MEDIAPLAYER_STREAM_ID).toBool())
+            d->stream->close();
+
+        return S_OK;
+    }
+
+    void finishRead()
+    {
+        if (!asyncResult)
+            return;
+
+        HRESULT hr;
+        ComPtr<MediaEngineReadResult> readResult;
+        hr = asyncResult->GetObject(&readResult);
+        RETURN_VOID_IF_FAILED("Failed to get read result object");
+        readResult->read(d->stream.data());
+        hr = MFInvokeCallback(asyncResult.Get());
+        RETURN_VOID_IF_FAILED("Failed to invoke read callback");
+        asyncResult.Reset();
+    }
+
+private:
+    QWinRTMediaPlayerControl *q;
+    QWinRTMediaPlayerControlPrivate *d;
+
+    ComPtr<IMFAsyncResult> asyncResult;
+};
+
+void QWinRTMediaPlayerControlPrivate::cleanup(QWinRTMediaPlayerControlPrivate *d)
+{
+    QtConcurrent::run(&QWinRTMediaPlayerControlPrivate::shutdown, d);
+}
+
+void QWinRTMediaPlayerControlPrivate::shutdown(QWinRTMediaPlayerControlPrivate *d)
+{
+    d->engine->Shutdown();
+    delete d;
+}
+
+QWinRTMediaPlayerControl::QWinRTMediaPlayerControl(IMFMediaEngineClassFactory *factory, QObject *parent)
+    : QMediaPlayerControl(parent), d_ptr(new QWinRTMediaPlayerControlPrivate)
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    d->state = QMediaPlayer::StoppedState;
+    d->mediaStatus = QMediaPlayer::NoMedia;
+    d->duration = 0;
+    d->position = 0;
+    d->playbackRate = 1.0;
+    d->volume = 100;
+    d->bufferStatus = 0;
+    d->muted = false;
+    d->seekable = false;
+    d->hasAudio = false;
+    d->hasVideo = false;
+    d->videoRenderer = Q_NULLPTR;
+    d->notifier = Make<MediaEngineNotify>(this, d);
+
+    HRESULT hr;
+    hr = MFCreateDXGIDeviceManager(&d->resetToken, &d->manager);
+    RETURN_VOID_IF_FAILED("Failed to create DXGI device manager");
+
+    hr = MFCreateAttributes(&d->configuration, 1);
+    Q_ASSERT_SUCCEEDED(hr);
+    hr = d->configuration->SetUnknown(MF_MEDIA_ENGINE_CALLBACK, d->notifier.Get());
+    Q_ASSERT_SUCCEEDED(hr);
+    hr = d->configuration->SetUnknown(MF_MEDIA_ENGINE_DXGI_MANAGER, d->manager.Get());
+    Q_ASSERT_SUCCEEDED(hr);
+    hr = d->configuration->SetUINT32(MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM);
+    Q_ASSERT_SUCCEEDED(hr);
+
+    ComPtr<IMFMediaEngine> engine;
+    hr = factory->CreateInstance(0, d->configuration.Get(), &engine);
+    Q_ASSERT_SUCCEEDED(hr);
+    hr = engine.As(&d->engine);
+    Q_ASSERT_SUCCEEDED(hr);
+
+    hr = d->engine->SetVolume(1.0);
+    Q_ASSERT_SUCCEEDED(hr);
+
+    d->sources = Make<MediaEngineSources>(d);
+    hr = d->engine->SetSourceElements(d->sources.Get());
+    Q_ASSERT_SUCCEEDED(hr);
+
+    d->streamProvider = Make<MediaEngineByteStream>(this, d);
+}
+
+QWinRTMediaPlayerControl::~QWinRTMediaPlayerControl()
+{
+}
+
+QMediaPlayer::State QWinRTMediaPlayerControl::state() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->state;
+}
+
+QMediaPlayer::MediaStatus QWinRTMediaPlayerControl::mediaStatus() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->mediaStatus;
+}
+
+qint64 QWinRTMediaPlayerControl::duration() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->duration;
+}
+
+qint64 QWinRTMediaPlayerControl::position() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->position;
+}
+
+void QWinRTMediaPlayerControl::setPosition(qint64 position)
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (d->position == position)
+        return;
+
+    HRESULT hr;
+    hr = d->engine->SetCurrentTime(double(position)/1000);
+    RETURN_VOID_IF_FAILED("Failed to seek to new position");
+
+    d->position = position;
+    emit positionChanged(d->position);
+
+    if (d->mediaStatus == QMediaPlayer::EndOfMedia) {
+        d->mediaStatus = QMediaPlayer::LoadedMedia;
+        emit mediaStatusChanged(d->mediaStatus);
+    }
+}
+
+int QWinRTMediaPlayerControl::volume() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->volume;
+}
+
+void QWinRTMediaPlayerControl::setVolume(int volume)
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (d->volume == volume)
+        return;
+
+    HRESULT hr;
+    hr = d->engine->SetVolume(double(volume)/100);
+    RETURN_VOID_IF_FAILED("Failed to set volume");
+
+    d->volume = volume;
+    emit volumeChanged(d->volume);
+}
+
+bool QWinRTMediaPlayerControl::isMuted() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->muted;
+}
+
+void QWinRTMediaPlayerControl::setMuted(bool muted)
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (d->muted == muted)
+        return;
+
+    HRESULT hr;
+    hr = d->engine->SetMuted(muted);
+    RETURN_VOID_IF_FAILED("Failed to mute volume");
+
+    d->muted = muted;
+    emit mutedChanged(d->muted);
+}
+
+int QWinRTMediaPlayerControl::bufferStatus() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->bufferStatus;
+}
+
+bool QWinRTMediaPlayerControl::isAudioAvailable() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->hasAudio;
+}
+
+bool QWinRTMediaPlayerControl::isVideoAvailable() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->hasVideo;
+}
+
+bool QWinRTMediaPlayerControl::isSeekable() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->seekable;
+}
+
+QMediaTimeRange QWinRTMediaPlayerControl::availablePlaybackRanges() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return QMediaTimeRange(0, d->duration);
+}
+
+qreal QWinRTMediaPlayerControl::playbackRate() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->playbackRate;
+}
+
+void QWinRTMediaPlayerControl::setPlaybackRate(qreal rate)
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (qFuzzyCompare(d->playbackRate, rate))
+        return;
+
+    HRESULT hr;
+    hr = d->engine->SetPlaybackRate(rate);
+    RETURN_VOID_IF_FAILED("Failed to set playback rate");
+}
+
+QMediaContent QWinRTMediaPlayerControl::media() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->media;
+}
+
+const QIODevice *QWinRTMediaPlayerControl::mediaStream() const
+{
+    Q_D(const QWinRTMediaPlayerControl);
+    return d->stream.data();
+}
+
+void QWinRTMediaPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream)
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (d->media == media)
+        return;
+
+    d->media = media;
+    d->stream.reset(stream);
+    if (d->hasAudio != false) {
+        d->hasAudio = false;
+        emit audioAvailableChanged(d->hasAudio);
+    }
+    if (d->hasVideo != false) {
+        d->hasVideo = false;
+        emit videoAvailableChanged(d->hasVideo);
+    }
+    if (d->seekable != false) {
+        d->seekable = false;
+        emit seekableChanged(d->seekable);
+    }
+    if (d->bufferStatus != 0) {
+        d->bufferStatus = 0;
+        emit bufferStatusChanged(d->bufferStatus);
+    }
+    if (d->position != 0) {
+        d->position = 0;
+        emit positionChanged(d->position);
+    }
+    if (d->duration != 0) {
+        d->duration = 0;
+        emit durationChanged(d->duration);
+    }
+    QMediaPlayer::MediaStatus mediaStatus = media.isNull() ? QMediaPlayer::NoMedia
+                                                           : QMediaPlayer::LoadingMedia;
+    if (d->mediaStatus != mediaStatus) {
+        d->mediaStatus = mediaStatus;
+        emit mediaStatusChanged(d->mediaStatus);
+    }
+    emit mediaChanged(media);
+
+    QString urlString;
+    if (!d->stream) {
+        // If we can read the file via Qt, use the byte stream approach
+        foreach (const QMediaResource &resource, media.resources()) {
+            const QUrl url = resource.url();
+            if (url.isLocalFile()) {
+                urlString = url.toLocalFile();
+                QScopedPointer<QFile> file(new QFile(urlString));
+                if (file->open(QFile::ReadOnly)) {
+                    file->setProperty(QT_WINRT_MEDIAPLAYER_STREAM_ID, true);
+                    d->stream.reset(file.take());
+                    break;
+                }
+            }
+        }
+    }
+
+    HRESULT hr;
+    if (d->stream) {
+        hr = d->engine->SetSourceFromByteStream(d->streamProvider.Get(),
+                                                reinterpret_cast<BSTR>(urlString.data()));
+        if (FAILED(hr))
+            emit error(QMediaPlayer::ResourceError, qt_error_string(hr));
+        return;
+    }
+
+    // Let Windows handle all other URLs
+    hr = d->engine->SetSource(Q_NULLPTR); // Resets the byte stream
+    Q_ASSERT_SUCCEEDED(hr);
+    hr = d->engine->Load();
+    if (FAILED(hr))
+        emit error(QMediaPlayer::ResourceError, qt_error_string(hr));
+
+    if (d->media.isNull() && d->stream.isNull())
+        return;
+
+    // Resume play/pause/stop
+    switch (d->state) {
+    case QMediaPlayer::StoppedState:
+        stop();
+        break;
+    case QMediaPlayer::PlayingState:
+        play();
+        break;
+    case QMediaPlayer::PausedState:
+        pause();
+        break;
+    }
+}
+
+void QWinRTMediaPlayerControl::play()
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (d->state != QMediaPlayer::PlayingState) {
+        d->state = QMediaPlayer::PlayingState;
+        emit stateChanged(d->state);
+    }
+
+    if (d->media.isNull() && d->stream.isNull())
+        return;
+
+    if (d->videoRenderer)
+        d->videoRenderer->ensureReady();
+
+    HRESULT hr = d->engine->Play();
+    if (FAILED(hr)) {
+        emit error(QMediaPlayer::ResourceError, qt_error_string(hr));
+        return;
+    }
+}
+
+void QWinRTMediaPlayerControl::pause()
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (d->state != QMediaPlayer::PausedState) {
+        d->state = QMediaPlayer::PausedState;
+        emit stateChanged(d->state);
+    }
+
+    if (d->media.isNull() && d->stream.isNull())
+        return;
+
+    HRESULT hr;
+    hr = d->engine->Pause();
+    if (FAILED(hr)) {
+        emit error(QMediaPlayer::ResourceError, qt_error_string(hr));
+        return;
+    }
+}
+
+void QWinRTMediaPlayerControl::stop()
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (d->state != QMediaPlayer::StoppedState) {
+        d->state = QMediaPlayer::StoppedState;
+        emit stateChanged(d->state);
+    }
+
+    if (d->mediaStatus == QMediaPlayer::BufferedMedia
+            || d->mediaStatus == QMediaPlayer::BufferingMedia) {
+        d->mediaStatus = QMediaPlayer::LoadedMedia;
+        emit mediaStatusChanged(d->mediaStatus);
+    }
+
+    if (d->media.isNull() && d->stream.isNull())
+        return;
+
+    setPosition(0);
+
+    HRESULT hr;
+    hr = d->engine->Pause();
+    if (FAILED(hr)) {
+        emit error(QMediaPlayer::ResourceError, qt_error_string(hr));
+        return;
+    }
+}
+
+QVideoRendererControl *QWinRTMediaPlayerControl::videoRendererControl()
+{
+    Q_D(QWinRTMediaPlayerControl);
+
+    if (!d->videoRenderer) {
+        d->videoRenderer = new QWinRTPlayerRendererControl(d->engine.Get(), d->manager.Get(),
+                                                          d->resetToken, this);
+    }
+
+    return d->videoRenderer;
+}
+
+void QWinRTMediaPlayerControl::finishRead()
+{
+    Q_D(QWinRTMediaPlayerControl);
+    d->streamProvider->finishRead();
+}
diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.h b/src/plugins/winrt/qwinrtmediaplayercontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..b615b62d953cb57e993b3d4a2296805970cd1e27
--- /dev/null
+++ b/src/plugins/winrt/qwinrtmediaplayercontrol.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTMEDIAPLAYERCONTROL_H
+#define QWINRTMEDIAPLAYERCONTROL_H
+
+#include <QtMultimedia/QMediaPlayerControl>
+
+struct IMFMediaEngineClassFactory;
+
+QT_USE_NAMESPACE
+
+class QVideoRendererControl;
+
+class QWinRTMediaPlayerControlPrivate;
+class QWinRTMediaPlayerControl : public QMediaPlayerControl
+{
+    Q_OBJECT
+public:
+    QWinRTMediaPlayerControl(IMFMediaEngineClassFactory *factory, QObject *parent = 0);
+    ~QWinRTMediaPlayerControl();
+
+    QMediaPlayer::State state() const Q_DECL_OVERRIDE;
+    QMediaPlayer::MediaStatus mediaStatus() const Q_DECL_OVERRIDE;
+
+    qint64 duration() const Q_DECL_OVERRIDE;
+
+    qint64 position() const Q_DECL_OVERRIDE;
+    void setPosition(qint64 position) Q_DECL_OVERRIDE;
+
+    int volume() const Q_DECL_OVERRIDE;
+    void setVolume(int volume) Q_DECL_OVERRIDE;
+
+    bool isMuted() const Q_DECL_OVERRIDE;
+    void setMuted(bool muted) Q_DECL_OVERRIDE;
+
+    int bufferStatus() const Q_DECL_OVERRIDE;
+
+    bool isAudioAvailable() const Q_DECL_OVERRIDE;
+    bool isVideoAvailable() const Q_DECL_OVERRIDE;
+
+    bool isSeekable() const Q_DECL_OVERRIDE;
+
+    QMediaTimeRange availablePlaybackRanges() const Q_DECL_OVERRIDE;
+
+    qreal playbackRate() const Q_DECL_OVERRIDE;
+    void setPlaybackRate(qreal rate) Q_DECL_OVERRIDE;
+
+    QMediaContent media() const Q_DECL_OVERRIDE;
+    const QIODevice *mediaStream() const Q_DECL_OVERRIDE;
+    void setMedia(const QMediaContent &media, QIODevice *stream) Q_DECL_OVERRIDE;
+
+    void play() Q_DECL_OVERRIDE;
+    void pause() Q_DECL_OVERRIDE;
+    void stop() Q_DECL_OVERRIDE;
+
+    QVideoRendererControl *videoRendererControl();
+
+private:
+    Q_INVOKABLE void finishRead();
+
+    QScopedPointer<QWinRTMediaPlayerControlPrivate, QWinRTMediaPlayerControlPrivate> d_ptr;
+    Q_DECLARE_PRIVATE(QWinRTMediaPlayerControl)
+};
+
+#endif // QWINRTMEDIAPLAYERCONTROL_H
diff --git a/src/plugins/winrt/qwinrtmediaplayerservice.cpp b/src/plugins/winrt/qwinrtmediaplayerservice.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cc147388711aa70664d614d22ece98f9528208fb
--- /dev/null
+++ b/src/plugins/winrt/qwinrtmediaplayerservice.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtmediaplayerservice.h"
+#include "qwinrtmediaplayercontrol.h"
+
+#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/QPointer>
+#include <QtMultimedia/QVideoRendererControl>
+
+#include <mfapi.h>
+#include <mfmediaengine.h>
+#include <wrl.h>
+
+using namespace Microsoft::WRL;
+
+QT_USE_NAMESPACE
+
+class QWinRTMediaPlayerServicePrivate
+{
+public:
+    QPointer<QWinRTMediaPlayerControl> player;
+
+    ComPtr<IMFMediaEngineClassFactory> factory;
+};
+
+QWinRTMediaPlayerService::QWinRTMediaPlayerService(QObject *parent)
+    : QMediaService(parent), d_ptr(new QWinRTMediaPlayerServicePrivate)
+{
+    Q_D(QWinRTMediaPlayerService);
+
+    d->player = Q_NULLPTR;
+
+    HRESULT hr = MFStartup(MF_VERSION);
+    Q_ASSERT(SUCCEEDED(hr));
+
+    MULTI_QI results = { &IID_IUnknown, NULL, 0 };
+    hr = CoCreateInstanceFromApp(CLSID_MFMediaEngineClassFactory, NULL,
+                                 CLSCTX_INPROC_SERVER, NULL, 1, &results);
+    Q_ASSERT(SUCCEEDED(hr));
+
+    hr = results.pItf->QueryInterface(d->factory.GetAddressOf());
+    Q_ASSERT(SUCCEEDED(hr));
+}
+
+QWinRTMediaPlayerService::~QWinRTMediaPlayerService()
+{
+    MFShutdown();
+}
+
+QMediaControl *QWinRTMediaPlayerService::requestControl(const char *name)
+{
+    Q_D(QWinRTMediaPlayerService);
+    if (qstrcmp(name, QMediaPlayerControl_iid) == 0) {
+        if (!d->player)
+            d->player = new QWinRTMediaPlayerControl(d->factory.Get(), this);
+        return d->player;
+    }
+    if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
+        if (!d->player)
+            return Q_NULLPTR;
+        return d->player->videoRendererControl();
+    }
+
+    return Q_NULLPTR;
+}
+
+void QWinRTMediaPlayerService::releaseControl(QMediaControl *control)
+{
+    Q_D(QWinRTMediaPlayerService);
+    if (control == d->player)
+        d->player->deleteLater();
+}
diff --git a/src/plugins/winrt/qwinrtmediaplayerservice.h b/src/plugins/winrt/qwinrtmediaplayerservice.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a249836581194035a8ba66b103f09c1c1a1f921
--- /dev/null
+++ b/src/plugins/winrt/qwinrtmediaplayerservice.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTMEDIAPLAYERSERVICE_H
+#define QWINRTMEDIAPLAYERSERVICE_H
+
+#include <QtMultimedia/QMediaService>
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTMediaPlayerServicePrivate;
+class QWinRTMediaPlayerService : public QMediaService
+{
+    Q_OBJECT
+public:
+    QWinRTMediaPlayerService(QObject *parent);
+    ~QWinRTMediaPlayerService();
+
+    QMediaControl *requestControl(const char *name);
+    void releaseControl(QMediaControl *control);
+
+private:
+    QScopedPointer<QWinRTMediaPlayerServicePrivate> d_ptr;
+    Q_DECLARE_PRIVATE(QWinRTMediaPlayerService)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTMEDIAPLAYERSERVICE_H
diff --git a/src/plugins/winrt/qwinrtplayerrenderercontrol.cpp b/src/plugins/winrt/qwinrtplayerrenderercontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..273a650df1edc94dedcf98b7b9d7f6f5e34f7bd2
--- /dev/null
+++ b/src/plugins/winrt/qwinrtplayerrenderercontrol.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtplayerrenderercontrol.h"
+
+#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/QGlobalStatic>
+#include <QtMultimedia/QAbstractVideoSurface>
+#include <QtMultimedia/QVideoSurfaceFormat>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QOpenGLTexture>
+#include <QtGui/QOpenGLContext>
+
+#define EGL_EGLEXT_PROTOTYPES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <d3d11.h>
+#include <mfapi.h>
+#include <mfmediaengine.h>
+#include <wrl.h>
+using namespace Microsoft::WRL;
+
+QT_USE_NAMESPACE
+
+template <typename T>
+class D3DDeviceLocker
+{
+public:
+    D3DDeviceLocker(IMFDXGIDeviceManager *manager, HANDLE deviceHandle, T **device)
+        : m_manager(manager), m_deviceHandle(deviceHandle)
+    {
+        HRESULT hr = m_manager->LockDevice(m_deviceHandle, IID_PPV_ARGS(device), TRUE);
+        if (FAILED(hr))
+            qErrnoWarning(hr, "Failed to lock the D3D device");
+    }
+
+    ~D3DDeviceLocker()
+    {
+        HRESULT hr = m_manager->UnlockDevice(m_deviceHandle, FALSE);
+        if (FAILED(hr))
+            qErrnoWarning(hr, "Failed to unlock the D3D device");
+    }
+
+private:
+    IMFDXGIDeviceManager *m_manager;
+    HANDLE m_deviceHandle;
+};
+
+class QWinRTPlayerRendererControlPrivate
+{
+public:
+    ComPtr<IMFMediaEngineEx> engine;
+    ComPtr<IMFDXGIDeviceManager> manager;
+    quint32 resetToken;
+    HANDLE deviceHandle;
+};
+
+QWinRTPlayerRendererControl::QWinRTPlayerRendererControl(IMFMediaEngineEx *engine, IMFDXGIDeviceManager *manager, quint32 resetToken, QObject *parent)
+    : QWinRTAbstractVideoRendererControl(QSize(), parent), d_ptr(new QWinRTPlayerRendererControlPrivate)
+{
+    Q_D(QWinRTPlayerRendererControl);
+
+    d->engine = engine;
+    d->manager = manager;
+    d->resetToken = resetToken;
+    d->deviceHandle = 0;
+}
+
+QWinRTPlayerRendererControl::~QWinRTPlayerRendererControl()
+{
+    shutdown();
+}
+
+bool QWinRTPlayerRendererControl::ensureReady()
+{
+    Q_D(QWinRTPlayerRendererControl);
+
+    HRESULT hr;
+    hr = d->manager->TestDevice(d->deviceHandle);
+    if (hr == MF_E_DXGI_NEW_VIDEO_DEVICE || FAILED(hr)) {
+        d->manager->CloseDeviceHandle(d->deviceHandle);
+
+        hr = d->manager->ResetDevice(d3dDevice(), d->resetToken);
+        RETURN_FALSE_IF_FAILED("Failed to reset the DXGI manager device");
+
+        hr = d->manager->OpenDeviceHandle(&d->deviceHandle);
+        RETURN_FALSE_IF_FAILED("Failed to open device handle");
+    }
+
+    return SUCCEEDED(hr);
+}
+
+bool QWinRTPlayerRendererControl::render(ID3D11Texture2D *texture)
+{
+    Q_D(QWinRTPlayerRendererControl);
+
+    if (!ensureReady())
+        return false;
+
+    HRESULT hr;
+    LONGLONG ts;
+    hr = d->engine->OnVideoStreamTick(&ts);
+    RETURN_FALSE_IF_FAILED("Failed to obtain video stream tick");
+    if (hr == S_FALSE) // Frame not available, nothing to do
+        return false;
+
+    ComPtr<ID3D11Device> device;
+    D3DDeviceLocker<ID3D11Device> locker(d->manager.Get(), d->deviceHandle, device.GetAddressOf());
+
+    MFVideoNormalizedRect sourceRect = { 0, 0, 1, 1 };
+    const QSize frameSize = size();
+    RECT destRect = { 0, 0, frameSize.width(), frameSize.height() };
+    MFARGB borderColor = { 255, 255, 255, 255 };
+    hr = d->engine->TransferVideoFrame(texture, &sourceRect, &destRect, &borderColor);
+    RETURN_FALSE_IF_FAILED("Failed to transfer video frame to DXGI surface");
+    return true;
+}
diff --git a/src/plugins/winrt/qwinrtplayerrenderercontrol.h b/src/plugins/winrt/qwinrtplayerrenderercontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d973cbfc61cce4d6d55d8846fa13e6e2a62fd84
--- /dev/null
+++ b/src/plugins/winrt/qwinrtplayerrenderercontrol.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTPLAYERRENDERERCONTROL_H
+#define QWINRTPLAYERRENDERERCONTROL_H
+
+#include "qwinrtabstractvideorenderercontrol.h"
+#include <QtMultimedia/QMediaPlayer>
+
+struct IMFMediaEngineEx;
+struct IMFDXGIDeviceManager;
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTPlayerRendererControlPrivate;
+class QWinRTPlayerRendererControl : public QWinRTAbstractVideoRendererControl
+{
+    Q_OBJECT
+public:
+    explicit QWinRTPlayerRendererControl(IMFMediaEngineEx *engine, IMFDXGIDeviceManager *manager, quint32 resetToken, QObject *parent);
+    ~QWinRTPlayerRendererControl();
+
+    bool ensureReady();
+
+    bool render(ID3D11Texture2D *texture) Q_DECL_OVERRIDE;
+
+private:
+    QScopedPointer<QWinRTPlayerRendererControlPrivate> d_ptr;
+    Q_DECLARE_PRIVATE(QWinRTPlayerRendererControl)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTPLAYERRENDERERCONTROL_H
diff --git a/src/plugins/winrt/qwinrtserviceplugin.cpp b/src/plugins/winrt/qwinrtserviceplugin.cpp
index 143b935473a4d174bdf97813657878b2f6fffb91..5d49b44a4543d6873ea2f50cb1fb3643777060eb 100644
--- a/src/plugins/winrt/qwinrtserviceplugin.cpp
+++ b/src/plugins/winrt/qwinrtserviceplugin.cpp
@@ -43,9 +43,15 @@
 #include <QtCore/QFile>
 
 #include "qwinrtserviceplugin.h"
+#include "qwinrtmediaplayerservice.h"
+
+QT_USE_NAMESPACE
 
 QMediaService *QWinRTServicePlugin::create(QString const &key)
 {
+    if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
+        return new QWinRTMediaPlayerService(this);
+
     return Q_NULLPTR;
 }
 
@@ -57,5 +63,8 @@ void QWinRTServicePlugin::release(QMediaService *service)
 QMediaServiceProviderHint::Features QWinRTServicePlugin::supportedFeatures(
         const QByteArray &service) const
 {
+    if (service == Q_MEDIASERVICE_MEDIAPLAYER)
+       return QMediaServiceProviderHint::StreamPlayback | QMediaServiceProviderHint::VideoSurface;
+
     return QMediaServiceProviderHint::Features();
 }
diff --git a/src/plugins/winrt/winrt.json b/src/plugins/winrt/winrt.json
index f4a1ceb478db9a9f77a430ffe150bff563a2098d..b85cfeb1223015895a6f45f03efbde518a91c411 100644
--- a/src/plugins/winrt/winrt.json
+++ b/src/plugins/winrt/winrt.json
@@ -1,4 +1,4 @@
 {
     "Keys": ["winrt"],
-    "Services": []
+    "Services": ["org.qt-project.qt.mediaplayer"]
 }
diff --git a/src/plugins/winrt/winrt.pro b/src/plugins/winrt/winrt.pro
index 82f97e48984c4db866a428399495c401b2062734..0ea90d22ec0f9853b3752f59d0e34a809e92ff94 100644
--- a/src/plugins/winrt/winrt.pro
+++ b/src/plugins/winrt/winrt.pro
@@ -8,9 +8,17 @@ load(qt_plugin)
 LIBS += -lmfplat -lmfuuid -loleaut32 -ld3d11
 
 HEADERS += \
+    qwinrtabstractvideorenderercontrol.h \
+    qwinrtmediaplayercontrol.h \
+    qwinrtmediaplayerservice.h \
+    qwinrtplayerrenderercontrol.h \
     qwinrtserviceplugin.h
 
 SOURCES += \
+    qwinrtabstractvideorenderercontrol.cpp \
+    qwinrtmediaplayercontrol.cpp \
+    qwinrtmediaplayerservice.cpp \
+    qwinrtplayerrenderercontrol.cpp \
     qwinrtserviceplugin.cpp
 
 OTHER_FILES += \
diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
index 7e9327a103f07d83cd759490a345463201be7805..5109d305b5c5d5a979be683cd4bba8ddf6f32b75 100644
--- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
+++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
@@ -764,6 +764,10 @@ void tst_QMediaPlayerBackend::playlist()
 
     player.play();
     QTRY_COMPARE_WITH_TIMEOUT(player.state(), QMediaPlayer::StoppedState, 10000);
+
+    if (player.mediaStatus() == QMediaPlayer::InvalidMedia)
+        QSKIP("Media player does not support M3U playlists");
+
     QCOMPARE(mediaSpy.count(), 2);
     // sample.m3u -> sample.m3u resolved -> test.wav ->
     // nested1.m3u -> nested1.m3u resolved -> test.wav ->