Merge remote-tracking branch 'origin/5.5' into dev

Change-Id: I7ac7db69c37cc9e5c5241a25b9a874986a23a886
This commit is contained in:
Liang Qi
2015-06-03 10:58:51 +02:00
63 changed files with 1848 additions and 363 deletions

View File

@@ -277,26 +277,28 @@ void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool
return;
QSize currentViewfinderResolution = m_camera->previewSize();
const qreal aspectRatio = qreal(captureSize.width()) / qreal(captureSize.height());
if (currentViewfinderResolution.isValid() &&
qAbs(aspectRatio - (qreal(currentViewfinderResolution.width()) / currentViewfinderResolution.height())) < 0.01) {
return;
}
QSize adjustedViewfinderResolution;
QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes();
for (int i = previewSizes.count() - 1; i >= 0; --i) {
const QSize &size = previewSizes.at(i);
// search for viewfinder resolution with the same aspect ratio
if (qAbs(aspectRatio - (qreal(size.width()) / size.height())) < 0.01) {
adjustedViewfinderResolution = size;
break;
}
}
if (!adjustedViewfinderResolution.isValid()) {
qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio.");
return;
if (m_captureMode.testFlag(QCamera::CaptureVideo) && m_camera->getPreferredPreviewSizeForVideo().isEmpty()) {
// According to the Android doc, if getPreferredPreviewSizeForVideo() returns null, it means
// the preview size cannot be different from the capture size
adjustedViewfinderResolution = captureSize;
} else {
// search for viewfinder resolution with the same aspect ratio
const qreal aspectRatio = qreal(captureSize.width()) / qreal(captureSize.height());
QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes();
for (int i = previewSizes.count() - 1; i >= 0; --i) {
const QSize &size = previewSizes.at(i);
if (qAbs(aspectRatio - (qreal(size.width()) / size.height())) < 0.01) {
adjustedViewfinderResolution = size;
break;
}
}
if (!adjustedViewfinderResolution.isValid()) {
qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio.");
return;
}
}
if (currentViewfinderResolution != adjustedViewfinderResolution) {

View File

@@ -48,7 +48,6 @@ QAndroidCaptureSession::QAndroidCaptureSession(QAndroidCameraSession *cameraSess
, m_duration(0)
, m_state(QMediaRecorder::StoppedState)
, m_status(QMediaRecorder::UnloadedStatus)
, m_resolutionDirty(false)
, m_containerFormatDirty(true)
, m_videoSettingsDirty(true)
, m_audioSettingsDirty(true)
@@ -321,9 +320,6 @@ void QAndroidCaptureSession::setVideoSettings(const QVideoEncoderSettings &setti
if (!m_cameraSession || m_videoSettings == settings)
return;
if (m_videoSettings.resolution() != settings.resolution())
m_resolutionDirty = true;
m_videoSettings = settings;
m_videoSettingsDirty = true;
}
@@ -376,7 +372,6 @@ void QAndroidCaptureSession::applySettings()
if (m_cameraSession && m_cameraSession->camera() && m_videoSettingsDirty) {
if (m_videoSettings.resolution().isEmpty()) {
m_videoSettings.setResolution(m_defaultSettings.videoResolution);
m_resolutionDirty = true;
} else if (!m_supportedResolutions.contains(m_videoSettings.resolution())) {
// if the requested resolution is not supported, find the closest one
QSize reqSize = m_videoSettings.resolution();
@@ -388,7 +383,6 @@ void QAndroidCaptureSession::applySettings()
}
int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
m_videoSettings.setResolution(m_supportedResolutions.at(closestIndex));
m_resolutionDirty = true;
}
if (m_videoSettings.frameRate() <= 0)
@@ -413,12 +407,8 @@ void QAndroidCaptureSession::applySettings()
void QAndroidCaptureSession::updateViewfinder()
{
if (!m_resolutionDirty)
return;
m_cameraSession->camera()->stopPreview();
m_cameraSession->adjustViewfinderSize(m_videoSettings.resolution(), false);
m_resolutionDirty = false;
}
void QAndroidCaptureSession::restartViewfinder()

View File

@@ -161,7 +161,6 @@ private:
QString m_containerFormat;
QAudioEncoderSettings m_audioSettings;
QVideoEncoderSettings m_videoSettings;
bool m_resolutionDirty;
bool m_containerFormatDirty;
bool m_videoSettingsDirty;
bool m_audioSettingsDirty;

View File

@@ -786,6 +786,9 @@ QSize AndroidCameraPrivate::getPreferredPreviewSizeForVideo()
QJNIObjectPrivate size = m_parameters.callObjectMethod("getPreferredPreviewSizeForVideo",
"()Landroid/hardware/Camera$Size;");
if (!size.isValid())
return QSize();
return QSize(size.getField<jint>("width"), size.getField<jint>("height"));
}

View File

@@ -63,6 +63,11 @@ public:
AVCaptureVideoDataOutput *videoDataOutput() const;
#ifdef Q_OS_IOS
AVFCaptureFramesDelegate *captureDelegate() const;
void resetCaptureDelegate() const;
#endif
Q_SIGNALS:
void surfaceChanged(QAbstractVideoSurface *surface);
@@ -80,6 +85,7 @@ private:
QVideoFrame m_lastViewfinderFrame;
QMutex m_vfMutex;
dispatch_queue_t m_delegateQueue;
};
QT_END_NAMESPACE

View File

@@ -143,6 +143,7 @@ private:
- (void) captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection;
@end
@implementation AVFCaptureFramesDelegate
@@ -163,25 +164,23 @@ private:
Q_UNUSED(connection);
Q_UNUSED(captureOutput);
// NB: on iOS captureOutput/connection can be nil (when recording a video -
// avfmediaassetwriter).
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
int width = CVPixelBufferGetWidth(imageBuffer);
int height = CVPixelBufferGetHeight(imageBuffer);
QVideoFrame::PixelFormat format =
AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(CVPixelBufferGetPixelFormatType(imageBuffer));
QAbstractVideoBuffer *buffer = new CVPixelBufferVideoBuffer(imageBuffer);
if (format == QVideoFrame::Format_Invalid)
return;
QVideoFrame::PixelFormat format = QVideoFrame::Format_RGB32;
if ([captureOutput isKindOfClass:[AVCaptureVideoDataOutput class]]) {
NSDictionary *settings = ((AVCaptureVideoDataOutput *)captureOutput).videoSettings;
if (settings && [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) {
NSNumber *avf = [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey];
format = AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat([avf unsignedIntValue]);
}
}
QVideoFrame frame(buffer, QSize(width, height), format);
QVideoFrame frame(new CVPixelBufferVideoBuffer(imageBuffer), QSize(width, height), format);
m_renderer->syncHandleViewfinderFrame(frame);
}
@end
@@ -197,6 +196,8 @@ AVFCameraRendererControl::~AVFCameraRendererControl()
{
[m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
[m_viewfinderFramesDelegate release];
if (m_delegateQueue)
dispatch_release(m_delegateQueue);
}
QAbstractVideoSurface *AVFCameraRendererControl::surface() const
@@ -223,17 +224,10 @@ void AVFCameraRendererControl::configureAVCaptureSession(AVFCameraSession *camer
m_videoDataOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
// Configure video output
dispatch_queue_t queue = dispatch_queue_create("vf_queue", NULL);
m_delegateQueue = dispatch_queue_create("vf_queue", NULL);
[m_videoDataOutput
setSampleBufferDelegate:m_viewfinderFramesDelegate
queue:queue];
dispatch_release(queue);
// Specify the pixel format
m_videoDataOutput.videoSettings =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
queue:m_delegateQueue];
[m_cameraSession->captureSession() addOutput:m_videoDataOutput];
}
@@ -291,6 +285,20 @@ AVCaptureVideoDataOutput *AVFCameraRendererControl::videoDataOutput() const
return m_videoDataOutput;
}
#ifdef Q_OS_IOS
AVFCaptureFramesDelegate *AVFCameraRendererControl::captureDelegate() const
{
return m_viewfinderFramesDelegate;
}
void AVFCameraRendererControl::resetCaptureDelegate() const
{
[m_videoDataOutput setSampleBufferDelegate:m_viewfinderFramesDelegate queue:m_delegateQueue];
}
#endif
void AVFCameraRendererControl::handleViewfinderFrame()
{
QVideoFrame frame;
@@ -301,8 +309,10 @@ void AVFCameraRendererControl::handleViewfinderFrame()
}
if (m_surface && frame.isValid()) {
if (m_surface->isActive() && m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat())
if (m_surface->isActive() && (m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat()
|| m_surface->surfaceFormat().frameSize() != frame.size())) {
m_surface->stop();
}
if (!m_surface->isActive()) {
QVideoSurfaceFormat format(frame.size(), frame.pixelFormat());

View File

@@ -41,13 +41,13 @@
QT_BEGIN_NAMESPACE
class QCameraControl;
class QMediaRecorderControl;
class AVFCameraControl;
class AVFCameraInfoControl;
class AVFCameraMetaDataControl;
class AVFVideoWindowControl;
class AVFVideoWidgetControl;
class AVFCameraRendererControl;
class AVFMediaRecorderControl;
class AVFImageCaptureControl;
class AVFCameraSession;
class AVFCameraDeviceControl;
@@ -59,6 +59,8 @@ class AVFCameraViewfinderSettingsControl2;
class AVFCameraViewfinderSettingsControl;
class AVFImageEncoderControl;
class AVFCameraFlashControl;
class AVFMediaRecorderControl;
class AVFMediaRecorderControlIOS;
class AVFCameraService : public QMediaService
{
@@ -75,7 +77,8 @@ public:
AVFCameraDeviceControl *videoDeviceControl() const { return m_videoDeviceControl; }
AVFAudioInputSelectorControl *audioInputSelectorControl() const { return m_audioInputSelectorControl; }
AVFCameraMetaDataControl *metaDataControl() const { return m_metaDataControl; }
AVFMediaRecorderControl *recorderControl() const { return m_recorderControl; }
AVFMediaRecorderControl *recorderControl() const;
AVFMediaRecorderControlIOS *recorderControlIOS() const;
AVFImageCaptureControl *imageCaptureControl() const { return m_imageCaptureControl; }
AVFCameraFocusControl *cameraFocusControl() const { return m_cameraFocusControl; }
AVFCameraExposureControl *cameraExposureControl() const {return m_cameraExposureControl; }
@@ -94,7 +97,7 @@ private:
AVFAudioInputSelectorControl *m_audioInputSelectorControl;
AVFCameraRendererControl *m_videoOutput;
AVFCameraMetaDataControl *m_metaDataControl;
AVFMediaRecorderControl *m_recorderControl;
QMediaRecorderControl *m_recorderControl;
AVFImageCaptureControl *m_imageCaptureControl;
AVFCameraFocusControl *m_cameraFocusControl;
AVFCameraExposureControl *m_cameraExposureControl;

View File

@@ -56,6 +56,7 @@
#ifdef Q_OS_IOS
#include "avfcamerazoomcontrol.h"
#include "avfmediarecordercontrol_ios.h"
#endif
#include <private/qmediaplaylistnavigator_p.h>
@@ -74,7 +75,14 @@ AVFCameraService::AVFCameraService(QObject *parent):
m_audioInputSelectorControl = new AVFAudioInputSelectorControl(this);
m_metaDataControl = new AVFCameraMetaDataControl(this);
#ifndef Q_OS_IOS
// This will connect a slot to 'captureModeChanged'
// and will break viewfinder by attaching AVCaptureMovieFileOutput
// in this slot.
m_recorderControl = new AVFMediaRecorderControl(this);
#else
m_recorderControl = new AVFMediaRecorderControlIOS(this);
#endif
m_imageCaptureControl = new AVFImageCaptureControl(this);
m_cameraFocusControl = new AVFCameraFocusControl(this);
m_cameraExposureControl = 0;
@@ -97,6 +105,10 @@ AVFCameraService::~AVFCameraService()
{
m_cameraControl->setState(QCamera::UnloadedState);
#ifdef Q_OS_IOS
delete m_recorderControl;
#endif
if (m_videoOutput) {
m_session->setVideoOutput(0);
delete m_videoOutput;
@@ -205,4 +217,23 @@ void AVFCameraService::releaseControl(QMediaControl *control)
}
AVFMediaRecorderControl *AVFCameraService::recorderControl() const
{
#ifdef Q_OS_IOS
return 0;
#else
return static_cast<AVFMediaRecorderControl *>(m_recorderControl);
#endif
}
AVFMediaRecorderControlIOS *AVFCameraService::recorderControlIOS() const
{
#ifdef Q_OS_OSX
return 0;
#else
return static_cast<AVFMediaRecorderControlIOS *>(m_recorderControl);
#endif
}
#include "moc_avfcameraservice.cpp"

View File

@@ -83,6 +83,8 @@ public:
void removeProbe(AVFMediaVideoProbeControl *probe);
FourCharCode defaultCodec();
AVCaptureDeviceInput *videoInput() const {return m_videoInput;}
public Q_SLOTS:
void setState(QCamera::State state);

View File

@@ -283,12 +283,12 @@ void AVFCameraSession::setState(QCamera::State newState)
if (m_state == QCamera::ActiveState) {
Q_EMIT readyToConfigureConnections();
[m_captureSession commitConfiguration];
[m_captureSession startRunning];
m_defaultCodec = 0;
defaultCodec();
applyImageEncoderSettings();
applyViewfinderSettings();
[m_captureSession commitConfiguration];
[m_captureSession startRunning];
}
if (oldState == QCamera::ActiveState) {
@@ -374,8 +374,7 @@ void AVFCameraSession::applyViewfinderSettings()
}
}
if (!vfSettings.isNull())
vfControl->applySettings();
vfControl->applySettings();
}
}

View File

@@ -78,6 +78,74 @@ private:
bool m_locked;
};
struct AVFObjectDeleter {
static void cleanup(NSObject *obj)
{
if (obj)
[obj release];
}
};
template<class T>
class AVFScopedPointer : public QScopedPointer<NSObject, AVFObjectDeleter>
{
public:
AVFScopedPointer() {}
explicit AVFScopedPointer(T *ptr) : QScopedPointer(ptr) {}
operator T*() const
{
// Quite handy operator to enable Obj-C messages: [ptr someMethod];
return data();
}
T *data() const
{
return static_cast<T *>(QScopedPointer::data());
}
T *take()
{
return static_cast<T *>(QScopedPointer::take());
}
};
template<>
class AVFScopedPointer<dispatch_queue_t>
{
public:
AVFScopedPointer() : m_queue(0) {}
explicit AVFScopedPointer(dispatch_queue_t q) : m_queue(q) {}
~AVFScopedPointer()
{
if (m_queue)
dispatch_release(m_queue);
}
operator dispatch_queue_t() const
{
// Quite handy operator to enable Obj-C messages: [ptr someMethod];
return m_queue;
}
dispatch_queue_t data() const
{
return m_queue;
}
void reset(dispatch_queue_t q = 0)
{
if (m_queue)
dispatch_release(m_queue);
m_queue = q;
}
private:
dispatch_queue_t m_queue;
Q_DISABLE_COPY(AVFScopedPointer);
};
inline QSysInfo::MacVersion qt_OS_limit(QSysInfo::MacVersion osxVersion,
QSysInfo::MacVersion iosVersion)
{

View File

@@ -59,13 +59,20 @@ AVFPSRange qt_connection_framerates(AVCaptureConnection *videoConnection)
}
}
if (videoConnection.supportsVideoMaxFrameDuration) {
const CMTime cmMax = videoConnection.videoMaxFrameDuration;
if (CMTimeCompare(cmMax, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(cmMax))
newRange.first = 1. / maxSeconds;
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_5_0)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
#endif
{
if (videoConnection.supportsVideoMaxFrameDuration) {
const CMTime cmMax = videoConnection.videoMaxFrameDuration;
if (CMTimeCompare(cmMax, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(cmMax))
newRange.first = 1. / maxSeconds;
}
}
}
#endif
return newRange;
}

