diff options
author | Lars Knoll <lars.knoll@qt.io> | 2021-01-25 14:59:09 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2021-01-29 08:52:07 +0000 |
commit | 2e77a041e162743b49d41fef545b143ae6c3a830 (patch) | |
tree | e6ba99e78d8cfeef5d3e4f800501335ab5615202 | |
parent | a1e4736628146f737cf4456ff560896e139b81cd (diff) |
Cleanup QCameraInfo
Various API changes to QCameraInfo:
* Remove the camera orientation from our API This is
an implementation detail that should never be exposed
to the user. For fixed cameras it's uninteresting
and for mobile cameras, we can use the physical orientation
of the device to create a stream that is oriented the
correct way.
* Add a QVideoFormat class describing a video format
* Add a QList<QVideoFormat> videoFormats()
* Add a QList<QSize> photoResolutions()
* Implement the API for gstreamer and macOS.
Change-Id: I9ffd9caeb6d07a6f267608a6bd794d99699fffbb
Reviewed-by: Doris Verria <doris.verria@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
26 files changed, 322 insertions, 177 deletions
diff --git a/cmake/FindGSTREAMER.cmake b/cmake/FindGStreamer.cmake index ef9edd485..ef9edd485 100644 --- a/cmake/FindGSTREAMER.cmake +++ b/cmake/FindGStreamer.cmake diff --git a/src/imports/multimedia/qdeclarativecamera.cpp b/src/imports/multimedia/qdeclarativecamera.cpp index d07f0015f..9c4004ef6 100644 --- a/src/imports/multimedia/qdeclarativecamera.cpp +++ b/src/imports/multimedia/qdeclarativecamera.cpp @@ -296,13 +296,13 @@ QDeclarativeCamera::Position QDeclarativeCamera::position() const void QDeclarativeCamera::setPosition(Position position) { - QCamera::Position pos = QCamera::Position(position); + QCameraInfo::Position pos = QCameraInfo::Position(position); if (pos == m_currentCameraInfo.position()) return; QByteArray id; - if (pos != QCamera::UnspecifiedPosition) { + if (pos != QCameraInfo::UnspecifiedPosition) { const QList<QCameraInfo> cameras = QMediaDeviceManager::videoInputs(); for (auto c : cameras) { if (c.position() == pos) { @@ -354,11 +354,6 @@ QString QDeclarativeCamera::displayName() const \since 5.4 */ -int QDeclarativeCamera::orientation() const -{ - return m_currentCameraInfo.orientation(); -} - void QDeclarativeCamera::setupDevice(const QString &deviceName) { QCameraInfo oldCameraInfo = m_currentCameraInfo; @@ -383,8 +378,6 @@ void QDeclarativeCamera::setupDevice(const QString &deviceName) emit displayNameChanged(); if (oldCameraInfo.position() != m_currentCameraInfo.position()) emit positionChanged(); - if (oldCameraInfo.orientation() != m_currentCameraInfo.orientation()) - emit orientationChanged(); setCameraState(previousState); } diff --git a/src/imports/multimedia/qdeclarativecamera_p.h b/src/imports/multimedia/qdeclarativecamera_p.h index f2cb38b51..6faa461f6 100644 --- a/src/imports/multimedia/qdeclarativecamera_p.h +++ b/src/imports/multimedia/qdeclarativecamera_p.h @@ -82,7 +82,6 @@ class QDeclarativeCamera : public QObject, public QQmlParserStatus Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged REVISION 1) Q_PROPERTY(Position position READ position WRITE setPosition NOTIFY positionChanged REVISION 1) Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged REVISION 1) - Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged REVISION 1) Q_PROPERTY(CaptureMode captureMode READ captureMode WRITE setCaptureMode NOTIFY captureModeChanged) Q_PROPERTY(State cameraState READ cameraState WRITE setCameraState NOTIFY cameraStateChanged) @@ -123,9 +122,9 @@ class QDeclarativeCamera : public QObject, public QQmlParserStatus public: enum Position { - UnspecifiedPosition = QCamera::UnspecifiedPosition, - BackFace = QCamera::BackFace, - FrontFace = QCamera::FrontFace + UnspecifiedPosition = QCameraInfo::UnspecifiedPosition, + BackFace = QCameraInfo::BackFace, + FrontFace = QCameraInfo::FrontFace }; enum CaptureMode { @@ -256,7 +255,6 @@ public: void setPosition(Position position); QString displayName() const; - int orientation() const; CaptureMode captureMode() const; State cameraState() const; @@ -301,7 +299,6 @@ Q_SIGNALS: Q_REVISION(1) void deviceIdChanged(); Q_REVISION(1) void positionChanged(); Q_REVISION(1) void displayNameChanged(); - Q_REVISION(1) void orientationChanged(); void captureModeChanged(); void cameraStateChanged(QDeclarativeCamera::State); diff --git a/src/imports/multimedia/qdeclarativemultimediaglobal.cpp b/src/imports/multimedia/qdeclarativemultimediaglobal.cpp index 5e851ab79..d678e07dc 100644 --- a/src/imports/multimedia/qdeclarativemultimediaglobal.cpp +++ b/src/imports/multimedia/qdeclarativemultimediaglobal.cpp @@ -160,7 +160,7 @@ static QJSValue cameraInfoToJSValue(QJSEngine *jsEngine, const QCameraInfo &came o.setProperty(QStringLiteral("deviceId"), QString::fromLatin1(camera.id())); o.setProperty(QStringLiteral("displayName"), camera.description()); o.setProperty(QStringLiteral("position"), int(camera.position())); - o.setProperty(QStringLiteral("orientation"), camera.orientation()); + // ### Add resolutions and framerates return o; } diff --git a/src/multimedia/camera/qcamera.cpp b/src/multimedia/camera/qcamera.cpp index b9e4b8f53..bc158969f 100644 --- a/src/multimedia/camera/qcamera.cpp +++ b/src/multimedia/camera/qcamera.cpp @@ -63,7 +63,7 @@ static void qRegisterCameraMetaTypes() qRegisterMetaType<QCamera::LockType>("QCamera::LockType"); qRegisterMetaType<QCamera::LockStatus>("QCamera::LockStatus"); qRegisterMetaType<QCamera::LockChangeReason>("QCamera::LockChangeReason"); - qRegisterMetaType<QCamera::Position>("QCamera::Position"); + qRegisterMetaType<QCameraInfo::Position>("QCameraInfo::Position"); } Q_CONSTRUCTOR_FUNCTION(qRegisterCameraMetaTypes) @@ -314,10 +314,10 @@ QCamera::QCamera(const QCameraInfo &cameraInfo, QObject *parent) back-facing cameras. If no camera is available at the specified \a position or if \a position is - QCamera::UnspecifiedPosition, the default camera is used. + QCameraInfo::UnspecifiedPosition, the default camera is used. */ -QCamera::QCamera(QCamera::Position position, QObject *parent) +QCamera::QCamera(QCameraInfo::Position position, QObject *parent) : QMediaSource(*new QCameraPrivate, parent, QMediaPlatformIntegration::instance()->createCaptureInterface(QMediaRecorder::AudioAndVideo)) @@ -1118,7 +1118,7 @@ void QCamera::unlock() */ /*! - \enum QCamera::Position + \enum QCameraInfo::Position \since 5.3 This enum specifies the physical position of the camera on the system hardware. diff --git a/src/multimedia/camera/qcamera.h b/src/multimedia/camera/qcamera.h index 9829e3ac2..80ebe88eb 100644 --- a/src/multimedia/camera/qcamera.h +++ b/src/multimedia/camera/qcamera.h @@ -52,6 +52,7 @@ #include <QtMultimedia/qcamerafocus.h> #include <QtMultimedia/qcameraimageprocessing.h> #include <QtMultimedia/qcameraviewfindersettings.h> +#include <QtMultimedia/qcamerainfo.h> #include <QtMultimedia/qmediaenumdebug.h> @@ -151,16 +152,9 @@ public: }; Q_DECLARE_FLAGS(LockTypes, LockType) - enum Position - { - UnspecifiedPosition, - BackFace, - FrontFace - }; - explicit QCamera(QObject *parent = nullptr); explicit QCamera(const QCameraInfo& cameraInfo, QObject *parent = nullptr); - explicit QCamera(QCamera::Position position, QObject *parent = nullptr); + explicit QCamera(QCameraInfo::Position position, QObject *parent = nullptr); ~QCamera(); QMultimedia::AvailabilityStatus availability() const override; @@ -273,7 +267,6 @@ Q_DECLARE_METATYPE(QCamera::CaptureModes) Q_DECLARE_METATYPE(QCamera::LockType) Q_DECLARE_METATYPE(QCamera::LockStatus) Q_DECLARE_METATYPE(QCamera::LockChangeReason) -Q_DECLARE_METATYPE(QCamera::Position) Q_MEDIA_ENUM_DEBUG(QCamera, State) Q_MEDIA_ENUM_DEBUG(QCamera, Status) @@ -282,6 +275,5 @@ Q_MEDIA_ENUM_DEBUG(QCamera, CaptureMode) Q_MEDIA_ENUM_DEBUG(QCamera, LockType) Q_MEDIA_ENUM_DEBUG(QCamera, LockStatus) Q_MEDIA_ENUM_DEBUG(QCamera, LockChangeReason) -Q_MEDIA_ENUM_DEBUG(QCamera, Position) #endif // QCAMERA_H diff --git a/src/multimedia/camera/qcamera_p.h b/src/multimedia/camera/qcamera_p.h index ea9926ca4..de10b7d9a 100644 --- a/src/multimedia/camera/qcamera_p.h +++ b/src/multimedia/camera/qcamera_p.h @@ -64,21 +64,21 @@ class QCameraPrivate : public QMediaSourcePrivate { Q_DECLARE_NON_CONST_PUBLIC(QCamera) public: - QCameraPrivate(): - QMediaSourcePrivate(), - control(nullptr), - cameraExposure(nullptr), - cameraFocus(nullptr), - imageProcessing(nullptr), - viewfinder(nullptr), - capture(nullptr), - state(QCamera::UnloadedState), - error(QCamera::NoError), - requestedLocks(QCamera::NoLock), - lockStatus(QCamera::Unlocked), - lockChangeReason(QCamera::UserRequest), - supressLockChangedSignal(false), - restartPending(false) + QCameraPrivate() + : QMediaSourcePrivate(), + control(nullptr), + cameraExposure(nullptr), + cameraFocus(nullptr), + imageProcessing(nullptr), + viewfinder(nullptr), + capture(nullptr), + state(QCamera::UnloadedState), + error(QCamera::NoError), + requestedLocks(QCamera::NoLock), + lockStatus(QCamera::Unlocked), + lockChangeReason(QCamera::UserRequest), + supressLockChangedSignal(false), + restartPending(false) { } diff --git a/src/multimedia/camera/qcamerainfo.cpp b/src/multimedia/camera/qcamerainfo.cpp index 4946142c2..571b749b0 100644 --- a/src/multimedia/camera/qcamerainfo.cpp +++ b/src/multimedia/camera/qcamerainfo.cpp @@ -43,6 +43,46 @@ QT_BEGIN_NAMESPACE +QCameraFormat::QCameraFormat(const QCameraFormat &other) + : d(other.d) +{ +} + +QCameraFormat &QCameraFormat::operator=(const QCameraFormat &other) +{ + d = other.d; + return *this; +} + +QCameraFormat::~QCameraFormat() +{ +} + +QVideoFrame::PixelFormat QCameraFormat::pixelFormat() const +{ + return d->pixelFormat; +} + +QSize QCameraFormat::resolution() const +{ + return d->resolution; +} + +float QCameraFormat::minFrameRate() const +{ + return d->minFrameRate; +} + +float QCameraFormat::maxFrameRate() const +{ + return d->maxFrameRate; +} + +QCameraFormat::QCameraFormat(QCameraFormatPrivate *p) + : d(p) +{ +} + /*! \class QCameraInfo \brief The QCameraInfo class provides general information about camera devices. @@ -76,19 +116,6 @@ QT_BEGIN_NAMESPACE QCameraInfo::QCameraInfo() = default; /*! - Constructs a camera info object for \a camera. - - You can use it to query information about the \a camera object passed as argument. - - If the \a camera is invalid, for example when no camera device is available on the system, - the QCameraInfo object will be invalid and isNull() will return true. -*/ -QCameraInfo::QCameraInfo(const QCamera &camera) - : QCameraInfo(camera.cameraInfo()) -{ -} - -/*! Constructs a copy of \a other. */ QCameraInfo::QCameraInfo(const QCameraInfo &other) @@ -116,8 +143,7 @@ bool QCameraInfo::operator==(const QCameraInfo &other) const return (d->id == other.d->id && d->description == other.d->description - && d->position == other.d->position - && d->orientation == other.d->orientation); + && d->position == other.d->position); } /*! @@ -154,28 +180,22 @@ QString QCameraInfo::description() const /*! Returns the physical position of the camera on the hardware system. */ -QCamera::Position QCameraInfo::position() const +QCameraInfo::Position QCameraInfo::position() const { - return d ? d->position : QCamera::UnspecifiedPosition; + return d ? d->position : QCameraInfo::UnspecifiedPosition; } -/*! - Returns the physical orientation of the camera sensor. - - The value is the orientation angle (clockwise, in steps of 90 degrees) of the camera sensor - in relation to the display in its natural orientation. - - You can show the camera image in the correct orientation by rotating it by this value in the - anti-clockwise direction. +QList<QSize> QCameraInfo::photoResolutions() const +{ + return d->photoResolutions; +} - For example, suppose a mobile device which is naturally in portrait orientation. The back-facing - camera is mounted in landscape. If the top side of the camera sensor is aligned with the - right edge of the screen in natural orientation, the value should be 270. If the top side of a - front-facing camera sensor is aligned with the right of the screen, the value should be 90. +/*! + Returns the video formats supported by the camera. */ -int QCameraInfo::orientation() const +QList<QCameraFormat> QCameraInfo::videoFormats() const { - return d ? d->orientation : 0; + return d ? d->videoFormats : QList<QCameraFormat>{}; } QCameraInfo::QCameraInfo(QCameraInfoPrivate *p) @@ -203,8 +223,7 @@ QDebug operator<<(QDebug d, const QCameraInfo &camera) d.maybeSpace() << QStringLiteral("QCameraInfo(name=%1, position=%2, orientation=%3)") .arg(camera.description()) .arg(QString::fromLatin1(QCamera::staticMetaObject.enumerator(QCamera::staticMetaObject.indexOfEnumerator("Position")) - .valueToKey(camera.position()))) - .arg(camera.orientation()); + .valueToKey(camera.position()))); return d.space(); } #endif diff --git a/src/multimedia/camera/qcamerainfo.h b/src/multimedia/camera/qcamerainfo.h index 8b640410a..afe9965a6 100644 --- a/src/multimedia/camera/qcamerainfo.h +++ b/src/multimedia/camera/qcamerainfo.h @@ -40,36 +40,71 @@ #ifndef QCAMERAINFO_H #define QCAMERAINFO_H -#include <QtMultimedia/qcamera.h> +#include <QtMultimedia/qvideoframe.h> #include <QtCore/qsharedpointer.h> QT_BEGIN_NAMESPACE -class QCameraInfoPrivate; +class QCameraFormatPrivate; +class Q_MULTIMEDIA_EXPORT QCameraFormat +{ +public: + QCameraFormat() = delete; + QCameraFormat(const QCameraFormat &other); + QCameraFormat &operator=(const QCameraFormat &other); + ~QCameraFormat(); + + QVideoFrame::PixelFormat pixelFormat() const; + QSize resolution() const; + float minFrameRate() const; + float maxFrameRate() const; + +private: + friend class QCameraFormatPrivate; + QCameraFormat(QCameraFormatPrivate *p); + QExplicitlySharedDataPointer<QCameraFormatPrivate> d; +}; +class QCameraInfoPrivate; class Q_MULTIMEDIA_EXPORT QCameraInfo { public: QCameraInfo(); - explicit QCameraInfo(const QCamera &camera); QCameraInfo(const QCameraInfo& other); + QCameraInfo& operator=(const QCameraInfo& other); ~QCameraInfo(); - QCameraInfo& operator=(const QCameraInfo& other); bool operator==(const QCameraInfo &other) const; inline bool operator!=(const QCameraInfo &other) const; bool isNull() const; QByteArray id() const; + QString description() const; + + // ### Add here and to QAudioDeviceInfo +// QByteArray groupId() const; +// QString groupDescription() const; + bool isDefault() const; - QString description() const; - QCamera::Position position() const; - int orientation() const; + enum Position + { + UnspecifiedPosition, + BackFace, + FrontFace + }; + + Position position() const; + + QList<QSize> photoResolutions() const; + QList<QCameraFormat> videoFormats() const; + + // ### Add zoom and other camera information - QCameraInfo(QCameraInfoPrivate *p); private: + friend class QCameraInfoPrivate; + QCameraInfo(QCameraInfoPrivate *p); QExplicitlySharedDataPointer<QCameraInfoPrivate> d; }; diff --git a/src/multimedia/camera/qcamerainfo_p.h b/src/multimedia/camera/qcamerainfo_p.h index 377a418e3..710bd0971 100644 --- a/src/multimedia/camera/qcamerainfo_p.h +++ b/src/multimedia/camera/qcamerainfo_p.h @@ -56,14 +56,29 @@ QT_BEGIN_NAMESPACE +class QCameraFormatPrivate : public QSharedData +{ +public: + QVideoFrame::PixelFormat pixelFormat; + QSize resolution; + float minFrameRate = 0; + float maxFrameRate = 0; + + QCameraFormat create() { return QCameraFormat(this); } +}; + class QCameraInfoPrivate : public QSharedData { public: QByteArray id; QString description; bool isDefault = false; - QCamera::Position position = QCamera::UnspecifiedPosition; + QCameraInfo::Position position = QCameraInfo::UnspecifiedPosition; int orientation = 0; + QList<QSize> photoResolutions; + QList<QCameraFormat> videoFormats; + + QCameraInfo create() { return QCameraInfo(this); } }; QT_END_NAMESPACE diff --git a/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp b/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp index f851caadd..d6c6488d2 100644 --- a/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp +++ b/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp @@ -82,7 +82,7 @@ void overview_viewfinder() void overview_camera_by_position() { //! [Camera overview position] - camera = new QCamera(QCamera::FrontFace); + camera = new QCamera(QCameraInfo::FrontFace); //! [Camera overview position] } @@ -128,7 +128,7 @@ void overview_viewfinder_orientation() const int screenAngle = screen->angleBetween(screen->nativeOrientation(), screen->orientation()); int rotation; - if (cameraInfo.position() == QCamera::BackFace) { + if (cameraInfo.position() == QCameraInfo::BackFace) { rotation = (cameraInfo.orientation() - screenAngle) % 360; } else { // Front position, compensate the mirror @@ -202,9 +202,9 @@ void camera_info() QCamera myCamera; QCameraInfo cameraInfo(myCamera); - if (cameraInfo.position() == QCamera::FrontFace) + if (cameraInfo.position() == QCameraInfo::FrontFace) qDebug() << "The camera is on the front face of the hardware system."; - else if (cameraInfo.position() == QCamera::BackFace) + else if (cameraInfo.position() == QCameraInfo::BackFace) qDebug() << "The camera is on the back face of the hardware system."; qDebug() << "The camera sensor orientation is " << cameraInfo.orientation() << " degrees."; diff --git a/src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp b/src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp index b609314a7..a9829ce4b 100644 --- a/src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp +++ b/src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp @@ -165,7 +165,7 @@ void QAndroidCameraSession::updateAvailableCameras() AndroidCamera::getCameraInfo(i, info); if (!info->id.isEmpty()) - g_availableCameras->append(QCameraInfo(info)); + g_availableCameras->append(info->create()); } } diff --git a/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp b/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp index 41e1fcf20..e7ca0e578 100644 --- a/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp +++ b/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp @@ -787,13 +787,13 @@ void AndroidCamera::getCameraInfo(int id, QCameraInfoPrivate *info) case AndroidCamera::CameraFacingBack: info->id = QByteArray("back"); info->description = QStringLiteral("Rear-facing camera"); - info->position = QCamera::BackFace; + info->position = QCameraInfo::BackFace; info->isDefault = true; break; case AndroidCamera::CameraFacingFront: info->id = QByteArray("front"); info->description = QStringLiteral("Front-facing camera"); - info->position = QCamera::FrontFace; + info->position = QCameraInfo::FrontFace; break; default: break; diff --git a/src/multimedia/platform/darwin/camera/avfcameracontrol.mm b/src/multimedia/platform/darwin/camera/avfcameracontrol.mm index 31de25d08..d340696f2 100644 --- a/src/multimedia/platform/darwin/camera/avfcameracontrol.mm +++ b/src/multimedia/platform/darwin/camera/avfcameracontrol.mm @@ -309,6 +309,9 @@ QVideoFrame::PixelFormat AVFCameraControl::QtPixelFormatFromCVFormat(unsigned av return QVideoFrame::Format_UYVY; case kCVPixelFormatType_422YpCbCr8_yuvs: return QVideoFrame::Format_YUYV; + case kCMVideoCodecType_JPEG: + case kCMVideoCodecType_JPEG_OpenDML: + return QVideoFrame::Format_Jpeg; default: return QVideoFrame::Format_Invalid; } diff --git a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h b/src/multimedia/platform/darwin/camera/avfcamerasession_p.h index 4ea8cb9b5..584bd9b1b 100644 --- a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h +++ b/src/multimedia/platform/darwin/camera/avfcamerasession_p.h @@ -70,12 +70,12 @@ class AVFCameraWindowControl; struct AVFCameraInfo { - AVFCameraInfo() : position(QCamera::UnspecifiedPosition), orientation(0) + AVFCameraInfo() : position(QCameraInfo::UnspecifiedPosition), orientation(0) { } QByteArray deviceId; QString description; - QCamera::Position position; + QCameraInfo::Position position; int orientation; }; diff --git a/src/multimedia/platform/darwin/camera/avfmediarecordercontrol_ios.mm b/src/multimedia/platform/darwin/camera/avfmediarecordercontrol_ios.mm index 666278a40..22989953f 100644 --- a/src/multimedia/platform/darwin/camera/avfmediarecordercontrol_ios.mm +++ b/src/multimedia/platform/darwin/camera/avfmediarecordercontrol_ios.mm @@ -269,10 +269,11 @@ void AVFMediaRecorderControlIOS::setState(QMediaRecorder::State state) QCameraInfo cameraInfo = m_service->session()->activeCameraInfo(); int screenOrientation = 360 - m_orientationHandler.currentOrientation(); float rotation = 0; - if (cameraInfo.position() == QCamera::FrontFace) - rotation = (screenOrientation + cameraInfo.orientation()) % 360; - else - rotation = (screenOrientation + (360 - cameraInfo.orientation())) % 360; + // ### +// if (cameraInfo.position() == QCameraInfo::FrontFace) +// rotation = (screenOrientation + cameraInfo.orientation()) % 360; +// else +// rotation = (screenOrientation + (360 - cameraInfo.orientation())) % 360; if ([m_writer setupWithFileURL:nsFileURL cameraService:m_service diff --git a/src/multimedia/platform/darwin/qdarwindevicemanager.mm b/src/multimedia/platform/darwin/qdarwindevicemanager.mm index 4e4642a3c..1a483dd72 100644 --- a/src/multimedia/platform/darwin/qdarwindevicemanager.mm +++ b/src/multimedia/platform/darwin/qdarwindevicemanager.mm @@ -44,7 +44,9 @@ #include "private/qcoreaudiodeviceinfo_p.h" #include "private/qcoreaudioinput_p.h" #include "private/qcoreaudiooutput_p.h" +#include "private/avfcameracontrol_p.h" +#include <CoreVideo/CoreVideo.h> #import <AVFoundation/AVFoundation.h> #if defined(Q_OS_IOS) || defined(Q_OS_TVOS) @@ -180,6 +182,8 @@ QDarwinDeviceManager::QDarwinDeviceManager() #else // ### This should use the audio session manager #endif + updateCameraDevices(); + updateAudioDevices(); } @@ -233,6 +237,7 @@ void QDarwinDeviceManager::updateCameraDevices() AVCaptureDevice *defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + for (AVCaptureDevice *device in videoDevices) { QCameraInfoPrivate *info = new QCameraInfoPrivate; @@ -241,8 +246,55 @@ void QDarwinDeviceManager::updateCameraDevices() info->id = QByteArray([[device uniqueID] UTF8String]); info->description = QString::fromNSString([device localizedName]); +// qDebug() << "Camera:" << info->description; + + QSet<QSize> photoResolutions; + QList<QCameraFormat> videoFormats; + + for (AVCaptureDeviceFormat *format in device.formats) { + if (![format.mediaType isEqualTo:AVMediaTypeVideo]) + continue; + + auto dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription); + QSize resolution(dimensions.width, dimensions.height); + photoResolutions.insert(resolution); +// qDebug() << " Format:" << resolution; + float maxFrameRate = 0; + float minFrameRate = 1.e6; + + auto encoding = CMVideoFormatDescriptionGetCodecType(format.formatDescription); + auto pixelFormat = AVFCameraControl::QtPixelFormatFromCVFormat(encoding); + // Ignore pixel formats we can't handle + if (pixelFormat == QVideoFrame::Format_Invalid) + continue; + + for (AVFrameRateRange *frameRateRange in format.videoSupportedFrameRateRanges) { + if (frameRateRange.minFrameRate < minFrameRate) + minFrameRate = frameRateRange.minFrameRate; + if (frameRateRange.maxFrameRate > maxFrameRate) + maxFrameRate = frameRateRange.maxFrameRate; + } +// qDebug() << " " << frameRateRange.minFrameRate << frameRateRange.maxFrameRate; + +#ifdef Q_OS_IOS + // ### +// CMVideoDimensions photoDim = format.highResolutionStillImageDimensions; +// QSize photoSize(photoDim.....) + // Add to photoresolutions +#endif + + auto *f = new QCameraFormatPrivate{ + QSharedData(), + pixelFormat, + resolution, + minFrameRate, + maxFrameRate + }; + videoFormats << f->create(); + } + info->videoFormats = videoFormats; - cameras.append(QCameraInfo(info)); + cameras.append(info->create()); } if (cameras != m_cameraDevices) { diff --git a/src/multimedia/platform/gstreamer/common/qgstutils.cpp b/src/multimedia/platform/gstreamer/common/qgstutils.cpp index 7903b48fe..49eec32b0 100644 --- a/src/multimedia/platform/gstreamer/common/qgstutils.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstutils.cpp @@ -898,26 +898,55 @@ QSize QGstUtils::structurePixelAspectRatio(const GstStructure *s) return ratio; } -QPair<qreal, qreal> QGstUtils::structureFrameRateRange(const GstStructure *s) +QPair<float, float> QGstUtils::structureFrameRateRange(const GstStructure *s) { - QPair<qreal, qreal> rate; + float minRate = 0.; + float maxRate = 0.; if (!s) - return rate; - - int n, d; - if (gst_structure_get_fraction(s, "framerate", &n, &d)) { - rate.second = qreal(n) / d; - rate.first = rate.second; - } else if (gst_structure_get_fraction(s, "max-framerate", &n, &d)) { - rate.second = qreal(n) / d; - if (gst_structure_get_fraction(s, "min-framerate", &n, &d)) - rate.first = qreal(n) / d; - else - rate.first = qreal(1); + return {0.f, 0.f}; + + auto extractFraction = [] (const GValue *v) -> float { + return (float)gst_value_get_fraction_numerator(v)/(float)gst_value_get_fraction_denominator(v); + }; + auto extractFrameRate = [&] (const GValue *v) { + auto insert = [&] (float min, float max) { + if (max > maxRate) + maxRate = max; + if (min < minRate) + minRate = min; + }; + + if (GST_VALUE_HOLDS_FRACTION(v)) { + float rate = extractFraction(v); + insert(rate, rate); + } else if (GST_VALUE_HOLDS_FRACTION_RANGE(v)) { + auto *min = gst_value_get_fraction_range_max(v); + auto *max = gst_value_get_fraction_range_max(v); + insert(extractFraction(min), extractFraction(max)); + } + }; + + const GValue *gstFrameRates = gst_structure_get_value(s, "framerate"); + if (gstFrameRates) { + if (GST_VALUE_HOLDS_LIST(gstFrameRates)) { + guint nFrameRates = gst_value_list_get_size(gstFrameRates); + for (guint f = 0; f < nFrameRates; ++f) { + extractFrameRate(gst_value_list_get_value(gstFrameRates, f)); + } + } else { + extractFrameRate(gstFrameRates); + } + } else { + const GValue *min = gst_structure_get_value(s, "min-framerate"); + const GValue *max = gst_structure_get_value(s, "max-framerate"); + if (min && max) { + minRate = extractFraction(min); + maxRate = extractFraction(max); + } } - return rate; + return {minRate, maxRate}; } typedef QMap<QString, QString> FileExtensionMap; diff --git a/src/multimedia/platform/gstreamer/common/qgstutils_p.h b/src/multimedia/platform/gstreamer/common/qgstutils_p.h index 796721589..8a95d0d5e 100644 --- a/src/multimedia/platform/gstreamer/common/qgstutils_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstutils_p.h @@ -77,7 +77,7 @@ namespace QGstUtils { QString name; QString description; int orientation; - QCamera::Position position; + QCameraInfo::Position position; QByteArray driver; }; @@ -115,7 +115,7 @@ namespace QGstUtils { Q_MULTIMEDIA_EXPORT QSize structureResolution(const GstStructure *s); Q_MULTIMEDIA_EXPORT QVideoFrame::PixelFormat structurePixelFormat(const GstStructure *s); Q_MULTIMEDIA_EXPORT QSize structurePixelAspectRatio(const GstStructure *s); - Q_MULTIMEDIA_EXPORT QPair<qreal, qreal> structureFrameRateRange(const GstStructure *s); + Q_MULTIMEDIA_EXPORT QPair<float, float> structureFrameRateRange(const GstStructure *s); Q_MULTIMEDIA_EXPORT QString fileExtensionForMimeType(const QString &mimeType); diff --git a/src/multimedia/platform/gstreamer/qgstreamerdevicemanager.cpp b/src/multimedia/platform/gstreamer/qgstreamerdevicemanager.cpp index df779a96c..db175075c 100644 --- a/src/multimedia/platform/gstreamer/qgstreamerdevicemanager.cpp +++ b/src/multimedia/platform/gstreamer/qgstreamerdevicemanager.cpp @@ -153,10 +153,40 @@ QList<QCameraInfo> QGstreamerDeviceManager::videoInputs() const gst_structure_get_boolean(properties, "is-default", &def); info->isDefault = def; if (def) - devices.prepend(QCameraInfo(info)); + devices.prepend(info->create()); else - devices.append(QCameraInfo(info)); + devices.append(info->create()); gst_structure_free(properties); + auto *caps = gst_device_get_caps(d); + if (caps) { + QList<QCameraFormat> formats; + QSet<QSize> photoResolutions; + + int size = gst_caps_get_size(caps); + for (int i = 0; i < size; ++i) { + auto *cap = gst_caps_get_structure(caps, i); + + QSize resolution = QGstUtils::structureResolution(cap); + if (!resolution.isValid()) + continue; + + auto pixelFormat = QGstUtils::structurePixelFormat(cap); + auto frameRate = QGstUtils::structureFrameRateRange(cap); + + auto *f = new QCameraFormatPrivate{ + QSharedData(), + pixelFormat, + resolution, + frameRate.first, + frameRate.second + }; + formats << f->create(); + photoResolutions.insert(resolution); + } + info->videoFormats = formats; + // ### sort resolutions? + info->photoResolutions = photoResolutions.values(); + } } } return devices; diff --git a/src/multimedia/platform/qnx/qqnxdevicemanager.cpp b/src/multimedia/platform/qnx/qqnxdevicemanager.cpp index 6b0d00dc9..d4c34d3d6 100644 --- a/src/multimedia/platform/qnx/qqnxdevicemanager.cpp +++ b/src/multimedia/platform/qnx/qqnxdevicemanager.cpp @@ -67,24 +67,24 @@ static QList<QCameraInfo> enumerateCameras() case CAMERA_UNIT_FRONT: p->id = BbCameraSession::cameraIdentifierFront(); p->description = tr("Front Camera"); - p->position = QCamera::FrontFace; + p->position = QCameraInfo::FrontFace; break; case CAMERA_UNIT_REAR: p->id = BbCameraSession::cameraIdentifierRear(); p->description = tr("Rear Camera"); - p->position = QCamera::BackFace; + p->position = QCameraInfo::BackFace; break; case CAMERA_UNIT_DESKTOP: p->id = devices->append(BbCameraSession::cameraIdentifierDesktop(); p->description = tr("Desktop Camera"); - p->position = QCamera::UnspecifiedPosition; + p->position = QCameraInfo::UnspecifiedPosition; break; default: break; } if (i == 0) p->isDefault = true; - cameras.append(QCameraInfo(p)); + cameras.append(p->create()); } return cameras; } diff --git a/src/multimedia/qmediadevicemanager.cpp b/src/multimedia/qmediadevicemanager.cpp index c83015c79..4873d1cd7 100644 --- a/src/multimedia/qmediadevicemanager.cpp +++ b/src/multimedia/qmediadevicemanager.cpp @@ -112,7 +112,7 @@ QList<QAudioDeviceInfo> QMediaDeviceManager::audioOutputs() /*! Returns a list of available cameras on the system which are located at \a position. - If \a position is not specified or if the value is QCamera::UnspecifiedPosition, a list of + If \a position is not specified or if the value is QCameraInfo::UnspecifiedPosition, a list of all available cameras will be returned. */ QList<QCameraInfo> QMediaDeviceManager::videoInputs() diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp index a64a9e157..2aae59509 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp @@ -44,6 +44,7 @@ #include <private/qvideooutputorientationhandler_p.h> #include <QtMultimedia/qmediasource.h> #include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qcamera.h> #include <private/qfactoryloader_p.h> #include <QtCore/qloggingcategory.h> @@ -321,7 +322,7 @@ void QDeclarativeVideoOutput::_q_updateCameraInfo() if (m_mediaSource) { const QCamera *camera = qobject_cast<const QCamera *>(m_mediaSource); if (camera) { - QCameraInfo info(*camera); + QCameraInfo info = camera->cameraInfo(); if (m_cameraInfo != info) { m_cameraInfo = info; @@ -433,20 +434,6 @@ void QDeclarativeVideoOutput::_q_updateGeometry() void QDeclarativeVideoOutput::_q_screenOrientationChanged(int orientation) { - // If the source is a camera, take into account its sensor position and orientation - if (!m_cameraInfo.isNull()) { - switch (m_cameraInfo.position()) { - case QCamera::FrontFace: - // Front facing cameras are flipped horizontally, compensate the mirror - orientation += (360 - m_cameraInfo.orientation()); - break; - case QCamera::BackFace: - default: - orientation += m_cameraInfo.orientation(); - break; - } - } - setOrientation(orientation % 360); } diff --git a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp index ce5b8e507..9b6bf700f 100644 --- a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp +++ b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp @@ -106,7 +106,6 @@ void tst_QCameraBackend::testCameraInfo() for (const QCameraInfo &info : cameras) { QVERIFY(!info.id().isEmpty()); QVERIFY(!info.description().isEmpty()); - QVERIFY(info.orientation() % 90 == 0); } } @@ -119,19 +118,19 @@ void tst_QCameraBackend::testCtorWithCameraInfo() QCameraInfo info = QMediaDeviceManager::defaultVideoInput(); QCamera camera(info); QCOMPARE(camera.error(), QCamera::NoError); - QCOMPARE(QCameraInfo(camera), info); + QCOMPARE(camera.cameraInfo(), info); } { QCameraInfo info = QMediaDeviceManager::videoInputs().first(); QCamera camera(info); QCOMPARE(camera.error(), QCamera::NoError); - QCOMPARE(QCameraInfo(camera), info); + QCOMPARE(camera.cameraInfo(), info); } { // loading an invalid CameraInfo should fail QCamera *camera = new QCamera(QCameraInfo()); QCOMPARE(camera->error(), QCamera::CameraError); - QVERIFY(QCameraInfo(*camera).isNull()); + QVERIFY(camera->cameraInfo().isNull()); delete camera; } } @@ -139,17 +138,17 @@ void tst_QCameraBackend::testCtorWithCameraInfo() void tst_QCameraBackend::testCtorWithPosition() { { - QCamera camera(QCamera::UnspecifiedPosition); + QCamera camera(QCameraInfo::UnspecifiedPosition); QCOMPARE(camera.error(), QCamera::NoError); } { - QCamera camera(QCamera::FrontFace); + QCamera camera(QCameraInfo::FrontFace); // even if no camera is available at this position, it should not fail // and load the default camera QCOMPARE(camera.error(), QCamera::NoError); } { - QCamera camera(QCamera::BackFace); + QCamera camera(QCameraInfo::BackFace); // even if no camera is available at this position, it should not fail // and load the default camera QCOMPARE(camera.error(), QCamera::NoError); diff --git a/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp b/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp index 48e71a5e2..4d064b0e6 100644 --- a/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp +++ b/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp @@ -1606,8 +1606,8 @@ void tst_QCamera::testEnumDebug() qDebug() << QCamera::NoLock; QTest::ignoreMessage(QtDebugMsg, "QCamera::LockExposure"); qDebug() << QCamera::LockExposure; - QTest::ignoreMessage(QtDebugMsg, "QCamera::FrontFace "); - qDebug() << QCamera::FrontFace; + QTest::ignoreMessage(QtDebugMsg, "QCameraInfo::FrontFace "); + qDebug() << QCameraInfo::FrontFace; } void tst_QCamera::testCameraControl() @@ -1622,9 +1622,9 @@ void tst_QCamera::testConstructor() QCameraInfo defaultCamera = QMediaDeviceManager::defaultVideoInput(); QCameraInfo frontCamera, backCamera; for (const auto &c : cameras) { - if (frontCamera.isNull() && c.position() == QCamera::FrontFace) + if (frontCamera.isNull() && c.position() == QCameraInfo::FrontFace) frontCamera = c; - if (backCamera.isNull() && c.position() == QCamera::BackFace) + if (backCamera.isNull() && c.position() == QCameraInfo::BackFace) backCamera = c; } QVERIFY(!defaultCamera.isNull()); @@ -1639,7 +1639,7 @@ void tst_QCamera::testConstructor() } { - QCamera camera(QCamera::FrontFace); + QCamera camera(QCameraInfo::FrontFace); QCOMPARE(camera.availability(), QMultimedia::Available); QCOMPARE(camera.error(), QCamera::NoError); QCOMPARE(camera.cameraInfo(), frontCamera); @@ -1657,11 +1657,11 @@ void tst_QCamera::testConstructor() QCamera camera(cameraInfo); QCOMPARE(camera.availability(), QMultimedia::Available); QCOMPARE(camera.error(), QCamera::NoError); - QCOMPARE(QCameraInfo(camera), cameraInfo); + QCOMPARE(camera.cameraInfo(), cameraInfo); } { - QCamera camera(QCamera::BackFace); + QCamera camera(QCameraInfo::BackFace); QCOMPARE(camera.availability(), QMultimedia::Available); QCOMPARE(camera.error(), QCamera::NoError); QCOMPARE(camera.cameraInfo(), backCamera); @@ -1669,7 +1669,7 @@ void tst_QCamera::testConstructor() { // Should load the default camera when UnspecifiedPosition is requested - QCamera camera(QCamera::UnspecifiedPosition); + QCamera camera(QCameraInfo::UnspecifiedPosition); QCOMPARE(camera.availability(), QMultimedia::Available); QCOMPARE(camera.error(), QCamera::NoError); QCOMPARE(camera.cameraInfo(), defaultCamera); diff --git a/tests/auto/unit/multimedia/qcamerainfo/tst_qcamerainfo.cpp b/tests/auto/unit/multimedia/qcamerainfo/tst_qcamerainfo.cpp index 42deae79b..53f86c095 100644 --- a/tests/auto/unit/multimedia/qcamerainfo/tst_qcamerainfo.cpp +++ b/tests/auto/unit/multimedia/qcamerainfo/tst_qcamerainfo.cpp @@ -77,37 +77,33 @@ void tst_QCameraInfo::constructor() { // default camera QCamera camera; - QCameraInfo info(camera); + QCameraInfo info(camera.cameraInfo()); QVERIFY(!info.isNull()); QCOMPARE(info.id(), QStringLiteral("othercamera")); QCOMPARE(info.description(), QStringLiteral("othercamera desc")); - QCOMPARE(info.position(), QCamera::UnspecifiedPosition); - QCOMPARE(info.orientation(), 0); + QCOMPARE(info.position(), QCameraInfo::UnspecifiedPosition); } auto cameras = QMediaDeviceManager::videoInputs(); QCameraInfo info; for (const auto &c : cameras) { - if (c.position() == QCamera::BackFace) + if (c.position() == QCameraInfo::BackFace) info = c; } QVERIFY(!info.isNull()); QCamera camera(info); QCOMPARE(info, camera.cameraInfo()); - QCOMPARE(info, QCameraInfo(camera)); QVERIFY(!info.isNull()); QCOMPARE(info.id(), QStringLiteral("backcamera")); QCOMPARE(info.description(), QStringLiteral("backcamera desc")); - QCOMPARE(info.position(), QCamera::BackFace); - QCOMPARE(info.orientation(), 90); + QCOMPARE(info.position(), QCameraInfo::BackFace); QCameraInfo info2(info); QVERIFY(!info2.isNull()); QCOMPARE(info2.id(), QStringLiteral("backcamera")); QCOMPARE(info2.description(), QStringLiteral("backcamera desc")); - QCOMPARE(info2.position(), QCamera::BackFace); - QCOMPARE(info2.orientation(), 90); + QCOMPARE(info2.position(), QCameraInfo::BackFace); } void tst_QCameraInfo::defaultCamera() @@ -117,11 +113,10 @@ void tst_QCameraInfo::defaultCamera() QVERIFY(!info.isNull()); QCOMPARE(info.id(), QStringLiteral("othercamera")); QCOMPARE(info.description(), QStringLiteral("othercamera desc")); - QCOMPARE(info.position(), QCamera::UnspecifiedPosition); - QCOMPARE(info.orientation(), 0); + QCOMPARE(info.position(), QCameraInfo::UnspecifiedPosition); QCamera camera(info); - QCOMPARE(QCameraInfo(camera), info); + QCOMPARE(camera.cameraInfo(), info); } void tst_QCameraInfo::availableCameras() @@ -133,26 +128,24 @@ void tst_QCameraInfo::availableCameras() QVERIFY(!info.isNull()); QCOMPARE(info.id(), QStringLiteral("backcamera")); QCOMPARE(info.description(), QStringLiteral("backcamera desc")); - QCOMPARE(info.position(), QCamera::BackFace); - QCOMPARE(info.orientation(), 90); + QCOMPARE(info.position(), QCameraInfo::BackFace); info = cameras.at(1); QVERIFY(!info.isNull()); QCOMPARE(info.id(), QStringLiteral("othercamera")); QCOMPARE(info.description(), QStringLiteral("othercamera desc")); - QCOMPARE(info.position(), QCamera::UnspecifiedPosition); - QCOMPARE(info.orientation(), 0); + QCOMPARE(info.position(), QCameraInfo::UnspecifiedPosition); -// cameras = QMediaDeviceManager::videoInputs(QCamera::BackFace); +// cameras = QMediaDeviceManager::videoInputs(QCameraInfo::BackFace); // QCOMPARE(cameras.count(), 1); // info = cameras.at(0); // QVERIFY(!info.isNull()); // QCOMPARE(info.id(), QStringLiteral("backcamera")); // QCOMPARE(info.description(), QStringLiteral("backcamera desc")); -// QCOMPARE(info.position(), QCamera::BackFace); +// QCOMPARE(info.position(), QCameraInfo::BackFace); // QCOMPARE(info.orientation(), 90); -// cameras = QMediaDeviceManager::videoInputs(QCamera::FrontFace); +// cameras = QMediaDeviceManager::videoInputs(QCameraInfo::FrontFace); // QCOMPARE(cameras.count(), 0); } @@ -167,13 +160,13 @@ void tst_QCameraInfo::equality_operators() { QCamera camera(defaultCamera); - QVERIFY(QCameraInfo(camera) == defaultCamera); - QVERIFY(QCameraInfo(camera) == cameras.at(1)); + QVERIFY(camera.cameraInfo() == defaultCamera); + QVERIFY(camera.cameraInfo() == cameras.at(1)); } { QCamera camera(cameras.at(0)); - QVERIFY(QCameraInfo(camera) == cameras.at(0)); + QVERIFY(camera.cameraInfo() == cameras.at(0)); } } |