diff options
Diffstat (limited to 'src')
60 files changed, 1839 insertions, 356 deletions
diff --git a/src/gsttools/qgstreamervideowidget.cpp b/src/gsttools/qgstreamervideowidget.cpp index 9a29d327..6e65b306 100644 --- a/src/gsttools/qgstreamervideowidget.cpp +++ b/src/gsttools/qgstreamervideowidget.cpp @@ -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 diff --git a/src/gsttools/qgstreamervideowindow.cpp b/src/gsttools/qgstreamervideowindow.cpp index 7dd6ab25..ee25acc4 100644 --- a/src/gsttools/qgstreamervideowindow.cpp +++ b/src/gsttools/qgstreamervideowindow.cpp @@ -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() diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp index 615348c1..31ac94e8 100644 --- a/src/gsttools/qgstvideorenderersink.cpp +++ b/src/gsttools/qgstvideorenderersink.cpp @@ -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); + + 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); + return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition); } GstCaps *QGstVideoRendererSink::get_caps(GstBaseSink *base, GstCaps *filter) diff --git a/src/gsttools/qvideosurfacegstsink.cpp b/src/gsttools/qvideosurfacegstsink.cpp index 4a786ea1..737bc648 100644 --- a/src/gsttools/qvideosurfacegstsink.cpp +++ b/src/gsttools/qvideosurfacegstsink.cpp @@ -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); + + 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); + return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition); } GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base) diff --git a/src/imports/multimedia/qdeclarativecameraflash.cpp b/src/imports/multimedia/qdeclarativecameraflash.cpp index 0bde737e..ae4fd939 100644 --- a/src/imports/multimedia/qdeclarativecameraflash.cpp +++ b/src/imports/multimedia/qdeclarativecameraflash.cpp @@ -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. diff --git a/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp b/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp index 49bc81ab..95b48696 100644 --- a/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp +++ b/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp @@ -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. */ /*! diff --git a/src/multimedia/doc/src/qtmultimedia-index.qdoc b/src/multimedia/doc/src/qtmultimedia-index.qdoc index 39e7cbc4..6dc89429 100644 --- a/src/multimedia/doc/src/qtmultimedia-index.qdoc +++ b/src/multimedia/doc/src/qtmultimedia-index.qdoc @@ -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} diff --git a/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h b/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h index 18670887..78bdf8cb 100644 --- a/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h +++ b/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h @@ -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); diff --git a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h index e8f61afe..a1ef5616 100644 --- a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h +++ b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h @@ -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); diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 2ff17592..4a64e1b1 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -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); + + 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 - if (qAbs(aspectRatio - (qreal(size.width()) / size.height())) < 0.01) { - adjustedViewfinderResolution = size; - break; + 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 (!adjustedViewfinderResolution.isValid()) { + qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio."); + return; + } } if (currentViewfinderResolution != adjustedViewfinderResolution) { diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp index af803302..aaad8fd8 100644 --- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp @@ -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() diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.h b/src/plugins/android/src/mediacapture/qandroidcapturesession.h index 90af39fd..a0e7a894 100644 --- a/src/plugins/android/src/mediacapture/qandroidcapturesession.h +++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.h @@ -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; diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index d9c8befa..7496e9cd 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -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")); } diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h index 92ab75bd..b8f92d9c 100644 --- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h @@ -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 diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm index cf13635f..52954128 100644 --- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm @@ -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); - - 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]); - } - } + if (format == QVideoFrame::Format_Invalid) + return; - 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()); diff --git a/src/plugins/avfoundation/camera/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h index d557872a..08b0ad26 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.h +++ b/src/plugins/avfoundation/camera/avfcameraservice.h @@ -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; diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index f163e129..fd473b37 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -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" diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 7b25a99c..2b322cfa 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -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); diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 6e4803f3..2cb3824d 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -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(); } } diff --git a/src/plugins/avfoundation/camera/avfcamerautility.h b/src/plugins/avfoundation/camera/avfcamerautility.h index 03a61460..42005a50 100644 --- a/src/plugins/avfoundation/camera/avfcamerautility.h +++ b/src/plugins/avfoundation/camera/avfcamerautility.h @@ -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) { diff --git a/src/plugins/avfoundation/camera/avfcamerautility.mm b/src/plugins/avfoundation/camera/avfcamerautility.mm index f8d5647e..f45169d0 100644 --- a/src/plugins/avfoundation/camera/avfcamerautility.mm +++ b/src/plugins/avfoundation/camera/avfcamerautility.mm @@ -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; } diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm index 60df1e2e..b32c0cd6 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -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. +#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 +#else // OSX < 10.7 or iOS < 7.0 { -#endif +#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); } diff --git a/src/plugins/avfoundation/camera/avfcamerazoomcontrol.mm b/src/plugins/avfoundation/camera/avfcamerazoomcontrol.mm index 8206112b..158073dc 100644 --- a/src/plugins/avfoundation/camera/avfcamerazoomcontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerazoomcontrol.mm @@ -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.; diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.h b/src/plugins/avfoundation/camera/avfmediaassetwriter.h new file mode 100644 index 00000000..eae70075 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.h @@ -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 diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm new file mode 100644 index 00000000..37004c1d --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm @@ -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 diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h new file mode 100644 index 00000000..78576948 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h @@ -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 diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm new file mode 100644 index 00000000..b763dbcc --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm @@ -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" diff --git a/src/plugins/avfoundation/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro index ac389df7..62afdcd8 100644 --- a/src/plugins/avfoundation/camera/camera.pro +++ b/src/plugins/avfoundation/camera/camera.pro @@ -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 +osx { + +HEADERS += avfmediarecordercontrol.h +OBJECTIVE_SOURCES += avfmediarecordercontrol.mm + +} + ios { -HEADERS += avfcamerazoomcontrol.h -OBJECTIVE_SOURCES += avfcamerazoomcontrol.mm +HEADERS += avfcamerazoomcontrol.h \ + avfmediaassetwriter.h \ + avfmediarecordercontrol_ios.h +OBJECTIVE_SOURCES += avfcamerazoomcontrol.mm \ + avfmediaassetwriter.mm \ + avfmediarecordercontrol_ios.mm } diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index 005c00a1..5ef1f9ba 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.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); diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp index ab6bcd52..2e2092be 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp +++ b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp @@ -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); diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterial.h b/src/plugins/videonode/imx6/qsgvivantevideomaterial.h index faefa1c9..faf4e8d2 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideomaterial.h +++ b/src/plugins/videonode/imx6/qsgvivantevideomaterial.h @@ -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 diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.cpp b/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.cpp index b51acfe6..a0a41773 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.cpp +++ b/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.cpp @@ -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"); } diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.h b/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.h index f902f763..f6e707da 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.h +++ b/src/plugins/videonode/imx6/qsgvivantevideomaterialshader.h @@ -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 diff --git a/src/plugins/videonode/imx6/qsgvivantevideonode.cpp b/src/plugins/videonode/imx6/qsgvivantevideonode.cpp index 42058f1b..229a69bc 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideonode.cpp +++ b/src/plugins/videonode/imx6/qsgvivantevideonode.cpp @@ -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; + } +} + + diff --git a/src/plugins/videonode/imx6/qsgvivantevideonode.h b/src/plugins/videonode/imx6/qsgvivantevideonode.h index ca088e21..c65fc11e 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideonode.h +++ b/src/plugins/videonode/imx6/qsgvivantevideonode.h @@ -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; diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp index 0f46e585..2d0b5413 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h index 278ec179..ed8b76a6 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index e8f433d4..e4a57764 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index a90d482e..95692cbc 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp index 1e6050a3..104484a6 100644 --- a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp +++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h index 38dbbf2c..dc880255 100644 --- a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h +++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcamerainfocontrol.cpp b/src/plugins/winrt/qwinrtcamerainfocontrol.cpp index 0a741eaa..69fc0a9a 100644 --- a/src/plugins/winrt/qwinrtcamerainfocontrol.cpp +++ b/src/plugins/winrt/qwinrtcamerainfocontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcamerainfocontrol.h b/src/plugins/winrt/qwinrtcamerainfocontrol.h index 7020b12d..5bad6cb0 100644 --- a/src/plugins/winrt/qwinrtcamerainfocontrol.h +++ b/src/plugins/winrt/qwinrtcamerainfocontrol.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameraservice.cpp b/src/plugins/winrt/qwinrtcameraservice.cpp index 275fbccf..09b56575 100644 --- a/src/plugins/winrt/qwinrtcameraservice.cpp +++ b/src/plugins/winrt/qwinrtcameraservice.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameraservice.h b/src/plugins/winrt/qwinrtcameraservice.h index 9565de62..eb3b0d01 100644 --- a/src/plugins/winrt/qwinrtcameraservice.h +++ b/src/plugins/winrt/qwinrtcameraservice.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp index bcae8a20..3b8a38bb 100644 --- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.h b/src/plugins/winrt/qwinrtcameravideorenderercontrol.h index 55ea1266..68e9bd9f 100644 --- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.h +++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp index 333a6d1e..0402553d 100644 --- a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp +++ b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.h b/src/plugins/winrt/qwinrtmediaplayercontrol.h index f2899531..34abcc12 100644 --- a/src/plugins/winrt/qwinrtmediaplayercontrol.h +++ b/src/plugins/winrt/qwinrtmediaplayercontrol.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtmediaplayerservice.cpp b/src/plugins/winrt/qwinrtmediaplayerservice.cpp index c8c34d83..a6b3d1f3 100644 --- a/src/plugins/winrt/qwinrtmediaplayerservice.cpp +++ b/src/plugins/winrt/qwinrtmediaplayerservice.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtmediaplayerservice.h b/src/plugins/winrt/qwinrtmediaplayerservice.h index 039ca309..7a2771fd 100644 --- a/src/plugins/winrt/qwinrtmediaplayerservice.h +++ b/src/plugins/winrt/qwinrtmediaplayerservice.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtplayerrenderercontrol.cpp b/src/plugins/winrt/qwinrtplayerrenderercontrol.cpp index cf815fcd..5a8f4b87 100644 --- a/src/plugins/winrt/qwinrtplayerrenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtplayerrenderercontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtplayerrenderercontrol.h b/src/plugins/winrt/qwinrtplayerrenderercontrol.h index 85fc00c5..c6d410b1 100644 --- a/src/plugins/winrt/qwinrtplayerrenderercontrol.h +++ b/src/plugins/winrt/qwinrtplayerrenderercontrol.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtserviceplugin.cpp b/src/plugins/winrt/qwinrtserviceplugin.cpp index c0e51907..fc0103d1 100644 --- a/src/plugins/winrt/qwinrtserviceplugin.cpp +++ b/src/plugins/winrt/qwinrtserviceplugin.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtserviceplugin.h b/src/plugins/winrt/qwinrtserviceplugin.h index 004ad89c..5f5cf559 100644 --- a/src/plugins/winrt/qwinrtserviceplugin.h +++ b/src/plugins/winrt/qwinrtserviceplugin.h @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp index 0352aaab..582a9fc6 100644 --- a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp +++ b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp @@ -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$ ** diff --git a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.h b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.h index df655f44..3b3e7c74 100644 --- a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.h +++ b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.h @@ -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$ ** diff --git a/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp b/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp index e3d1ebde..55fae714 100644 --- a/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp +++ b/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp @@ -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); diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp index c638b306..7a9dfdaa 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp @@ -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); } diff --git a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp index 9da1023b..c920ba3b 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp @@ -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]); } |