Merge remote-tracking branch 'origin/5.5' into dev
Change-Id: I7ac7db69c37cc9e5c5241a25b9a874986a23a886
This commit is contained in:
@@ -98,7 +98,10 @@ QGstreamerVideoWidgetControl::QGstreamerVideoWidgetControl(QObject *parent)
|
||||
, m_widget(0)
|
||||
, m_fullScreen(false)
|
||||
{
|
||||
m_videoSink = gst_element_factory_make ("xvimagesink", NULL);
|
||||
// The QWidget needs to have a native X window handle to be able to use xvimagesink.
|
||||
// Bail out if Qt is not using xcb (the control will then be ignored by the plugin)
|
||||
if (QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0)
|
||||
m_videoSink = gst_element_factory_make ("xvimagesink", NULL);
|
||||
|
||||
if (m_videoSink) {
|
||||
// Check if the xv sink is usable
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <private/qgstutils_p.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
@@ -57,7 +58,9 @@ QGstreamerVideoWindow::QGstreamerVideoWindow(QObject *parent, const char *elemen
|
||||
{
|
||||
if (elementName) {
|
||||
m_videoSink = gst_element_factory_make(elementName, NULL);
|
||||
} else {
|
||||
} else if (QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0) {
|
||||
// We need a native X window handle to be able to use xvimagesink.
|
||||
// Bail out if Qt is not using xcb (the control will then be ignored by the plugin)
|
||||
m_videoSink = gst_element_factory_make("xvimagesink", NULL);
|
||||
}
|
||||
|
||||
@@ -68,8 +71,6 @@ QGstreamerVideoWindow::QGstreamerVideoWindow(QObject *parent, const char *elemen
|
||||
addProbeToPad(pad);
|
||||
gst_object_unref(GST_OBJECT(pad));
|
||||
}
|
||||
else
|
||||
qDebug() << "No m_videoSink available!";
|
||||
}
|
||||
|
||||
QGstreamerVideoWindow::~QGstreamerVideoWindow()
|
||||
|
||||
@@ -222,6 +222,17 @@ bool QVideoSurfaceGstDelegate::proposeAllocation(GstQuery *query)
|
||||
}
|
||||
}
|
||||
|
||||
void QVideoSurfaceGstDelegate::flush()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
m_flush = true;
|
||||
m_renderBuffer = 0;
|
||||
m_renderCondition.wakeAll();
|
||||
|
||||
notify();
|
||||
}
|
||||
|
||||
GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
@@ -388,6 +399,8 @@ QGstVideoRendererSink *QGstVideoRendererSink::createSink(QAbstractVideoSurface *
|
||||
|
||||
sink->delegate = new QVideoSurfaceGstDelegate(surface);
|
||||
|
||||
g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink);
|
||||
|
||||
return sink;
|
||||
}
|
||||
|
||||
@@ -472,13 +485,41 @@ void QGstVideoRendererSink::finalize(GObject *object)
|
||||
G_OBJECT_CLASS(sink_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
void QGstVideoRendererSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d)
|
||||
{
|
||||
Q_UNUSED(o);
|
||||
Q_UNUSED(p);
|
||||
QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(d);
|
||||
|
||||
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
|
||||
g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL);
|
||||
|
||||
if (!showPrerollFrame) {
|
||||
GstState state = GST_STATE_VOID_PENDING;
|
||||
gst_element_get_state(GST_ELEMENT(sink), &state, NULL, GST_CLOCK_TIME_NONE);
|
||||
// show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means
|
||||
// the QMediaPlayer was stopped from the paused state.
|
||||
// We need to flush the current frame.
|
||||
if (state == GST_STATE_PAUSED)
|
||||
sink->delegate->flush();
|
||||
}
|
||||
}
|
||||
|
||||
GstStateChangeReturn QGstVideoRendererSink::change_state(
|
||||
GstElement *element, GstStateChange transition)
|
||||
{
|
||||
Q_UNUSED(element);
|
||||
QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(element);
|
||||
|
||||
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(
|
||||
element, transition);
|
||||
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
|
||||
g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, NULL);
|
||||
|
||||
// If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to
|
||||
// GST_STATE_PAUSED, it means the QMediaPlayer was stopped.
|
||||
// We need to flush the current frame.
|
||||
if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame)
|
||||
sink->delegate->flush();
|
||||
|
||||
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition);
|
||||
}
|
||||
|
||||
GstCaps *QGstVideoRendererSink::get_caps(GstBaseSink *base, GstCaps *filter)
|
||||
|
||||
@@ -184,6 +184,21 @@ void QVideoSurfaceGstDelegate::clearPoolBuffers()
|
||||
m_pool->clear();
|
||||
}
|
||||
|
||||
void QVideoSurfaceGstDelegate::flush()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
m_frame = QVideoFrame();
|
||||
m_renderCondition.wakeAll();
|
||||
|
||||
if (QThread::currentThread() == thread()) {
|
||||
if (!m_surface.isNull())
|
||||
m_surface->present(m_frame);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this, "queuedFlush", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
|
||||
{
|
||||
if (!m_surface) {
|
||||
@@ -244,6 +259,14 @@ void QVideoSurfaceGstDelegate::queuedStop()
|
||||
m_setupCondition.wakeAll();
|
||||
}
|
||||
|
||||
void QVideoSurfaceGstDelegate::queuedFlush()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (!m_surface.isNull())
|
||||
m_surface->present(QVideoFrame());
|
||||
}
|
||||
|
||||
void QVideoSurfaceGstDelegate::queuedRender()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
@@ -316,6 +339,8 @@ QVideoSurfaceGstSink *QVideoSurfaceGstSink::createSink(QAbstractVideoSurface *su
|
||||
|
||||
sink->delegate = new QVideoSurfaceGstDelegate(surface);
|
||||
|
||||
g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink);
|
||||
|
||||
return sink;
|
||||
}
|
||||
|
||||
@@ -420,13 +445,40 @@ void QVideoSurfaceGstSink::finalize(GObject *object)
|
||||
G_OBJECT_CLASS(sink_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
GstStateChangeReturn QVideoSurfaceGstSink::change_state(
|
||||
GstElement *element, GstStateChange transition)
|
||||
void QVideoSurfaceGstSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d)
|
||||
{
|
||||
Q_UNUSED(element);
|
||||
Q_UNUSED(o);
|
||||
Q_UNUSED(p);
|
||||
QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(d);
|
||||
|
||||
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(
|
||||
element, transition);
|
||||
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
|
||||
g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL);
|
||||
|
||||
if (!showPrerollFrame) {
|
||||
GstState state = GST_STATE_VOID_PENDING;
|
||||
gst_element_get_state(GST_ELEMENT(sink), &state, NULL, GST_CLOCK_TIME_NONE);
|
||||
// show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means
|
||||
// the QMediaPlayer was stopped from the paused state.
|
||||
// We need to flush the current frame.
|
||||
if (state == GST_STATE_PAUSED)
|
||||
sink->delegate->flush();
|
||||
}
|
||||
}
|
||||
|
||||
GstStateChangeReturn QVideoSurfaceGstSink::change_state(GstElement *element, GstStateChange transition)
|
||||
{
|
||||
QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(element);
|
||||
|
||||
gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
|
||||
g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, NULL);
|
||||
|
||||
// If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to
|
||||
// GST_STATE_PAUSED, it means the QMediaPlayer was stopped.
|
||||
// We need to flush the current frame.
|
||||
if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame)
|
||||
sink->delegate->flush();
|
||||
|
||||
return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition);
|
||||
}
|
||||
|
||||
GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base)
|
||||
|
||||
@@ -113,7 +113,10 @@ bool QDeclarativeCameraFlash::isFlashReady() const
|
||||
\row \li Camera.FlashAuto \li Automatic flash.
|
||||
\row \li Camera.FlashRedEyeReduction \li Red eye reduction flash.
|
||||
\row \li Camera.FlashFill \li Use flash to fillin shadows.
|
||||
\row \li Camera.FlashTorch \li Constant light source, useful for focusing and video capture.
|
||||
\row \li Camera.FlashTorch \li Constant light source. If supported, torch can be
|
||||
enabled without loading the camera.
|
||||
\row \li Camera.FlashVideoLight \li Constant light source, useful for video capture.
|
||||
The light is turned on only while the camera is active.
|
||||
\row \li Camera.FlashSlowSyncFrontCurtain
|
||||
\li Use the flash in conjunction with a slow shutter speed.
|
||||
This mode allows better exposure of distant objects and/or motion blur effect.
|
||||
|
||||
@@ -96,7 +96,7 @@ QCameraViewfinderSettingsControl::~QCameraViewfinderSettingsControl()
|
||||
Viewfinder pixel format, QVideoFrame::PixelFormat
|
||||
\value UserParameter
|
||||
The base value for platform specific extended parameters.
|
||||
For such parameters the sequential values starting from UserParameter shuld be used.
|
||||
For such parameters the sequential values starting from UserParameter should be used.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
||||
@@ -130,6 +130,11 @@
|
||||
\endlist
|
||||
|
||||
\section2 Platform Notes
|
||||
|
||||
The \l{Qt Multimedia Backends} wiki provides a summary of features
|
||||
supported by each platform plugin made available by this module. The
|
||||
following topics provide more platform-specific information.
|
||||
|
||||
\list
|
||||
\li \l{Qt Multimedia on BlackBerry}{BlackBerry}
|
||||
\li \l{Qt Multimedia on Windows}{Windows}
|
||||
|
||||
@@ -99,6 +99,8 @@ public:
|
||||
void unlock();
|
||||
bool proposeAllocation(GstQuery *query);
|
||||
|
||||
void flush();
|
||||
|
||||
GstFlowReturn render(GstBuffer *buffer);
|
||||
|
||||
bool event(QEvent *event);
|
||||
@@ -145,6 +147,8 @@ private:
|
||||
|
||||
static void finalize(GObject *object);
|
||||
|
||||
static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d);
|
||||
|
||||
static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
|
||||
|
||||
static GstCaps *get_caps(GstBaseSink *sink, GstCaps *filter);
|
||||
|
||||
@@ -96,11 +96,14 @@ public:
|
||||
QMutex *poolMutex() { return &m_poolMutex; }
|
||||
void clearPoolBuffers();
|
||||
|
||||
void flush();
|
||||
|
||||
GstFlowReturn render(GstBuffer *buffer);
|
||||
|
||||
private slots:
|
||||
void queuedStart();
|
||||
void queuedStop();
|
||||
void queuedFlush();
|
||||
void queuedRender();
|
||||
|
||||
void updateSupportedFormats();
|
||||
@@ -139,6 +142,8 @@ private:
|
||||
|
||||
static void finalize(GObject *object);
|
||||
|
||||
static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d);
|
||||
|
||||
static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
|
||||
|
||||
static GstCaps *get_caps(GstBaseSink *sink);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.;
|
||||
|
||||
|
||||
119
src/plugins/avfoundation/camera/avfmediaassetwriter.h
Normal file
119
src/plugins/avfoundation/camera/avfmediaassetwriter.h
Normal 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
|
||||
474
src/plugins/avfoundation/camera/avfmediaassetwriter.mm
Normal file
474
src/plugins/avfoundation/camera/avfmediaassetwriter.mm
Normal 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
|
||||
108
src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h
Normal file
108
src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h
Normal 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
|
||||
349
src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm
Normal file
349
src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm
Normal 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"
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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$
|
||||
**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
#include <private/qmediapluginloader_p.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
static void initResource() {
|
||||
Q_INIT_RESOURCE(qtmultimediaquicktools);
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(qLcVideo, "qt.multimedia.video")
|
||||
@@ -130,6 +134,7 @@ QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) :
|
||||
m_autoOrientation(false),
|
||||
m_screenOrientationHandler(0)
|
||||
{
|
||||
initResource();
|
||||
setFlag(ItemHasContents, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -318,7 +318,8 @@ void QSGVideoMaterial_YUV::bind()
|
||||
|
||||
m_frame = QVideoFrame();
|
||||
} else {
|
||||
for (int i = 0; i < m_planeCount; ++i) {
|
||||
// Go backwards to finish with GL_TEXTURE0
|
||||
for (int i = m_planeCount - 1; i >= 0; --i) {
|
||||
functions->glActiveTexture(GL_TEXTURE0 + i);
|
||||
functions->glBindTexture(GL_TEXTURE_2D, m_textureIds[i]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user