View File

@@ -76,31 +76,40 @@ void qt_set_framerate_limits(AVCaptureConnection *videoConnection,
return;
}
const qreal minFPS = settings.minimumFrameRate();
const qreal maxFPS = settings.maximumFrameRate();
CMTime minDuration = kCMTimeInvalid;
CMTime maxDuration = kCMTimeInvalid;
if (minFPS > 0. || maxFPS > 0.) {
if (maxFPS) {
if (!videoConnection.supportsVideoMinFrameDuration)
qDebugCamera() << Q_FUNC_INFO << "maximum framerate is not supported";
else
minDuration = CMTimeMake(1, maxFPS);
}
if (maxFPS > 0.) {
if (!videoConnection.supportsVideoMinFrameDuration)
qDebugCamera() << Q_FUNC_INFO << "maximum framerate is not supported";
else
minDuration = CMTimeMake(1, maxFPS);
}
if (videoConnection.supportsVideoMinFrameDuration)
videoConnection.videoMinFrameDuration = minDuration;
if (minFPS) {
const qreal minFPS = settings.minimumFrameRate();
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_5_0)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_9) {
if (minFPS > 0.)
qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
} else
#endif
{
CMTime maxDuration = kCMTimeInvalid;
if (minFPS > 0.) {
if (!videoConnection.supportsVideoMaxFrameDuration)
qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
else
maxDuration = CMTimeMake(1, minFPS);
}
if (videoConnection.supportsVideoMaxFrameDuration)
videoConnection.videoMaxFrameDuration = maxDuration;
}
if (videoConnection.supportsVideoMinFrameDuration)
videoConnection.videoMinFrameDuration = minDuration;
if (videoConnection.supportsVideoMaxFrameDuration)
videoConnection.videoMaxFrameDuration = maxDuration;
#else
if (minFPS > 0.)
qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
#endif
}
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
@@ -171,12 +180,21 @@ void qt_set_framerate_limits(AVCaptureDevice *captureDevice,
#ifdef Q_OS_IOS
[captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
[captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
#else
#else // Q_OS_OSX
if (CMTimeCompare(minFrameDuration, kCMTimeInvalid))
[captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
if (CMTimeCompare(maxFrameDuration, kCMTimeInvalid))
[captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
#endif
{
if (CMTimeCompare(maxFrameDuration, kCMTimeInvalid))
[captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
}
#endif // QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
#endif // Q_OS_OSX
}
#endif // Platform SDK >= 10.9, >= 7.0.
@@ -197,15 +215,23 @@ AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnec
fps.second = 1. / minSeconds; // Max FPS = 1 / MinDuration.
}
const CMTime maxDuration = captureDevice.activeVideoMaxFrameDuration;
if (CMTimeCompare(maxDuration, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(maxDuration))
fps.first = 1. / maxSeconds; // Min FPS = 1 / MaxDuration.
}
} else {
#else
{
#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
#if QT_OSX_DEPLOYMENT_TARGET_BELOW(__MAC_10_9)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
#endif
{
const CMTime maxDuration = captureDevice.activeVideoMaxFrameDuration;
if (CMTimeCompare(maxDuration, kCMTimeInvalid)) {
if (const Float64 maxSeconds = CMTimeGetSeconds(maxDuration))
fps.first = 1. / maxSeconds; // Min FPS = 1 / MaxDuration.
}
}
#endif // QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
} else {
#else // OSX < 10.7 or iOS < 7.0
{
#endif // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
fps = qt_connection_framerates(videoConnection);
}
@@ -459,13 +485,7 @@ QVector<QVideoFrame::PixelFormat> AVFCameraViewfinderSettingsControl2::viewfinde
Q_ASSERT(m_videoOutput);
QVector<QVideoFrame::PixelFormat> qtFormats;
QList<QVideoFrame::PixelFormat> filter;
NSArray *pixelFormats = [m_videoOutput availableVideoCVPixelFormatTypes];
const QAbstractVideoSurface *surface = m_service->videoOutput() ? m_service->videoOutput()->surface() : 0;
if (surface)
filter = surface->supportedPixelFormats();
for (NSObject *obj in pixelFormats) {
if (![obj isKindOfClass:[NSNumber class]])
@@ -474,8 +494,8 @@ QVector<QVideoFrame::PixelFormat> AVFCameraViewfinderSettingsControl2::viewfinde
NSNumber *formatAsNSNumber = static_cast<NSNumber *>(obj);
// It's actually FourCharCode (== UInt32):
const QVideoFrame::PixelFormat qtFormat(QtPixelFormatFromCVFormat([formatAsNSNumber unsignedIntValue]));
if (qtFormat != QVideoFrame::Format_Invalid && (!surface || filter.contains(qtFormat))
&& !qtFormats.contains(qtFormat)) { // Can happen, for example, with 8BiPlanar existing in video/full range.
if (qtFormat != QVideoFrame::Format_Invalid
&& !qtFormats.contains(qtFormat)) { // Can happen, for example, with 8BiPlanar existing in video/full range.
qtFormats << qtFormat;
}
}
@@ -550,22 +570,33 @@ void AVFCameraViewfinderSettingsControl2::applySettings()
#endif
unsigned avfPixelFormat = 0;
if (m_settings.pixelFormat() != QVideoFrame::Format_Invalid &&
convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) {
[videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
} else {
// We have to set the pixel format, otherwise AVFoundation can change it to something we do not support.
if (NSObject *oldFormat = [m_videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) {
[videoSettings setObject:oldFormat forKey:(id)kCVPixelBufferPixelFormatTypeKey];
} else {
[videoSettings setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
if (!convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) {
// 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
const QVector<QVideoFrame::PixelFormat> deviceFormats = viewfinderPixelFormats();
QList<QVideoFrame::PixelFormat> surfaceFormats;
if (m_service->videoOutput() && m_service->videoOutput()->surface())
surfaceFormats = m_service->videoOutput()->surface()->supportedPixelFormats();
QVideoFrame::PixelFormat format = deviceFormats.first();
for (int i = 0; i < surfaceFormats.count(); ++i) {
const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i);
if (deviceFormats.contains(surfaceFormat)) {
format = surfaceFormat;
break;
}
}
CVPixelFormatFromQtFormat(format, avfPixelFormat);
}
if (videoSettings.count)
if (avfPixelFormat != 0) {
[videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
m_videoOutput.videoSettings = videoSettings;
}
qt_set_framerate_limits(m_captureDevice, m_videoConnection, m_settings);
}

View File

@@ -128,11 +128,11 @@ void AVFCameraZoomControl::cameraStateChanged()
return;
}
if (captureDevice.activeFormat.videoMaxZoomFactor > 1.
&& !qFuzzyCompare(m_maxZoomFactor, captureDevice.activeFormat.videoMaxZoomFactor)) {
m_maxZoomFactor = captureDevice.activeFormat.videoMaxZoomFactor;
Q_EMIT maximumDigitalZoomChanged(m_maxZoomFactor);
if (captureDevice.activeFormat.videoMaxZoomFactor > 1.) {
if (!qFuzzyCompare(m_maxZoomFactor, captureDevice.activeFormat.videoMaxZoomFactor)) {
m_maxZoomFactor = captureDevice.activeFormat.videoMaxZoomFactor;
Q_EMIT maximumDigitalZoomChanged(m_maxZoomFactor);
}
} else if (!qFuzzyCompare(m_maxZoomFactor, CGFloat(1.))) {
m_maxZoomFactor = 1.;

View File

@@ -0,0 +1,119 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef AVFMEDIAASSETWRITER_H
#define AVFMEDIAASSETWRITER_H
#include "avfcamerautility.h"
#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmutex.h>
#include <AVFoundation/AVFoundation.h>
QT_BEGIN_NAMESPACE
class AVFCameraService;
class AVFMediaAssetWriterDelegate
{
public:
virtual ~AVFMediaAssetWriterDelegate();
virtual void assetWriterStarted() = 0;
virtual void assetWriterFailedToStart() = 0;
virtual void assetWriterFailedToStop() = 0;
virtual void assetWriterFinished() = 0;
};
typedef QAtomicInteger<bool> AVFAtomicBool;
typedef QAtomicInteger<qint64> AVFAtomicInt64;
QT_END_NAMESPACE
// TODO: any reasonable error handling requires smart pointers, otherwise it's getting crappy immediately.
@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate,
AVCaptureAudioDataOutputSampleBufferDelegate>
{
@private
AVFCameraService *m_service;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVAssetWriterInput> m_cameraWriterInput;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVCaptureDeviceInput> m_audioInput;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVCaptureAudioDataOutput> m_audioOutput;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVAssetWriterInput> m_audioWriterInput;
// High priority serial queue for video output:
QT_MANGLE_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_videoQueue;
// Serial queue for audio output:
QT_MANGLE_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_audioQueue;
// Queue to write sample buffers:
__weak dispatch_queue_t m_writerQueue;
QT_MANGLE_NAMESPACE(AVFScopedPointer)<AVAssetWriter> m_assetWriter;
// Delegate's queue.
__weak dispatch_queue_t m_delegateQueue;
// TODO: QPointer??
QT_PREPEND_NAMESPACE(AVFMediaAssetWriterDelegate) *m_delegate;
bool m_setStartTime;
QT_MANGLE_NAMESPACE(AVFAtomicBool) m_stopped;
bool m_stoppedInternal;
bool m_aborted;
QT_MANGLE_NAMESPACE(QMutex) m_writerMutex;
@public
QT_MANGLE_NAMESPACE(AVFAtomicInt64) m_durationInMs;
@private
CMTime m_startTime;
CMTime m_lastTimeStamp;
}
- (id)initWithQueue:(dispatch_queue_t)writerQueue
delegate:(QT_PREPEND_NAMESPACE(AVFMediaAssetWriterDelegate) *)delegate
delegateQueue:(dispatch_queue_t)delegateQueue;
- (bool)setupWithFileURL:(NSURL *)fileURL
cameraService:(QT_PREPEND_NAMESPACE(AVFCameraService) *)service;
- (void)start;
- (void)stop;
// This to be called if control's dtor gets called,
// on the control's thread.
- (void)abort;
@end
#endif // AVFMEDIAASSETWRITER_H

View File

@@ -0,0 +1,474 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "avfaudioinputselectorcontrol.h"
#include "avfcamerarenderercontrol.h"
#include "avfmediaassetwriter.h"
#include "avfcameraservice.h"
#include "avfcamerasession.h"
#include "avfcameradebug.h"
//#include <QtCore/qmutexlocker.h>
#include <QtCore/qsysinfo.h>
QT_USE_NAMESPACE
namespace {
bool qt_camera_service_isValid(AVFCameraService *service)
{
if (!service || !service->session())
return false;
AVFCameraSession *session = service->session();
if (!session->captureSession())
return false;
if (!session->videoInput())
return false;
if (!service->videoOutput()
|| !service->videoOutput()->videoDataOutput()) {
return false;
}
return true;
}
}
AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate()
{
}
@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) (PrivateAPI)
- (bool)addAudioCapture;
- (bool)addWriterInputs;
- (void)setQueues;
- (NSDictionary *)videoSettings;
- (NSDictionary *)audioSettings;
- (void)updateDuration:(CMTime)newTimeStamp;
@end
@implementation QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)
- (id)initWithQueue:(dispatch_queue_t)writerQueue
delegate:(AVFMediaAssetWriterDelegate *)delegate
delegateQueue:(dispatch_queue_t)delegateQueue
{
Q_ASSERT(writerQueue);
Q_ASSERT(delegate);
Q_ASSERT(delegateQueue);
if (self = [super init]) {
m_writerQueue = writerQueue;
m_delegate = delegate;
m_delegateQueue = delegateQueue;
m_setStartTime = true;
m_stopped.store(true);
m_stoppedInternal = false;
m_aborted = false;
m_startTime = kCMTimeInvalid;
m_lastTimeStamp = kCMTimeInvalid;
m_durationInMs.store(0);
}
return self;
}
- (bool)setupWithFileURL:(NSURL *)fileURL
cameraService:(AVFCameraService *)service
{
Q_ASSERT(fileURL);
if (!qt_camera_service_isValid(service)) {
qDebugCamera() << Q_FUNC_INFO << "invalid camera service";
return false;
}
m_service = service;
m_videoQueue.reset(dispatch_queue_create("video-output-queue", DISPATCH_QUEUE_SERIAL));
if (!m_videoQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create video queue";
return false;
}
dispatch_set_target_queue(m_videoQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
m_audioQueue.reset(dispatch_queue_create("audio-output-queue", DISPATCH_QUEUE_SERIAL));
if (!m_audioQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create audio queue";
// But we still can write video!
}
m_assetWriter.reset([[AVAssetWriter alloc] initWithURL:fileURL fileType:AVFileTypeQuickTimeMovie error:nil]);
if (!m_assetWriter) {
qDebugCamera() << Q_FUNC_INFO << "failed to create asset writer";
return false;
}
bool audioCaptureOn = false;
if (m_audioQueue)
audioCaptureOn = [self addAudioCapture];
if (![self addWriterInputs]) {
if (audioCaptureOn) {
AVCaptureSession *session = m_service->session()->captureSession();
[session removeOutput:m_audioOutput];
[session removeInput:m_audioInput];
m_audioOutput.reset();
m_audioInput.reset();
}
m_assetWriter.reset();
return false;
}
// Ready to start ...
return true;
}
- (void)start
{
// To be executed on a writer's queue.
const QMutexLocker lock(&m_writerMutex);
if (m_aborted)
return;
[self setQueues];
m_setStartTime = true;
m_stopped.store(false);
m_stoppedInternal = false;
[m_assetWriter startWriting];
AVCaptureSession *session = m_service->session()->captureSession();
if (!session.running)
[session startRunning];
}
- (void)stop
{
// To be executed on a writer's queue.
const QMutexLocker lock(&m_writerMutex);
if (m_aborted)
return;
if (m_stopped.load()) {
// Should never happen, but ...
// if something went wrong in a recorder control
// and we set state stopped without starting first ...
// m_stoppedIntenal will be false, but m_stopped - true.
return;
}
m_stopped.store(true);
m_stoppedInternal = true;
[m_assetWriter finishWritingWithCompletionHandler:^{
// TODO: make sure the session exist and we can call stop/remove on it.
AVCaptureSession *session = m_service->session()->captureSession();
[session stopRunning];
[session removeOutput:m_audioOutput];
[session removeInput:m_audioInput];
dispatch_async(m_delegateQueue, ^{
m_delegate->assetWriterFinished();
});
}];
}
- (void)abort
{
// To be executed on any thread, prevents writer from
// accessing any external object (probably deleted by this time)
const QMutexLocker lock(&m_writerMutex);
m_aborted = true;
if (m_stopped.load())
return;
[m_assetWriter finishWritingWithCompletionHandler:^{
}];
}
- (void)setStartTimeFrom:(CMSampleBufferRef)sampleBuffer
{
// Writer's queue only.
Q_ASSERT(m_setStartTime);
Q_ASSERT(sampleBuffer);
dispatch_async(m_delegateQueue, ^{
m_delegate->assetWriterStarted();
});
m_durationInMs.store(0);
m_startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
m_lastTimeStamp = m_startTime;
[m_assetWriter startSessionAtSourceTime:m_startTime];
m_setStartTime = false;
}
- (void)writeVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
Q_ASSERT(sampleBuffer);
// This code is executed only on a writer's queue, but
// it can access potentially deleted objects, so we
// need a lock and m_aborted flag test.
{
const QMutexLocker lock(&m_writerMutex);
if (!m_aborted && !m_stoppedInternal) {
if (m_setStartTime)
[self setStartTimeFrom:sampleBuffer];
if (m_cameraWriterInput.data().readyForMoreMediaData) {
[self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
[m_cameraWriterInput appendSampleBuffer:sampleBuffer];
}
}
}
CFRelease(sampleBuffer);
}
- (void)writeAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
// This code is executed only on a writer's queue.
// it does not touch any shared/external data.
Q_ASSERT(sampleBuffer);
{
const QMutexLocker lock(&m_writerMutex);
if (!m_aborted && !m_stoppedInternal) {
if (m_setStartTime)
[self setStartTimeFrom:sampleBuffer];
if (m_audioWriterInput.data().readyForMoreMediaData) {
[self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
[m_audioWriterInput appendSampleBuffer:sampleBuffer];
}
}
}
CFRelease(sampleBuffer);
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
Q_UNUSED(connection)
// This method can be called on either video or audio queue, never on a writer's
// queue - it does not access any shared data except this atomic flag below.
if (m_stopped.load())
return;
// Even if we are stopped now, we still do not access any data.
if (!CMSampleBufferDataIsReady(sampleBuffer)) {
qDebugCamera() << Q_FUNC_INFO << "sample buffer is not ready, skipping.";
return;
}
CFRetain(sampleBuffer);
if (captureOutput != m_audioOutput.data()) {
{
const QMutexLocker lock(&m_writerMutex);
if (m_aborted || m_stoppedInternal) {
CFRelease(sampleBuffer);
return;
}
// Find renderercontrol's delegate and invoke its method to
// show updated viewfinder's frame.
if (m_service && m_service->videoOutput()) {
NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *vfDelegate =
(NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *)m_service->videoOutput()->captureDelegate();
if (vfDelegate)
[vfDelegate captureOutput:nil didOutputSampleBuffer:sampleBuffer fromConnection:nil];
}
}
dispatch_async(m_writerQueue, ^{
[self writeVideoSampleBuffer:sampleBuffer];
});
} else {
dispatch_async(m_writerQueue, ^{
[self writeAudioSampleBuffer:sampleBuffer];
});
}
}
- (bool)addAudioCapture
{
Q_ASSERT(m_service && m_service->session() && m_service->session()->captureSession());
if (!m_service->audioInputSelectorControl())
return false;
AVCaptureSession *captureSession = m_service->session()->captureSession();
AVCaptureDevice *audioDevice = m_service->audioInputSelectorControl()->createCaptureDevice();
if (!audioDevice) {
qWarning() << Q_FUNC_INFO << "no audio input device available";
return false;
} else {
NSError *error = nil;
m_audioInput.reset([[AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error] retain]);
if (!m_audioInput || error) {
qWarning() << Q_FUNC_INFO << "failed to create audio device input";
m_audioInput.reset();
return false;
} else if (![captureSession canAddInput:m_audioInput]) {
qWarning() << Q_FUNC_INFO << "could not connect the audio input";
m_audioInput.reset();
return false;
} else {
[captureSession addInput:m_audioInput];
}
}
m_audioOutput.reset([[AVCaptureAudioDataOutput alloc] init]);
if (m_audioOutput && [captureSession canAddOutput:m_audioOutput]) {
[captureSession addOutput:m_audioOutput];
} else {
qDebugCamera() << Q_FUNC_INFO << "failed to add audio output";
[captureSession removeInput:m_audioInput];
m_audioInput.reset();
m_audioOutput.reset();
return false;
}
return true;
}
- (bool)addWriterInputs
{
Q_ASSERT(m_service && m_service->videoOutput()
&& m_service->videoOutput()->videoDataOutput());
Q_ASSERT(m_assetWriter);
m_cameraWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:[self videoSettings]]);
if (!m_cameraWriterInput) {
qDebugCamera() << Q_FUNC_INFO << "failed to create camera writer input";
return false;
}
if ([m_assetWriter canAddInput:m_cameraWriterInput]) {
[m_assetWriter addInput:m_cameraWriterInput];
} else {
qDebugCamera() << Q_FUNC_INFO << "failed to add camera writer input";
m_cameraWriterInput.reset();
return false;
}
m_cameraWriterInput.data().expectsMediaDataInRealTime = YES;
if (m_audioOutput) {
m_audioWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:[self audioSettings]]);
if (!m_audioWriterInput) {
qDebugCamera() << Q_FUNC_INFO << "failed to create audio writer input";
// But we still can record video.
} else if ([m_assetWriter canAddInput:m_audioWriterInput]) {
[m_assetWriter addInput:m_audioWriterInput];
m_audioWriterInput.data().expectsMediaDataInRealTime = YES;
} else {
qDebugCamera() << Q_FUNC_INFO << "failed to add audio writer input";
m_audioWriterInput.reset();
// We can (still) write video though ...
}
}
return true;
}
- (void)setQueues
{
Q_ASSERT(m_service && m_service->videoOutput() && m_service->videoOutput()->videoDataOutput());
Q_ASSERT(m_videoQueue);
[m_service->videoOutput()->videoDataOutput() setSampleBufferDelegate:self queue:m_videoQueue];
if (m_audioOutput) {
Q_ASSERT(m_audioQueue);
[m_audioOutput setSampleBufferDelegate:self queue:m_audioQueue];
}
}
- (NSDictionary *)videoSettings
{
// TODO: these settings should be taken from
// the video encoding settings control.
// For now we either take recommended (iOS >= 7.0)
// or some hardcoded values - they are still better than nothing (nil).
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
AVCaptureVideoDataOutput *videoOutput = m_service->videoOutput()->videoDataOutput();
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0 && videoOutput)
return [videoOutput recommendedVideoSettingsForAssetWriterWithOutputFileType:AVFileTypeQuickTimeMovie];
#endif
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:1280], AVVideoWidthKey,
[NSNumber numberWithInt:720], AVVideoHeightKey, nil];
return videoSettings;
}
- (NSDictionary *)audioSettings
{
// TODO: these settings should be taken from
// the video/audio encoder settings control.
// For now we either take recommended (iOS >= 7.0)
// or nil - this seems to be good enough.
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0 && m_audioOutput)
return [m_audioOutput recommendedAudioSettingsForAssetWriterWithOutputFileType:AVFileTypeQuickTimeMovie];
#endif
return nil;
}
- (void)updateDuration:(CMTime)newTimeStamp
{
Q_ASSERT(CMTimeCompare(m_startTime, kCMTimeInvalid));
Q_ASSERT(CMTimeCompare(m_lastTimeStamp, kCMTimeInvalid));
if (CMTimeCompare(newTimeStamp, m_lastTimeStamp) > 0) {
const CMTime duration = CMTimeSubtract(newTimeStamp, m_startTime);
if (!CMTimeCompare(duration, kCMTimeInvalid))
return;
m_durationInMs.store(CMTimeGetSeconds(duration) * 1000);
m_lastTimeStamp = newTimeStamp;
}
}
@end

View File

@@ -0,0 +1,108 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef AVFMEDIARECORDERCONTROL_IOS_H
#define AVFMEDIARECORDERCONTROL_IOS_H
#include "avfmediaassetwriter.h"
#include "avfstoragelocation.h"
#include "avfcamerautility.h"
#include <QtMultimedia/qmediarecordercontrol.h>
#include <QtCore/qglobal.h>
#include <QtCore/qurl.h>
#include <AVFoundation/AVFoundation.h>
QT_BEGIN_NAMESPACE
class AVFCameraService;
class QString;
class QUrl;
class AVFMediaRecorderControlIOS : public QMediaRecorderControl, public AVFMediaAssetWriterDelegate
{
Q_OBJECT
public:
AVFMediaRecorderControlIOS(AVFCameraService *service, QObject *parent = 0);
~AVFMediaRecorderControlIOS();
QUrl outputLocation() const Q_DECL_OVERRIDE;
bool setOutputLocation(const QUrl &location) Q_DECL_OVERRIDE;
QMediaRecorder::State state() const Q_DECL_OVERRIDE;
QMediaRecorder::Status status() const Q_DECL_OVERRIDE;
qint64 duration() const Q_DECL_OVERRIDE;
bool isMuted() const Q_DECL_OVERRIDE;
qreal volume() const Q_DECL_OVERRIDE;
void applySettings() Q_DECL_OVERRIDE;
public Q_SLOTS:
void setState(QMediaRecorder::State state) Q_DECL_OVERRIDE;
void setMuted(bool muted) Q_DECL_OVERRIDE;
void setVolume(qreal volume) Q_DECL_OVERRIDE;
// Writer delegate:
private:
void assetWriterStarted() Q_DECL_OVERRIDE;
void assetWriterFailedToStart() Q_DECL_OVERRIDE;
void assetWriterFailedToStop() Q_DECL_OVERRIDE;
void assetWriterFinished() Q_DECL_OVERRIDE;
private Q_SLOTS:
void captureModeChanged(QCamera::CaptureModes);
void cameraStatusChanged(QCamera::Status newStatus);
private:
void stopWriter();
AVFCameraService *m_service;
AVFScopedPointer<dispatch_queue_t> m_writerQueue;
AVFScopedPointer<QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)> m_writer;
QUrl m_outputLocation;
AVFStorageLocation m_storageLocation;
QMediaRecorder::State m_state;
QMediaRecorder::Status m_lastStatus;
};
QT_END_NAMESPACE
#endif // AVFMEDIARECORDERCONTROL_IOS_H

View File

@@ -0,0 +1,349 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "avfmediarecordercontrol_ios.h"
#include "avfcamerarenderercontrol.h"
#include "avfcamerasession.h"
#include "avfcameracontrol.h"
#include "avfcameraservice.h"
#include "avfcameradebug.h"
#include <QtCore/qdebug.h>
QT_USE_NAMESPACE
namespace {
bool qt_is_writable_file_URL(NSURL *fileURL)
{
Q_ASSERT(fileURL);
if (![fileURL isFileURL])
return false;
if (NSString *path = [[fileURL path] stringByExpandingTildeInPath]) {
return [[NSFileManager defaultManager]
isWritableFileAtPath:[path stringByDeletingLastPathComponent]];
}
return false;
}
bool qt_file_exists(NSURL *fileURL)
{
Q_ASSERT(fileURL);
if (NSString *path = [[fileURL path] stringByExpandingTildeInPath])
return [[NSFileManager defaultManager] fileExistsAtPath:path];
return false;
}
}
AVFMediaRecorderControlIOS::AVFMediaRecorderControlIOS(AVFCameraService *service, QObject *parent)
: QMediaRecorderControl(parent)
, m_service(service)
, m_state(QMediaRecorder::StoppedState)
, m_lastStatus(QMediaRecorder::UnloadedStatus)
{
Q_ASSERT(service);
m_writerQueue.reset(dispatch_queue_create("asset-writer-queue", DISPATCH_QUEUE_SERIAL));
if (!m_writerQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer's queue";
return;
}
m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithQueue:m_writerQueue
delegate:this delegateQueue:dispatch_get_main_queue()]);
if (!m_writer) {
qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer";
return;
}
AVFCameraControl *cameraControl = m_service->cameraControl();
if (!cameraControl) {
qDebugCamera() << Q_FUNC_INFO << "camera control is nil";
return;
}
connect(cameraControl, SIGNAL(captureModeChanged(QCamera::CaptureModes)),
SLOT(captureModeChanged(QCamera::CaptureModes)));
connect(cameraControl, SIGNAL(statusChanged(QCamera::Status)),
SLOT(cameraStatusChanged(QCamera::Status)));
}
AVFMediaRecorderControlIOS::~AVFMediaRecorderControlIOS()
{
[m_writer abort];
}
QUrl AVFMediaRecorderControlIOS::outputLocation() const
{
return m_outputLocation;
}
bool AVFMediaRecorderControlIOS::setOutputLocation(const QUrl &location)
{
m_outputLocation = location;
return location.scheme() == QLatin1String("file") || location.scheme().isEmpty();
}
QMediaRecorder::State AVFMediaRecorderControlIOS::state() const
{
return m_state;
}
QMediaRecorder::Status AVFMediaRecorderControlIOS::status() const
{
return m_lastStatus;
}
qint64 AVFMediaRecorderControlIOS::duration() const
{
return m_writer.data()->m_durationInMs.load();
}
bool AVFMediaRecorderControlIOS::isMuted() const
{
return false;
}
qreal AVFMediaRecorderControlIOS::volume() const
{
return 1.;
}
void AVFMediaRecorderControlIOS::applySettings()
{
}
void AVFMediaRecorderControlIOS::setState(QMediaRecorder::State state)
{
Q_ASSERT(m_service->session()
&& m_service->session()->captureSession());
if (!m_writer) {
qDebugCamera() << Q_FUNC_INFO << "Invalid recorder";
return;
}
if (state == m_state)
return;
switch (state) {
case QMediaRecorder::RecordingState:
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
if (!(cameraControl->captureMode() & QCamera::CaptureVideo)) {
qDebugCamera() << Q_FUNC_INFO << "wrong capture mode, CaptureVideo expected";
Q_EMIT error(QMediaRecorder::ResourceError, tr("Failed to start recording"));
return;
}
if (cameraControl->status() != QCamera::ActiveStatus) {
qDebugCamera() << Q_FUNC_INFO << "can not start record while camera is not active";
Q_EMIT error(QMediaRecorder::ResourceError, tr("Failed to start recording"));
return;
}
const QString path(m_outputLocation.scheme() == QLatin1String("file") ?
m_outputLocation.path() : m_outputLocation.toString());
const QUrl fileURL(QUrl::fromLocalFile(m_storageLocation.generateFileName(path, QCamera::CaptureVideo,
QLatin1String("clip_"), QLatin1String("mp4"))));
NSURL *nsFileURL = fileURL.toNSURL();
if (!nsFileURL) {
qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL;
Q_EMIT error(QMediaRecorder::ResourceError, tr("Invalid output file URL"));
return;
}
if (!qt_is_writable_file_URL(nsFileURL)) {
qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
<< "(the location is not writable)";
Q_EMIT error(QMediaRecorder::ResourceError, tr("Non-writeable file location"));
return;
}
if (qt_file_exists(nsFileURL)) {
// We test for/handle this error here since AWAssetWriter will raise an
// Objective-C exception, which is not good at all.
qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
<< "(file already exists)";
Q_EMIT error(QMediaRecorder::ResourceError, tr("File already exists"));
return;
}
AVCaptureSession *session = m_service->session()->captureSession();
// We stop session now so that no more frames for renderer's queue
// generated, will restart in assetWriterStarted.
[session stopRunning];
if ([m_writer setupWithFileURL:nsFileURL cameraService:m_service]) {
m_state = QMediaRecorder::RecordingState;
m_lastStatus = QMediaRecorder::StartingStatus;
Q_EMIT actualLocationChanged(fileURL);
Q_EMIT stateChanged(m_state);
Q_EMIT statusChanged(m_lastStatus);
dispatch_async(m_writerQueue, ^{
[m_writer start];
});
} else {
[session startRunning];
Q_EMIT error(QMediaRecorder::FormatError, tr("Failed to start recording"));
}
} break;
case QMediaRecorder::PausedState:
{
Q_EMIT error(QMediaRecorder::FormatError, tr("Recording pause not supported"));
return;
} break;
case QMediaRecorder::StoppedState:
{
// Do not check the camera status, we can stop if we started.
stopWriter();
}
}
}
void AVFMediaRecorderControlIOS::setMuted(bool muted)
{
Q_UNUSED(muted)
qDebugCamera() << Q_FUNC_INFO << "not implemented";
}
void AVFMediaRecorderControlIOS::setVolume(qreal volume)
{
Q_UNUSED(volume);
qDebugCamera() << Q_FUNC_INFO << "not implemented";
}
void AVFMediaRecorderControlIOS::assetWriterStarted()
{
m_lastStatus = QMediaRecorder::RecordingStatus;
Q_EMIT statusChanged(QMediaRecorder::RecordingStatus);
}
void AVFMediaRecorderControlIOS::assetWriterFailedToStart()
{
}
void AVFMediaRecorderControlIOS::assetWriterFailedToStop()
{
}
void AVFMediaRecorderControlIOS::assetWriterFinished()
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
const QMediaRecorder::Status lastStatus = m_lastStatus;
if (cameraControl->captureMode() & QCamera::CaptureVideo)
m_lastStatus = QMediaRecorder::LoadedStatus;
else
m_lastStatus = QMediaRecorder::UnloadedStatus;
m_service->videoOutput()->resetCaptureDelegate();
[m_service->session()->captureSession() startRunning];
if (m_lastStatus != lastStatus)
Q_EMIT statusChanged(m_lastStatus);
}
void AVFMediaRecorderControlIOS::captureModeChanged(QCamera::CaptureModes newMode)
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
const QMediaRecorder::Status lastStatus = m_lastStatus;
if (newMode & QCamera::CaptureVideo) {
if (cameraControl->status() == QCamera::ActiveStatus)
m_lastStatus = QMediaRecorder::LoadedStatus;
} else {
if (m_lastStatus == QMediaRecorder::RecordingStatus)
return stopWriter();
else
m_lastStatus = QMediaRecorder::UnloadedStatus;
}
if (m_lastStatus != lastStatus)
Q_EMIT statusChanged(m_lastStatus);
}
void AVFMediaRecorderControlIOS::cameraStatusChanged(QCamera::Status newStatus)
{
AVFCameraControl *cameraControl = m_service->cameraControl();
Q_ASSERT(cameraControl);
const QMediaRecorder::Status lastStatus = m_lastStatus;
const bool isCapture = cameraControl->captureMode() & QCamera::CaptureVideo;
if (newStatus == QCamera::StartingStatus) {
if (isCapture && m_lastStatus == QMediaRecorder::UnloadedStatus)
m_lastStatus = QMediaRecorder::LoadingStatus;
} else if (newStatus == QCamera::ActiveStatus) {
if (isCapture && m_lastStatus == QMediaRecorder::LoadingStatus)
m_lastStatus = QMediaRecorder::LoadedStatus;
} else {
if (m_lastStatus == QMediaRecorder::RecordingStatus)
return stopWriter();
if (newStatus == QCamera::UnloadedStatus)
m_lastStatus = QMediaRecorder::UnloadedStatus;
}
if (lastStatus != m_lastStatus)
Q_EMIT statusChanged(m_lastStatus);
}
void AVFMediaRecorderControlIOS::stopWriter()
{
if (m_lastStatus == QMediaRecorder::RecordingStatus) {
m_state = QMediaRecorder::StoppedState;
m_lastStatus = QMediaRecorder::FinalizingStatus;
Q_EMIT stateChanged(m_state);
Q_EMIT statusChanged(m_lastStatus);
dispatch_async(m_writerQueue, ^{
[m_writer stop];
});
}
}
#include "moc_avfmediarecordercontrol_ios.cpp"

