diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-12-16 15:36:55 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-12-16 15:36:56 +0100 |
commit | 967e0eb22f8e85db185d093b95da57e3ec41e7cc (patch) | |
tree | fda0a86c20dfde5681a07df5a0b2a71f7438818c /src/plugins | |
parent | 75e5708832ce31a7edd4f4c1eb15f5b5f3d72c14 (diff) | |
parent | ecce937a054e4a96597cb13c40d216bddbd45891 (diff) |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I4fea8b03bc8baaa97e95413f05d13f0f505705d3
Diffstat (limited to 'src/plugins')
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( |