diff --git a/dist/changes-5.1.1 b/dist/changes-5.1.1
new file mode 100644
index 0000000000000000000000000000000000000000..45fc4ded5507b51e1f76d0e256a595bd98053da6
--- /dev/null
+++ b/dist/changes-5.1.1
@@ -0,0 +1,45 @@
+Qt 5.1.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.1.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+  http://qt-project.org/doc/qt-5.1/
+
+The Qt version 5.1 series is binary compatible with the 5.0.x series.
+Applications compiled for 5.0 will continue to run with 5.1.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+  http://bugreports.qt-project.org/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+*                      Platform Specific Changes                           *
+****************************************************************************
+
+Qt for Windows
+--------------
+
+ - Use correct default audio output and input devices on Windows.
+ - [QTBUG-29206] DirectShow: avoid unnecessary RGB32 -> BGR32 conversion.
+ - [QTBUG-32282] DirectShow: Don't create the widget and renderer controls
+    until requested.
+ - [QTBUG-23822] Fix resource leak in directshow plugin.
+ - WMF: fixed MediaPlayer buffering logic.
+
+Qt for Android
+--------------
+
+ - Fixed potential memory leak when destroying a media player.
+ - Fixed media player showing black frames on some hardware.
+ - [QTBUG-31422] Make it possible for the media player to play assets.
+ - Fixed Java exception being thrown at app startup when using multimedia.
+
+Qt for BlackBerry
+-----------------
+
+ - [QTBUG-31534] Fix frame size of video playback.
diff --git a/examples/multimedia/video/qmlvideofx/main.cpp b/examples/multimedia/video/qmlvideofx/main.cpp
index b0698e2368652d1639725a3eedd5f9b50dff87d9..7465deab857d938a83f61d40d3b10f445e523fe0 100644
--- a/examples/multimedia/video/qmlvideofx/main.cpp
+++ b/examples/multimedia/video/qmlvideofx/main.cpp
@@ -116,21 +116,13 @@ int main(int argc, char *argv[])
     FileReader fileReader;
     viewer.rootContext()->setContextProperty("fileReader", &fileReader);
 
-    QUrl appPath(QString("file://%1").arg(app.applicationDirPath()));
-    QUrl imagePath;
+    const QUrl appPath(QUrl::fromLocalFile(app.applicationDirPath()));
     const QStringList picturesLocation = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
-    if (picturesLocation.isEmpty())
-        imagePath = appPath.resolved(QUrl("images"));
-    else
-        imagePath = QString("file://%1").arg(picturesLocation.first());
+    const QUrl imagePath = picturesLocation.isEmpty() ? appPath : QUrl::fromLocalFile(picturesLocation.first());
     viewer.rootContext()->setContextProperty("imagePath", imagePath);
 
-    QUrl videoPath;
     const QStringList moviesLocation = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation);
