diff options
Diffstat (limited to 'src/plugins')
18 files changed, 610 insertions, 29 deletions
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index f3ad84836..a0f809376 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -53,7 +53,6 @@ #include <qdebug.h> #include <qvideoframe.h> #include <private/qmemoryvideobuffer_p.h> -#include <private/qvideoframe_p.h> #include <QtCore/private/qjnihelpers_p.h> QT_BEGIN_NAMESPACE @@ -749,7 +748,7 @@ void QAndroidCameraSession::processPreviewImage(int id, const QVideoFrame &frame transform.scale(-1, 1); transform.rotate(rotation); - emit imageCaptured(id, qt_imageFromVideoFrame(frame).transformed(transform)); + emit imageCaptured(id, frame.image().transformed(transform)); } void QAndroidCameraSession::onNewPreviewFrame(const QVideoFrame &frame) diff --git a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp index ef86af896..66eafc765 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp @@ -176,12 +176,12 @@ void QAndroidMetaDataReaderControl::extractMetadata(QAndroidMetaDataReaderContro if (!string.isNull()) { metadata.insert(isVideo ? QMediaMetaData::LeadPerformer : QMediaMetaData::ContributingArtist, - string.split('/', QString::SkipEmptyParts)); + string.split('/', Qt::SkipEmptyParts)); } string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Author); if (!string.isNull()) - metadata.insert(QMediaMetaData::Author, string.split('/', QString::SkipEmptyParts)); + metadata.insert(QMediaMetaData::Author, string.split('/', Qt::SkipEmptyParts)); string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Bitrate); if (!string.isNull()) { @@ -196,7 +196,7 @@ void QAndroidMetaDataReaderControl::extractMetadata(QAndroidMetaDataReaderContro string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Composer); if (!string.isNull()) - metadata.insert(QMediaMetaData::Composer, string.split('/', QString::SkipEmptyParts)); + metadata.insert(QMediaMetaData::Composer, string.split('/', Qt::SkipEmptyParts)); string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Date); if (!string.isNull()) @@ -231,7 +231,7 @@ void QAndroidMetaDataReaderControl::extractMetadata(QAndroidMetaDataReaderContro string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Writer); if (!string.isNull()) - metadata.insert(QMediaMetaData::Writer, string.split('/', QString::SkipEmptyParts)); + metadata.insert(QMediaMetaData::Writer, string.split('/', Qt::SkipEmptyParts)); string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Year); if (!string.isNull()) diff --git a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp index f899481f0..de8422b86 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp +++ b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp @@ -271,7 +271,7 @@ void AndroidMediaPlayer::setAudioRole(QAudio::Role role) void AndroidMediaPlayer::setCustomAudioRole(const QString &role) { - QStringList roles = role.split(",", QString::SkipEmptyParts); + QStringList roles = role.split(",", Qt::SkipEmptyParts); int type = 0; // CONTENT_TYPE_UNKNOWN int usage = 0; // USAGE_UNKNOWN diff --git a/src/plugins/avfoundation/camera/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h index 2969882b0..ec2884217 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.h +++ b/src/plugins/avfoundation/camera/avfcameraservice.h @@ -70,6 +70,7 @@ class AVFMediaRecorderControlIOS; class AVFAudioEncoderSettingsControl; class AVFVideoEncoderSettingsControl; class AVFMediaContainerControl; +class AVFCameraWindowControl; class AVFCameraService : public QMediaService { @@ -120,6 +121,7 @@ private: AVFAudioEncoderSettingsControl *m_audioEncoderSettingsControl; AVFVideoEncoderSettingsControl *m_videoEncoderSettingsControl; AVFMediaContainerControl *m_mediaContainerControl; + AVFCameraWindowControl *m_captureWindowControl; }; QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index 33b4b72aa..627ecf67c 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -61,6 +61,7 @@ #include "avfaudioencodersettingscontrol.h" #include "avfvideoencodersettingscontrol.h" #include "avfmediacontainercontrol.h" +#include "avfcamerawindowcontrol.h" #ifdef Q_OS_IOS #include "avfcamerazoomcontrol.h" @@ -74,7 +75,8 @@ QT_USE_NAMESPACE AVFCameraService::AVFCameraService(QObject *parent): QMediaService(parent), - m_videoOutput(nullptr) + m_videoOutput(nullptr), + m_captureWindowControl(nullptr) { m_session = new AVFCameraSession(this); m_cameraControl = new AVFCameraControl(this); @@ -119,6 +121,12 @@ AVFCameraService::~AVFCameraService() delete m_recorderControl; #endif + if (m_captureWindowControl) { + m_session->setCapturePreviewOutput(nullptr); + delete m_captureWindowControl; + m_captureWindowControl = nullptr; + } + if (m_videoOutput) { m_session->setVideoOutput(nullptr); delete m_videoOutput; @@ -210,6 +218,14 @@ QMediaControl *AVFCameraService::requestControl(const char *name) return m_cameraZoomControl; #endif + if (!m_captureWindowControl) { + if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + m_captureWindowControl = new AVFCameraWindowControl(this); + m_session->setCapturePreviewOutput(m_captureWindowControl); + return m_captureWindowControl; + } + } + if (!m_videoOutput) { if (qstrcmp(name, QVideoRendererControl_iid) == 0) m_videoOutput = new AVFCameraRendererControl(this); @@ -234,6 +250,11 @@ void AVFCameraService::releaseControl(QMediaControl *control) delete m_videoOutput; m_videoOutput = nullptr; } + else if (m_captureWindowControl == control) { + m_session->setCapturePreviewOutput(nullptr); + delete m_captureWindowControl; + m_captureWindowControl = nullptr; + } } diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 103ec0e17..a449bb806 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -54,6 +54,7 @@ class AVFCameraControl; class AVFCameraService; class AVFCameraRendererControl; class AVFMediaVideoProbeControl; +class AVFCameraWindowControl; struct AVFCameraInfo { @@ -79,6 +80,7 @@ public: AVFCameraInfo activeCameraInfo() const { return m_activeCameraInfo; } void setVideoOutput(AVFCameraRendererControl *output); + void setCapturePreviewOutput(AVFCameraWindowControl *output); AVCaptureSession *captureSession() const { return m_captureSession; } AVCaptureDevice *videoCaptureDevice() const; @@ -122,6 +124,7 @@ private: AVFCameraService *m_service; AVFCameraRendererControl *m_videoOutput; + AVFCameraWindowControl *m_capturePreviewWindowOutput; QCamera::State m_state; bool m_active; diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 3c5f8f09a..6ee9c2636 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -48,6 +48,7 @@ #include "avfcameraviewfindersettingscontrol.h" #include "avfimageencodercontrol.h" #include "avfcamerautility.h" +#include "avfcamerawindowcontrol.h" #include <CoreFoundation/CoreFoundation.h> #include <Foundation/Foundation.h> @@ -146,6 +147,7 @@ QList<AVFCameraInfo> AVFCameraSession::m_cameraDevices; AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent) : QObject(parent) , m_service(service) + , m_capturePreviewWindowOutput(nullptr) , m_state(QCamera::UnloadedState) , m_active(false) , m_videoInput(nil) @@ -160,6 +162,10 @@ AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent) AVFCameraSession::~AVFCameraSession() { + if (m_capturePreviewWindowOutput) { + m_capturePreviewWindowOutput->setLayer(nil); + } + if (m_videoInput) { [m_captureSession removeInput:m_videoInput]; [m_videoInput release]; @@ -257,6 +263,29 @@ void AVFCameraSession::setVideoOutput(AVFCameraRendererControl *output) output->configureAVCaptureSession(this); } +void AVFCameraSession::setCapturePreviewOutput(AVFCameraWindowControl *output) +{ +#ifdef QT_DEBUG_AVF + qDebug() << Q_FUNC_INFO << output; +#endif + + if (m_capturePreviewWindowOutput == output) + return; + + if (m_capturePreviewWindowOutput) + m_capturePreviewWindowOutput->setLayer(nil); + + m_capturePreviewWindowOutput = output; + + if (m_capturePreviewWindowOutput) { + AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:m_captureSession]; + m_capturePreviewWindowOutput->setLayer(previewLayer); + if (AVFCameraViewfinderSettingsControl2 *vfControl = m_service->viewfinderSettingsControl2()) { + m_capturePreviewWindowOutput->setNativeSize(vfControl->viewfinderSettings().resolution()); + } + } +} + AVCaptureDevice *AVFCameraSession::videoCaptureDevice() const { if (m_videoInput) @@ -409,6 +438,10 @@ bool AVFCameraSession::applyViewfinderSettings() } vfControl->applySettings(vfSettings); + + if (m_capturePreviewWindowOutput) + m_capturePreviewWindowOutput->setNativeSize(vfControl->viewfinderSettings().resolution()); + return !vfSettings.isNull(); } diff --git a/src/plugins/avfoundation/camera/avfcamerawindowcontrol.h b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.h new file mode 100644 index 000000000..d1a950e38 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 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-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFCAMERAWINDOWCONTROL_H +#define AVFCAMERAWINDOWCONTROL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QVideoWindowControl> + +@class AVCaptureVideoPreviewLayer; +#if defined(Q_OS_MACOS) +@class NSView; +typedef NSView NativeView; +#else +@class UIView; +typedef UIView NativeView; +#endif + +QT_BEGIN_NAMESPACE + +class AVFCameraWindowControl : public QVideoWindowControl +{ + Q_OBJECT +public: + AVFCameraWindowControl(QObject *parent = nullptr); + virtual ~AVFCameraWindowControl() override; + + // QVideoWindowControl interface +public: + WId winId() const override; + void setWinId(WId id) override; + + QRect displayRect() const override; + void setDisplayRect(const QRect &rect) override; + + bool isFullScreen() const override; + void setFullScreen(bool fullScreen) override; + + void repaint() override; + + QSize nativeSize() const override; + + Qt::AspectRatioMode aspectRatioMode() const override; + void setAspectRatioMode(Qt::AspectRatioMode mode) override; + + int brightness() const override; + void setBrightness(int brightness) override; + + int contrast() const override; + void setContrast(int contrast) override; + + int hue() const override; + void setHue(int hue) override; + + int saturation() const override; + void setSaturation(int saturation) override; + + // AVF Camera implementation details + void setNativeSize(QSize size); + void setLayer(AVCaptureVideoPreviewLayer *capturePreviewLayer); + +private: + void updateAspectRatio(); + void updateCaptureLayerBounds(); + + void retainNativeLayer(); + void releaseNativeLayer(); + + void attachNativeLayer(); + void detachNativeLayer(); + + WId m_winId{0}; + QRect m_displayRect; + bool m_fullscreen{false}; + Qt::AspectRatioMode m_aspectRatioMode{Qt::IgnoreAspectRatio}; + QSize m_nativeSize; + AVCaptureVideoPreviewLayer *m_captureLayer{nullptr}; + NativeView *m_nativeView{nullptr}; +}; + +QT_END_NAMESPACE + +#endif // AVFCAMERAWINDOWCONTROL_H diff --git a/src/plugins/avfoundation/camera/avfcamerawindowcontrol.mm b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.mm new file mode 100644 index 000000000..5154d0646 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.mm @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 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-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcamerawindowcontrol.h" + +#import <AVFoundation/AVFoundation.h> +#import <QuartzCore/CATransaction.h> + +#if QT_HAS_INCLUDE(<AppKit/AppKit.h>) +#import <AppKit/AppKit.h> +#endif + +#if QT_HAS_INCLUDE(<UIKit/UIKit.h>) +#import <UIKit/UIKit.h> +#endif + +QT_USE_NAMESPACE + +AVFCameraWindowControl::AVFCameraWindowControl(QObject *parent) + : QVideoWindowControl(parent) +{ + setObjectName(QStringLiteral("AVFCameraWindowControl")); +} + +AVFCameraWindowControl::~AVFCameraWindowControl() +{ + releaseNativeLayer(); +} + +WId AVFCameraWindowControl::winId() const +{ + return m_winId; +} + +void AVFCameraWindowControl::setWinId(WId id) +{ + if (m_winId == id) + return; + + m_winId = id; + + detachNativeLayer(); + m_nativeView = (NativeView*)m_winId; + attachNativeLayer(); +} + +QRect AVFCameraWindowControl::displayRect() const +{ + return m_displayRect; +} + +void AVFCameraWindowControl::setDisplayRect(const QRect &rect) +{ + if (m_displayRect != rect) { + m_displayRect = rect; + updateCaptureLayerBounds(); + } +} + +bool AVFCameraWindowControl::isFullScreen() const +{ + return m_fullscreen; +} + +void AVFCameraWindowControl::setFullScreen(bool fullscreen) +{ + if (m_fullscreen != fullscreen) { + m_fullscreen = fullscreen; + Q_EMIT fullScreenChanged(fullscreen); + } +} + +void AVFCameraWindowControl::repaint() +{ + if (m_captureLayer) + [m_captureLayer setNeedsDisplay]; +} + +QSize AVFCameraWindowControl::nativeSize() const +{ + return m_nativeSize; +} + +void AVFCameraWindowControl::setNativeSize(QSize size) +{ + if (m_nativeSize != size) { + m_nativeSize = size; + Q_EMIT nativeSizeChanged(); + } +} + +Qt::AspectRatioMode AVFCameraWindowControl::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void AVFCameraWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + if (m_aspectRatioMode != mode) { + m_aspectRatioMode = mode; + updateAspectRatio(); + } +} + +int AVFCameraWindowControl::brightness() const +{ + return 0; +} + +void AVFCameraWindowControl::setBrightness(int brightness) +{ + if (0 != brightness) + qWarning("AVFCameraWindowControl doesn't support changing Brightness"); +} + +int AVFCameraWindowControl::contrast() const +{ + return 0; +} + +void AVFCameraWindowControl::setContrast(int contrast) +{ + if (0 != contrast) + qWarning("AVFCameraWindowControl doesn't support changing Contrast"); +} + +int AVFCameraWindowControl::hue() const +{ + return 0; +} + +void AVFCameraWindowControl::setHue(int hue) +{ + if (0 != hue) + qWarning("AVFCameraWindowControl doesn't support changing Hue"); +} + +int AVFCameraWindowControl::saturation() const +{ + return 0; +} + +void AVFCameraWindowControl::setSaturation(int saturation) +{ + if (0 != saturation) + qWarning("AVFCameraWindowControl doesn't support changing Saturation"); +} + +void AVFCameraWindowControl::setLayer(AVCaptureVideoPreviewLayer *capturePreviewLayer) +{ + if (m_captureLayer == capturePreviewLayer) + return; + + releaseNativeLayer(); + + m_captureLayer = capturePreviewLayer; + + if (m_captureLayer) + retainNativeLayer(); +} + +void AVFCameraWindowControl::updateAspectRatio() +{ + if (m_captureLayer) { + switch (m_aspectRatioMode) { + case Qt::IgnoreAspectRatio: + [m_captureLayer setVideoGravity:AVLayerVideoGravityResize]; + break; + case Qt::KeepAspectRatio: + [m_captureLayer setVideoGravity:AVLayerVideoGravityResizeAspect]; + break; + case Qt::KeepAspectRatioByExpanding: + [m_captureLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; + break; + default: + break; + } + } +} + +void AVFCameraWindowControl::updateCaptureLayerBounds() +{ + if (m_captureLayer && m_nativeView) { + [CATransaction begin]; + [CATransaction setDisableActions: YES]; // disable animation/flicks + m_captureLayer.frame = m_displayRect.toCGRect(); + [CATransaction commit]; + } +} + +void AVFCameraWindowControl::retainNativeLayer() +{ + [m_captureLayer retain]; + + updateAspectRatio(); + attachNativeLayer(); +} + +void AVFCameraWindowControl::releaseNativeLayer() +{ + if (m_captureLayer) { + detachNativeLayer(); + [m_captureLayer release]; + m_captureLayer = nullptr; + } +} + +void AVFCameraWindowControl::attachNativeLayer() +{ + if (m_captureLayer && m_nativeView) { +#if defined(Q_OS_MACOS) + m_nativeView.wantsLayer = YES; +#endif + CALayer *nativeLayer = m_nativeView.layer; + [nativeLayer addSublayer:m_captureLayer]; + updateCaptureLayerBounds(); + } +} + +void AVFCameraWindowControl::detachNativeLayer() +{ + if (m_captureLayer && m_nativeView) + [m_captureLayer removeFromSuperlayer]; +} + +#include "moc_avfcamerawindowcontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm index dbaf3ed41..55a20b1bd 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm @@ -48,7 +48,6 @@ #include <QtCore/qbuffer.h> #include <QtConcurrent/qtconcurrentrun.h> #include <QtGui/qimagereader.h> -#include <private/qvideoframe_p.h> QT_USE_NAMESPACE @@ -214,7 +213,7 @@ void AVFImageCaptureControl::makeCapturePreview(CaptureRequest request, QTransform transform; transform.rotate(rotation); - Q_EMIT imageCaptured(request.captureId, qt_imageFromVideoFrame(frame).transformed(transform)); + Q_EMIT imageCaptured(request.captureId, frame.image().transformed(transform)); request.previewReady->release(); } diff --git a/src/plugins/avfoundation/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro index 4b960ed5a..70caf7536 100644 --- a/src/plugins/avfoundation/camera/camera.pro +++ b/src/plugins/avfoundation/camera/camera.pro @@ -42,7 +42,8 @@ HEADERS += \ avfcameraflashcontrol.h \ avfvideoencodersettingscontrol.h \ avfmediacontainercontrol.h \ - avfaudioencodersettingscontrol.h + avfaudioencodersettingscontrol.h \ + avfcamerawindowcontrol.h OBJECTIVE_SOURCES += \ avfcameraserviceplugin.mm \ @@ -65,7 +66,8 @@ OBJECTIVE_SOURCES += \ avfcameraflashcontrol.mm \ avfvideoencodersettingscontrol.mm \ avfmediacontainercontrol.mm \ - avfaudioencodersettingscontrol.mm + avfaudioencodersettingscontrol.mm \ + avfcamerawindowcontrol.mm osx { diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h index 7a268a3d9..db29e88aa 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h @@ -67,7 +67,7 @@ public: QMediaPlayer::MediaStatus mediaStatus() const; QMediaContent media() const; - const QIODevice *mediaStream() const; + QIODevice *mediaStream() const; void setMedia(const QMediaContent &content, QIODevice *stream); qint64 position() const; @@ -110,6 +110,9 @@ public Q_SLOTS: void processDurationChange(qint64 duration); + void streamReady(); + void streamDestroyed(); + Q_SIGNALS: void positionChanged(qint64 position); void durationChanged(qint64 duration); @@ -128,6 +131,7 @@ private: void setAudioAvailable(bool available); void setVideoAvailable(bool available); void setSeekable(bool seekable); + void resetStream(QIODevice *stream = nullptr); AVFMediaPlayerService *m_service; AVFVideoOutput *m_videoOutput; diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index ba902a53c..424f30008 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -42,6 +42,7 @@ #include "avfvideooutput.h" #include <qpointer.h> +#include <QFileInfo> #import <AVFoundation/AVFoundation.h> @@ -66,7 +67,7 @@ static void *AVFMediaPlayerSessionObserverBufferLikelyToKeepUpContext = &AVFMedi static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMediaPlayerSessionObserverCurrentItemObservationContext; static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext = &AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext; -@interface AVFMediaPlayerSessionObserver : NSObject +@interface AVFMediaPlayerSessionObserver : NSObject<AVAssetResourceLoaderDelegate> @property (readonly, getter=player) AVPlayer* m_player; @property (readonly, getter=playerItem) AVPlayerItem* m_playerItem; @@ -74,7 +75,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext @property (readonly, getter=session) AVFMediaPlayerSession* m_session; - (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session; -- (void) setURL:(NSURL *)url; +- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType; - (void) unloadMedia; - (void) prepareToPlayAsset:(AVURLAsset *)asset withKeys:(NSArray *)requestedKeys; - (void) assetFailedToPrepareForPlayback:(NSError *)error; @@ -84,6 +85,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext change:(NSDictionary *)change context:(void *)context; - (void) detatchSession; - (void) dealloc; +- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest; @end @implementation AVFMediaPlayerSessionObserver @@ -95,6 +97,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext AVPlayerLayer *m_playerLayer; NSURL *m_URL; BOOL m_bufferIsLikelyToKeepUp; + NSData *m_data; + NSString *m_mimeType; } @synthesize m_player, m_playerItem, m_playerLayer, m_session; @@ -109,8 +113,11 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext return self; } -- (void) setURL:(NSURL *)url +- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType { + [m_mimeType release]; + m_mimeType = [mimeType retain]; + if (m_URL != url) { [m_URL release]; @@ -122,6 +129,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext // use __block to avoid maintaining strong references on variables captured by the // following block callback __block AVURLAsset *asset = [[AVURLAsset URLAssetWithURL:m_URL options:nil] retain]; + [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()]; + __block NSArray *requestedKeys = [[NSArray arrayWithObjects:AVF_TRACKS_KEY, AVF_PLAYABLE_KEY, nil] retain]; __block AVFMediaPlayerSessionObserver *blockSelf = self; @@ -403,9 +412,48 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext [m_URL release]; } + [m_mimeType release]; [super dealloc]; } +- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest +{ + Q_UNUSED(resourceLoader); + + if (![loadingRequest.request.URL.scheme isEqualToString:@"iodevice"]) + return NO; + + QIODevice *device = m_session->mediaStream(); + if (!device) + return NO; + + device->seek(loadingRequest.dataRequest.requestedOffset); + if (loadingRequest.contentInformationRequest) { + loadingRequest.contentInformationRequest.contentType = m_mimeType; + loadingRequest.contentInformationRequest.contentLength = device->size(); + loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES; + } + + if (loadingRequest.dataRequest) { + NSInteger requestedLength = loadingRequest.dataRequest.requestedLength; + int maxBytes = qMin(32 * 1064, int(requestedLength)); + char buffer[maxBytes]; + NSInteger submitted = 0; + while (submitted < requestedLength) { + qint64 len = device->read(buffer, maxBytes); + if (len < 1) + break; + + [loadingRequest.dataRequest respondWithData:[NSData dataWithBytes:buffer length:len]]; + submitted += len; + } + + // Finish loading even if not all bytes submitted. + [loadingRequest finishLoading]; + } + + return YES; +} @end AVFMediaPlayerSession::AVFMediaPlayerSession(AVFMediaPlayerService *service, QObject *parent) @@ -483,11 +531,23 @@ QMediaContent AVFMediaPlayerSession::media() const return m_resources; } -const QIODevice *AVFMediaPlayerSession::mediaStream() const +QIODevice *AVFMediaPlayerSession::mediaStream() const { return m_mediaStream; } +static void setURL(void *observer, const QString &url, const QString &mimeType = QString()) +{ + NSString *urlString = [NSString stringWithUTF8String:url.toUtf8().constData()]; + NSURL *nsurl = [NSURL URLWithString:urlString]; + [static_cast<AVFMediaPlayerSessionObserver*>(observer) setURL:nsurl mimeType:[NSString stringWithUTF8String:mimeType.toLatin1().constData()]]; +} + +static void setStreamURL(void *observer, const QString &url) +{ + setURL(observer, QLatin1String("iodevice://") + url, QFileInfo(url).suffix()); +} + void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) { #ifdef QT_DEBUG_AVF @@ -497,7 +557,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st [static_cast<AVFMediaPlayerSessionObserver*>(m_observer) unloadMedia]; m_resources = content; - m_mediaStream = stream; + resetStream(stream); setAudioAvailable(false); setVideoAvailable(false); @@ -508,7 +568,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st const QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; const QMediaPlayer::State oldState = m_state; - if (content.isNull() || content.request().url().isEmpty()) { + if (!m_mediaStream && (content.isNull() || content.request().url().isEmpty())) { m_mediaStatus = QMediaPlayer::NoMedia; if (m_mediaStatus != oldMediaStatus) Q_EMIT mediaStatusChanged(m_mediaStatus); @@ -524,11 +584,16 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st if (m_mediaStatus != oldMediaStatus) Q_EMIT mediaStatusChanged(m_mediaStatus); - //Load AVURLAsset - //initialize asset using content's URL - NSString *urlString = [NSString stringWithUTF8String:content.request().url().toEncoded().constData()]; - NSURL *url = [NSURL URLWithString:urlString]; - [static_cast<AVFMediaPlayerSessionObserver*>(m_observer) setURL:url]; + if (m_mediaStream) { + // If there is a data, try to load it, + // otherwise wait for readyRead. + if (m_mediaStream->size()) + setStreamURL(m_observer, m_resources.request().url().toString()); + } else { + //Load AVURLAsset + //initialize asset using content's URL + setURL(m_observer, m_resources.request().url().toString()); + } m_state = QMediaPlayer::StoppedState; if (m_state != oldState) @@ -969,3 +1034,28 @@ void AVFMediaPlayerSession::processMediaLoadError() Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media")); } + +void AVFMediaPlayerSession::streamReady() +{ + setStreamURL(m_observer, m_resources.request().url().toString()); +} + +void AVFMediaPlayerSession::streamDestroyed() +{ + resetStream(nullptr); +} + +void AVFMediaPlayerSession::resetStream(QIODevice *stream) +{ + if (m_mediaStream) { + disconnect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayerSession::streamReady); + disconnect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayerSession::streamDestroyed); + } + + m_mediaStream = stream; + + if (m_mediaStream) { + connect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayerSession::streamReady); + connect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayerSession::streamDestroyed); + } +} diff --git a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm index e06ddc4b0..63bdee4f5 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm @@ -177,7 +177,11 @@ void AVFVideoRendererControl::setSurface(QAbstractVideoSurface *surface) #endif //Check for needed formats to render as OpenGL Texture - m_enableOpenGL = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32); + auto handleGlEnabled = [this] { + m_enableOpenGL = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32); + }; + handleGlEnabled(); + connect(m_surface, &QAbstractVideoSurface::supportedFormatsChanged, this, handleGlEnabled); //If we already have a layer, but changed surfaces start rendering again if (m_playerLayer && !m_displayLink->isActive()) { diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index a0c120816..cee3e9c56 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -44,7 +44,6 @@ #include <QtMultimedia/qvideosurfaceformat.h> #include <QtMultimedia/qcameraimagecapture.h> #include <private/qmemoryvideobuffer_p.h> -#include <private/qvideoframe_p.h> #include "dscamerasession.h" #include "dsvideorenderer.h" @@ -637,7 +636,7 @@ void DSCameraSession::presentFrame() if (m_capturedFrame.isValid()) { - captureImage = qt_imageFromVideoFrame(m_capturedFrame); + captureImage = m_capturedFrame.image(); const bool needsVerticalMirroring = m_previewSurfaceFormat.scanLineDirection() != QVideoSurfaceFormat::TopToBottom; captureImage = captureImage.mirrored(m_needsHorizontalMirroring, needsVerticalMirroring); // also causes a deep copy of the data diff --git a/src/plugins/gstreamer/camerabin/camerabinzoom.cpp b/src/plugins/gstreamer/camerabin/camerabinzoom.cpp index bb3659493..401e13207 100644 --- a/src/plugins/gstreamer/camerabin/camerabinzoom.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinzoom.cpp @@ -51,7 +51,9 @@ CameraBinZoom::CameraBinZoom(CameraBinSession *session) , m_requestedOpticalZoom(1.0) , m_requestedDigitalZoom(1.0) { - + GstElement *camerabin = m_session->cameraBin(); + g_signal_connect(G_OBJECT(camerabin), "notify::zoom", G_CALLBACK(updateZoom), this); + g_signal_connect(G_OBJECT(camerabin), "notify::max-zoom", G_CALLBACK(updateMaxZoom), this); } CameraBinZoom::~CameraBinZoom() @@ -114,4 +116,32 @@ void CameraBinZoom::zoomTo(qreal optical, qreal digital) emit currentDigitalZoomChanged(digital); } +void CameraBinZoom::updateZoom(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(p); + + gfloat zoomFactor = 1.0; + g_object_get(o, ZOOM_PROPERTY, &zoomFactor, NULL); + + CameraBinZoom *zoom = reinterpret_cast<CameraBinZoom *>(d); + + QMetaObject::invokeMethod(zoom, "currentDigitalZoomChanged", + Qt::QueuedConnection, + Q_ARG(qreal, zoomFactor)); +} + +void CameraBinZoom::updateMaxZoom(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(p); + + gfloat zoomFactor = 1.0; + g_object_get(o, MAX_ZOOM_PROPERTY, &zoomFactor, NULL); + + CameraBinZoom *zoom = reinterpret_cast<CameraBinZoom *>(d); + + QMetaObject::invokeMethod(zoom, "maximumDigitalZoomChanged", + Qt::QueuedConnection, + Q_ARG(qreal, zoomFactor)); +} + QT_END_NAMESPACE diff --git a/src/plugins/gstreamer/camerabin/camerabinzoom.h b/src/plugins/gstreamer/camerabin/camerabinzoom.h index 8ad4764b2..858ada2da 100644 --- a/src/plugins/gstreamer/camerabin/camerabinzoom.h +++ b/src/plugins/gstreamer/camerabin/camerabinzoom.h @@ -41,6 +41,7 @@ #define CAMERABINZOOMCONTROL_H #include <qcamerazoomcontrol.h> +#include <gst/gst.h> QT_BEGIN_NAMESPACE @@ -64,6 +65,9 @@ public: void zoomTo(qreal optical, qreal digital) override; private: + static void updateZoom(GObject *o, GParamSpec *p, gpointer d); + static void updateMaxZoom(GObject *o, GParamSpec *p, gpointer d); + CameraBinSession *m_session; qreal m_requestedOpticalZoom; qreal m_requestedDigitalZoom; diff --git a/src/plugins/m3u/qm3uhandler.cpp b/src/plugins/m3u/qm3uhandler.cpp index 017c32d92..5e05994ef 100644 --- a/src/plugins/m3u/qm3uhandler.cpp +++ b/src/plugins/m3u/qm3uhandler.cpp @@ -163,7 +163,7 @@ public: virtual bool writeItem(const QMediaContent& item) { - *m_textStream << item.request().url().toString() << endl; + *m_textStream << item.request().url().toString() << Qt::endl; return true; } |