Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I4fea8b03bc8baaa97e95413f05d13f0f505705d3
This commit is contained in:
@@ -175,8 +175,6 @@ void QCameraPrivate::_q_error(int error, const QString &errorString)
|
|||||||
|
|
||||||
void QCameraPrivate::setState(QCamera::State newState)
|
void QCameraPrivate::setState(QCamera::State newState)
|
||||||
{
|
{
|
||||||
Q_Q(QCamera);
|
|
||||||
|
|
||||||
unsetError();
|
unsetError();
|
||||||
|
|
||||||
if (!control) {
|
if (!control) {
|
||||||
@@ -184,13 +182,8 @@ void QCameraPrivate::setState(QCamera::State newState)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == newState)
|
|
||||||
return;
|
|
||||||
|
|
||||||
restartPending = false;
|
restartPending = false;
|
||||||
state = newState;
|
control->setState(newState);
|
||||||
control->setState(state);
|
|
||||||
emit q->stateChanged(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCameraPrivate::_q_updateState(QCamera::State newState)
|
void QCameraPrivate::_q_updateState(QCamera::State newState)
|
||||||
@@ -203,7 +196,6 @@ void QCameraPrivate::_q_updateState(QCamera::State newState)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (newState != state) {
|
if (newState != state) {
|
||||||
qDebug() << "Camera state changed:" << newState;
|
|
||||||
state = newState;
|
state = newState;
|
||||||
emit q->stateChanged(state);
|
emit q->stateChanged(state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ ANDROID_FEATURES += \
|
|||||||
MODULE_PLUGIN_TYPES = \
|
MODULE_PLUGIN_TYPES = \
|
||||||
mediaservice \
|
mediaservice \
|
||||||
audio \
|
audio \
|
||||||
video/videonode
|
video/videonode \
|
||||||
|
playlistformats
|
||||||
|
|
||||||
win32: LIBS_PRIVATE += -luuid
|
win32: LIBS_PRIVATE += -luuid
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,11 @@
|
|||||||
package org.qtproject.qt5.android.multimedia;
|
package org.qtproject.qt5.android.multimedia;
|
||||||
|
|
||||||
import android.hardware.Camera;
|
import android.hardware.Camera;
|
||||||
|
import android.graphics.ImageFormat;
|
||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import java.lang.Math;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public class QtCamera implements Camera.ShutterCallback,
|
public class QtCamera implements Camera.ShutterCallback,
|
||||||
Camera.PictureCallback,
|
Camera.PictureCallback,
|
||||||
@@ -52,6 +55,11 @@ public class QtCamera implements Camera.ShutterCallback,
|
|||||||
{
|
{
|
||||||
private int m_cameraId = -1;
|
private int m_cameraId = -1;
|
||||||
private Camera m_camera = null;
|
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";
|
private static final String TAG = "Qt Camera";
|
||||||
|
|
||||||
@@ -97,6 +105,7 @@ public class QtCamera implements Camera.ShutterCallback,
|
|||||||
|
|
||||||
public void release()
|
public void release()
|
||||||
{
|
{
|
||||||
|
m_isReleased = true;
|
||||||
m_camera.release();
|
m_camera.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +143,22 @@ public class QtCamera implements Camera.ShutterCallback,
|
|||||||
|
|
||||||
public void startPreview()
|
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();
|
m_camera.startPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,11 +177,6 @@ public class QtCamera implements Camera.ShutterCallback,
|
|||||||
m_camera.cancelAutoFocus();
|
m_camera.cancelAutoFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestPreviewFrame()
|
|
||||||
{
|
|
||||||
m_camera.setOneShotPreviewCallback(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void takePicture()
|
public void takePicture()
|
||||||
{
|
{
|
||||||
try {
|
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
|
@Override
|
||||||
public void onShutter()
|
public void onShutter()
|
||||||
{
|
{
|
||||||
@@ -181,7 +232,15 @@ public class QtCamera implements Camera.ShutterCallback,
|
|||||||
@Override
|
@Override
|
||||||
public void onPreviewFrame(byte[] data, Camera camera)
|
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
|
@Override
|
||||||
@@ -193,5 +252,4 @@ public class QtCamera implements Camera.ShutterCallback,
|
|||||||
private static native void notifyAutoFocusComplete(int id, boolean success);
|
private static native void notifyAutoFocusComplete(int id, boolean success);
|
||||||
private static native void notifyPictureExposed(int id);
|
private static native void notifyPictureExposed(int id);
|
||||||
private static native void notifyPictureCaptured(int id, byte[] data);
|
private static native void notifyPictureCaptured(int id, byte[] data);
|
||||||
private static native void notifyPreviewFrame(int id, byte[] data);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
|
|||||||
, m_selectedCamera(0)
|
, m_selectedCamera(0)
|
||||||
, m_camera(0)
|
, m_camera(0)
|
||||||
, m_nativeOrientation(0)
|
, m_nativeOrientation(0)
|
||||||
|
, m_previewOrientation(0)
|
||||||
, m_videoOutput(0)
|
, m_videoOutput(0)
|
||||||
, m_captureMode(QCamera::CaptureViewfinder)
|
, m_captureMode(QCamera::CaptureViewfinder)
|
||||||
, m_state(QCamera::UnloadedState)
|
, m_state(QCamera::UnloadedState)
|
||||||
@@ -182,11 +183,20 @@ bool QAndroidCameraSession::open()
|
|||||||
if (m_camera) {
|
if (m_camera) {
|
||||||
connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
|
connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
|
||||||
connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray)));
|
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();
|
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;
|
m_status = QCamera::LoadedStatus;
|
||||||
|
|
||||||
if (m_camera->getPreviewFormat() != JCamera::NV21)
|
if (m_camera->getPreviewFormat() != JCamera::NV21)
|
||||||
m_camera->setPreviewFormat(JCamera::NV21);
|
m_camera->setPreviewFormat(JCamera::NV21);
|
||||||
|
|
||||||
emit opened();
|
emit opened();
|
||||||
} else {
|
} else {
|
||||||
m_status = QCamera::UnavailableStatus;
|
m_status = QCamera::UnavailableStatus;
|
||||||
@@ -257,8 +267,16 @@ void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_camera->previewSize() != viewfinderResolution) {
|
if (m_camera->previewSize() != viewfinderResolution) {
|
||||||
if (m_videoOutput)
|
if (m_videoOutput) {
|
||||||
m_videoOutput->setVideoSize(viewfinderResolution);
|
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 preview is started, we have to stop it first before changing its size
|
||||||
if (m_previewStarted && restartPreview)
|
if (m_previewStarted && restartPreview)
|
||||||
@@ -282,6 +300,7 @@ void QAndroidCameraSession::startPreview()
|
|||||||
|
|
||||||
applyImageSettings();
|
applyImageSettings();
|
||||||
adjustViewfinderSize(m_imageSettings.resolution());
|
adjustViewfinderSize(m_imageSettings.resolution());
|
||||||
|
m_camera->setDisplayOrientation(m_previewOrientation);
|
||||||
|
|
||||||
if (m_videoOutput && m_videoOutput->isReady())
|
if (m_videoOutput && m_videoOutput->isReady())
|
||||||
onVideoOutputReady(true);
|
onVideoOutputReady(true);
|
||||||
@@ -464,7 +483,6 @@ int QAndroidCameraSession::capture(const QString &fileName)
|
|||||||
// adjust picture rotation depending on the device orientation
|
// adjust picture rotation depending on the device orientation
|
||||||
m_camera->setRotation(currentCameraRotation());
|
m_camera->setRotation(currentCameraRotation());
|
||||||
|
|
||||||
m_camera->requestPreviewFrame();
|
|
||||||
m_camera->takePicture();
|
m_camera->takePicture();
|
||||||
} else {
|
} else {
|
||||||
//: Drive mode is the camera's shutter mode, for example single shot, continuos exposure, etc.
|
//: Drive mode is the camera's shutter mode, for example single shot, continuos exposure, etc.
|
||||||
@@ -489,6 +507,13 @@ void QAndroidCameraSession::onCameraPictureExposed()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
emit imageExposed(m_currentImageCaptureId);
|
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)
|
void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data)
|
||||||
@@ -551,17 +576,7 @@ void QAndroidCameraSession::processCapturedImage(int id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidCameraSession::onCameraPreviewFrameAvailable(const QByteArray &data)
|
void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, int rotation)
|
||||||
{
|
|
||||||
if (m_captureCanceled || m_readyForCapture)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
|
|
||||||
m_currentImageCaptureId,
|
|
||||||
data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data)
|
|
||||||
{
|
{
|
||||||
QSize frameSize = m_camera->previewSize();
|
QSize frameSize = m_camera->previewSize();
|
||||||
QImage preview(frameSize, QImage::Format_ARGB32);
|
QImage preview(frameSize, QImage::Format_ARGB32);
|
||||||
@@ -570,11 +585,17 @@ void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data)
|
|||||||
frameSize.width(),
|
frameSize.width(),
|
||||||
frameSize.height());
|
frameSize.height());
|
||||||
|
|
||||||
|
QTransform transform;
|
||||||
|
|
||||||
// Preview display of front-facing cameras is flipped horizontally, but the frame data
|
// 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
|
// we get here is not. Flip it ourselves if the camera is front-facing to match what the user
|
||||||
// sees on the viewfinder.
|
// sees on the viewfinder.
|
||||||
if (m_camera->getFacing() == JCamera::CameraFacingFront)
|
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);
|
emit imageCaptured(id, preview);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void onCameraPictureExposed();
|
void onCameraPictureExposed();
|
||||||
void onCameraPictureCaptured(const QByteArray &data);
|
void onCameraPictureCaptured(const QByteArray &data);
|
||||||
void onCameraPreviewFrameAvailable(const QByteArray &data);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool open();
|
bool open();
|
||||||
@@ -124,7 +123,7 @@ private:
|
|||||||
void stopPreview();
|
void stopPreview();
|
||||||
|
|
||||||
void applyImageSettings();
|
void applyImageSettings();
|
||||||
void processPreviewImage(int id, const QByteArray &data);
|
void processPreviewImage(int id, const QByteArray &data, int rotation);
|
||||||
void processCapturedImage(int id,
|
void processCapturedImage(int id,
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
const QSize &resolution,
|
const QSize &resolution,
|
||||||
@@ -134,6 +133,7 @@ private:
|
|||||||
int m_selectedCamera;
|
int m_selectedCamera;
|
||||||
JCamera *m_camera;
|
JCamera *m_camera;
|
||||||
int m_nativeOrientation;
|
int m_nativeOrientation;
|
||||||
|
int m_previewOrientation;
|
||||||
QAndroidVideoOutput *m_videoOutput;
|
QAndroidVideoOutput *m_videoOutput;
|
||||||
|
|
||||||
QCamera::CaptureModes m_captureMode;
|
QCamera::CaptureModes m_captureMode;
|
||||||
|
|||||||
@@ -218,10 +218,19 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
|
|||||||
return;
|
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())
|
if (!mediaPath.isEmpty())
|
||||||
mMediaPlayer->setDataSource(uri);
|
mMediaPlayer->setDataSource(mediaPath);
|
||||||
else
|
else
|
||||||
setMediaStatus(QMediaPlayer::NoMedia);
|
setMediaStatus(QMediaPlayer::NoMedia);
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include <qglobal.h>
|
#include <qglobal.h>
|
||||||
#include <QMediaPlayerControl>
|
#include <QMediaPlayerControl>
|
||||||
#include <qsize.h>
|
#include <qsize.h>
|
||||||
|
#include <QtCore/QTemporaryFile>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@@ -114,6 +115,7 @@ private:
|
|||||||
QMediaPlayer::State mPendingState;
|
QMediaPlayer::State mPendingState;
|
||||||
qint64 mPendingPosition;
|
qint64 mPendingPosition;
|
||||||
bool mPendingSetMedia;
|
bool mPendingSetMedia;
|
||||||
|
QScopedPointer<QTemporaryFile> mTempFile;
|
||||||
|
|
||||||
void setState(QMediaPlayer::State state);
|
void setState(QMediaPlayer::State state);
|
||||||
void setMediaStatus(QMediaPlayer::MediaStatus status);
|
void setMediaStatus(QMediaPlayer::MediaStatus status);
|
||||||
|
|||||||
@@ -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)
|
JCamera::JCamera(int cameraId, jobject cam)
|
||||||
: QObject()
|
: QObject()
|
||||||
, QJNIObjectPrivate(cam)
|
, QJNIObjectPrivate(cam)
|
||||||
, m_cameraId(cameraId)
|
, m_cameraId(cameraId)
|
||||||
|
, m_rotation(0)
|
||||||
, m_hasAPI14(false)
|
, m_hasAPI14(false)
|
||||||
{
|
{
|
||||||
if (isValid()) {
|
if (isValid()) {
|
||||||
@@ -205,6 +194,11 @@ int JCamera::getNativeOrientation()
|
|||||||
return m_info.getField<jint>("orientation");
|
return m_info.getField<jint>("orientation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JCamera::setDisplayOrientation(int degrees)
|
||||||
|
{
|
||||||
|
callMethod<void>("setDisplayOrientation", "(I)V", degrees);
|
||||||
|
}
|
||||||
|
|
||||||
QSize JCamera::getPreferredPreviewSizeForVideo()
|
QSize JCamera::getPreferredPreviewSizeForVideo()
|
||||||
{
|
{
|
||||||
if (!m_parameters.isValid())
|
if (!m_parameters.isValid())
|
||||||
@@ -612,10 +606,16 @@ void JCamera::setRotation(int rotation)
|
|||||||
if (!m_parameters.isValid())
|
if (!m_parameters.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_rotation = rotation;
|
||||||
m_parameters.callMethod<void>("setRotation", "(I)V", rotation);
|
m_parameters.callMethod<void>("setRotation", "(I)V", rotation);
|
||||||
applyParameters();
|
applyParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int JCamera::getRotation() const
|
||||||
|
{
|
||||||
|
return m_rotation;
|
||||||
|
}
|
||||||
|
|
||||||
QList<QSize> JCamera::getSupportedPictureSizes()
|
QList<QSize> JCamera::getSupportedPictureSizes()
|
||||||
{
|
{
|
||||||
QList<QSize> list;
|
QList<QSize> list;
|
||||||
@@ -655,16 +655,28 @@ void JCamera::setJpegQuality(int quality)
|
|||||||
applyParameters();
|
applyParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JCamera::requestPreviewFrame()
|
|
||||||
{
|
|
||||||
callMethod<void>("requestPreviewFrame");
|
|
||||||
}
|
|
||||||
|
|
||||||
void JCamera::takePicture()
|
void JCamera::takePicture()
|
||||||
{
|
{
|
||||||
callMethod<void>("takePicture");
|
callMethod<void>("takePicture");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray JCamera::fetchLastPreviewFrame()
|
||||||
|
{
|
||||||
|
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()
|
void JCamera::startPreview()
|
||||||
{
|
{
|
||||||
callMethod<void>("startPreview");
|
callMethod<void>("startPreview");
|
||||||
@@ -708,8 +720,7 @@ QStringList JCamera::callStringListMethod(const char *methodName)
|
|||||||
static JNINativeMethod methods[] = {
|
static JNINativeMethod methods[] = {
|
||||||
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
|
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
|
||||||
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
|
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
|
||||||
{"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
|
{"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}
|
||||||
{"notifyPreviewFrame", "(I[B)V", (void *)notifyPreviewFrame}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool JCamera::initJNI(JNIEnv *env)
|
bool JCamera::initJNI(JNIEnv *env)
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ public:
|
|||||||
CameraFacing getFacing();
|
CameraFacing getFacing();
|
||||||
int getNativeOrientation();
|
int getNativeOrientation();
|
||||||
|
|
||||||
|
void setDisplayOrientation(int degrees);
|
||||||
|
|
||||||
QSize getPreferredPreviewSizeForVideo();
|
QSize getPreferredPreviewSizeForVideo();
|
||||||
QList<QSize> getSupportedPreviewSizes();
|
QList<QSize> getSupportedPreviewSizes();
|
||||||
|
|
||||||
@@ -136,6 +138,7 @@ public:
|
|||||||
void setWhiteBalance(const QString &value);
|
void setWhiteBalance(const QString &value);
|
||||||
|
|
||||||
void setRotation(int rotation);
|
void setRotation(int rotation);
|
||||||
|
int getRotation() const;
|
||||||
|
|
||||||
QList<QSize> getSupportedPictureSizes();
|
QList<QSize> getSupportedPictureSizes();
|
||||||
void setPictureSize(const QSize &size);
|
void setPictureSize(const QSize &size);
|
||||||
@@ -144,10 +147,10 @@ public:
|
|||||||
void startPreview();
|
void startPreview();
|
||||||
void stopPreview();
|
void stopPreview();
|
||||||
|
|
||||||
void requestPreviewFrame();
|
|
||||||
|
|
||||||
void takePicture();
|
void takePicture();
|
||||||
|
|
||||||
|
QByteArray fetchLastPreviewFrame();
|
||||||
|
|
||||||
static bool initJNI(JNIEnv *env);
|
static bool initJNI(JNIEnv *env);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
@@ -158,8 +161,6 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
void whiteBalanceChanged();
|
void whiteBalanceChanged();
|
||||||
|
|
||||||
void previewFrameAvailable(const QByteArray &data);
|
|
||||||
|
|
||||||
void pictureExposed();
|
void pictureExposed();
|
||||||
void pictureCaptured(const QByteArray &data);
|
void pictureCaptured(const QByteArray &data);
|
||||||
|
|
||||||
@@ -174,6 +175,7 @@ private:
|
|||||||
QJNIObjectPrivate m_parameters;
|
QJNIObjectPrivate m_parameters;
|
||||||
|
|
||||||
QSize m_previewSize;
|
QSize m_previewSize;
|
||||||
|
int m_rotation;
|
||||||
|
|
||||||
bool m_hasAPI14;
|
bool m_hasAPI14;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,339 +68,6 @@
|
|||||||
#include <wmcodecdsp.h>
|
#include <wmcodecdsp.h>
|
||||||
|
|
||||||
//#define DEBUG_MEDIAFOUNDATION
|
//#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)
|
MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
|
||||||
: m_playerService(playerService)
|
: m_playerService(playerService)
|
||||||
@@ -411,6 +78,8 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
|
|||||||
, m_rateSupport(0)
|
, m_rateSupport(0)
|
||||||
, m_volumeControl(0)
|
, m_volumeControl(0)
|
||||||
, m_netsourceStatistics(0)
|
, m_netsourceStatistics(0)
|
||||||
|
, m_duration(0)
|
||||||
|
, m_sourceResolver(0)
|
||||||
, m_hCloseEvent(0)
|
, m_hCloseEvent(0)
|
||||||
, m_closing(false)
|
, m_closing(false)
|
||||||
, m_pendingRate(1)
|
, m_pendingRate(1)
|
||||||
@@ -536,7 +205,7 @@ void MFPlayerSession::load(const QMediaContent &media, QIODevice *stream)
|
|||||||
clear();
|
clear();
|
||||||
QMediaResourceList resources = media.resources();
|
QMediaResourceList resources = media.resources();
|
||||||
|
|
||||||
if (m_status == QMediaPlayer::LoadingMedia)
|
if (m_status == QMediaPlayer::LoadingMedia && m_sourceResolver)
|
||||||
m_sourceResolver->cancel();
|
m_sourceResolver->cancel();
|
||||||
|
|
||||||
if (resources.isEmpty() && !stream) {
|
if (resources.isEmpty() && !stream) {
|
||||||
@@ -581,7 +250,7 @@ void MFPlayerSession::handleSourceError(long hr)
|
|||||||
|
|
||||||
void MFPlayerSession::handleMediaSourceReady()
|
void MFPlayerSession::handleMediaSourceReady()
|
||||||
{
|
{
|
||||||
if (QMediaPlayer::LoadingMedia != m_status)
|
if (QMediaPlayer::LoadingMedia != m_status || !m_sourceResolver)
|
||||||
return;
|
return;
|
||||||
#ifdef DEBUG_MEDIAFOUNDATION
|
#ifdef DEBUG_MEDIAFOUNDATION
|
||||||
qDebug() << "handleMediaSourceReady";
|
qDebug() << "handleMediaSourceReady";
|
||||||
@@ -1786,7 +1455,7 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
|
|||||||
{
|
{
|
||||||
HRESULT hrStatus = S_OK;
|
HRESULT hrStatus = S_OK;
|
||||||
HRESULT hr = sessionEvent->GetStatus(&hrStatus);
|
HRESULT hr = sessionEvent->GetStatus(&hrStatus);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr) || !m_session) {
|
||||||
sessionEvent->Release();
|
sessionEvent->Release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1085,6 +1085,9 @@ namespace
|
|||||||
HRESULT onDispatchWorkItem(IMFAsyncResult* pAsyncResult)
|
HRESULT onDispatchWorkItem(IMFAsyncResult* pAsyncResult)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
|
if (m_shutdown)
|
||||||
|
return MF_E_SHUTDOWN;
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
IUnknown *pState = NULL;
|
IUnknown *pState = NULL;
|
||||||
hr = pAsyncResult->GetState(&pState);
|
hr = pAsyncResult->GetState(&pState);
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ void SourceResolver::load(QMediaResourceList& resources, QIODevice* stream)
|
|||||||
#ifdef TEST_STREAMING
|
#ifdef TEST_STREAMING
|
||||||
//Testing stream function
|
//Testing stream function
|
||||||
if (url.scheme() == QLatin1String("file")) {
|
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)) {
|
if (stream->open(QIODevice::ReadOnly)) {
|
||||||
m_stream = new MFStream(stream, true);
|
m_stream = new MFStream(stream, true);
|
||||||
hr = m_sourceResolver->BeginCreateObjectFromByteStream(
|
hr = m_sourceResolver->BeginCreateObjectFromByteStream(
|
||||||
@@ -217,7 +217,7 @@ void SourceResolver::load(QMediaResourceList& resources, QIODevice* stream)
|
|||||||
if (url.scheme() == QLatin1String("qrc")) {
|
if (url.scheme() == QLatin1String("qrc")) {
|
||||||
// If the canonical URL refers to a Qt resource, open with QFile and use
|
// If the canonical URL refers to a Qt resource, open with QFile and use
|
||||||
// the stream playback capability to play.
|
// the stream playback capability to play.
|
||||||
stream = new QFile(QLatin1Char(':') + url.path(), this);
|
stream = new QFile(QLatin1Char(':') + url.path());
|
||||||
if (stream->open(QIODevice::ReadOnly)) {
|
if (stream->open(QIODevice::ReadOnly)) {
|
||||||
m_stream = new MFStream(stream, true);
|
m_stream = new MFStream(stream, true);
|
||||||
hr = m_sourceResolver->BeginCreateObjectFromByteStream(
|
hr = m_sourceResolver->BeginCreateObjectFromByteStream(
|
||||||
|
|||||||
Reference in New Issue
Block a user