summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-12-16 15:36:55 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-12-16 15:36:56 +0100
commit967e0eb22f8e85db185d093b95da57e3ec41e7cc (patch)
treefda0a86c20dfde5681a07df5a0b2a71f7438818c /src/plugins
parent75e5708832ce31a7edd4f4c1eb15f5b5f3d72c14 (diff)
parentecce937a054e4a96597cb13c40d216bddbd45891 (diff)
Merge remote-tracking branch 'origin/stable' into dev
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java72
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp53
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.h4
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp15
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h2
-rw-r--r--src/plugins/android/src/wrappers/jcamera.cpp47
-rw-r--r--src/plugins/android/src/wrappers/jcamera.h10
-rw-r--r--src/plugins/wmf/player/mfplayersession.cpp341
-rw-r--r--src/plugins/wmf/player/mfvideorenderercontrol.cpp3
-rw-r--r--src/plugins/wmf/sourceresolver.cpp4
10 files changed, 163 insertions, 388 deletions
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
index 3d891196f..4aa07b713 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
@@ -42,8 +42,11 @@
package org.qtproject.qt5.android.multimedia;
import android.hardware.Camera;
+import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.util.Log;
+import java.lang.Math;
+import java.util.concurrent.locks.ReentrantLock;
public class QtCamera implements Camera.ShutterCallback,
Camera.PictureCallback,
@@ -52,6 +55,11 @@ public class QtCamera implements Camera.ShutterCallback,
{
private int m_cameraId = -1;
private Camera m_camera = null;
+ private byte[] m_cameraPreviewFirstBuffer = null;
+ private byte[] m_cameraPreviewSecondBuffer = null;
+ private int m_actualPreviewBuffer = 0;
+ private final ReentrantLock m_buffersLock = new ReentrantLock();
+ private boolean m_isReleased = false;
private static final String TAG = "Qt Camera";
@@ -97,6 +105,7 @@ public class QtCamera implements Camera.ShutterCallback,
public void release()
{
+ m_isReleased = true;
m_camera.release();
}
@@ -134,6 +143,22 @@ public class QtCamera implements Camera.ShutterCallback,
public void startPreview()
{
+ Camera.Size previewSize = m_camera.getParameters().getPreviewSize();
+ double bytesPerPixel = ImageFormat.getBitsPerPixel(m_camera.getParameters().getPreviewFormat()) / 8.0;
+ int bufferSizeNeeded = (int)Math.ceil(bytesPerPixel*previewSize.width*previewSize.height);
+
+ //We need to clear preview buffers queue here, but there is no method to do it
+ //Though just resetting preview callback do the trick
+ m_camera.setPreviewCallback(null);
+ m_buffersLock.lock();
+ if (m_cameraPreviewFirstBuffer == null || m_cameraPreviewFirstBuffer.length < bufferSizeNeeded)
+ m_cameraPreviewFirstBuffer = new byte[bufferSizeNeeded];
+ if (m_cameraPreviewSecondBuffer == null || m_cameraPreviewSecondBuffer.length < bufferSizeNeeded)
+ m_cameraPreviewSecondBuffer = new byte[bufferSizeNeeded];
+ addCallbackBuffer();
+ m_buffersLock.unlock();
+ m_camera.setPreviewCallbackWithBuffer(this);
+
m_camera.startPreview();
}
@@ -152,11 +177,6 @@ public class QtCamera implements Camera.ShutterCallback,
m_camera.cancelAutoFocus();
}
- public void requestPreviewFrame()
- {
- m_camera.setOneShotPreviewCallback(this);
- }
-
public void takePicture()
{
try {
@@ -166,6 +186,37 @@ public class QtCamera implements Camera.ShutterCallback,
}
}
+ public byte[] lockAndFetchPreviewBuffer()
+ {
+ //This method should always be followed by unlockPreviewBuffer()
+ //This method is not just a getter. It also marks last preview as already seen one.
+ //We should reset actualBuffer flag here to make sure we will not use old preview with future captures
+ byte[] result = null;
+ m_buffersLock.lock();
+ if (m_actualPreviewBuffer == 1)
+ result = m_cameraPreviewFirstBuffer;
+ else if (m_actualPreviewBuffer == 2)
+ result = m_cameraPreviewSecondBuffer;
+ m_actualPreviewBuffer = 0;
+ return result;
+ }
+
+ public void unlockPreviewBuffer()
+ {
+ if (m_buffersLock.isHeldByCurrentThread())
+ m_buffersLock.unlock();
+ }
+
+ private void addCallbackBuffer()
+ {
+ if (m_isReleased)
+ return;
+
+ m_camera.addCallbackBuffer((m_actualPreviewBuffer == 1)
+ ? m_cameraPreviewSecondBuffer
+ : m_cameraPreviewFirstBuffer);
+ }
+
@Override
public void onShutter()
{
@@ -181,7 +232,15 @@ public class QtCamera implements Camera.ShutterCallback,
@Override
public void onPreviewFrame(byte[] data, Camera camera)
{
- notifyPreviewFrame(m_cameraId, data);
+ m_buffersLock.lock();
+ if (data == m_cameraPreviewFirstBuffer)
+ m_actualPreviewBuffer = 1;
+ else if (data == m_cameraPreviewSecondBuffer)
+ m_actualPreviewBuffer = 2;
+ else
+ m_actualPreviewBuffer = 0;
+ addCallbackBuffer();
+ m_buffersLock.unlock();
}
@Override
@@ -193,5 +252,4 @@ public class QtCamera implements Camera.ShutterCallback,
private static native void notifyAutoFocusComplete(int id, boolean success);
private static native void notifyPictureExposed(int id);
private static native void notifyPictureCaptured(int id, byte[] data);
- private static native void notifyPreviewFrame(int id, byte[] data);
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
index 3a50139c3..55065cb46 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
@@ -92,6 +92,7 @@ QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
, m_selectedCamera(0)
, m_camera(0)
, m_nativeOrientation(0)
+ , m_previewOrientation(0)
, m_videoOutput(0)
, m_captureMode(QCamera::CaptureViewfinder)
, m_state(QCamera::UnloadedState)
@@ -182,11 +183,20 @@ bool QAndroidCameraSession::open()
if (m_camera) {
connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray)));
- connect(m_camera, SIGNAL(previewFrameAvailable(QByteArray)), this, SLOT(onCameraPreviewFrameAvailable(QByteArray)));
+
m_nativeOrientation = m_camera->getNativeOrientation();
+
+ // Preview orientation will always match the device natural orientation
+ if (m_camera->getFacing() == JCamera::CameraFacingFront)
+ m_previewOrientation = 360 - m_nativeOrientation;
+ else
+ m_previewOrientation = m_nativeOrientation;
+
m_status = QCamera::LoadedStatus;
+
if (m_camera->getPreviewFormat() != JCamera::NV21)
m_camera->setPreviewFormat(JCamera::NV21);
+
emit opened();
} else {
m_status = QCamera::UnavailableStatus;
@@ -257,8 +267,16 @@ void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool
}
if (m_camera->previewSize() != viewfinderResolution) {
- if (m_videoOutput)
- m_videoOutput->setVideoSize(viewfinderResolution);
+ if (m_videoOutput) {
+ QSize size = viewfinderResolution;
+
+ // If the preview orientation is not the defaut one (0 or 180 degrees),
+ // we have to invert the output aspect ratio.
+ if (m_previewOrientation % 180)
+ size.transpose();
+
+ m_videoOutput->setVideoSize(size);
+ }
// if preview is started, we have to stop it first before changing its size
if (m_previewStarted && restartPreview)
@@ -282,6 +300,7 @@ void QAndroidCameraSession::startPreview()
applyImageSettings();
adjustViewfinderSize(m_imageSettings.resolution());
+ m_camera->setDisplayOrientation(m_previewOrientation);
if (m_videoOutput && m_videoOutput->isReady())
onVideoOutputReady(true);
@@ -464,7 +483,6 @@ int QAndroidCameraSession::capture(const QString &fileName)
// adjust picture rotation depending on the device orientation
m_camera->setRotation(currentCameraRotation());
- m_camera->requestPreviewFrame();
m_camera->takePicture();
} else {
//: Drive mode is the camera's shutter mode, for example single shot, continuos exposure, etc.
@@ -489,6 +507,13 @@ void QAndroidCameraSession::onCameraPictureExposed()
return;
emit imageExposed(m_currentImageCaptureId);
+ QByteArray lastFrame = m_camera->fetchLastPreviewFrame();
+ if (lastFrame.size()) {
+ QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
+ m_currentImageCaptureId,
+ lastFrame,
+ m_camera->getRotation());
+ }
}
void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data)
@@ -551,17 +576,7 @@ void QAndroidCameraSession::processCapturedImage(int id,
}
}
-void QAndroidCameraSession::onCameraPreviewFrameAvailable(const QByteArray &data)
-{
- if (m_captureCanceled || m_readyForCapture)
- return;
-
- QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
- m_currentImageCaptureId,
- data);
-}
-
-void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data)
+void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, int rotation)
{
QSize frameSize = m_camera->previewSize();
QImage preview(frameSize, QImage::Format_ARGB32);
@@ -570,11 +585,17 @@ void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data)
frameSize.width(),
frameSize.height());
+ QTransform transform;
+
// Preview display of front-facing cameras is flipped horizontally, but the frame data
// we get here is not. Flip it ourselves if the camera is front-facing to match what the user
// sees on the viewfinder.
if (m_camera->getFacing() == JCamera::CameraFacingFront)
- preview = preview.transformed(QTransform().scale(-1, 1));
+ transform.scale(-1, 1);
+
+ transform.rotate(rotation);
+
+ preview = preview.transformed(transform);
emit imageCaptured(id, preview);
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
index 897cf52d1..61d8c1a17 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
@@ -114,7 +114,6 @@ private Q_SLOTS:
void onCameraPictureExposed();
void onCameraPictureCaptured(const QByteArray &data);
- void onCameraPreviewFrameAvailable(const QByteArray &data);
private:
bool open();
@@ -124,7 +123,7 @@ private:
void stopPreview();
void applyImageSettings();
- void processPreviewImage(int id, const QByteArray &data);
+ void processPreviewImage(int id, const QByteArray &data, int rotation);
void processCapturedImage(int id,
const QByteArray &data,
const QSize &resolution,
@@ -134,6 +133,7 @@ private:
int m_selectedCamera;
JCamera *m_camera;
int m_nativeOrientation;
+ int m_previewOrientation;
QAndroidVideoOutput *m_videoOutput;
QCamera::CaptureModes m_captureMode;
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
index 54c04e5c9..ce73263d3 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -218,10 +218,19 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
return;
}
- const QString uri = mediaContent.canonicalUrl().toString();
+ const QUrl url = mediaContent.canonicalUrl();
+ QString mediaPath;
+ if (url.scheme() == QLatin1String("qrc")) {
+ const QString path = url.toString().mid(3);
+ mTempFile.reset(QTemporaryFile::createNativeFile(path));
+ if (!mTempFile.isNull())
+ mediaPath = QLatin1String("file://") + mTempFile->fileName();
+ } else {
+ mediaPath = url.toString();
+ }
- if (!uri.isEmpty())
- mMediaPlayer->setDataSource(uri);
+ if (!mediaPath.isEmpty())
+ mMediaPlayer->setDataSource(mediaPath);
else
setMediaStatus(QMediaPlayer::NoMedia);
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
index ef1d325e5..fadac3c19 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
@@ -45,6 +45,7 @@
#include <qglobal.h>
#include <QMediaPlayerControl>
#include <qsize.h>
+#include <QtCore/QTemporaryFile>
QT_BEGIN_NAMESPACE
@@ -114,6 +115,7 @@ private:
QMediaPlayer::State mPendingState;
qint64 mPendingPosition;
bool mPendingSetMedia;
+ QScopedPointer<QTemporaryFile> mTempFile;
void setState(QMediaPlayer::State state);
void setMediaStatus(QMediaPlayer::MediaStatus status);
diff --git a/src/plugins/android/src/wrappers/jcamera.cpp b/src/plugins/android/src/wrappers/jcamera.cpp
index 2d42ffbd6..5712ae356 100644
--- a/src/plugins/android/src/wrappers/jcamera.cpp
+++ b/src/plugins/android/src/wrappers/jcamera.cpp
@@ -102,22 +102,11 @@ static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
}
}
-static void notifyPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data)
-{
- JCamera *obj = g_objectMap.value(id, 0);
- if (obj) {
- QByteArray bytes;
- int arrayLength = env->GetArrayLength(data);
- bytes.resize(arrayLength);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
- Q_EMIT obj->previewFrameAvailable(bytes);
- }
-}
-
JCamera::JCamera(int cameraId, jobject cam)
: QObject()
, QJNIObjectPrivate(cam)
, m_cameraId(cameraId)
+ , m_rotation(0)
, m_hasAPI14(false)
{
if (isValid()) {
@@ -205,6 +194,11 @@ int JCamera::getNativeOrientation()
return m_info.getField<jint>("orientation");
}
+void JCamera::setDisplayOrientation(int degrees)
+{
+ callMethod<void>("setDisplayOrientation", "(I)V", degrees);
+}
+
QSize JCamera::getPreferredPreviewSizeForVideo()
{
if (!m_parameters.isValid())
@@ -612,10 +606,16 @@ void JCamera::setRotation(int rotation)
if (!m_parameters.isValid())
return;
+ m_rotation = rotation;
m_parameters.callMethod<void>("setRotation", "(I)V", rotation);
applyParameters();
}
+int JCamera::getRotation() const
+{
+ return m_rotation;
+}
+
QList<QSize> JCamera::getSupportedPictureSizes()
{
QList<QSize> list;
@@ -655,14 +655,26 @@ void JCamera::setJpegQuality(int quality)
applyParameters();
}
-void JCamera::requestPreviewFrame()
+void JCamera::takePicture()
{
- callMethod<void>("requestPreviewFrame");
+ callMethod<void>("takePicture");
}
-void JCamera::takePicture()
+QByteArray JCamera::fetchLastPreviewFrame()
{
- callMethod<void>("takePicture");
+ QJNIEnvironmentPrivate env;
+ QJNIObjectPrivate dataObj = callObjectMethod("lockAndFetchPreviewBuffer", "()[B");
+ if (!dataObj.object()) {
+ callMethod<void>("unlockPreviewBuffer");
+ return QByteArray();
+ }
+ jbyteArray data = static_cast<jbyteArray>(dataObj.object());
+ QByteArray bytes;
+ int arrayLength = env->GetArrayLength(data);
+ bytes.resize(arrayLength);
+ env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+ callMethod<void>("unlockPreviewBuffer");
+ return bytes;
}
void JCamera::startPreview()
@@ -708,8 +720,7 @@ QStringList JCamera::callStringListMethod(const char *methodName)
static JNINativeMethod methods[] = {
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
- {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
- {"notifyPreviewFrame", "(I[B)V", (void *)notifyPreviewFrame}
+ {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}
};
bool JCamera::initJNI(JNIEnv *env)
diff --git a/src/plugins/android/src/wrappers/jcamera.h b/src/plugins/android/src/wrappers/jcamera.h
index 464ca3cb2..6bba98402 100644
--- a/src/plugins/android/src/wrappers/jcamera.h
+++ b/src/plugins/android/src/wrappers/jcamera.h
@@ -82,6 +82,8 @@ public:
CameraFacing getFacing();
int getNativeOrientation();
+ void setDisplayOrientation(int degrees);
+
QSize getPreferredPreviewSizeForVideo();
QList<QSize> getSupportedPreviewSizes();
@@ -136,6 +138,7 @@ public:
void setWhiteBalance(const QString &value);
void setRotation(int rotation);
+ int getRotation() const;
QList<QSize> getSupportedPictureSizes();
void setPictureSize(const QSize &size);
@@ -144,10 +147,10 @@ public:
void startPreview();
void stopPreview();
- void requestPreviewFrame();
-
void takePicture();
+ QByteArray fetchLastPreviewFrame();
+
static bool initJNI(JNIEnv *env);
Q_SIGNALS:
@@ -158,8 +161,6 @@ Q_SIGNALS:
void whiteBalanceChanged();
- void previewFrameAvailable(const QByteArray &data);
-
void pictureExposed();
void pictureCaptured(const QByteArray &data);
@@ -174,6 +175,7 @@ private:
QJNIObjectPrivate m_parameters;
QSize m_previewSize;
+ int m_rotation;
bool m_hasAPI14;
};
diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp
index 8e0235e94..04b46ec0d 100644
--- a/src/plugins/wmf/player/mfplayersession.cpp
+++ b/src/plugins/wmf/player/mfplayersession.cpp
@@ -68,339 +68,6 @@
#include <wmcodecdsp.h>
//#define DEBUG_MEDIAFOUNDATION
-//#define TEST_STREAMING
-
-namespace
-{
- //MFStream is added for supporting QIODevice type of media source.
- //It is used to delegate invocations from media foundation(through IMFByteStream) to QIODevice.
- class MFStream : public QObject, public IMFByteStream
- {
- Q_OBJECT
- public:
- MFStream(QIODevice *stream, bool ownStream)
- : m_cRef(1)
- , m_stream(stream)
- , m_ownStream(ownStream)
- , m_currentReadResult(0)
- {
- //Move to the thread of the stream object
- //to make sure invocations on stream
- //are happened in the same thread of stream object
- this->moveToThread(stream->thread());
- connect(stream, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
- }
-
- ~MFStream()
- {
- if (m_currentReadResult)
- m_currentReadResult->Release();
- if (m_ownStream)
- m_stream->deleteLater();
- }
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject)
- {
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFByteStream) {
- *ppvObject = static_cast<IMFByteStream*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef(void)
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- STDMETHODIMP_(ULONG) Release(void)
- {
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0) {
- this->deleteLater();
- }
- return cRef;
- }
-
-
- //from IMFByteStream
- STDMETHODIMP GetCapabilities(DWORD *pdwCapabilities)
- {
- if (!pdwCapabilities)
- return E_INVALIDARG;
- *pdwCapabilities = MFBYTESTREAM_IS_READABLE;
- if (!m_stream->isSequential())
- *pdwCapabilities |= MFBYTESTREAM_IS_SEEKABLE;
- return S_OK;
- }
-
- STDMETHODIMP GetLength(QWORD *pqwLength)
- {
- if (!pqwLength)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- *pqwLength = QWORD(m_stream->size());
- return S_OK;
- }
-
- STDMETHODIMP SetLength(QWORD)
- {
- return E_NOTIMPL;
- }
-
- STDMETHODIMP GetCurrentPosition(QWORD *pqwPosition)
- {
- if (!pqwPosition)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- *pqwPosition = m_stream->pos();
- return S_OK;
- }
-
- STDMETHODIMP SetCurrentPosition(QWORD qwPosition)
- {
- QMutexLocker locker(&m_mutex);
- //SetCurrentPosition may happend during the BeginRead/EndRead pair,
- //refusing to execute SetCurrentPosition during that time seems to be
- //the simplest workable solution
- if (m_currentReadResult)
- return S_FALSE;
-
- bool seekOK = m_stream->seek(qint64(qwPosition));
- if (seekOK)
- return S_OK;
- else
- return S_FALSE;
- }
-
- STDMETHODIMP IsEndOfStream(BOOL *pfEndOfStream)
- {
- if (!pfEndOfStream)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- *pfEndOfStream = m_stream->atEnd() ? TRUE : FALSE;
- return S_OK;
- }
-
- STDMETHODIMP Read(BYTE *pb, ULONG cb, ULONG *pcbRead)
- {
- QMutexLocker locker(&m_mutex);
- qint64 read = m_stream->read((char*)(pb), qint64(cb));
- if (pcbRead)
- *pcbRead = ULONG(read);
- return S_OK;
- }
-
- STDMETHODIMP BeginRead(BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback,
- IUnknown *punkState)
- {
- if (!pCallback || !pb)
- return E_INVALIDARG;
-
- Q_ASSERT(m_currentReadResult == NULL);
-
- AsyncReadState *state = new (std::nothrow) AsyncReadState(pb, cb);
- if (state == NULL)
- return E_OUTOFMEMORY;
-
- HRESULT hr = MFCreateAsyncResult(state, pCallback, punkState, &m_currentReadResult);
- state->Release();
- if (FAILED(hr))
- return hr;
-
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
- return hr;
- }
-
- STDMETHODIMP EndRead(IMFAsyncResult* pResult, ULONG *pcbRead)
- {
- if (!pcbRead)
- return E_INVALIDARG;
- IUnknown *pUnk;
- pResult->GetObject(&pUnk);
- AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
- *pcbRead = state->bytesRead();
- pUnk->Release();
-
- m_currentReadResult->Release();
- m_currentReadResult = NULL;
-
- return S_OK;
- }
-
- STDMETHODIMP Write(const BYTE *, ULONG, ULONG *)
- {
- return E_NOTIMPL;
- }
-
- STDMETHODIMP BeginWrite(const BYTE *, ULONG ,
- IMFAsyncCallback *,
- IUnknown *)
- {
- return E_NOTIMPL;
- }
-
- STDMETHODIMP EndWrite(IMFAsyncResult *,
- ULONG *)
- {
- return E_NOTIMPL;
- }
-
- STDMETHODIMP Seek(
- MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
- LONGLONG llSeekOffset,
- DWORD,
- QWORD *pqwCurrentPosition)
- {
- QMutexLocker locker(&m_mutex);
- if (m_currentReadResult)
- return S_FALSE;
-
- qint64 pos = qint64(llSeekOffset);
- switch (SeekOrigin) {
- case msoCurrent:
- pos += m_stream->pos();
- break;
- }
- bool seekOK = m_stream->seek(pos);
- if (*pqwCurrentPosition)
- *pqwCurrentPosition = pos;
- if (seekOK)
- return S_OK;
- else
- return S_FALSE;
- }
-
- STDMETHODIMP Flush()
- {
- return E_NOTIMPL;
- }
-
- STDMETHODIMP Close()
- {
- QMutexLocker locker(&m_mutex);
- if (m_ownStream)
- m_stream->close();
- return S_OK;
- }
-
- private:
- //AsyncReadState is a helper class used in BeginRead for asynchronous operation
- //to record some BeginRead parameters, so these parameters could be
- //used later when actually executing the read operation in another thread.
- class AsyncReadState : public IUnknown
- {
- public:
- AsyncReadState(BYTE *pb, ULONG cb)
- : m_cRef(1)
- , m_pb(pb)
- , m_cb(cb)
- , m_cbRead(0)
- {
- }
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject)
- {
- if (!ppvObject)
- return E_POINTER;
-
- if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef(void)
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- STDMETHODIMP_(ULONG) Release(void)
- {
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return cRef;
- }
-
- BYTE* pb() const { return m_pb; }
- ULONG cb() const { return m_cb; }
- ULONG bytesRead() const { return m_cbRead; }
-
- void setBytesRead(ULONG cbRead) { m_cbRead = cbRead; }
-
- private:
- long m_cRef;
- BYTE *m_pb;
- ULONG m_cb;
- ULONG m_cbRead;
- };
-
- long m_cRef;
- QIODevice *m_stream;
- bool m_ownStream;
- DWORD m_workQueueId;
- QMutex m_mutex;
-
- void doRead()
- {
- bool readDone = true;
- IUnknown *pUnk = NULL;
- HRESULT hr = m_currentReadResult->GetObject(&pUnk);
- if (SUCCEEDED(hr)) {
- //do actual read
- AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
- ULONG cbRead;
- Read(state->pb(), state->cb() - state->bytesRead(), &cbRead);
- pUnk->Release();
-
- state->setBytesRead(cbRead + state->bytesRead());
- if (state->cb() > state->bytesRead() && !m_stream->atEnd()) {
- readDone = false;
- }
- }
-
- if (readDone) {
- //now inform the original caller
- m_currentReadResult->SetStatus(hr);
- MFInvokeCallback(m_currentReadResult);
- }
- }
-
-
- private Q_SLOTS:
- void handleReadyRead()
- {
- doRead();
- }
-
- protected:
- void customEvent(QEvent *event)
- {
- if (event->type() != QEvent::User) {
- QObject::customEvent(event);
- return;
- }
- doRead();
- }
- IMFAsyncResult *m_currentReadResult;
- };
-}
-
MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
: m_playerService(playerService)
@@ -411,6 +78,8 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
, m_rateSupport(0)
, m_volumeControl(0)
, m_netsourceStatistics(0)
+ , m_duration(0)
+ , m_sourceResolver(0)
, m_hCloseEvent(0)
, m_closing(false)
, m_pendingRate(1)
@@ -536,7 +205,7 @@ void MFPlayerSession::load(const QMediaContent &media, QIODevice *stream)
clear();
QMediaResourceList resources = media.resources();
- if (m_status == QMediaPlayer::LoadingMedia)
+ if (m_status == QMediaPlayer::LoadingMedia && m_sourceResolver)
m_sourceResolver->cancel();
if (resources.isEmpty() && !stream) {
@@ -581,7 +250,7 @@ void MFPlayerSession::handleSourceError(long hr)
void MFPlayerSession::handleMediaSourceReady()
{
- if (QMediaPlayer::LoadingMedia != m_status)
+ if (QMediaPlayer::LoadingMedia != m_status || !m_sourceResolver)
return;
#ifdef DEBUG_MEDIAFOUNDATION
qDebug() << "handleMediaSourceReady";
@@ -1786,7 +1455,7 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
{
HRESULT hrStatus = S_OK;
HRESULT hr = sessionEvent->GetStatus(&hrStatus);
- if (FAILED(hr)) {
+ if (FAILED(hr) || !m_session) {
sessionEvent->Release();
return;
}
diff --git a/src/plugins/wmf/player/mfvideorenderercontrol.cpp b/src/plugins/wmf/player/mfvideorenderercontrol.cpp
index 83768c8e2..e10cebb26 100644
--- a/src/plugins/wmf/player/mfvideorenderercontrol.cpp
+++ b/src/plugins/wmf/player/mfvideorenderercontrol.cpp
@@ -1085,6 +1085,9 @@ namespace
HRESULT onDispatchWorkItem(IMFAsyncResult* pAsyncResult)
{
QMutexLocker locker(&m_mutex);
+ if (m_shutdown)
+ return MF_E_SHUTDOWN;
+
HRESULT hr = S_OK;
IUnknown *pState = NULL;
hr = pAsyncResult->GetState(&pState);
diff --git a/src/plugins/wmf/sourceresolver.cpp b/src/plugins/wmf/sourceresolver.cpp
index 3f39671f9..9ac126bda 100644
--- a/src/plugins/wmf/sourceresolver.cpp
+++ b/src/plugins/wmf/sourceresolver.cpp
@@ -197,7 +197,7 @@ void SourceResolver::load(QMediaResourceList& resources, QIODevice* stream)
#ifdef TEST_STREAMING
//Testing stream function
if (url.scheme() == QLatin1String("file")) {
- stream = new QFile(url.path().mid(1), this);
+ stream = new QFile(url.path().mid(1));
if (stream->open(QIODevice::ReadOnly)) {
m_stream = new MFStream(stream, true);
hr = m_sourceResolver->BeginCreateObjectFromByteStream(
@@ -217,7 +217,7 @@ void SourceResolver::load(QMediaResourceList& resources, QIODevice* stream)
if (url.scheme() == QLatin1String("qrc")) {
// If the canonical URL refers to a Qt resource, open with QFile and use
// the stream playback capability to play.
- stream = new QFile(QLatin1Char(':') + url.path(), this);
+ stream = new QFile(QLatin1Char(':') + url.path());
if (stream->open(QIODevice::ReadOnly)) {
m_stream = new MFStream(stream, true);
hr = m_sourceResolver->BeginCreateObjectFromByteStream(