View File

@@ -27,7 +27,6 @@ HEADERS += \
avfcameracontrol.h \
avfcamerametadatacontrol.h \
avfimagecapturecontrol.h \
avfmediarecordercontrol.h \
avfcameraservice.h \
avfcamerasession.h \
avfstoragelocation.h \
@@ -49,7 +48,6 @@ OBJECTIVE_SOURCES += \
avfcameracontrol.mm \
avfcamerametadatacontrol.mm \
avfimagecapturecontrol.mm \
avfmediarecordercontrol.mm \
avfcameraservice.mm \
avfcamerasession.mm \
avfstoragelocation.mm \
@@ -66,9 +64,20 @@ OBJECTIVE_SOURCES += \
avfimageencodercontrol.mm \
avfcameraflashcontrol.mm
ios {
osx {
HEADERS += avfcamerazoomcontrol.h
OBJECTIVE_SOURCES += avfcamerazoomcontrol.mm
HEADERS += avfmediarecordercontrol.h
OBJECTIVE_SOURCES += avfmediarecordercontrol.mm
}
ios {
HEADERS += avfcamerazoomcontrol.h \
avfmediaassetwriter.h \
avfmediarecordercontrol_ios.h
OBJECTIVE_SOURCES += avfcamerazoomcontrol.mm \
avfmediaassetwriter.mm \
avfmediarecordercontrol_ios.mm
}

View File

@@ -728,7 +728,7 @@ void AVFMediaPlayerSession::setVolume(int volume)
return;
}
[player setVolume:m_volume / 100.0f];
[player setVolume:volume / 100.0f];
m_volume = volume;
Q_EMIT volumeChanged(m_volume);
@@ -752,7 +752,7 @@ void AVFMediaPlayerSession::setMuted(bool muted)
return;
}
[player setMuted:m_muted];
[player setMuted:muted];
m_muted = muted;
Q_EMIT mutedChanged(muted);

