Merge remote-tracking branch 'origin/5.5' into 5.6
Change-Id: I1373622a6d1fd0e2d35df2da79860a373056387f
This commit is contained in:
@@ -98,7 +98,7 @@ public:
|
|||||||
trUtf8("CameraImageProcessing is provided by Camera"));
|
trUtf8("CameraImageProcessing is provided by Camera"));
|
||||||
|
|
||||||
// 5.2 types
|
// 5.2 types
|
||||||
qmlRegisterRevision<QDeclarativeVideoOutput, 2>(uri, 5, 2);
|
qmlRegisterType<QDeclarativeVideoOutput, 2>(uri, 5, 2, "VideoOutput");
|
||||||
|
|
||||||
// 5.3 types
|
// 5.3 types
|
||||||
// Nothing changed, but adding "import QtMultimedia 5.3" in QML will fail unless at
|
// Nothing changed, but adding "import QtMultimedia 5.3" in QML will fail unless at
|
||||||
@@ -107,13 +107,13 @@ public:
|
|||||||
|
|
||||||
// 5.4 types
|
// 5.4 types
|
||||||
qmlRegisterSingletonType<QDeclarativeMultimediaGlobal>(uri, 5, 4, "QtMultimedia", multimedia_global_object);
|
qmlRegisterSingletonType<QDeclarativeMultimediaGlobal>(uri, 5, 4, "QtMultimedia", multimedia_global_object);
|
||||||
qmlRegisterRevision<QDeclarativeCamera, 1>(uri, 5, 4);
|
qmlRegisterType<QDeclarativeCamera, 1>(uri, 5, 4, "Camera");
|
||||||
qmlRegisterUncreatableType<QDeclarativeCameraViewfinder>(uri, 5, 4, "CameraViewfinder",
|
qmlRegisterUncreatableType<QDeclarativeCameraViewfinder>(uri, 5, 4, "CameraViewfinder",
|
||||||
trUtf8("CameraViewfinder is provided by Camera"));
|
trUtf8("CameraViewfinder is provided by Camera"));
|
||||||
|
|
||||||
// 5.5 types
|
// 5.5 types
|
||||||
qmlRegisterUncreatableType<QDeclarativeCameraImageProcessing, 1>(uri, 5, 5, "CameraImageProcessing", trUtf8("CameraImageProcessing is provided by Camera"));
|
qmlRegisterUncreatableType<QDeclarativeCameraImageProcessing, 1>(uri, 5, 5, "CameraImageProcessing", trUtf8("CameraImageProcessing is provided by Camera"));
|
||||||
qmlRegisterRevision<QDeclarativeCamera, 2>(uri, 5, 5);
|
qmlRegisterType<QDeclarativeCamera, 2>(uri, 5, 5, "Camera");
|
||||||
|
|
||||||
// 5.6 types
|
// 5.6 types
|
||||||
qmlRegisterType<QDeclarativeAudio, 1>(uri, 5, 6, "Audio");
|
qmlRegisterType<QDeclarativeAudio, 1>(uri, 5, 6, "Audio");
|
||||||
|
|||||||
@@ -270,8 +270,12 @@ Module {
|
|||||||
Component {
|
Component {
|
||||||
name: "QDeclarativeCamera"
|
name: "QDeclarativeCamera"
|
||||||
prototype: "QObject"
|
prototype: "QObject"
|
||||||
exports: ["QtMultimedia/Camera 5.0"]
|
exports: [
|
||||||
exportMetaObjectRevisions: [0]
|
"QtMultimedia/Camera 5.0",
|
||||||
|
"QtMultimedia/Camera 5.4",
|
||||||
|
"QtMultimedia/Camera 5.5"
|
||||||
|
]
|
||||||
|
exportMetaObjectRevisions: [0, 1, 2]
|
||||||
Enum {
|
Enum {
|
||||||
name: "Position"
|
name: "Position"
|
||||||
values: {
|
values: {
|
||||||
@@ -543,7 +547,7 @@ Module {
|
|||||||
name: "supportedViewfinderFrameRateRanges"
|
name: "supportedViewfinderFrameRateRanges"
|
||||||
revision: 2
|
revision: 2
|
||||||
type: "QJSValue"
|
type: "QJSValue"
|
||||||
Parameter { name: "resolution"; type: "QSize" }
|
Parameter { name: "resolution"; type: "QJSValue" }
|
||||||
}
|
}
|
||||||
Method { name: "supportedViewfinderFrameRateRanges"; revision: 2; type: "QJSValue" }
|
Method { name: "supportedViewfinderFrameRateRanges"; revision: 2; type: "QJSValue" }
|
||||||
}
|
}
|
||||||
@@ -1654,8 +1658,11 @@ Module {
|
|||||||
name: "QDeclarativeVideoOutput"
|
name: "QDeclarativeVideoOutput"
|
||||||
defaultProperty: "data"
|
defaultProperty: "data"
|
||||||
prototype: "QQuickItem"
|
prototype: "QQuickItem"
|
||||||
exports: ["QtMultimedia/VideoOutput 5.0"]
|
exports: [
|
||||||
exportMetaObjectRevisions: [0]
|
"QtMultimedia/VideoOutput 5.0",
|
||||||
|
"QtMultimedia/VideoOutput 5.2"
|
||||||
|
]
|
||||||
|
exportMetaObjectRevisions: [0, 2]
|
||||||
Enum {
|
Enum {
|
||||||
name: "FillMode"
|
name: "FillMode"
|
||||||
values: {
|
values: {
|
||||||
|
|||||||
@@ -1013,12 +1013,17 @@ QJSValue QDeclarativeCamera::supportedViewfinderResolutions(qreal minimumFrameRa
|
|||||||
|
|
||||||
\since 5.5
|
\since 5.5
|
||||||
*/
|
*/
|
||||||
QJSValue QDeclarativeCamera::supportedViewfinderFrameRateRanges(const QSize &resolution)
|
QJSValue QDeclarativeCamera::supportedViewfinderFrameRateRanges(const QJSValue &resolution)
|
||||||
{
|
{
|
||||||
QQmlEngine *engine = qmlEngine(this);
|
QQmlEngine *engine = qmlEngine(this);
|
||||||
|
|
||||||
QCameraViewfinderSettings settings;
|
QCameraViewfinderSettings settings;
|
||||||
settings.setResolution(resolution);
|
if (!resolution.isUndefined()) {
|
||||||
|
QJSValue width = resolution.property(QStringLiteral("width"));
|
||||||
|
QJSValue height = resolution.property(QStringLiteral("height"));
|
||||||
|
if (width.isNumber() && height.isNumber())
|
||||||
|
settings.setResolution(width.toInt(), height.toInt());
|
||||||
|
}
|
||||||
QList<QCamera::FrameRateRange> frameRateRanges = m_camera->supportedViewfinderFrameRateRanges(settings);
|
QList<QCamera::FrameRateRange> frameRateRanges = m_camera->supportedViewfinderFrameRateRanges(settings);
|
||||||
|
|
||||||
QJSValue supportedFrameRateRanges = engine->newArray(frameRateRanges.count());
|
QJSValue supportedFrameRateRanges = engine->newArray(frameRateRanges.count());
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
#include <QtCore/qdatetime.h>
|
#include <QtCore/qdatetime.h>
|
||||||
#include <QtQml/qqmlparserstatus.h>
|
#include <QtQml/qqmlparserstatus.h>
|
||||||
#include <QtQml/qqml.h>
|
#include <QtQml/qqml.h>
|
||||||
|
#include <QtQml/qjsvalue.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@@ -297,7 +298,7 @@ public Q_SLOTS:
|
|||||||
Q_REVISION(2) QJSValue supportedViewfinderResolutions(qreal minimumFrameRate = 0.0,
|
Q_REVISION(2) QJSValue supportedViewfinderResolutions(qreal minimumFrameRate = 0.0,
|
||||||
qreal maximumFrameRate = 0.0);
|
qreal maximumFrameRate = 0.0);
|
||||||
|
|
||||||
Q_REVISION(2) QJSValue supportedViewfinderFrameRateRanges(const QSize &resolution = QSize());
|
Q_REVISION(2) QJSValue supportedViewfinderFrameRateRanges(const QJSValue &resolution = QJSValue());
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void errorChanged();
|
void errorChanged();
|
||||||
|
|||||||
@@ -129,7 +129,10 @@ QDeclarativeRadioData::~QDeclarativeRadioData()
|
|||||||
*/
|
*/
|
||||||
QDeclarativeRadioData::Availability QDeclarativeRadioData::availability() const
|
QDeclarativeRadioData::Availability QDeclarativeRadioData::availability() const
|
||||||
{
|
{
|
||||||
return Availability(m_radioData->availability());
|
if (m_radioData)
|
||||||
|
return Availability(m_radioData->availability());
|
||||||
|
|
||||||
|
return Unavailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -141,7 +144,10 @@ QDeclarativeRadioData::Availability QDeclarativeRadioData::availability() const
|
|||||||
*/
|
*/
|
||||||
QString QDeclarativeRadioData::stationId() const
|
QString QDeclarativeRadioData::stationId() const
|
||||||
{
|
{
|
||||||
return m_radioData->stationId();
|
if (m_radioData)
|
||||||
|
return m_radioData->stationId();
|
||||||
|
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -206,7 +212,10 @@ QString QDeclarativeRadioData::stationId() const
|
|||||||
*/
|
*/
|
||||||
QDeclarativeRadioData::ProgramType QDeclarativeRadioData::programType() const
|
QDeclarativeRadioData::ProgramType QDeclarativeRadioData::programType() const
|
||||||
{
|
{
|
||||||
return static_cast<QDeclarativeRadioData::ProgramType>(m_radioData->programType());
|
if (m_radioData)
|
||||||
|
return static_cast<QDeclarativeRadioData::ProgramType>(m_radioData->programType());
|
||||||
|
|
||||||
|
return Undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -216,7 +225,10 @@ QDeclarativeRadioData::ProgramType QDeclarativeRadioData::programType() const
|
|||||||
*/
|
*/
|
||||||
QString QDeclarativeRadioData::programTypeName() const
|
QString QDeclarativeRadioData::programTypeName() const
|
||||||
{
|
{
|
||||||
return m_radioData->programTypeName();
|
if (m_radioData)
|
||||||
|
return m_radioData->programTypeName();
|
||||||
|
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -226,7 +238,10 @@ QString QDeclarativeRadioData::programTypeName() const
|
|||||||
*/
|
*/
|
||||||
QString QDeclarativeRadioData::stationName() const
|
QString QDeclarativeRadioData::stationName() const
|
||||||
{
|
{
|
||||||
return m_radioData->stationName();
|
if (m_radioData)
|
||||||
|
return m_radioData->stationName();
|
||||||
|
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -238,7 +253,10 @@ QString QDeclarativeRadioData::stationName() const
|
|||||||
*/
|
*/
|
||||||
QString QDeclarativeRadioData::radioText() const
|
QString QDeclarativeRadioData::radioText() const
|
||||||
{
|
{
|
||||||
return m_radioData->radioText();
|
if (m_radioData)
|
||||||
|
return m_radioData->radioText();
|
||||||
|
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -250,12 +268,16 @@ QString QDeclarativeRadioData::radioText() const
|
|||||||
*/
|
*/
|
||||||
bool QDeclarativeRadioData::alternativeFrequenciesEnabled() const
|
bool QDeclarativeRadioData::alternativeFrequenciesEnabled() const
|
||||||
{
|
{
|
||||||
return m_radioData->isAlternativeFrequenciesEnabled();
|
if (m_radioData)
|
||||||
|
return m_radioData->isAlternativeFrequenciesEnabled();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QDeclarativeRadioData::setAlternativeFrequenciesEnabled(bool enabled)
|
void QDeclarativeRadioData::setAlternativeFrequenciesEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
m_radioData->setAlternativeFrequenciesEnabled(enabled);
|
if (m_radioData)
|
||||||
|
m_radioData->setAlternativeFrequenciesEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QDeclarativeRadioData::_q_programTypeChanged(QRadioData::ProgramType programType)
|
void QDeclarativeRadioData::_q_programTypeChanged(QRadioData::ProgramType programType)
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ void QSoundEffectPrivate::setCategory(const QString &category)
|
|||||||
}
|
}
|
||||||
|
|
||||||
PrivateSoundSource::PrivateSoundSource(QSoundEffectPrivate* s):
|
PrivateSoundSource::PrivateSoundSource(QSoundEffectPrivate* s):
|
||||||
|
QIODevice(s),
|
||||||
m_loopCount(1),
|
m_loopCount(1),
|
||||||
m_runningCount(0),
|
m_runningCount(0),
|
||||||
m_playing(false),
|
m_playing(false),
|
||||||
|
|||||||
@@ -73,29 +73,60 @@ public:
|
|||||||
: QAbstractVideoBuffer(GLTextureHandle)
|
: QAbstractVideoBuffer(GLTextureHandle)
|
||||||
, m_control(control)
|
, m_control(control)
|
||||||
, m_textureUpdated(false)
|
, m_textureUpdated(false)
|
||||||
|
, m_mapMode(NotMapped)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~AndroidTextureVideoBuffer() {}
|
virtual ~AndroidTextureVideoBuffer() {}
|
||||||
|
|
||||||
MapMode mapMode() const { return NotMapped; }
|
MapMode mapMode() const { return m_mapMode; }
|
||||||
uchar *map(MapMode, int*, int*) { return 0; }
|
|
||||||
void unmap() {}
|
uchar *map(MapMode mode, int *numBytes, int *bytesPerLine)
|
||||||
|
{
|
||||||
|
if (m_mapMode == NotMapped && mode == ReadOnly) {
|
||||||
|
updateFrame();
|
||||||
|
m_mapMode = mode;
|
||||||
|
m_image = m_control->m_fbo->toImage();
|
||||||
|
|
||||||
|
if (numBytes)
|
||||||
|
*numBytes = m_image.byteCount();
|
||||||
|
|
||||||
|
if (bytesPerLine)
|
||||||
|
*bytesPerLine = m_image.bytesPerLine();
|
||||||
|
|
||||||
|
return m_image.bits();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmap()
|
||||||
|
{
|
||||||
|
m_image = QImage();
|
||||||
|
m_mapMode = NotMapped;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant handle() const
|
QVariant handle() const
|
||||||
|
{
|
||||||
|
AndroidTextureVideoBuffer *that = const_cast<AndroidTextureVideoBuffer*>(this);
|
||||||
|
that->updateFrame();
|
||||||
|
return m_control->m_fbo->texture();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateFrame()
|
||||||
{
|
{
|
||||||
if (!m_textureUpdated) {
|
if (!m_textureUpdated) {
|
||||||
// update the video texture (called from the render thread)
|
// update the video texture (called from the render thread)
|
||||||
m_control->renderFrameToFbo();
|
m_control->renderFrameToFbo();
|
||||||
m_textureUpdated = true;
|
m_textureUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_control->m_fbo->texture();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
QAndroidVideoRendererControl *m_control;
|
||||||
mutable QAndroidVideoRendererControl *m_control;
|
bool m_textureUpdated;
|
||||||
mutable bool m_textureUpdated;
|
MapMode m_mapMode;
|
||||||
|
QImage m_image;
|
||||||
};
|
};
|
||||||
|
|
||||||
QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
|
QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ public:
|
|||||||
|
|
||||||
AVCaptureVideoDataOutput *videoDataOutput() const;
|
AVCaptureVideoDataOutput *videoDataOutput() const;
|
||||||
|
|
||||||
|
bool supportsTextures() const { return m_supportsTextures; }
|
||||||
|
|
||||||
#ifdef Q_OS_IOS
|
#ifdef Q_OS_IOS
|
||||||
AVFCaptureFramesDelegate *captureDelegate() const;
|
AVFCaptureFramesDelegate *captureDelegate() const;
|
||||||
void resetCaptureDelegate() const;
|
void resetCaptureDelegate() const;
|
||||||
@@ -81,11 +83,18 @@ private:
|
|||||||
AVFCameraSession *m_cameraSession;
|
AVFCameraSession *m_cameraSession;
|
||||||
AVCaptureVideoDataOutput *m_videoDataOutput;
|
AVCaptureVideoDataOutput *m_videoDataOutput;
|
||||||
|
|
||||||
|
bool m_supportsTextures;
|
||||||
bool m_needsHorizontalMirroring;
|
bool m_needsHorizontalMirroring;
|
||||||
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
CVOpenGLESTextureCacheRef m_textureCache;
|
||||||
|
#endif
|
||||||
|
|
||||||
QVideoFrame m_lastViewfinderFrame;
|
QVideoFrame m_lastViewfinderFrame;
|
||||||
QMutex m_vfMutex;
|
QMutex m_vfMutex;
|
||||||
dispatch_queue_t m_delegateQueue;
|
dispatch_queue_t m_delegateQueue;
|
||||||
|
|
||||||
|
friend class CVImageVideoBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
@@ -38,6 +38,10 @@
|
|||||||
#include "avfcameraservice.h"
|
#include "avfcameraservice.h"
|
||||||
#include "avfcameradebug.h"
|
#include "avfcameradebug.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
#include <QtGui/qopengl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QtMultimedia/qabstractvideosurface.h>
|
#include <QtMultimedia/qabstractvideosurface.h>
|
||||||
#include <QtMultimedia/qabstractvideobuffer.h>
|
#include <QtMultimedia/qabstractvideobuffer.h>
|
||||||
|
|
||||||
@@ -45,20 +49,32 @@
|
|||||||
|
|
||||||
QT_USE_NAMESPACE
|
QT_USE_NAMESPACE
|
||||||
|
|
||||||
class CVPixelBufferVideoBuffer : public QAbstractPlanarVideoBuffer
|
class CVImageVideoBuffer : public QAbstractPlanarVideoBuffer
|
||||||
{
|
{
|
||||||
friend class CVPixelBufferVideoBufferPrivate;
|
|
||||||
public:
|
public:
|
||||||
CVPixelBufferVideoBuffer(CVPixelBufferRef buffer)
|
CVImageVideoBuffer(CVImageBufferRef buffer, AVFCameraRendererControl *renderer)
|
||||||
|
#ifndef Q_OS_IOS
|
||||||
: QAbstractPlanarVideoBuffer(NoHandle)
|
: QAbstractPlanarVideoBuffer(NoHandle)
|
||||||
|
#else
|
||||||
|
: QAbstractPlanarVideoBuffer(renderer->supportsTextures()
|
||||||
|
&& CVPixelBufferGetPixelFormatType(buffer) == kCVPixelFormatType_32BGRA
|
||||||
|
? GLTextureHandle : NoHandle)
|
||||||
|
, m_texture(0)
|
||||||
|
#endif
|
||||||
, m_buffer(buffer)
|
, m_buffer(buffer)
|
||||||
|
, m_renderer(renderer)
|
||||||
, m_mode(NotMapped)
|
, m_mode(NotMapped)
|
||||||
{
|
{
|
||||||
CVPixelBufferRetain(m_buffer);
|
CVPixelBufferRetain(m_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~CVPixelBufferVideoBuffer()
|
~CVImageVideoBuffer()
|
||||||
{
|
{
|
||||||
|
CVImageVideoBuffer::unmap();
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
if (m_texture)
|
||||||
|
CFRelease(m_texture);
|
||||||
|
#endif
|
||||||
CVPixelBufferRelease(m_buffer);
|
CVPixelBufferRelease(m_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +94,9 @@ public:
|
|||||||
|
|
||||||
// For a bi-planar format we have to set the parameters correctly:
|
// For a bi-planar format we have to set the parameters correctly:
|
||||||
if (mode != QAbstractVideoBuffer::NotMapped && m_mode == QAbstractVideoBuffer::NotMapped) {
|
if (mode != QAbstractVideoBuffer::NotMapped && m_mode == QAbstractVideoBuffer::NotMapped) {
|
||||||
CVPixelBufferLockBaseAddress(m_buffer, 0);
|
CVPixelBufferLockBaseAddress(m_buffer, mode == QAbstractVideoBuffer::ReadOnly
|
||||||
|
? kCVPixelBufferLock_ReadOnly
|
||||||
|
: 0);
|
||||||
|
|
||||||
if (numBytes)
|
if (numBytes)
|
||||||
*numBytes = CVPixelBufferGetDataSize(m_buffer);
|
*numBytes = CVPixelBufferGetDataSize(m_buffer);
|
||||||
@@ -103,8 +121,9 @@ public:
|
|||||||
uchar *map(MapMode mode, int *numBytes, int *bytesPerLine)
|
uchar *map(MapMode mode, int *numBytes, int *bytesPerLine)
|
||||||
{
|
{
|
||||||
if (mode != NotMapped && m_mode == NotMapped) {
|
if (mode != NotMapped && m_mode == NotMapped) {
|
||||||
CVPixelBufferLockBaseAddress(m_buffer, 0);
|
CVPixelBufferLockBaseAddress(m_buffer, mode == QAbstractVideoBuffer::ReadOnly
|
||||||
|
? kCVPixelBufferLock_ReadOnly
|
||||||
|
: 0);
|
||||||
if (numBytes)
|
if (numBytes)
|
||||||
*numBytes = CVPixelBufferGetDataSize(m_buffer);
|
*numBytes = CVPixelBufferGetDataSize(m_buffer);
|
||||||
|
|
||||||
@@ -121,13 +140,63 @@ public:
|
|||||||
void unmap()
|
void unmap()
|
||||||
{
|
{
|
||||||
if (m_mode != NotMapped) {
|
if (m_mode != NotMapped) {
|
||||||
|
CVPixelBufferUnlockBaseAddress(m_buffer, m_mode == QAbstractVideoBuffer::ReadOnly
|
||||||
|
? kCVPixelBufferLock_ReadOnly
|
||||||
|
: 0);
|
||||||
m_mode = NotMapped;
|
m_mode = NotMapped;
|
||||||
CVPixelBufferUnlockBaseAddress(m_buffer, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant handle() const
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
// Called from the render thread, so there is a current OpenGL context
|
||||||
|
|
||||||
|
if (!m_renderer->m_textureCache) {
|
||||||
|
CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault,
|
||||||
|
NULL,
|
||||||
|
[EAGLContext currentContext],
|
||||||
|
NULL,
|
||||||
|
&m_renderer->m_textureCache);
|
||||||
|
|
||||||
|
if (err != kCVReturnSuccess)
|
||||||
|
qWarning("Error creating texture cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_renderer->m_textureCache && !m_texture) {
|
||||||
|
CVOpenGLESTextureCacheFlush(m_renderer->m_textureCache, 0);
|
||||||
|
|
||||||
|
CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
|
||||||
|
m_renderer->m_textureCache,
|
||||||
|
m_buffer,
|
||||||
|
NULL,
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
GL_RGBA,
|
||||||
|
CVPixelBufferGetWidth(m_buffer),
|
||||||
|
CVPixelBufferGetHeight(m_buffer),
|
||||||
|
GL_BGRA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
0,
|
||||||
|
&m_texture);
|
||||||
|
if (err != kCVReturnSuccess)
|
||||||
|
qWarning("Error creating texture from buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_texture)
|
||||||
|
return CVOpenGLESTextureGetName(m_texture);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return QVariant();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CVPixelBufferRef m_buffer;
|
#ifdef Q_OS_IOS
|
||||||
|
mutable CVOpenGLESTextureRef m_texture;
|
||||||
|
#endif
|
||||||
|
CVImageBufferRef m_buffer;
|
||||||
|
AVFCameraRendererControl *m_renderer;
|
||||||
MapMode m_mode;
|
MapMode m_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -171,13 +240,25 @@ private:
|
|||||||
|
|
||||||
int width = CVPixelBufferGetWidth(imageBuffer);
|
int width = CVPixelBufferGetWidth(imageBuffer);
|
||||||
int height = CVPixelBufferGetHeight(imageBuffer);
|
int height = CVPixelBufferGetHeight(imageBuffer);
|
||||||
QVideoFrame::PixelFormat format =
|
QVideoFrame::PixelFormat format;
|
||||||
AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(CVPixelBufferGetPixelFormatType(imageBuffer));
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
bool useTexture = m_renderer->supportsTextures()
|
||||||
|
&& CVPixelBufferGetPixelFormatType(imageBuffer) == kCVPixelFormatType_32BGRA;
|
||||||
|
|
||||||
|
if (useTexture)
|
||||||
|
format = QVideoFrame::Format_BGRA32;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
format = AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(CVPixelBufferGetPixelFormatType(imageBuffer));
|
||||||
|
|
||||||
if (format == QVideoFrame::Format_Invalid)
|
if (format == QVideoFrame::Format_Invalid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QVideoFrame frame(new CVPixelBufferVideoBuffer(imageBuffer), QSize(width, height), format);
|
QVideoFrame frame(new CVImageVideoBuffer(imageBuffer, m_renderer),
|
||||||
|
QSize(width, height),
|
||||||
|
format);
|
||||||
|
|
||||||
m_renderer->syncHandleViewfinderFrame(frame);
|
m_renderer->syncHandleViewfinderFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +268,11 @@ private:
|
|||||||
AVFCameraRendererControl::AVFCameraRendererControl(QObject *parent)
|
AVFCameraRendererControl::AVFCameraRendererControl(QObject *parent)
|
||||||
: QVideoRendererControl(parent)
|
: QVideoRendererControl(parent)
|
||||||
, m_surface(0)
|
, m_surface(0)
|
||||||
|
, m_supportsTextures(false)
|
||||||
, m_needsHorizontalMirroring(false)
|
, m_needsHorizontalMirroring(false)
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
, m_textureCache(0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this];
|
m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this];
|
||||||
}
|
}
|
||||||
@@ -198,6 +283,10 @@ AVFCameraRendererControl::~AVFCameraRendererControl()
|
|||||||
[m_viewfinderFramesDelegate release];
|
[m_viewfinderFramesDelegate release];
|
||||||
if (m_delegateQueue)
|
if (m_delegateQueue)
|
||||||
dispatch_release(m_delegateQueue);
|
dispatch_release(m_delegateQueue);
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
if (m_textureCache)
|
||||||
|
CFRelease(m_textureCache);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QAbstractVideoSurface *AVFCameraRendererControl::surface() const
|
QAbstractVideoSurface *AVFCameraRendererControl::surface() const
|
||||||
@@ -209,6 +298,11 @@ void AVFCameraRendererControl::setSurface(QAbstractVideoSurface *surface)
|
|||||||
{
|
{
|
||||||
if (m_surface != surface) {
|
if (m_surface != surface) {
|
||||||
m_surface = surface;
|
m_surface = surface;
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
m_supportsTextures = m_surface
|
||||||
|
? m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGRA32)
|
||||||
|
: false;
|
||||||
|
#endif
|
||||||
Q_EMIT surfaceChanged(surface);
|
Q_EMIT surfaceChanged(surface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,21 +355,6 @@ void AVFCameraRendererControl::syncHandleViewfinderFrame(const QVideoFrame &fram
|
|||||||
|
|
||||||
m_lastViewfinderFrame = frame;
|
m_lastViewfinderFrame = frame;
|
||||||
|
|
||||||
if (m_needsHorizontalMirroring) {
|
|
||||||
m_lastViewfinderFrame.map(QAbstractVideoBuffer::ReadOnly);
|
|
||||||
|
|
||||||
// no deep copy
|
|
||||||
QImage image(m_lastViewfinderFrame.bits(),
|
|
||||||
m_lastViewfinderFrame.size().width(),
|
|
||||||
m_lastViewfinderFrame.size().height(),
|
|
||||||
m_lastViewfinderFrame.bytesPerLine(),
|
|
||||||
QImage::Format_RGB32);
|
|
||||||
|
|
||||||
QImage mirrored = image.mirrored(true, false);
|
|
||||||
|
|
||||||
m_lastViewfinderFrame.unmap();
|
|
||||||
m_lastViewfinderFrame = QVideoFrame(mirrored);
|
|
||||||
}
|
|
||||||
if (m_cameraSession && m_lastViewfinderFrame.isValid())
|
if (m_cameraSession && m_lastViewfinderFrame.isValid())
|
||||||
m_cameraSession->onCameraFrameFetched(m_lastViewfinderFrame);
|
m_cameraSession->onCameraFrameFetched(m_lastViewfinderFrame);
|
||||||
}
|
}
|
||||||
@@ -315,7 +394,9 @@ void AVFCameraRendererControl::handleViewfinderFrame()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m_surface->isActive()) {
|
if (!m_surface->isActive()) {
|
||||||
QVideoSurfaceFormat format(frame.size(), frame.pixelFormat());
|
QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(), frame.handleType());
|
||||||
|
if (m_needsHorizontalMirroring)
|
||||||
|
format.setProperty("mirrored", true);
|
||||||
|
|
||||||
if (!m_surface->start(format)) {
|
if (!m_surface->start(format)) {
|
||||||
qWarning() << "Failed to start viewfinder m_surface, format:" << format;
|
qWarning() << "Failed to start viewfinder m_surface, format:" << format;
|
||||||
|
|||||||
@@ -573,22 +573,29 @@ void AVFCameraViewfinderSettingsControl2::applySettings()
|
|||||||
if (!convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) {
|
if (!convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) {
|
||||||
// If the the pixel format is not specified or invalid, pick the preferred video surface
|
// If the the pixel format is not specified or invalid, pick the preferred video surface
|
||||||
// format, or if no surface is set, the preferred capture device format
|
// format, or if no surface is set, the preferred capture device format
|
||||||
|
|
||||||
const QVector<QVideoFrame::PixelFormat> deviceFormats = viewfinderPixelFormats();
|
const QVector<QVideoFrame::PixelFormat> deviceFormats = viewfinderPixelFormats();
|
||||||
QList<QVideoFrame::PixelFormat> surfaceFormats;
|
QVideoFrame::PixelFormat pickedFormat = deviceFormats.first();
|
||||||
if (m_service->videoOutput() && m_service->videoOutput()->surface())
|
|
||||||
surfaceFormats = m_service->videoOutput()->surface()->supportedPixelFormats();
|
|
||||||
|
|
||||||
QVideoFrame::PixelFormat format = deviceFormats.first();
|
QAbstractVideoSurface *surface = m_service->videoOutput() ? m_service->videoOutput()->surface()
|
||||||
|
: 0;
|
||||||
|
if (surface) {
|
||||||
|
if (m_service->videoOutput()->supportsTextures()) {
|
||||||
|
pickedFormat = QVideoFrame::Format_ARGB32;
|
||||||
|
} else {
|
||||||
|
QList<QVideoFrame::PixelFormat> surfaceFormats = m_service->videoOutput()->surface()->supportedPixelFormats();
|
||||||
|
|
||||||
for (int i = 0; i < surfaceFormats.count(); ++i) {
|
for (int i = 0; i < surfaceFormats.count(); ++i) {
|
||||||
const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i);
|
const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i);
|
||||||
if (deviceFormats.contains(surfaceFormat)) {
|
if (deviceFormats.contains(surfaceFormat)) {
|
||||||
format = surfaceFormat;
|
pickedFormat = surfaceFormat;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CVPixelFormatFromQtFormat(format, avfPixelFormat);
|
CVPixelFormatFromQtFormat(pickedFormat, avfPixelFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avfPixelFormat != 0) {
|
if (avfPixelFormat != 0) {
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ void AVFMediaPlayerControl::setSession(AVFMediaPlayerSession *session)
|
|||||||
connect(m_session, SIGNAL(audioAvailableChanged(bool)), this, SIGNAL(audioAvailableChanged(bool)));
|
connect(m_session, SIGNAL(audioAvailableChanged(bool)), this, SIGNAL(audioAvailableChanged(bool)));
|
||||||
connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool)));
|
connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool)));
|
||||||
connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString)));
|
connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString)));
|
||||||
|
connect(m_session, &AVFMediaPlayerSession::playbackRateChanged,
|
||||||
|
this, &AVFMediaPlayerControl::playbackRateChanged);
|
||||||
|
connect(m_session, &AVFMediaPlayerSession::seekableChanged,
|
||||||
|
this, &AVFMediaPlayerControl::seekableChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMediaPlayer::State AVFMediaPlayerControl::state() const
|
QMediaPlayer::State AVFMediaPlayerControl::state() const
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ public:
|
|||||||
|
|
||||||
qreal playbackRate() const;
|
qreal playbackRate() const;
|
||||||
|
|
||||||
|
inline bool isVolumeSupported() const { return m_volumeSupported; }
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void setPlaybackRate(qreal rate);
|
void setPlaybackRate(qreal rate);
|
||||||
|
|
||||||
@@ -106,6 +108,8 @@ Q_SIGNALS:
|
|||||||
void mutedChanged(bool muted);
|
void mutedChanged(bool muted);
|
||||||
void audioAvailableChanged(bool audioAvailable);
|
void audioAvailableChanged(bool audioAvailable);
|
||||||
void videoAvailableChanged(bool videoAvailable);
|
void videoAvailableChanged(bool videoAvailable);
|
||||||
|
void playbackRateChanged(qreal rate);
|
||||||
|
void seekableChanged(bool seekable);
|
||||||
void error(int error, const QString &errorString);
|
void error(int error, const QString &errorString);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -148,6 +152,7 @@ private:
|
|||||||
|
|
||||||
void setAudioAvailable(bool available);
|
void setAudioAvailable(bool available);
|
||||||
void setVideoAvailable(bool available);
|
void setVideoAvailable(bool available);
|
||||||
|
void setSeekable(bool seekable);
|
||||||
|
|
||||||
AVFMediaPlayerService *m_service;
|
AVFMediaPlayerService *m_service;
|
||||||
AVFVideoOutput *m_videoOutput;
|
AVFVideoOutput *m_videoOutput;
|
||||||
@@ -158,14 +163,17 @@ private:
|
|||||||
QMediaContent m_resources;
|
QMediaContent m_resources;
|
||||||
ResourceHandler m_resourceHandler;
|
ResourceHandler m_resourceHandler;
|
||||||
|
|
||||||
|
const bool m_volumeSupported;
|
||||||
bool m_muted;
|
bool m_muted;
|
||||||
bool m_tryingAsync;
|
bool m_tryingAsync;
|
||||||
int m_volume;
|
int m_volume;
|
||||||
qreal m_rate;
|
qreal m_rate;
|
||||||
|
qint64 m_requestedPosition;
|
||||||
|
|
||||||
qint64 m_duration;
|
qint64 m_duration;
|
||||||
bool m_videoAvailable;
|
bool m_videoAvailable;
|
||||||
bool m_audioAvailable;
|
bool m_audioAvailable;
|
||||||
|
bool m_seekable;
|
||||||
|
|
||||||
void *m_observer;
|
void *m_observer;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -121,19 +121,28 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe
|
|||||||
|
|
||||||
- (void) unloadMedia
|
- (void) unloadMedia
|
||||||
{
|
{
|
||||||
if (m_player)
|
|
||||||
[m_player setRate:0.0];
|
|
||||||
if (m_playerItem) {
|
if (m_playerItem) {
|
||||||
[m_playerItem removeObserver:self forKeyPath:AVF_STATUS_KEY];
|
[m_playerItem removeObserver:self forKeyPath:AVF_STATUS_KEY];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||||
object:m_playerItem];
|
object:m_playerItem];
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||||
name:AVPlayerItemTimeJumpedNotification
|
name:AVPlayerItemTimeJumpedNotification
|
||||||
object:m_playerItem];
|
object:m_playerItem];
|
||||||
m_playerItem = 0;
|
m_playerItem = 0;
|
||||||
}
|
}
|
||||||
|
if (m_player) {
|
||||||
|
[m_player setRate:0.0];
|
||||||
|
[m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY];
|
||||||
|
[m_player removeObserver:self forKeyPath:AVF_RATE_KEY];
|
||||||
|
[m_player release];
|
||||||
|
m_player = 0;
|
||||||
|
}
|
||||||
|
if (m_playerLayer) {
|
||||||
|
[m_playerLayer release];
|
||||||
|
m_playerLayer = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) prepareToPlayAsset:(AVURLAsset *)asset
|
- (void) prepareToPlayAsset:(AVURLAsset *)asset
|
||||||
@@ -203,30 +212,15 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe
|
|||||||
name:AVPlayerItemTimeJumpedNotification
|
name:AVPlayerItemTimeJumpedNotification
|
||||||
object:m_playerItem];
|
object:m_playerItem];
|
||||||
|
|
||||||
|
|
||||||
//Clean up old player if we have one
|
|
||||||
if (m_player) {
|
|
||||||
[m_player setRate:0.0];
|
|
||||||
[m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY];
|
|
||||||
[m_player removeObserver:self forKeyPath:AVF_RATE_KEY];
|
|
||||||
[m_player release];
|
|
||||||
m_player = 0;
|
|
||||||
|
|
||||||
if (m_playerLayer) {
|
|
||||||
[m_playerLayer release];
|
|
||||||
m_playerLayer = 0; //Will have been released
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get a new AVPlayer initialized to play the specified player item.
|
//Get a new AVPlayer initialized to play the specified player item.
|
||||||
m_player = [AVPlayer playerWithPlayerItem:m_playerItem];
|
m_player = [AVPlayer playerWithPlayerItem:m_playerItem];
|
||||||
[m_player retain];
|
[m_player retain];
|
||||||
|
|
||||||
#if defined(Q_OS_OSX)
|
|
||||||
//Set the initial volume on new player object
|
//Set the initial volume on new player object
|
||||||
if (self.session)
|
if (self.session && self.session->isVolumeSupported()) {
|
||||||
m_player.volume = m_session->volume() / 100.0f;
|
[m_player setVolume:m_session->volume() / 100.0f];
|
||||||
#endif
|
[m_player setMuted:m_session->isMuted()];
|
||||||
|
}
|
||||||
|
|
||||||
//Create a new player layer if we don't have one already
|
//Create a new player layer if we don't have one already
|
||||||
if (!m_playerLayer)
|
if (!m_playerLayer)
|
||||||
@@ -354,18 +348,6 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe
|
|||||||
#endif
|
#endif
|
||||||
[self unloadMedia];
|
[self unloadMedia];
|
||||||
|
|
||||||
if (m_player) {
|
|
||||||
[m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY];
|
|
||||||
[m_player removeObserver:self forKeyPath:AVF_RATE_KEY];
|
|
||||||
[m_player release];
|
|
||||||
m_player = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_playerLayer) {
|
|
||||||
[m_playerLayer release];
|
|
||||||
m_playerLayer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_URL) {
|
if (m_URL) {
|
||||||
[m_URL release];
|
[m_URL release];
|
||||||
}
|
}
|
||||||
@@ -382,13 +364,20 @@ AVFMediaPlayerSession::AVFMediaPlayerSession(AVFMediaPlayerService *service, QOb
|
|||||||
, m_state(QMediaPlayer::StoppedState)
|
, m_state(QMediaPlayer::StoppedState)
|
||||||
, m_mediaStatus(QMediaPlayer::NoMedia)
|
, m_mediaStatus(QMediaPlayer::NoMedia)
|
||||||
, m_mediaStream(0)
|
, m_mediaStream(0)
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
, m_volumeSupported(QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0)
|
||||||
|
#else
|
||||||
|
, m_volumeSupported(true)
|
||||||
|
#endif
|
||||||
, m_muted(false)
|
, m_muted(false)
|
||||||
, m_tryingAsync(false)
|
, m_tryingAsync(false)
|
||||||
, m_volume(100)
|
, m_volume(100)
|
||||||
, m_rate(1.0)
|
, m_rate(1.0)
|
||||||
|
, m_requestedPosition(-1)
|
||||||
, m_duration(0)
|
, m_duration(0)
|
||||||
, m_videoAvailable(false)
|
, m_videoAvailable(false)
|
||||||
, m_audioAvailable(false)
|
, m_audioAvailable(false)
|
||||||
|
, m_seekable(false)
|
||||||
{
|
{
|
||||||
m_observer = [[AVFMediaPlayerSessionObserver alloc] initWithMediaPlayerSession:this];
|
m_observer = [[AVFMediaPlayerSessionObserver alloc] initWithMediaPlayerSession:this];
|
||||||
}
|
}
|
||||||
@@ -458,23 +447,26 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st
|
|||||||
qDebug() << Q_FUNC_INFO << content.canonicalUrl();
|
qDebug() << Q_FUNC_INFO << content.canonicalUrl();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
[(AVFMediaPlayerSessionObserver*)m_observer unloadMedia];
|
||||||
|
|
||||||
m_resources = content;
|
m_resources = content;
|
||||||
m_mediaStream = stream;
|
m_mediaStream = stream;
|
||||||
|
|
||||||
setAudioAvailable(false);
|
setAudioAvailable(false);
|
||||||
setVideoAvailable(false);
|
setVideoAvailable(false);
|
||||||
|
setSeekable(false);
|
||||||
|
m_requestedPosition = -1;
|
||||||
|
Q_EMIT positionChanged(position());
|
||||||
|
|
||||||
QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus;
|
QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus;
|
||||||
|
|
||||||
if (content.isNull() || content.canonicalUrl().isEmpty()) {
|
if (content.isNull() || content.canonicalUrl().isEmpty()) {
|
||||||
[(AVFMediaPlayerSessionObserver*)m_observer unloadMedia];
|
|
||||||
m_mediaStatus = QMediaPlayer::NoMedia;
|
m_mediaStatus = QMediaPlayer::NoMedia;
|
||||||
if (m_state != QMediaPlayer::StoppedState)
|
if (m_state != QMediaPlayer::StoppedState)
|
||||||
Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
|
Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
|
||||||
|
|
||||||
if (m_mediaStatus != oldMediaStatus)
|
if (m_mediaStatus != oldMediaStatus)
|
||||||
Q_EMIT mediaStatusChanged(m_mediaStatus);
|
Q_EMIT mediaStatusChanged(m_mediaStatus);
|
||||||
Q_EMIT positionChanged(position());
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -482,6 +474,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st
|
|||||||
if (m_mediaStatus != oldMediaStatus)
|
if (m_mediaStatus != oldMediaStatus)
|
||||||
Q_EMIT mediaStatusChanged(m_mediaStatus);
|
Q_EMIT mediaStatusChanged(m_mediaStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load AVURLAsset
|
//Load AVURLAsset
|
||||||
//initialize asset using content's URL
|
//initialize asset using content's URL
|
||||||
NSString *urlString = [NSString stringWithUTF8String:content.canonicalUrl().toEncoded().constData()];
|
NSString *urlString = [NSString stringWithUTF8String:content.canonicalUrl().toEncoded().constData()];
|
||||||
@@ -494,7 +487,7 @@ qint64 AVFMediaPlayerSession::position() const
|
|||||||
AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
|
AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
|
||||||
|
|
||||||
if (!playerItem)
|
if (!playerItem)
|
||||||
return 0;
|
return m_requestedPosition != -1 ? m_requestedPosition : 0;
|
||||||
|
|
||||||
CMTime time = [playerItem currentTime];
|
CMTime time = [playerItem currentTime];
|
||||||
return static_cast<quint64>(float(time.value) / float(time.timescale) * 1000.0f);
|
return static_cast<quint64>(float(time.value) / float(time.timescale) * 1000.0f);
|
||||||
@@ -563,7 +556,16 @@ bool AVFMediaPlayerSession::isVideoAvailable() const
|
|||||||
|
|
||||||
bool AVFMediaPlayerSession::isSeekable() const
|
bool AVFMediaPlayerSession::isSeekable() const
|
||||||
{
|
{
|
||||||
return true;
|
return m_seekable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AVFMediaPlayerSession::setSeekable(bool seekable)
|
||||||
|
{
|
||||||
|
if (m_seekable == seekable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_seekable = seekable;
|
||||||
|
Q_EMIT seekableChanged(seekable);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMediaTimeRange AVFMediaPlayerSession::availablePlaybackRanges() const
|
QMediaTimeRange AVFMediaPlayerSession::availablePlaybackRanges() const
|
||||||
@@ -602,10 +604,10 @@ void AVFMediaPlayerSession::setPlaybackRate(qreal rate)
|
|||||||
m_rate = rate;
|
m_rate = rate;
|
||||||
|
|
||||||
AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
|
AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
|
||||||
|
if (player && m_state == QMediaPlayer::PlayingState)
|
||||||
if (player != 0 && m_state == QMediaPlayer::PlayingState) {
|
|
||||||
[player setRate:m_rate];
|
[player setRate:m_rate];
|
||||||
}
|
|
||||||
|
Q_EMIT playbackRateChanged(m_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVFMediaPlayerSession::setPosition(qint64 pos)
|
void AVFMediaPlayerSession::setPosition(qint64 pos)
|
||||||
@@ -614,14 +616,23 @@ void AVFMediaPlayerSession::setPosition(qint64 pos)
|
|||||||
qDebug() << Q_FUNC_INFO << pos;
|
qDebug() << Q_FUNC_INFO << pos;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( !isSeekable() || pos == position())
|
if (pos == position())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
|
AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
|
||||||
|
if (!playerItem) {
|
||||||
if (!playerItem)
|
m_requestedPosition = pos;
|
||||||
|
Q_EMIT positionChanged(m_requestedPosition);
|
||||||
return;
|
return;
|
||||||
|
} else if (!isSeekable()) {
|
||||||
|
if (m_requestedPosition != -1) {
|
||||||
|
m_requestedPosition = -1;
|
||||||
|
Q_EMIT positionChanged(position());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = qMax(qint64(0), pos);
|
||||||
if (duration() > 0)
|
if (duration() > 0)
|
||||||
pos = qMin(pos, duration());
|
pos = qMin(pos, duration());
|
||||||
|
|
||||||
@@ -655,8 +666,10 @@ void AVFMediaPlayerSession::play()
|
|||||||
processLoadStateChange();
|
processLoadStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_mediaStatus == QMediaPlayer::LoadedMedia || m_mediaStatus == QMediaPlayer::BufferedMedia)
|
if (m_mediaStatus == QMediaPlayer::LoadedMedia || m_mediaStatus == QMediaPlayer::BufferedMedia) {
|
||||||
[[(AVFMediaPlayerSessionObserver*)m_observer player] play];
|
// Setting the rate starts playback
|
||||||
|
[[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate];
|
||||||
|
}
|
||||||
|
|
||||||
//processLoadStateChange();
|
//processLoadStateChange();
|
||||||
Q_EMIT stateChanged(m_state);
|
Q_EMIT stateChanged(m_state);
|
||||||
@@ -697,8 +710,8 @@ void AVFMediaPlayerSession::stop()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_state = QMediaPlayer::StoppedState;
|
m_state = QMediaPlayer::StoppedState;
|
||||||
m_rate = 0.0f;
|
// AVPlayer doesn't have stop(), only pause() and play().
|
||||||
[[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate];
|
[[(AVFMediaPlayerSessionObserver*)m_observer player] pause];
|
||||||
setPosition(0);
|
setPosition(0);
|
||||||
|
|
||||||
if (m_videoOutput) {
|
if (m_videoOutput) {
|
||||||
@@ -716,21 +729,20 @@ void AVFMediaPlayerSession::setVolume(int volume)
|
|||||||
qDebug() << Q_FUNC_INFO << volume;
|
qDebug() << Q_FUNC_INFO << volume;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_volume == volume)
|
if (!m_volumeSupported) {
|
||||||
return;
|
|
||||||
|
|
||||||
AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
|
|
||||||
if (!player)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (![player respondsToSelector:@selector(setVolume:)]) {
|
|
||||||
qWarning("%s not implemented, requires iOS 7 or later", Q_FUNC_INFO);
|
qWarning("%s not implemented, requires iOS 7 or later", Q_FUNC_INFO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[player setVolume:volume / 100.0f];
|
if (m_volume == volume)
|
||||||
|
return;
|
||||||
|
|
||||||
m_volume = volume;
|
m_volume = volume;
|
||||||
|
|
||||||
|
AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
|
||||||
|
if (player)
|
||||||
|
[player setVolume:volume / 100.0f];
|
||||||
|
|
||||||
Q_EMIT volumeChanged(m_volume);
|
Q_EMIT volumeChanged(m_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -739,22 +751,21 @@ void AVFMediaPlayerSession::setMuted(bool muted)
|
|||||||
#ifdef QT_DEBUG_AVF
|
#ifdef QT_DEBUG_AVF
|
||||||
qDebug() << Q_FUNC_INFO << muted;
|
qDebug() << Q_FUNC_INFO << muted;
|
||||||
#endif
|
#endif
|
||||||
if (m_muted == muted)
|
|
||||||
return;
|
|
||||||
|
|
||||||
AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
|
if (!m_volumeSupported) {
|
||||||
if (!player)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// iOS: setMuted exists since iOS 7.0, thus check if it exists
|
|
||||||
if (![player respondsToSelector:@selector(setMuted:)]) {
|
|
||||||
qWarning("%s not implemented, requires iOS 7 or later", Q_FUNC_INFO);
|
qWarning("%s not implemented, requires iOS 7 or later", Q_FUNC_INFO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[player setMuted:muted];
|
if (m_muted == muted)
|
||||||
|
return;
|
||||||
|
|
||||||
m_muted = muted;
|
m_muted = muted;
|
||||||
|
|
||||||
|
AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
|
||||||
|
if (player)
|
||||||
|
[player setMuted:muted];
|
||||||
|
|
||||||
Q_EMIT mutedChanged(muted);
|
Q_EMIT mutedChanged(muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,6 +778,11 @@ void AVFMediaPlayerSession::processEOS()
|
|||||||
Q_EMIT positionChanged(position());
|
Q_EMIT positionChanged(position());
|
||||||
m_mediaStatus = QMediaPlayer::EndOfMedia;
|
m_mediaStatus = QMediaPlayer::EndOfMedia;
|
||||||
|
|
||||||
|
// At this point, frames should not be rendered anymore.
|
||||||
|
// Clear the output layer to make sure of that.
|
||||||
|
if (m_videoOutput)
|
||||||
|
m_videoOutput->setLayer(0);
|
||||||
|
|
||||||
Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
|
Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
|
||||||
Q_EMIT mediaStatusChanged(m_mediaStatus);
|
Q_EMIT mediaStatusChanged(m_mediaStatus);
|
||||||
}
|
}
|
||||||
@@ -801,6 +817,8 @@ void AVFMediaPlayerSession::processLoadStateChange()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSeekable([[playerItem seekableTimeRanges] count] > 0);
|
||||||
|
|
||||||
// Get the native size of the video, and reset the bounds of the player layer
|
// Get the native size of the video, and reset the bounds of the player layer
|
||||||
AVPlayerLayer *playerLayer = [(AVFMediaPlayerSessionObserver*)m_observer playerLayer];
|
AVPlayerLayer *playerLayer = [(AVFMediaPlayerSessionObserver*)m_observer playerLayer];
|
||||||
if (videoTrack && playerLayer) {
|
if (videoTrack && playerLayer) {
|
||||||
@@ -818,11 +836,16 @@ void AVFMediaPlayerSession::processLoadStateChange()
|
|||||||
if (m_duration != currentDuration)
|
if (m_duration != currentDuration)
|
||||||
Q_EMIT durationChanged(m_duration = currentDuration);
|
Q_EMIT durationChanged(m_duration = currentDuration);
|
||||||
|
|
||||||
|
if (m_requestedPosition != -1) {
|
||||||
|
setPosition(m_requestedPosition);
|
||||||
|
m_requestedPosition = -1;
|
||||||
|
}
|
||||||
|
|
||||||
newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia;
|
newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia;
|
||||||
|
|
||||||
if (m_state == QMediaPlayer::PlayingState && [(AVFMediaPlayerSessionObserver*)m_observer player]) {
|
if (m_state == QMediaPlayer::PlayingState && [(AVFMediaPlayerSessionObserver*)m_observer player]) {
|
||||||
|
// Setting the rate is enough to start playback, no need to call play()
|
||||||
[[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate];
|
[[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate];
|
||||||
[[(AVFMediaPlayerSessionObserver*)m_observer player] play];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,6 +860,10 @@ void AVFMediaPlayerSession::processPositionChange()
|
|||||||
|
|
||||||
void AVFMediaPlayerSession::processMediaLoadError()
|
void AVFMediaPlayerSession::processMediaLoadError()
|
||||||
{
|
{
|
||||||
|
if (m_requestedPosition != -1) {
|
||||||
|
m_requestedPosition = -1;
|
||||||
|
Q_EMIT positionChanged(position());
|
||||||
|
}
|
||||||
Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media"));
|
Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media"));
|
||||||
Q_EMIT mediaStatusChanged(m_mediaStatus = QMediaPlayer::InvalidMedia);
|
Q_EMIT mediaStatusChanged(m_mediaStatus = QMediaPlayer::InvalidMedia);
|
||||||
Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
|
Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
|
||||||
|
|||||||
@@ -144,4 +144,158 @@ TestCase {
|
|||||||
|
|
||||||
cameraLoader.sourceComponent = undefined;
|
cameraLoader.sourceComponent = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_supportedViewfinderResolutions_data() {
|
||||||
|
// see mockcameraviewfindersettingscontrol.h for expected values
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: "all",
|
||||||
|
minimumFrameRate: 0, maximumFrameRate: 0,
|
||||||
|
expectedResolutions: [
|
||||||
|
{ width: 320, height: 240 },
|
||||||
|
{ width: 640, height: 480 },
|
||||||
|
{ width: 1280, height: 720 },
|
||||||
|
{ width: 1920, height: 1080 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "invalid minimumFrameRate",
|
||||||
|
minimumFrameRate: 2, maximumFrameRate: 0,
|
||||||
|
expectedResolutions: [ ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "minimumFrameRate=5",
|
||||||
|
minimumFrameRate: 5, maximumFrameRate: 0,
|
||||||
|
expectedResolutions: [
|
||||||
|
{ width: 1920, height: 1080 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "minimumFrameRate=10",
|
||||||
|
minimumFrameRate: 10, maximumFrameRate: 0,
|
||||||
|
expectedResolutions: [
|
||||||
|
{ width: 1280, height: 720 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "minimumFrameRate=30",
|
||||||
|
minimumFrameRate: 30, maximumFrameRate: 0,
|
||||||
|
expectedResolutions: [
|
||||||
|
{ width: 320, height: 240 },
|
||||||
|
{ width: 640, height: 480 },
|
||||||
|
{ width: 1280, height: 720 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "invalid maximumFrameRate",
|
||||||
|
minimumFrameRate: 0, maximumFrameRate: 2,
|
||||||
|
expectedResolutions: [ ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "maximumFrameRate=10",
|
||||||
|
minimumFrameRate: 0, maximumFrameRate: 10,
|
||||||
|
expectedResolutions: [
|
||||||
|
{ width: 1280, height: 720 },
|
||||||
|
{ width: 1920, height: 1080 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "minimumFrameRate=10, maximumFrameRate=10",
|
||||||
|
minimumFrameRate: 10, maximumFrameRate: 10,
|
||||||
|
expectedResolutions: [
|
||||||
|
{ width: 1280, height: 720 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "minimumFrameRate=30, maximumFrameRate=30",
|
||||||
|
minimumFrameRate: 30, maximumFrameRate: 30,
|
||||||
|
expectedResolutions: [
|
||||||
|
{ width: 320, height: 240 },
|
||||||
|
{ width: 640, height: 480 },
|
||||||
|
{ width: 1280, height: 720 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_supportedViewfinderResolutions(data) {
|
||||||
|
cameraLoader.sourceComponent = cameraComponent;
|
||||||
|
var camera = cameraLoader.item;
|
||||||
|
|
||||||
|
var actualResolutions = camera.supportedViewfinderResolutions(data.minimumFrameRate, data.maximumFrameRate);
|
||||||
|
compare(actualResolutions.length, data.expectedResolutions.length);
|
||||||
|
for (var i = 0; i < actualResolutions.length; ++i) {
|
||||||
|
compare(actualResolutions[i].width, data.expectedResolutions[i].width);
|
||||||
|
compare(actualResolutions[i].height, data.expectedResolutions[i].height);
|
||||||
|
}
|
||||||
|
|
||||||
|
cameraLoader.sourceComponent = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_supportedViewfinderFrameRateRanges_data() {
|
||||||
|
// see mockcameraviewfindersettingscontrol.h for expected values
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: "all",
|
||||||
|
expectedFrameRateRanges: [
|
||||||
|
{ minimumFrameRate: 5, maximumFrameRate: 10 },
|
||||||
|
{ minimumFrameRate: 10, maximumFrameRate: 10 },
|
||||||
|
{ minimumFrameRate: 30, maximumFrameRate: 30 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "invalid",
|
||||||
|
resolution: { width: 452472, height: 444534 },
|
||||||
|
expectedFrameRateRanges: [ ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "320, 240",
|
||||||
|
resolution: { width: 320, height: 240 },
|
||||||
|
expectedFrameRateRanges: [
|
||||||
|
{ minimumFrameRate: 30, maximumFrameRate: 30 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "1280, 720",
|
||||||
|
resolution: { width: 1280, height: 720 },
|
||||||
|
expectedFrameRateRanges: [
|
||||||
|
{ minimumFrameRate: 10, maximumFrameRate: 10 },
|
||||||
|
{ minimumFrameRate: 30, maximumFrameRate: 30 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: "1920, 1080",
|
||||||
|
resolution: { width: 1920, height: 1080 },
|
||||||
|
expectedFrameRateRanges: [
|
||||||
|
{ minimumFrameRate: 5, maximumFrameRate: 10 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_supportedViewfinderFrameRateRanges(data) {
|
||||||
|
cameraLoader.sourceComponent = cameraComponent;
|
||||||
|
var camera = cameraLoader.item;
|
||||||
|
|
||||||
|
// Pass the resolution as an object
|
||||||
|
var actualFrameRateRanges = camera.supportedViewfinderFrameRateRanges(data.resolution);
|
||||||
|
compare(actualFrameRateRanges.length, data.expectedFrameRateRanges.length);
|
||||||
|
for (var i = 0; i < actualFrameRateRanges.length; ++i) {
|
||||||
|
compare(actualFrameRateRanges[i].minimumFrameRate, data.expectedFrameRateRanges[i].minimumFrameRate);
|
||||||
|
compare(actualFrameRateRanges[i].maximumFrameRate, data.expectedFrameRateRanges[i].maximumFrameRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the resolution as a size
|
||||||
|
if (typeof data.resolution !== 'undefined') {
|
||||||
|
actualFrameRateRanges = camera.supportedViewfinderFrameRateRanges(Qt.size(data.resolution.width, data.resolution.height));
|
||||||
|
compare(actualFrameRateRanges.length, data.expectedFrameRateRanges.length);
|
||||||
|
for (i = 0; i < actualFrameRateRanges.length; ++i) {
|
||||||
|
compare(actualFrameRateRanges[i].minimumFrameRate, data.expectedFrameRateRanges[i].minimumFrameRate);
|
||||||
|
compare(actualFrameRateRanges[i].maximumFrameRate, data.expectedFrameRateRanges[i].maximumFrameRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cameraLoader.sourceComponent = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user