From def89d71716c7909351f6ccce512a0bff6492417 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 9 Apr 2015 15:14:36 +0200 Subject: AVFoundation: fix QCameraInfo::availableCameras() on OS X. Cameras can be dynamically added or removed on OS X. Make sure the cache is updated often enough so QCameraInfo::availableCameras() return an up to date list. Task-number: QTBUG-39708 Change-Id: Id806d52278e1a29163fcc6707da7f86c0f3e7c0d Reviewed-by: Timur Pocheptsov --- .../avfoundation/camera/avfcameraserviceplugin.mm | 18 +++++-- src/plugins/avfoundation/camera/avfcamerasession.h | 10 ++-- .../avfoundation/camera/avfcamerasession.mm | 59 +++++++++++++--------- .../avfoundation/camera/avfvideodevicecontrol.mm | 10 ++-- 4 files changed, 59 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm index 414a84751..99966f09b 100644 --- a/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm +++ b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm @@ -71,18 +71,26 @@ void AVFServicePlugin::release(QMediaService *service) QByteArray AVFServicePlugin::defaultDevice(const QByteArray &service) const { - if (service == Q_MEDIASERVICE_CAMERA) - return AVFCameraSession::defaultCameraDevice(); + if (service == Q_MEDIASERVICE_CAMERA) { + int i = AVFCameraSession::defaultCameraIndex(); + if (i != -1) + return AVFCameraSession::availableCameraDevices().at(i).deviceId; + } return QByteArray(); } QList AVFServicePlugin::devices(const QByteArray &service) const { - if (service == Q_MEDIASERVICE_CAMERA) - return AVFCameraSession::availableCameraDevices(); + QList devs; + + if (service == Q_MEDIASERVICE_CAMERA) { + const QList &cameras = AVFCameraSession::availableCameraDevices(); + Q_FOREACH (const AVFCameraInfo &info, cameras) + devs.append(info.deviceId); + } - return QList(); + return devs; } QString AVFServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 75ca3f4ce..8ce7461df 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -52,6 +52,7 @@ struct AVFCameraInfo AVFCameraInfo() : position(QCamera::UnspecifiedPosition), orientation(0) { } + QByteArray deviceId; QString description; QCamera::Position position; int orientation; @@ -64,8 +65,8 @@ public: AVFCameraSession(AVFCameraService *service, QObject *parent = 0); ~AVFCameraSession(); - static const QByteArray &defaultCameraDevice(); - static const QList &availableCameraDevices(); + static int defaultCameraIndex(); + static const QList &availableCameraDevices(); static AVFCameraInfo cameraDeviceInfo(const QByteArray &device); void setVideoOutput(AVFVideoRendererControl *output); @@ -93,9 +94,8 @@ private: static void updateCameraDevices(); void attachInputDevices(); - static QByteArray m_defaultCameraDevice; - static QList m_cameraDevices; - static QMap m_cameraInfo; + static int m_defaultCameraIndex; + static QList m_cameraDevices; AVFCameraService *m_service; AVFVideoRendererControl *m_videoOutput; diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index a72ef5041..4d4b2f657 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -52,14 +52,14 @@ #include #include +#include #include QT_USE_NAMESPACE -QByteArray AVFCameraSession::m_defaultCameraDevice; -QList AVFCameraSession::m_cameraDevices; -QMap AVFCameraSession::m_cameraInfo; +int AVFCameraSession::m_defaultCameraIndex; +QList AVFCameraSession::m_cameraDevices; @interface AVFCameraSessionObserver : NSObject { @@ -172,45 +172,55 @@ AVFCameraSession::~AVFCameraSession() [m_captureSession release]; } -const QByteArray &AVFCameraSession::defaultCameraDevice() +int AVFCameraSession::defaultCameraIndex() { - if (m_cameraDevices.isEmpty()) - updateCameraDevices(); - - return m_defaultCameraDevice; + updateCameraDevices(); + return m_defaultCameraIndex; } -const QList &AVFCameraSession::availableCameraDevices() +const QList &AVFCameraSession::availableCameraDevices() { - if (m_cameraDevices.isEmpty()) - updateCameraDevices(); - + updateCameraDevices(); return m_cameraDevices; } AVFCameraInfo AVFCameraSession::cameraDeviceInfo(const QByteArray &device) { - if (m_cameraDevices.isEmpty()) - updateCameraDevices(); + updateCameraDevices(); - return m_cameraInfo.value(device); + Q_FOREACH (const AVFCameraInfo &info, m_cameraDevices) { + if (info.deviceId == device) + return info; + } + + return AVFCameraInfo(); } void AVFCameraSession::updateCameraDevices() { - m_defaultCameraDevice.clear(); +#ifdef Q_OS_IOS + // Cameras can't change dynamically on iOS. Update only once. + if (!m_cameraDevices.isEmpty()) + return; +#else + // On OS X, cameras can be added or removed. Update the list every time, but not more than + // once every 500 ms + static QElapsedTimer timer; + if (timer.isValid() && timer.elapsed() < 500) // ms + return; +#endif + + m_defaultCameraIndex = -1; m_cameraDevices.clear(); - m_cameraInfo.clear(); AVCaptureDevice *defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - if (defaultDevice) - m_defaultCameraDevice = QByteArray([[defaultDevice uniqueID] UTF8String]); - NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice *device in videoDevices) { - QByteArray deviceId([[device uniqueID] UTF8String]); + if (defaultDevice && [defaultDevice.uniqueID isEqualToString:device.uniqueID]) + m_defaultCameraIndex = m_cameraDevices.count(); AVFCameraInfo info; + info.deviceId = QByteArray([[device uniqueID] UTF8String]); info.description = QString::fromNSString([device localizedName]); // There is no API to get the camera sensor orientation, however, cameras are always @@ -235,9 +245,12 @@ void AVFCameraSession::updateCameraDevices() break; } - m_cameraDevices << deviceId; - m_cameraInfo.insert(deviceId, info); + m_cameraDevices.append(info); } + +#ifndef Q_OS_IOS + timer.restart(); +#endif } void AVFCameraSession::setVideoOutput(AVFVideoRendererControl *output) diff --git a/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm b/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm index 03736c395..1730437f8 100644 --- a/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm +++ b/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm @@ -65,25 +65,25 @@ int AVFVideoDeviceControl::deviceCount() const QString AVFVideoDeviceControl::deviceName(int index) const { - const QList &devices = AVFCameraSession::availableCameraDevices(); + const QList &devices = AVFCameraSession::availableCameraDevices(); if (index < 0 || index >= devices.count()) return QString(); - return QString::fromUtf8(devices.at(index)); + return QString::fromUtf8(devices.at(index).deviceId); } QString AVFVideoDeviceControl::deviceDescription(int index) const { - const QList &devices = AVFCameraSession::availableCameraDevices(); + const QList &devices = AVFCameraSession::availableCameraDevices(); if (index < 0 || index >= devices.count()) return QString(); - return AVFCameraSession::cameraDeviceInfo(devices.at(index)).description; + return devices.at(index).description; } int AVFVideoDeviceControl::defaultDevice() const { - return AVFCameraSession::availableCameraDevices().indexOf(AVFCameraSession::defaultCameraDevice()); + return AVFCameraSession::defaultCameraIndex(); } int AVFVideoDeviceControl::selectedDevice() const -- cgit v1.2.3