View File

@@ -60,6 +60,8 @@ QSGVivanteVideoMaterial::QSGVivanteVideoMaterial() :
#endif
setFlag(Blending, false);
mShader = new QSGVivanteVideoMaterialShader;
}
QSGVivanteVideoMaterial::~QSGVivanteVideoMaterial()
@@ -73,7 +75,7 @@ QSGMaterialType *QSGVivanteVideoMaterial::type() const {
}
QSGMaterialShader *QSGVivanteVideoMaterial::createShader() const {
return new QSGVivanteVideoMaterialShader;
return mShader;
}
int QSGVivanteVideoMaterial::compare(const QSGMaterial *other) const {
@@ -175,18 +177,49 @@ GLuint QSGVivanteVideoMaterial::vivanteMapping(QVideoFrame vF)
glGenTextures(1, &tmpTexId);
mBitsToTextureMap.insert(vF.bits(), tmpTexId);
// Determine the full width & height. Full means: actual width/height plus extra padding pixels.
// The full width can be deduced from the bytesPerLine value. The full height is calculated
// by calculating the distance between the start of the first and second planes, and dividing
// it by the stride (= the bytesPerLine). If there is only one plane, we don't worry about
// extra padding rows, since there are no adjacent extra planes.
// XXX: This assumes the distance between bits(1) and bits(0) is exactly the size of the first
// plane (the Y plane in the case of YUV data). A better way would be to have a dedicated
// planeSize() or planeOffset() getter.
// Also, this assumes that planes are tightly packed, that is, there is no space between them.
// It is okay to assume this here though, because the Vivante direct textures also assume that.
// In other words, if the planes aren't tightly packed, then the direct textures won't be able
// to render the frame correctly anyway.
int fullWidth = vF.bytesPerLine() / QSGVivanteVideoNode::getBytesForPixelFormat(vF.pixelFormat());
int fullHeight = (vF.planeCount() > 1) ? ((vF.bits(1) - vF.bits(0)) / vF.bytesPerLine()) : vF.height();
// The uscale is the ratio of actual width to the full width (same for vscale and height).
// Since the vivante direct textures do not offer a way to explicitly specify the amount of padding
// columns and rows, we use a trick. We show the full frame - including the padding pixels - in the
// texture, but render only a subset of that texture. This subset goes from (0,0) to (uScale, vScale).
// In the shader, the texture coordinates (which go from (0.0, 0.0) to (1.0, 1.0)) are multiplied by
// the u/v scale values. Since 1.0 * x = x, this effectively limits the texture coordinates from
// (0.0, 0.0) - (1.0, 1.0) to (0.0, 0.0) - (uScale, vScale).
float uScale = float(vF.width()) / float(fullWidth);
float vScale = float(vF.height()) / float(fullHeight);
mShader->setUVScale(uScale, vScale);
const uchar *constBits = vF.bits();
void *bits = (void*)constBits;
#ifdef QT_VIVANTE_VIDEO_DEBUG
qDebug() << Q_FUNC_INFO << "new texture, texId: " << tmpTexId << "; constBits: " << constBits;
qDebug() << Q_FUNC_INFO
<< "new texture, texId: " << tmpTexId
<< "; constBits: " << constBits
<< "; actual/full width: " << vF.width() << "/" << fullWidth
<< "; actual/full height: " << vF.height() << "/" << fullHeight
<< "; UV scale: U " << uScale << " V " << vScale;
#endif
GLuint physical = ~0U;
glBindTexture(GL_TEXTURE_2D, tmpTexId);
glTexDirectVIVMap_LOCAL(GL_TEXTURE_2D,
vF.width(), vF.height(),
fullWidth, fullHeight,
QSGVivanteVideoNode::getVideoFormat2GLFormatMap().value(vF.pixelFormat()),
&bits, &physical);

View File

@@ -43,6 +43,8 @@
#include <private/qsgvideonode_p.h>
class QSGVivanteVideoMaterialShader;
class QSGVivanteVideoMaterial : public QSGMaterial
{
public:
@@ -78,6 +80,8 @@ private:
GLuint mTexDirectTexture;
GLvoid *mTexDirectPlanes[3];
QSGVivanteVideoMaterialShader *mShader;
};
#endif // QSGVIDEOMATERIAL_VIVMAP_H

View File

@@ -35,6 +35,13 @@
#include "qsgvivantevideonode.h"
#include "qsgvivantevideomaterial.h"
QSGVivanteVideoMaterialShader::QSGVivanteVideoMaterialShader() :
mUScale(1),
mVScale(1),
mNewUVScale(true)
{
}
void QSGVivanteVideoMaterialShader::updateState(const RenderState &state,
QSGMaterial *newMaterial,
QSGMaterial *oldMaterial)
@@ -48,6 +55,10 @@ void QSGVivanteVideoMaterialShader::updateState(const RenderState &state,
mat->setOpacity(state.opacity());
program()->setUniformValue(mIdOpacity, state.opacity());
}
if (mNewUVScale) {
program()->setUniformValue(mIdUVScale, mUScale, mVScale);
mNewUVScale = false;
}
if (state.isMatrixDirty())
program()->setUniformValue(mIdMatrix, state.combinedMatrix());
}
@@ -61,6 +72,13 @@ const char * const *QSGVivanteVideoMaterialShader::attributeNames() const {
return names;
}
void QSGVivanteVideoMaterialShader::setUVScale(float uScale, float vScale)
{
mUScale = uScale;
mVScale = vScale;
mNewUVScale = true;
}
const char *QSGVivanteVideoMaterialShader::vertexShader() const {
static const char *shader =
"uniform highp mat4 qt_Matrix; \n"
@@ -78,12 +96,13 @@ const char *QSGVivanteVideoMaterialShader::fragmentShader() const {
static const char *shader =
"uniform sampler2D texture;"
"uniform lowp float opacity;"
"uniform highp vec2 uvScale;"
""
"varying highp vec2 qt_TexCoord;"
""
"void main()"
"{"
" gl_FragColor = vec4(texture2D( texture, qt_TexCoord ).rgb, 1.0) * opacity;\n"
" gl_FragColor = vec4(texture2D( texture, qt_TexCoord * uvScale ).rgb, 1.0) * opacity;\n"
"}";
return shader;
}
@@ -93,4 +112,5 @@ void QSGVivanteVideoMaterialShader::initialize() {
mIdMatrix = program()->uniformLocation("qt_Matrix");
mIdTexture = program()->uniformLocation("texture");
mIdOpacity = program()->uniformLocation("opacity");
mIdUVScale = program()->uniformLocation("uvScale");
}

View File

@@ -39,9 +39,13 @@
class QSGVivanteVideoMaterialShader : public QSGMaterialShader
{
public:
QSGVivanteVideoMaterialShader();
void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
virtual char const *const *attributeNames() const;
void setUVScale(float uScale, float vScale);
protected:
virtual const char *vertexShader() const;
virtual const char *fragmentShader() const;
@@ -51,6 +55,11 @@ private:
int mIdMatrix;
int mIdTexture;
int mIdOpacity;
int mIdUVScale;
float mUScale;
float mVScale;
bool mNewUVScale;
};
#endif // QSGVIDEOMATERIALSHADER_VIVANTE_H

View File

@@ -78,4 +78,23 @@ const QMap<QVideoFrame::PixelFormat, GLenum>& QSGVivanteVideoNode::getVideoForma
}
int QSGVivanteVideoNode::getBytesForPixelFormat(QVideoFrame::PixelFormat pixelformat)
{
switch (pixelformat) {
case QVideoFrame::Format_YUV420P: return 1;
case QVideoFrame::Format_YV12: return 1;
case QVideoFrame::Format_NV12: return 1;
case QVideoFrame::Format_NV21: return 1;
case QVideoFrame::Format_UYVY: return 2;
case QVideoFrame::Format_YUYV: return 2;
case QVideoFrame::Format_RGB32: return 4;
case QVideoFrame::Format_ARGB32: return 4;
case QVideoFrame::Format_BGR32: return 4;
case QVideoFrame::Format_BGRA32: return 4;
case QVideoFrame::Format_RGB565: return 2;
default: return 1;
}
}

View File

@@ -49,6 +49,7 @@ public:
void setCurrentFrame(const QVideoFrame &frame, FrameFlags flags);
static const QMap<QVideoFrame::PixelFormat, GLenum>& getVideoFormat2GLFormatMap();
static int getBytesForPixelFormat(QVideoFrame::PixelFormat pixelformat);
private:
QVideoSurfaceFormat mFormat;

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -5,7 +5,7 @@
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -16,16 +16,19 @@
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**

View File

@@ -389,7 +389,8 @@ void MFAudioDecoderControl::handleSampleAdded()
s->Release();
}
}
m_cachedAudioBuffer = QAudioBuffer(abuf, m_audioFormat, qint64(sampleStartTime / 10000));
// WMF uses 100-nanosecond units, QAudioDecoder uses milliseconds, QAudioBuffer uses microseconds...
m_cachedAudioBuffer = QAudioBuffer(abuf, m_audioFormat, qint64(sampleStartTime / 10));
m_bufferReady = true;
emit positionChanged(m_position);
emit bufferAvailableChanged(m_bufferReady);