-    if (moviesLocation.isEmpty())
-        videoPath = appPath.resolved(QUrl("./"));
-    else
-        videoPath = QString("file://%1").arg(moviesLocation.first());
+    const QUrl videoPath = moviesLocation.isEmpty() ? appPath : QUrl::fromLocalFile(moviesLocation.first());
     viewer.rootContext()->setContextProperty("videoPath", videoPath);
 
     viewer.setTitle("qmlvideofx");
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/FileBrowser.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/FileBrowser.qml
index 3d4343c2578c5e9286eb6d38ced61cedf6862b65..7c86103614adafb050f799ff91f1fe8c470d894c 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/FileBrowser.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/FileBrowser.qml
@@ -102,7 +102,10 @@ Rectangle {
                 Rectangle {
                     id: wrapper
                     function launch() {
-                        var path = "file://" + filePath
+                        var path = "file://";
+                        if (filePath.length > 2 && filePath[1] === ':') // Windows drive logic, see QUrl::fromLocalFile()
+                            path += '/';
+                        path += filePath;
                         if (folders.isFolder(index))
                             down(path);
                         else
@@ -307,7 +310,7 @@ Rectangle {
                     MouseArea { id: upRegion; anchors.centerIn: parent
                         width: 56
                         height: 56
-                        onClicked: if (folders.parentFolder != "") up()
+                        onClicked: up()
                     }
                     states: [
                         State {
@@ -353,6 +356,8 @@ Rectangle {
 
             function up() {
                 var path = folders.parentFolder;
+                if (path.toString().length === 0 || path.toString() === 'file:')
+                    return;
                 if (folders == folders1) {
                     view = view2
                     folders = folders2;
diff --git a/src/gsttools/qvideosurfacegstsink.cpp b/src/gsttools/qvideosurfacegstsink.cpp
index 94aa1262e83b8d7eb203894b5daf6ef50a3c03ff..f91c1192d4c3f2a6c4ad982c7c9a52611e6c70a7 100644
--- a/src/gsttools/qvideosurfacegstsink.cpp
+++ b/src/gsttools/qvideosurfacegstsink.cpp
@@ -713,13 +713,14 @@ QVideoSurfaceFormat QVideoSurfaceGstSink::formatForCaps(GstCaps *caps, int *byte
 
 void QVideoSurfaceGstSink::setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer)
 {
+    // GStreamer uses nanoseconds, Qt uses microseconds
     qint64 startTime = GST_BUFFER_TIMESTAMP(buffer);
     if (startTime >= 0) {
-        frame->setStartTime(startTime/G_GINT64_CONSTANT (1000000));
+        frame->setStartTime(startTime/G_GINT64_CONSTANT (1000));
 
         qint64 duration = GST_BUFFER_DURATION(buffer);
         if (duration >= 0)
-            frame->setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000000));
+            frame->setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000));
     }
 }
 
diff --git a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp b/src/multimedia/audio/qsoundeffect_qaudio_p.cpp
index 835f60b45fcbb4c56642ec7d8533d3b11e2c69c0..524c856a2fd78850b06eaa2b832a61e6ce798577 100644
--- a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp
+++ b/src/multimedia/audio/qsoundeffect_qaudio_p.cpp
@@ -369,7 +369,7 @@ void PrivateSoundSource::stateChanged(QAudio::State state)
 
 qint64 PrivateSoundSource::readData( char* data, qint64 len)
 {
-    if (m_runningCount > 0 && m_playing) {
+    if ((m_runningCount > 0  || m_runningCount == QSoundEffect::Infinite) && m_playing) {
 
         if (m_sample->state() != QSample::Ready)
             return 0;
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
index d1abf658e488bbb8f597ba6a1ba939055908e333..2ca07a63e9fc006b50a61f60f09c9e1392d32f87 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
@@ -191,8 +191,8 @@ public class QtAndroidMediaPlayer extends MediaPlayer
         @Override
         public void onPrepared(final MediaPlayer mp)
         {
-            onMediaPlayerInfoNative(MEDIA_PLAYER_DURATION, getDuration(), mID);
             onMediaPlayerInfoNative(MEDIA_PLAYER_READY, 0, mID);
+            onMediaPlayerInfoNative(MEDIA_PLAYER_DURATION, getDuration(), mID);
             mPreparing = false;
         }
 
diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp
index a70f4e1302ee65e6d628e90aee89d83e6d3f082d..4dc56ebd98fe07e1fe471e6ef520d320a6bebd4c 100644
--- a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp
+++ b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -98,8 +98,9 @@ QMediaPlayer::MediaStatus QAndroidMediaPlayerControl::mediaStatus() const
 qint64 QAndroidMediaPlayerControl::duration() const
 {
     return (mCurrentMediaStatus == QMediaPlayer::InvalidMedia
-            || mCurrentMediaStatus == QMediaPlayer::NoMedia) ? 0
-                                                             : mMediaPlayer->getDuration();
+            || mCurrentMediaStatus == QMediaPlayer::NoMedia
+            || !mMediaPlayerReady) ? 0
+                                   : mMediaPlayer->getDuration();
 }
 
 qint64 QAndroidMediaPlayerControl::position() const
@@ -330,14 +331,12 @@ void QAndroidMediaPlayerControl::onMediaPlayerInfo(qint32 what, qint32 extra)
         setState(QMediaPlayer::StoppedState);
         break;
     case JMediaPlayer::MEDIA_PLAYER_READY:
+        setMediaStatus(QMediaPlayer::LoadedMedia);
         if (mBuffering) {
             setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia
                                                  : QMediaPlayer::BufferingMedia);
         } else {
-            setMediaStatus(QMediaPlayer::LoadedMedia);
-            mBufferPercent = 100;
-            Q_EMIT bufferStatusChanged(mBufferPercent);
-            updateAvailablePlaybackRanges();
+            onBufferChanged(100);
         }
         setAudioAvailable(true);
         mMediaPlayerReady = true;
@@ -402,7 +401,7 @@ void QAndroidMediaPlayerControl::onError(qint32 what, qint32 extra)
 
 void QAndroidMediaPlayerControl::onBufferChanged(qint32 percent)
 {
-    mBuffering = true;
+    mBuffering = percent != 100;
     mBufferPercent = percent;
     Q_EMIT bufferStatusChanged(mBufferPercent);
 
diff --git a/src/plugins/android/wrappers/jsurfacetexture.cpp b/src/plugins/android/wrappers/jsurfacetexture.cpp
index 107f7be39f790b0b488f3cfaf0e4b91721b5ec32..34edf1b66cf4f91d4554147a1f41f66bbc4769c6 100644
--- a/src/plugins/android/wrappers/jsurfacetexture.cpp
+++ b/src/plugins/android/wrappers/jsurfacetexture.cpp
@@ -60,13 +60,13 @@ JSurfaceTexture::JSurfaceTexture(unsigned int texName)
     , QJNIObject(g_qtSurfaceTextureClass, "(I)V", jint(texName))
     , m_texID(int(texName))
 {
-    if (m_jobject)
+    if (isValid())
         g_objectMap.insert(int(texName), this);
 }
 
 JSurfaceTexture::~JSurfaceTexture()
 {
-    if (m_jobject)
+    if (isValid())
         g_objectMap.remove(m_texID);
 }
 
diff --git a/src/plugins/wmf/evrcustompresenter.cpp b/src/plugins/wmf/evrcustompresenter.cpp
index eb73e672058cf998e7340667f2118d60c644cdb8..70acbddbaf567a048ef2d33e1d0b01c4dc9d50d2 100644
--- a/src/plugins/wmf/evrcustompresenter.cpp
+++ b/src/plugins/wmf/evrcustompresenter.cpp
@@ -50,6 +50,7 @@
 #include <qabstractvideosurface.h>
 #include <qthread.h>
 #include <qcoreapplication.h>
+#include <qmath.h>
 #include <QtCore/qdebug.h>
 #include <d3d9.h>
 #include <dshow.h>
@@ -325,7 +326,7 @@ HRESULT Scheduler::processSample(IMFSample *sample, LONG *pNextSleep)
             // Adjust the sleep time for the clock rate. (The presentation clock runs
             // at m_fRate, but sleeping uses the system clock.)
             if (m_playbackRate != 0)
-                nextSleep = (LONG)(nextSleep / fabsf(m_playbackRate));
+                nextSleep = (LONG)(nextSleep / qFabs(m_playbackRate));
 
             // Don't present yet.
             presentNow = false;
@@ -987,7 +988,7 @@ HRESULT EVRCustomPresenter::IsRateSupported(BOOL thin, float rate, float *neares
     // Note: We have no minimum rate (that is, we support anything down to 0).
     maxRate = getMaxRate(thin);
 
-    if (fabsf(rate) > maxRate) {
+    if (qFabs(rate) > maxRate) {
         // The (absolute) requested rate exceeds the maximum rate.
         hr = MF_E_UNSUPPORTED_RATE;
 
diff --git a/src/plugins/wmf/evrd3dpresentengine.cpp b/src/plugins/wmf/evrd3dpresentengine.cpp
index c67b5d4480b7b96045da3674928070a30d0f910a..01a5c3341747f5b2defbd1180b3b100cef708edb 100644
--- a/src/plugins/wmf/evrd3dpresentengine.cpp
+++ b/src/plugins/wmf/evrd3dpresentengine.cpp
@@ -288,9 +288,21 @@ void D3DPresentEngine::presentSample(void *opaque, qint64)
     }
 
     if (surface && updateTexture(surface)) {
-        m_surface->present(QVideoFrame(new TextureVideoBuffer(m_glTexture),
-                                       m_surfaceFormat.frameSize(),
-                                       m_surfaceFormat.pixelFormat()));
+        QVideoFrame frame = QVideoFrame(new TextureVideoBuffer(m_glTexture),
+                                        m_surfaceFormat.frameSize(),
+                                        m_surfaceFormat.pixelFormat());
+
+        // WMF uses 100-nanosecond units, Qt uses microseconds
+        LONGLONG startTime = -1;
+        if (SUCCEEDED(sample->GetSampleTime(&startTime))) {
+            frame.setStartTime(startTime * 0.1);
+
+            LONGLONG duration = -1;
+            if (SUCCEEDED(sample->GetSampleDuration(&duration)))
+                frame.setEndTime((startTime + duration) * 0.1);
+        }
+
+        m_surface->present(frame);
     }
 
 done:
diff --git a/src/plugins/wmf/mftvideo.cpp b/src/plugins/wmf/mftvideo.cpp
index acec88d6be6fab0a8a5428f08646fbb0d8ef09e5..8e7ce069333549057c2135bfeba81031e325bc02 100644
--- a/src/plugins/wmf/mftvideo.cpp
+++ b/src/plugins/wmf/mftvideo.cpp
@@ -632,13 +632,14 @@ QVideoFrame MFTransform::makeVideoFrame()
         // That is why we copy data from IMFMediaBuffer here.
         frame = QVideoFrame(new QMemoryVideoBuffer(array, m_bytesPerLine), m_format.frameSize(), m_format.pixelFormat());
 
+        // WMF uses 100-nanosecond units, Qt uses microseconds
         LONGLONG startTime = -1;
         if (SUCCEEDED(m_sample->GetSampleTime(&startTime))) {
-            frame.setStartTime(startTime);
+            frame.setStartTime(startTime * 0.1);
 
             LONGLONG duration = -1;
             if (SUCCEEDED(m_sample->GetSampleDuration(&duration)))
-                frame.setEndTime(startTime + duration);
+                frame.setEndTime((startTime + duration) * 0.1);
         }
     } while (false);
 
diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp
index fb150c3e9e934a4d23306e75c5a7bc3cad84d4ab..4e4b56589a327742d3cfd18b7312c1c95fa9272b 100644
--- a/src/plugins/wmf/player/mfplayersession.cpp
+++ b/src/plugins/wmf/player/mfplayersession.cpp
@@ -1918,19 +1918,17 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
         changeStatus(QMediaPlayer::BufferedMedia);
         emit bufferStatusChanged(bufferStatus());
         break;
-    case MEEndOfPresentation:
-        stop();
-        changeStatus(QMediaPlayer::EndOfMedia);
-        m_varStart.vt = VT_I8;
-        //keep reporting the final position after end of media
-        m_varStart.hVal.QuadPart = m_duration;
-        break;
     case MESessionEnded:
         m_pendingState = NoPending;
         m_state.command = CmdStop;
         m_state.prevCmd = CmdNone;
         m_request.command = CmdNone;
         m_request.prevCmd = CmdNone;
+
+        changeStatus(QMediaPlayer::EndOfMedia);
+        m_varStart.vt = VT_I8;
+        //keep reporting the final position after end of media
+        m_varStart.hVal.QuadPart = m_duration;
         break;
     case MEEndOfPresentationSegment:
         break;
@@ -1993,6 +1991,8 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
             }
         }
         break;
+    default:
+        break;
     }
 
     sessionEvent->Release();
diff --git a/src/plugins/wmf/player/mfvideorenderercontrol.cpp b/src/plugins/wmf/player/mfvideorenderercontrol.cpp
index 8f73244c0afe0ec70ef47af920b2e85a60f4315f..83768c8e227fdbe1c21650a91415e675b49618cd 100644
--- a/src/plugins/wmf/player/mfvideorenderercontrol.cpp
+++ b/src/plugins/wmf/player/mfvideorenderercontrol.cpp
@@ -254,6 +254,8 @@ namespace
             , m_workQueueCB(this, &MediaStream::onDispatchWorkItem)
             , m_finalizeResult(0)
             , m_scheduledBuffer(0)
+            , m_bufferStartTime(-1)
+            , m_bufferDuration(-1)
             , m_presentationClock(0)
             , m_currentMediaType(0)
             , m_prerolling(false)
@@ -839,10 +841,13 @@ namespace
             QMutexLocker locker(&m_mutex);
             if (!m_scheduledBuffer)
                 return;
-            m_surface->present(QVideoFrame(
-                    new MediaSampleVideoBuffer(m_scheduledBuffer, m_bytesPerLine),
-                    m_surfaceFormat.frameSize(),
-                    m_surfaceFormat.pixelFormat()));
+            QVideoFrame frame = QVideoFrame(
+                        new MediaSampleVideoBuffer(m_scheduledBuffer, m_bytesPerLine),
+                        m_surfaceFormat.frameSize(),
+                        m_surfaceFormat.pixelFormat());
+            frame.setStartTime(m_bufferStartTime * 0.1);
+            frame.setEndTime((m_bufferStartTime + m_bufferDuration) * 0.1);
+            m_surface->present(frame);
             m_scheduledBuffer->Release();
             m_scheduledBuffer = NULL;
             if (m_rate != 0)
@@ -1309,8 +1314,10 @@ namespace
 
         HRESULT processSampleData(IMFSample *pSample)
         {
-            LONGLONG time;
+            LONGLONG time, duration = -1;
             HRESULT hr = pSample->GetSampleTime(&time);
+            if (SUCCEEDED(hr))
+               pSample->GetSampleDuration(&duration);
 
             if (m_prerolling) {
                 if (SUCCEEDED(hr) && time >= m_prerollTargetTime) {
@@ -1320,6 +1327,7 @@ namespace
                         SampleBuffer sb;
                         sb.m_buffer = pBuffer;
                         sb.m_time = time;
+                        sb.m_duration = duration;
                         m_bufferCache.push_back(sb);
                         endPreroll(S_OK);
                     }
@@ -1336,6 +1344,7 @@ namespace
                         SampleBuffer sb;
                         sb.m_buffer = pBuffer;
                         sb.m_time = time;
+                        sb.m_duration = duration;
                         m_bufferCache.push_back(sb);
                     }
                     if (m_rate == 0)
@@ -1351,6 +1360,7 @@ namespace
         public:
             IMFMediaBuffer *m_buffer;
             LONGLONG m_time;
+            LONGLONG m_duration;
         };
         QList<SampleBuffer> m_bufferCache;
         static const int BUFFER_CACHE_SIZE = 2;
@@ -1383,6 +1393,8 @@ namespace
                         continue;
                     }
                     m_scheduledBuffer = sb.m_buffer;
+                    m_bufferStartTime = sb.m_time;
+                    m_bufferDuration = sb.m_duration;
                     QCoreApplication::postEvent(m_rendererControl, new PresentEvent(sb.m_time));
                     if (m_rate == 0)
                         queueEvent(MEStreamSinkScrubSampleComplete, GUID_NULL, S_OK, NULL);
@@ -1393,6 +1405,8 @@ namespace
                 queueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
         }
         IMFMediaBuffer *m_scheduledBuffer;
+        MFTIME m_bufferStartTime;
+        MFTIME m_bufferDuration;
         IMFPresentationClock *m_presentationClock;
         float m_rate;
     };