summaryrefslogtreecommitdiffstats
path: root/src/plugins/blackberry/camera/bbcamerasession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/blackberry/camera/bbcamerasession.cpp')
-rw-r--r--src/plugins/blackberry/camera/bbcamerasession.cpp1373
1 files changed, 1373 insertions, 0 deletions
diff --git a/src/plugins/blackberry/camera/bbcamerasession.cpp b/src/plugins/blackberry/camera/bbcamerasession.cpp
new file mode 100644
index 000000000..d07e84495
--- /dev/null
+++ b/src/plugins/blackberry/camera/bbcamerasession.cpp
@@ -0,0 +1,1373 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt 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 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "bbcamerasession.h"
+
+#include "bbcameraorientationhandler.h"
+#include "bbcameraviewfindersettingscontrol.h"
+
+#include <QAbstractVideoSurface>
+#include <QBuffer>
+#include <QDebug>
+#include <QImage>
+#include <QUrl>
+#include <QVideoSurfaceFormat>
+#include <qmath.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+static QString errorToString(camera_error_t error)
+{
+ switch (error) {
+ case CAMERA_EOK:
+ return QLatin1String("No error");
+ case CAMERA_EAGAIN:
+ return QLatin1String("Camera unavailable");
+ case CAMERA_EINVAL:
+ return QLatin1String("Inavlid argument");
+ case CAMERA_ENODEV:
+ return QLatin1String("Camera not found");
+ case CAMERA_EMFILE:
+ return QLatin1String("File table overflow");
+ case CAMERA_EBADF:
+ return QLatin1String("Invalid handle passed");
+ case CAMERA_EACCESS:
+ return QLatin1String("No permission");
+ case CAMERA_EBADR:
+ return QLatin1String("Invalid file descriptor");
+ case CAMERA_ENOENT:
+ return QLatin1String("File or directory does not exists");
+ case CAMERA_ENOMEM:
+ return QLatin1String("Memory allocation failed");
+ case CAMERA_EOPNOTSUPP:
+ return QLatin1String("Operation not supported");
+ case CAMERA_ETIMEDOUT:
+ return QLatin1String("Communication timeout");
+ case CAMERA_EALREADY:
+ return QLatin1String("Operation already in progress");
+ case CAMERA_ENOSPC:
+ return QLatin1String("Disk is full");
+ case CAMERA_EUNINIT:
+ return QLatin1String("Camera library not initialized");
+ case CAMERA_EREGFAULT:
+ return QLatin1String("Callback registration failed");
+ case CAMERA_EMICINUSE:
+ return QLatin1String("Microphone in use already");
+ case CAMERA_EDESKTOPCAMERAINUSE:
+ return QLatin1String("Desktop camera in use already");
+ default:
+ return QLatin1String("Unknown error");
+ }
+}
+
+QDebug operator<<(QDebug debug, camera_error_t error)
+{
+ debug.nospace() << errorToString(error);
+ return debug.space();
+}
+
+BbCameraSession::BbCameraSession(QObject *parent)
+ : QObject(parent)
+ , m_nativeCameraOrientation(0)
+ , m_orientationHandler(new BbCameraOrientationHandler(this))
+ , m_status(QCamera::UnloadedStatus)
+ , m_state(QCamera::UnloadedState)
+ , m_captureMode(QCamera::CaptureStillImage)
+ , m_device("bb:RearCamera")
+ , m_previewIsVideo(true)
+ , m_surface(0)
+ , m_captureImageDriveMode(QCameraImageCapture::SingleImageCapture)
+ , m_lastImageCaptureId(0)
+ , m_captureDestination(QCameraImageCapture::CaptureToFile)
+ , m_locksApplyMode(IndependentMode)
+ , m_focusLockStatus(QCamera::Unlocked)
+ , m_videoState(QMediaRecorder::StoppedState)
+ , m_videoStatus(QMediaRecorder::LoadedStatus)
+ , m_handle(CAMERA_HANDLE_INVALID)
+{
+ connect(this, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateReadyForCapture()));
+ connect(this, SIGNAL(captureModeChanged(QCamera::CaptureModes)), SLOT(updateReadyForCapture()));
+ connect(m_orientationHandler, SIGNAL(orientationChanged(int)), SLOT(deviceOrientationChanged(int)));
+}
+
+BbCameraSession::~BbCameraSession()
+{
+ stopViewFinder();
+ closeCamera();
+}
+
+camera_handle_t BbCameraSession::handle() const
+{
+ return m_handle;
+}
+
+QCamera::State BbCameraSession::state() const
+{
+ return m_state;
+}
+
+void BbCameraSession::setState(QCamera::State state)
+{
+ if (m_state == state)
+ return;
+
+ const QCamera::State previousState = m_state;
+
+ if (previousState == QCamera::UnloadedState) {
+ if (state == QCamera::LoadedState) {
+ if (openCamera()) {
+ m_state = state;
+ }
+ } else if (state == QCamera::ActiveState) {
+ if (openCamera()) {
+ applyConfiguration();
+ if (startViewFinder()) {
+ m_state = state;
+ }
+ }
+ }
+ } else if (previousState == QCamera::LoadedState) {
+ if (state == QCamera::UnloadedState) {
+ closeCamera();
+ m_state = state;
+ } else if (state == QCamera::ActiveState) {
+ applyConfiguration();
+ if (startViewFinder()) {
+ m_state = state;
+ }
+ }
+ } else if (previousState == QCamera::ActiveState) {
+ if (state == QCamera::LoadedState) {
+ stopViewFinder();
+ m_state = state;
+ } else if (state == QCamera::UnloadedState) {
+ stopViewFinder();
+ closeCamera();
+ m_state = state;
+ }
+ }
+
+ if (m_state != previousState)
+ emit stateChanged(m_state);
+}
+
+QCamera::Status BbCameraSession::status() const
+{
+ return m_status;
+}
+
+QCamera::CaptureModes BbCameraSession::captureMode() const
+{
+ return m_captureMode;
+}
+
+void BbCameraSession::setCaptureMode(QCamera::CaptureModes captureMode)
+{
+ if (m_captureMode == captureMode)
+ return;
+
+ m_captureMode = captureMode;
+ emit captureModeChanged(m_captureMode);
+}
+
+bool BbCameraSession::isCaptureModeSupported(QCamera::CaptureModes mode) const
+{
+ if (m_handle == CAMERA_HANDLE_INVALID) {
+ // the camera has not been loaded yet via QCamera::load(), so
+ // we open it temporarily to peek for the supported capture modes
+
+ camera_unit_t unit = CAMERA_UNIT_REAR;
+ if (m_device == cameraIdentifierFront())
+ unit = CAMERA_UNIT_FRONT;
+ else if (m_device == cameraIdentifierRear())
+ unit = CAMERA_UNIT_REAR;
+ else if (m_device == cameraIdentifierDesktop())
+ unit = CAMERA_UNIT_DESKTOP;
+
+ camera_handle_t handle;
+ const camera_error_t result = camera_open(unit, CAMERA_MODE_RW, &handle);
+ if (result != CAMERA_EOK)
+ return true;
+
+ const bool supported = isCaptureModeSupported(handle, mode);
+
+ camera_close(handle);
+
+ return supported;
+ } else {
+ return isCaptureModeSupported(m_handle, mode);
+ }
+}
+
+QByteArray BbCameraSession::cameraIdentifierFront()
+{
+ return "bb:FrontCamera";
+}
+
+QByteArray BbCameraSession::cameraIdentifierRear()
+{
+ return "bb:RearCamera";
+}
+
+QByteArray BbCameraSession::cameraIdentifierDesktop()
+{
+ return "bb:DesktopCamera";
+}
+
+void BbCameraSession::setDevice(const QByteArray &device)
+{
+ m_device = device;
+}
+
+QByteArray BbCameraSession::device() const
+{
+ return m_device;
+}
+
+QAbstractVideoSurface* BbCameraSession::surface() const
+{
+ return m_surface;
+}
+
+void BbCameraSession::setSurface(QAbstractVideoSurface *surface)
+{
+ QMutexLocker locker(&m_surfaceMutex);
+
+ if (m_surface == surface)
+ return;
+
+ m_surface = surface;
+}
+
+bool BbCameraSession::isReadyForCapture() const
+{
+ if (m_captureMode & QCamera::CaptureStillImage)
+ return (m_status == QCamera::ActiveStatus);
+
+ if (m_captureMode & QCamera::CaptureVideo)
+ return (m_status == QCamera::ActiveStatus);
+
+ return false;
+}
+
+QCameraImageCapture::DriveMode BbCameraSession::driveMode() const
+{
+ return m_captureImageDriveMode;
+}
+
+void BbCameraSession::setDriveMode(QCameraImageCapture::DriveMode mode)
+{
+ m_captureImageDriveMode = mode;
+}
+
+/**
+ * A helper structure that keeps context data for image capture callbacks.
+ */
+struct ImageCaptureData
+{
+ int requestId;
+ QString fileName;
+ BbCameraSession *session;
+};
+
+static void imageCaptureShutterCallback(camera_handle_t handle, void *context)
+{
+ Q_UNUSED(handle)
+
+ const ImageCaptureData *data = static_cast<ImageCaptureData*>(context);
+
+ // We are inside a worker thread here, so emit imageExposed inside the main thread
+ QMetaObject::invokeMethod(data->session, "imageExposed", Qt::QueuedConnection,
+ Q_ARG(int, data->requestId));
+}
+
+static void imageCaptureImageCallback(camera_handle_t handle, camera_buffer_t *buffer, void *context)
+{
+ Q_UNUSED(handle)
+
+ QScopedPointer<ImageCaptureData> data(static_cast<ImageCaptureData*>(context));
+
+ if (buffer->frametype != CAMERA_FRAMETYPE_JPEG) {
+ // We are inside a worker thread here, so emit error signal inside the main thread
+ QMetaObject::invokeMethod(data->session, "imageCaptureError", Qt::QueuedConnection,
+ Q_ARG(int, data->requestId),
+ Q_ARG(QCameraImageCapture::Error, QCameraImageCapture::FormatError),
+ Q_ARG(QString, QObject::tr("Camera provides image in unsupported format")));
+ return;
+ }
+
+ const QByteArray rawData((const char*)buffer->framebuf, buffer->framedesc.jpeg.bufsize);
+
+ QImage image;
+ const bool ok = image.loadFromData(rawData, "JPG");
+ if (!ok) {
+ const QString errorMessage = QObject::tr("Could not load JPEG data from frame");
+ // We are inside a worker thread here, so emit error signal inside the main thread
+ QMetaObject::invokeMethod(data->session, "imageCaptureError", Qt::QueuedConnection,
+ Q_ARG(int, data->requestId),
+ Q_ARG(QCameraImageCapture::Error, QCameraImageCapture::FormatError),
+ Q_ARG(QString, errorMessage));
+ return;
+ }
+
+
+ // We are inside a worker thread here, so invoke imageCaptured inside the main thread
+ QMetaObject::invokeMethod(data->session, "imageCaptured", Qt::QueuedConnection,
+ Q_ARG(int, data->requestId),
+ Q_ARG(QImage, image),
+ Q_ARG(QString, data->fileName));
+}
+
+int BbCameraSession::capture(const QString &fileName)
+{
+ m_lastImageCaptureId++;
+
+ if (!isReadyForCapture()) {
+ emit imageCaptureError(m_lastImageCaptureId, QCameraImageCapture::NotReadyError, tr("Camera not ready"));
+ return m_lastImageCaptureId;
+ }
+
+ if (m_captureImageDriveMode == QCameraImageCapture::SingleImageCapture) {
+ // prepare context object for callback
+ ImageCaptureData *context = new ImageCaptureData;
+ context->requestId = m_lastImageCaptureId;
+ context->fileName = fileName;
+ context->session = this;
+
+ const camera_error_t result = camera_take_photo(m_handle,
+ imageCaptureShutterCallback,
+ 0,
+ 0,
+ imageCaptureImageCallback,
+ context, false);
+
+ if (result != CAMERA_EOK)
+ qWarning() << "Unable to take photo:" << result;
+ } else {
+ // TODO: implement burst mode when available in Qt API
+ }
+
+ return m_lastImageCaptureId;
+}
+
+void BbCameraSession::cancelCapture()
+{
+ // BB10 API doesn't provide functionality for that
+}
+
+bool BbCameraSession::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
+{
+ // capture to buffer, file and both are supported.
+ return destination & (QCameraImageCapture::CaptureToFile | QCameraImageCapture::CaptureToBuffer);
+}
+
+QCameraImageCapture::CaptureDestinations BbCameraSession::captureDestination() const
+{
+ return m_captureDestination;
+}
+
+void BbCameraSession::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
+{
+ if (m_captureDestination != destination) {
+ m_captureDestination = destination;
+ emit captureDestinationChanged(m_captureDestination);
+ }
+}
+
+QList<QSize> BbCameraSession::supportedResolutions(const QImageEncoderSettings&, bool *continuous) const
+{
+ if (continuous)
+ *continuous = false;
+
+ if (m_status == QCamera::UnloadedStatus)
+ return QList<QSize>();
+
+ if (m_captureMode & QCamera::CaptureStillImage) {
+ return supportedResolutions(QCamera::CaptureStillImage);
+ } else if (m_captureMode & QCamera::CaptureVideo) {
+ return supportedResolutions(QCamera::CaptureVideo);
+ }
+
+ return QList<QSize>();
+}
+
+QImageEncoderSettings BbCameraSession::imageSettings() const
+{
+ return m_imageEncoderSettings;
+}
+
+void BbCameraSession::setImageSettings(const QImageEncoderSettings &settings)
+{
+ m_imageEncoderSettings = settings;
+ if (m_imageEncoderSettings.codec().isEmpty())
+ m_imageEncoderSettings.setCodec(QLatin1String("jpeg"));
+}
+
+QCamera::LockTypes BbCameraSession::supportedLocks() const
+{
+ if (m_locksApplyMode == FocusOnlyMode)
+ return QCamera::LockFocus;
+ else
+ return (QCamera::LockExposure | QCamera::LockWhiteBalance | QCamera::LockFocus);
+}
+
+QCamera::LockStatus BbCameraSession::lockStatus(QCamera::LockType lock) const
+{
+ switch (lock) {
+ case QCamera::LockExposure:
+ return QCamera::Unlocked;
+ case QCamera::LockWhiteBalance:
+ return QCamera::Unlocked;
+ case QCamera::LockFocus:
+ return m_focusLockStatus;
+ default:
+ return QCamera::Unlocked;
+ }
+}
+
+void BbCameraSession::searchAndLock(QCamera::LockTypes locks)
+{
+ m_currentLockTypes |= locks;
+
+ uint32_t lockModes = CAMERA_3A_NONE;
+
+ switch (m_locksApplyMode) {
+ case IndependentMode:
+ if (m_currentLockTypes & QCamera::LockExposure)
+ lockModes |= CAMERA_3A_AUTOEXPOSURE;
+ if (m_currentLockTypes & QCamera::LockWhiteBalance)
+ lockModes |= CAMERA_3A_AUTOWHITEBALANCE;
+ if (m_currentLockTypes & QCamera::LockFocus)
+ lockModes |= CAMERA_3A_AUTOFOCUS;
+ break;
+ case FocusExposureBoundMode:
+ if ((m_currentLockTypes & QCamera::LockExposure) || (m_currentLockTypes & QCamera::LockFocus))
+ lockModes = (CAMERA_3A_AUTOEXPOSURE | CAMERA_3A_AUTOFOCUS);
+ break;
+ case AllBoundMode:
+ lockModes = (CAMERA_3A_AUTOEXPOSURE | CAMERA_3A_AUTOFOCUS | CAMERA_3A_AUTOWHITEBALANCE);
+ break;
+ case FocusOnlyMode:
+ lockModes = CAMERA_3A_AUTOFOCUS;
+ break;
+ }
+
+ const camera_error_t result = camera_set_3a_lock(m_handle, lockModes);
+
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to set lock modes:" << result;
+ }
+}
+
+void BbCameraSession::unlock(QCamera::LockTypes locks)
+{
+ m_currentLockTypes &= ~locks;
+
+ uint32_t lockModes = CAMERA_3A_NONE;
+
+ switch (m_locksApplyMode) {
+ case IndependentMode:
+ if (m_currentLockTypes & QCamera::LockExposure)
+ lockModes |= CAMERA_3A_AUTOEXPOSURE;
+ if (m_currentLockTypes & QCamera::LockWhiteBalance)
+ lockModes |= CAMERA_3A_AUTOWHITEBALANCE;
+ if (m_currentLockTypes & QCamera::LockFocus)
+ lockModes |= CAMERA_3A_AUTOFOCUS;
+ break;
+ case FocusExposureBoundMode:
+ if ((m_currentLockTypes & QCamera::LockExposure) || (m_currentLockTypes & QCamera::LockFocus))
+ lockModes = (CAMERA_3A_AUTOEXPOSURE | CAMERA_3A_AUTOFOCUS);
+ break;
+ case AllBoundMode:
+ lockModes = (CAMERA_3A_AUTOEXPOSURE | CAMERA_3A_AUTOFOCUS | CAMERA_3A_AUTOWHITEBALANCE);
+ break;
+ case FocusOnlyMode:
+ lockModes = CAMERA_3A_AUTOFOCUS;
+ break;
+ }
+
+ const camera_error_t result = camera_set_3a_lock(m_handle, lockModes);
+
+ if (result != CAMERA_EOK)
+ qWarning() << "Unable to set lock modes:" << result;
+}
+
+QUrl BbCameraSession::outputLocation() const
+{
+ return QUrl::fromLocalFile(m_videoOutputLocation);
+}
+
+bool BbCameraSession::setOutputLocation(const QUrl &location)
+{
+ m_videoOutputLocation = location.toLocalFile();
+
+ return true;
+}
+
+QMediaRecorder::State BbCameraSession::videoState() const
+{
+ return m_videoState;
+}
+
+void BbCameraSession::setVideoState(QMediaRecorder::State state)
+{
+ if (m_videoState == state)
+ return;
+
+ const QMediaRecorder::State previousState = m_videoState;
+
+ if (previousState == QMediaRecorder::StoppedState) {
+ if (state == QMediaRecorder::RecordingState) {
+ if (startVideoRecording()) {
+ m_videoState = state;
+ }
+ } else if (state == QMediaRecorder::PausedState) {
+ // do nothing
+ }
+ } else if (previousState == QMediaRecorder::RecordingState) {
+ if (state == QMediaRecorder::StoppedState) {
+ stopVideoRecording();
+ m_videoState = state;
+ } else if (state == QMediaRecorder::PausedState) {
+ //TODO: (pause) not supported by BB10 API yet
+ }
+ } else if (previousState == QMediaRecorder::PausedState) {
+ if (state == QMediaRecorder::StoppedState) {
+ stopVideoRecording();
+ m_videoState = state;
+ } else if (state == QMediaRecorder::RecordingState) {
+ //TODO: (resume) not supported by BB10 API yet
+ }
+ }
+
+ emit videoStateChanged(m_videoState);
+}
+
+QMediaRecorder::Status BbCameraSession::videoStatus() const
+{
+ return m_videoStatus;
+}
+
+qint64 BbCameraSession::duration() const
+{
+ return (m_videoRecordingDuration.isValid() ? m_videoRecordingDuration.elapsed() : 0);
+}
+
+void BbCameraSession::applyVideoSettings()
+{
+ if (m_handle == CAMERA_HANDLE_INVALID)
+ return;
+
+ // apply viewfinder configuration
+ const QList<QSize> videoOutputResolutions = supportedResolutions(QCamera::CaptureVideo);
+
+ if (!m_videoEncoderSettings.resolution().isValid() || !videoOutputResolutions.contains(m_videoEncoderSettings.resolution()))
+ m_videoEncoderSettings.setResolution(videoOutputResolutions.first());
+
+ QSize viewfinderResolution;
+
+ if (m_previewIsVideo) {
+ // The viewfinder is responsible for encoding the video frames, so the resolutions must match.
+ viewfinderResolution = m_videoEncoderSettings.resolution();
+ } else {
+ // The frames are encoded separately from the viewfinder, so only the aspect ratio must match.
+ const QSize videoResolution = m_videoEncoderSettings.resolution();
+ const qreal aspectRatio = static_cast<qreal>(videoResolution.width())/static_cast<qreal>(videoResolution.height());
+
+ QList<QSize> sizes = supportedViewfinderResolutions(QCamera::CaptureVideo);
+ std::reverse(sizes.begin(), sizes.end()); // use smallest possible resolution
+ foreach (const QSize &size, sizes) {
+ // search for viewfinder resolution with the same aspect ratio
+ if (qFuzzyCompare(aspectRatio, (static_cast<qreal>(size.width())/static_cast<qreal>(size.height())))) {
+ viewfinderResolution = size;
+ break;
+ }
+ }
+ }
+
+ Q_ASSERT(viewfinderResolution.isValid());
+
+ camera_error_t result = CAMERA_EOK;
+ result = camera_set_videovf_property(m_handle,
+ CAMERA_IMGPROP_WIDTH, viewfinderResolution.width(),
+ CAMERA_IMGPROP_HEIGHT, viewfinderResolution.height(),
+ CAMERA_IMGPROP_ROTATION, 360 - m_nativeCameraOrientation);
+
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to apply video viewfinder settings:" << result;
+ return;
+ }
+
+ QString videoCodec = m_videoEncoderSettings.codec();
+ if (videoCodec.isEmpty())
+ videoCodec = QLatin1String("h264");
+
+ camera_videocodec_t cameraVideoCodec = CAMERA_VIDEOCODEC_H264;
+ if (videoCodec == QLatin1String("none"))
+ cameraVideoCodec = CAMERA_VIDEOCODEC_NONE;
+ else if (videoCodec == QLatin1String("avc1"))
+ cameraVideoCodec = CAMERA_VIDEOCODEC_AVC1;
+ else if (videoCodec == QLatin1String("h264"))
+ cameraVideoCodec = CAMERA_VIDEOCODEC_H264;
+
+ const QSize resolution = m_videoEncoderSettings.resolution();
+
+ qreal frameRate = m_videoEncoderSettings.frameRate();
+ if (frameRate == 0) {
+ const QList<qreal> frameRates = supportedFrameRates(QVideoEncoderSettings(), 0);
+ if (!frameRates.isEmpty())
+ frameRate = frameRates.last();
+ }
+
+ QString audioCodec = m_audioEncoderSettings.codec();
+ if (audioCodec.isEmpty())
+ audioCodec = QLatin1String("aac");
+
+ camera_audiocodec_t cameraAudioCodec = CAMERA_AUDIOCODEC_AAC;
+ if (audioCodec == QLatin1String("none"))
+ cameraAudioCodec = CAMERA_AUDIOCODEC_NONE;
+ else if (audioCodec == QLatin1String("aac"))
+ cameraAudioCodec = CAMERA_AUDIOCODEC_AAC;
+ else if (audioCodec == QLatin1String("raw"))
+ cameraAudioCodec = CAMERA_AUDIOCODEC_RAW;
+
+ result = camera_set_video_property(m_handle,
+ CAMERA_IMGPROP_WIDTH, resolution.width(),
+ CAMERA_IMGPROP_HEIGHT, resolution.height(),
+ CAMERA_IMGPROP_VIDEOCODEC, cameraVideoCodec,
+ CAMERA_IMGPROP_AUDIOCODEC, cameraAudioCodec);
+
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to apply video settings:" << result;
+ emit videoError(QMediaRecorder::ResourceError, tr("Unable to apply video settings"));
+ }
+}
+
+QList<QSize> BbCameraSession::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const
+{
+ Q_UNUSED(settings);
+
+ if (continuous)
+ *continuous = false;
+
+ return supportedResolutions(QCamera::CaptureVideo);
+}
+
+QList<qreal> BbCameraSession::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const
+{
+ Q_UNUSED(settings);
+
+ if (m_handle == CAMERA_HANDLE_INVALID)
+ return QList<qreal>();
+
+ int supported = 0;
+ double rates[20];
+ bool maxmin = false;
+
+ /**
+ * Since in current version of the BB10 platform the video viewfinder encodes the video frames, we use
+ * the values as returned by camera_get_video_vf_framerates().
+ */
+ const camera_error_t result = camera_get_video_vf_framerates(m_handle, 20, &supported, rates, &maxmin);
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to retrieve supported viewfinder framerates:" << result;
+ return QList<qreal>();
+ }
+
+ QList<qreal> frameRates;
+ for (int i = 0; i < supported; ++i)
+ frameRates << rates[i];
+
+ if (continuous)
+ *continuous = maxmin;
+
+ return frameRates;
+}
+
+QVideoEncoderSettings BbCameraSession::videoSettings() const
+{
+ return m_videoEncoderSettings;
+}
+
+void BbCameraSession::setVideoSettings(const QVideoEncoderSettings &settings)
+{
+ m_videoEncoderSettings = settings;
+}
+
+QAudioEncoderSettings BbCameraSession::audioSettings() const
+{
+ return m_audioEncoderSettings;
+}
+
+void BbCameraSession::setAudioSettings(const QAudioEncoderSettings &settings)
+{
+ m_audioEncoderSettings = settings;
+}
+
+static QImage convertFrameToImage(camera_buffer_t *buffer)
+{
+ if (buffer->frametype != CAMERA_FRAMETYPE_NV12)
+ return QImage();
+
+ const unsigned int width = buffer->framedesc.nv12.width;
+ const unsigned int height = buffer->framedesc.nv12.height;
+
+ /**
+ * Copying the data from the buffer into our own data array and working
+ * on this copy is actually faster than working on the buffer.
+ * Looks like we hit some cache misses here, since the stride inside the
+ * NV12 frame is really large (4096) in comparison to the actual image width (768)
+ */
+ const unsigned long long size = width*height + width*height/2;
+ unsigned char *data = new unsigned char[size];
+
+ unsigned char *source = buffer->framebuf;
+ unsigned char *dest = data;
+ for (uint row = 0; row < height; ++row) {
+ memcpy(dest, source, width);
+ source += buffer->framedesc.nv12.stride;
+ dest += width;
+ }
+
+ source = buffer->framebuf + buffer->framedesc.nv12.uv_offset;
+ for (uint row = 0; row < height/2; ++row) {
+ memcpy(dest, source, width);
+ source += buffer->framedesc.nv12.uv_stride;
+ dest += width;
+ }
+
+ QImage image(width, height, QImage::Format_RGB32);
+
+ unsigned char *dataPtr = data;
+ unsigned char *uvDataPtr = 0;
+ unsigned int uv_base_offset = width*height;
+ int yValue = 0;
+ int uValue = 0;
+ int vValue = 0;
+ int bValue = 0;
+ int gValue = 0;
+ int rValue = 0;
+ unsigned char *rowStart = 0;
+
+ unsigned char *imageDest = 0;
+ for (unsigned int y = 0; y < height; ++y) {
+ imageDest = const_cast<unsigned char*>(image.constScanLine(y));
+ rowStart = data + (uv_base_offset + (width*qFloor(y/2.0)));
+ for (unsigned int x = 0; x < width; ++x) {
+ uvDataPtr = rowStart + (qFloor(x/2)*2);
+
+ yValue = ((*dataPtr++) - 16) * 1.164;
+ uValue = ((*uvDataPtr++) - 128);
+ vValue = ((*uvDataPtr) - 128);
+
+ bValue = yValue + 2.018 * uValue;
+ gValue = yValue - 0.813 * vValue - 0.391 * uValue;
+ rValue = yValue + 1.596 * vValue;
+
+ *imageDest = qBound(0, bValue, 255);
+ imageDest++;
+ *imageDest = qBound(0, gValue, 255);
+ imageDest++;
+ *imageDest = qBound(0, rValue, 255);
+ imageDest++;
+ *imageDest = 255;
+ imageDest++;
+ }
+ }
+
+ delete [] data;
+
+ return image;
+}
+
+void BbCameraSession::handlePhotoViewFinderData(camera_buffer_t *buffer)
+{
+ QTransform transform;
+
+ transform.rotate(m_nativeCameraOrientation);
+
+ const QImage frame = convertFrameToImage(buffer).transformed(transform);
+
+ QMutexLocker locker(&m_surfaceMutex);
+ if (m_surface) {
+ if (frame.size() != m_surface->surfaceFormat().frameSize()) {
+ m_surface->stop();
+ m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_RGB32));
+ }
+
+ QVideoFrame videoFrame(frame);
+
+ m_surface->present(videoFrame);
+ }
+}
+
+
+void BbCameraSession::handleVideoViewFinderData(camera_buffer_t *buffer)
+{
+ QTransform transform;
+
+ transform.rotate(m_nativeCameraOrientation);
+
+ const QImage frame = convertFrameToImage(buffer).transformed(transform);
+
+ QMutexLocker locker(&m_surfaceMutex);
+ if (m_surface) {
+ if (frame.size() != m_surface->surfaceFormat().frameSize()) {
+ m_surface->stop();
+ m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_RGB32));
+ }
+
+ QVideoFrame videoFrame(frame);
+
+ m_surface->present(videoFrame);
+ }
+}
+
+void BbCameraSession::updateReadyForCapture()
+{
+ emit readyForCaptureChanged(isReadyForCapture());
+}
+
+void BbCameraSession::imageCaptured(int requestId, const QImage &rawImage, const QString &fileName)
+{
+ QTransform transform;
+
+ // subtract out the native rotation
+ transform.rotate(m_nativeCameraOrientation);
+
+ // subtract out the current device orientation
+ if (m_device == cameraIdentifierRear())
+ transform.rotate(360 - m_orientationHandler->orientation());
+ else
+ transform.rotate(m_orientationHandler->orientation());
+
+ const QImage image = rawImage.transformed(transform);
+
+ // Generate snap preview as downscaled image
+ {
+ QSize previewSize = image.size();
+ int downScaleSteps = 0;
+ while (previewSize.width() > 800 && downScaleSteps < 8) {
+ previewSize.rwidth() /= 2;
+ previewSize.rheight() /= 2;
+ downScaleSteps++;
+ }
+
+ const QImage snapPreview = image.scaled(previewSize);
+
+ emit imageCaptured(requestId, snapPreview);
+ }
+
+ if (m_captureDestination & QCameraImageCapture::CaptureToBuffer) {
+ QVideoFrame frame(image);
+
+ emit imageAvailable(requestId, frame);
+ }
+
+ if (m_captureDestination & QCameraImageCapture::CaptureToFile) {
+ const QString actualFileName = m_mediaStorageLocation.generateFileName(fileName,
+ QCamera::CaptureStillImage,
+ QLatin1String("IMG_"),
+ QLatin1String("jpg"));
+
+ QFile file(actualFileName);
+ if (file.open(QFile::WriteOnly)) {
+ if (image.save(&file, "JPG")) {
+ emit imageSaved(requestId, actualFileName);
+ } else {
+ emit imageCaptureError(requestId, QCameraImageCapture::OutOfSpaceError, file.errorString());
+ }
+ } else {
+ const QString errorMessage = tr("Could not open destination file:\n%1").arg(actualFileName);
+ emit imageCaptureError(requestId, QCameraImageCapture::ResourceError, errorMessage);
+ }
+ }
+}
+
+void BbCameraSession::handleFocusStatusChanged(int value)
+{
+ const camera_focusstate_t focusState = static_cast<camera_focusstate_t>(value);
+
+ switch (focusState) {
+ case CAMERA_FOCUSSTATE_NONE:
+ case CAMERA_FOCUSSTATE_WAITING:
+ m_focusLockStatus = QCamera::Unlocked;
+ emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::UserRequest);
+ break;
+ case CAMERA_FOCUSSTATE_SEARCHING:
+ m_focusLockStatus = QCamera::Searching;
+ emit lockStatusChanged(QCamera::LockFocus, QCamera::Searching, QCamera::UserRequest);
+ break;
+ case CAMERA_FOCUSSTATE_FAILED:
+ m_focusLockStatus = QCamera::Unlocked;
+ emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed);
+ break;
+ case CAMERA_FOCUSSTATE_LOCKED:
+ m_focusLockStatus = QCamera::Locked;
+ emit lockStatusChanged(QCamera::LockFocus, QCamera::Locked, QCamera::LockAcquired);
+ break;
+ case CAMERA_FOCUSSTATE_SCENECHANGE:
+ m_focusLockStatus = QCamera::Unlocked;
+ emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockTemporaryLost);
+ break;
+ default:
+ break;
+ }
+}
+
+void BbCameraSession::handleVideoRecordingPaused()
+{
+ //TODO: implement once BB10 API supports pausing a video
+}
+
+void BbCameraSession::handleVideoRecordingResumed()
+{
+ if (m_videoStatus == QMediaRecorder::StartingStatus) {
+ m_videoStatus = QMediaRecorder::RecordingStatus;
+ emit videoStatusChanged(m_videoStatus);
+
+ m_videoRecordingDuration.restart();
+ }
+}
+
+void BbCameraSession::deviceOrientationChanged(int angle)
+{
+ if (m_handle != CAMERA_HANDLE_INVALID)
+ camera_set_device_orientation(m_handle, angle);
+}
+
+void BbCameraSession::handleCameraPowerUp()
+{
+ stopViewFinder();
+ startViewFinder();
+}
+
+bool BbCameraSession::openCamera()
+{
+ if (m_handle != CAMERA_HANDLE_INVALID) // camera is already open
+ return true;
+
+ m_status = QCamera::LoadingStatus;
+ emit statusChanged(m_status);
+
+ camera_unit_t unit = CAMERA_UNIT_REAR;
+ if (m_device == cameraIdentifierFront())
+ unit = CAMERA_UNIT_FRONT;
+ else if (m_device == cameraIdentifierRear())
+ unit = CAMERA_UNIT_REAR;
+ else if (m_device == cameraIdentifierDesktop())
+ unit = CAMERA_UNIT_DESKTOP;
+
+ camera_error_t result = camera_open(unit, CAMERA_MODE_RW, &m_handle);
+ if (result != CAMERA_EOK) {
+ m_handle = CAMERA_HANDLE_INVALID;
+ m_status = QCamera::UnloadedStatus;
+ emit statusChanged(m_status);
+
+ qWarning() << "Unable to open camera:" << result;
+ emit error(QCamera::CameraError, tr("Unable to open camera"));
+ return false;
+ }
+
+ result = camera_get_native_orientation(m_handle, &m_nativeCameraOrientation);
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to retrieve native camera orientation:" << result;
+ emit error(QCamera::CameraError, tr("Unable to retrieve native camera orientation"));
+ return false;
+ }
+
+ m_previewIsVideo = camera_has_feature(m_handle, CAMERA_FEATURE_PREVIEWISVIDEO);
+
+ m_status = QCamera::LoadedStatus;
+ emit statusChanged(m_status);
+
+ return true;
+}
+
+void BbCameraSession::closeCamera()
+{
+ if (m_handle == CAMERA_HANDLE_INVALID) // camera is closed already
+ return;
+
+ m_status = QCamera::UnloadingStatus;
+ emit statusChanged(m_status);
+
+ const camera_error_t result = camera_close(m_handle);
+ if (result != CAMERA_EOK) {
+ m_status = QCamera::LoadedStatus;
+ emit statusChanged(m_status);
+
+ qWarning() << "Unable to close camera:" << result;
+ emit error(QCamera::CameraError, tr("Unable to close camera"));
+ return;
+ }
+
+ m_handle = CAMERA_HANDLE_INVALID;
+
+ m_status = QCamera::UnloadedStatus;
+ emit statusChanged(m_status);
+}
+
+static void photoViewFinderDataCallback(camera_handle_t handle, camera_buffer_t *buffer, void *context)
+{
+ Q_UNUSED(handle)
+
+ BbCameraSession *session = static_cast<BbCameraSession*>(context);
+ session->handlePhotoViewFinderData(buffer);
+}
+
+static void videoViewFinderDataCallback(camera_handle_t handle, camera_buffer_t *buffer, void *context)
+{
+ Q_UNUSED(handle)
+
+ BbCameraSession *session = static_cast<BbCameraSession*>(context);
+ session->handleVideoViewFinderData(buffer);
+}
+
+static void viewFinderStatusCallback(camera_handle_t handle, camera_devstatus_t status, uint16_t value, void *context)
+{
+ Q_UNUSED(handle)
+
+ if (status == CAMERA_STATUS_FOCUS_CHANGE) {
+ BbCameraSession *session = static_cast<BbCameraSession*>(context);
+ QMetaObject::invokeMethod(session, "handleFocusStatusChanged", Qt::QueuedConnection, Q_ARG(int, value));
+ } else if (status == CAMERA_STATUS_POWERUP) {
+ BbCameraSession *session = static_cast<BbCameraSession*>(context);
+ QMetaObject::invokeMethod(session, "handleCameraPowerUp", Qt::QueuedConnection);
+ }
+}
+
+bool BbCameraSession::startViewFinder()
+{
+ m_status = QCamera::StartingStatus;
+ emit statusChanged(m_status);
+
+ QSize viewfinderResolution;
+ camera_error_t result = CAMERA_EOK;
+ if (m_captureMode & QCamera::CaptureStillImage) {
+ result = camera_start_photo_viewfinder(m_handle, photoViewFinderDataCallback, viewFinderStatusCallback, this);
+ viewfinderResolution = currentViewfinderResolution(QCamera::CaptureStillImage);
+ } else if (m_captureMode & QCamera::CaptureVideo) {
+ result = camera_start_video_viewfinder(m_handle, videoViewFinderDataCallback, viewFinderStatusCallback, this);
+ viewfinderResolution = currentViewfinderResolution(QCamera::CaptureVideo);
+ }
+
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to start viewfinder:" << result;
+ return false;
+ }
+
+ // retrieve information about lock apply modes
+ {
+ int supported = 0;
+ uint32_t modes[20];
+
+ const camera_error_t result = camera_get_3a_lock_modes(m_handle, 20, &supported, modes);
+
+ if (result == CAMERA_EOK) {
+ // see API documentation of camera_get_3a_lock_modes for explanation of case discrimination below
+ if (supported == 4) {
+ m_locksApplyMode = IndependentMode;
+ } else if (supported == 3) {
+ m_locksApplyMode = FocusExposureBoundMode;
+ } else if (supported == 2) {
+ if (modes[0] == (CAMERA_3A_AUTOFOCUS | CAMERA_3A_AUTOEXPOSURE | CAMERA_3A_AUTOWHITEBALANCE))
+ m_locksApplyMode = AllBoundMode;
+ else
+ m_locksApplyMode = FocusOnlyMode;
+ }
+ }
+ }
+
+ const int angle = m_orientationHandler->orientation();
+
+ const QSize rotatedSize = ((angle == 0 || angle == 180) ? viewfinderResolution
+ : viewfinderResolution.transposed());
+
+ m_surfaceMutex.lock();
+ if (m_surface) {
+ const bool ok = m_surface->start(QVideoSurfaceFormat(rotatedSize, QVideoFrame::Format_RGB32));
+ if (!ok)
+ qWarning() << "Unable to start camera viewfinder surface";
+ }
+ m_surfaceMutex.unlock();
+
+ m_status = QCamera::ActiveStatus;
+ emit statusChanged(m_status);
+
+ return true;
+}
+
+void BbCameraSession::stopViewFinder()
+{
+ m_status = QCamera::StoppingStatus;
+ emit statusChanged(m_status);
+
+ m_surfaceMutex.lock();
+ if (m_surface) {
+ m_surface->stop();
+ }
+ m_surfaceMutex.unlock();
+
+ camera_error_t result = CAMERA_EOK;
+ if (m_captureMode & QCamera::CaptureStillImage)
+ result = camera_stop_photo_viewfinder(m_handle);
+ else if (m_captureMode & QCamera::CaptureVideo)
+ result = camera_stop_video_viewfinder(m_handle);
+
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to stop viewfinder:" << result;
+ return;
+ }
+
+ m_status = QCamera::LoadedStatus;
+ emit statusChanged(m_status);
+}
+
+void BbCameraSession::applyConfiguration()
+{
+ if (m_captureMode & QCamera::CaptureStillImage) {
+ const QList<QSize> photoOutputResolutions = supportedResolutions(QCamera::CaptureStillImage);
+
+ if (!m_imageEncoderSettings.resolution().isValid() || !photoOutputResolutions.contains(m_imageEncoderSettings.resolution()))
+ m_imageEncoderSettings.setResolution(photoOutputResolutions.first());
+
+ const QSize photoResolution = m_imageEncoderSettings.resolution();
+ const qreal aspectRatio = static_cast<qreal>(photoResolution.width())/static_cast<qreal>(photoResolution.height());
+
+ // apply viewfinder configuration
+ QSize viewfinderResolution;
+ QList<QSize> sizes = supportedViewfinderResolutions(QCamera::CaptureStillImage);
+ std::reverse(sizes.begin(), sizes.end()); // use smallest possible resolution
+ foreach (const QSize &size, sizes) {
+ // search for viewfinder resolution with the same aspect ratio
+ if (qFuzzyCompare(aspectRatio, (static_cast<qreal>(size.width())/static_cast<qreal>(size.height())))) {
+ viewfinderResolution = size;
+ break;
+ }
+ }
+
+ Q_ASSERT(viewfinderResolution.isValid());
+
+ camera_error_t result = camera_set_photovf_property(m_handle,
+ CAMERA_IMGPROP_WIDTH, viewfinderResolution.width(),
+ CAMERA_IMGPROP_HEIGHT, viewfinderResolution.height(),
+ CAMERA_IMGPROP_FORMAT, CAMERA_FRAMETYPE_NV12,
+ CAMERA_IMGPROP_ROTATION, 360 - m_nativeCameraOrientation);
+
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to apply photo viewfinder settings:" << result;
+ return;
+ }
+
+
+ int jpegQuality = 100;
+ switch (m_imageEncoderSettings.quality()) {
+ case QMultimedia::VeryLowQuality:
+ jpegQuality = 20;
+ break;
+ case QMultimedia::LowQuality:
+ jpegQuality = 40;
+ break;
+ case QMultimedia::NormalQuality:
+ jpegQuality = 60;
+ break;
+ case QMultimedia::HighQuality:
+ jpegQuality = 80;
+ break;
+ case QMultimedia::VeryHighQuality:
+ jpegQuality = 100;
+ break;
+ }
+
+ // apply photo configuration
+ result = camera_set_photo_property(m_handle,
+ CAMERA_IMGPROP_WIDTH, photoResolution.width(),
+ CAMERA_IMGPROP_HEIGHT, photoResolution.height(),
+ CAMERA_IMGPROP_JPEGQFACTOR, jpegQuality,
+ CAMERA_IMGPROP_ROTATION, 360 - m_nativeCameraOrientation);
+
+ if (result != CAMERA_EOK) {
+ qWarning() << "Unable to apply photo settings:" << result;
+ return;
+ }
+
+ } else if (m_captureMode & QCamera::CaptureVideo) {
+ applyVideoSettings();
+ }
+}
+
+static void videoRecordingStatusCallback(camera_handle_t handle, camera_devstatus_t status, uint16_t value, void *context)
+{
+ Q_UNUSED(handle)
+ Q_UNUSED(value)
+
+ if (status == CAMERA_STATUS_VIDEO_PAUSE) {
+ BbCameraSession *session = static_cast<BbCameraSession*>(context);
+ QMetaObject::invokeMethod(session, "handleVideoRecordingPaused", Qt::QueuedConnection);
+ } else if (status == CAMERA_STATUS_VIDEO_RESUME) {
+ BbCameraSession *session = static_cast<BbCameraSession*>(context);
+ QMetaObject::invokeMethod(session, "handleVideoRecordingResumed", Qt::QueuedConnection);
+ }
+}
+
+bool BbCameraSession::startVideoRecording()
+{
+ m_videoRecordingDuration.invalidate();
+
+ m_videoStatus = QMediaRecorder::StartingStatus;
+ emit videoStatusChanged(m_videoStatus);
+
+ if (m_videoOutputLocation.isEmpty())
+ m_videoOutputLocation = m_mediaStorageLocation.generateFileName(QLatin1String("VID_"), m_mediaStorageLocation.defaultDir(QCamera::CaptureVideo), QLatin1String("mp4"));
+
+ emit actualLocationChanged(m_videoOutputLocation);
+
+ const camera_error_t result = camera_start_video(m_handle, QFile::encodeName(m_videoOutputLocation), 0, videoRecordingStatusCallback, this);
+ if (result != CAMERA_EOK) {
+ m_videoStatus = QMediaRecorder::LoadedStatus;
+ emit videoStatusChanged(m_videoStatus);
+
+ emit videoError(QMediaRecorder::ResourceError, tr("Unable to start video recording"));
+ return false;
+ }
+
+ return true;
+}
+
+void BbCameraSession::stopVideoRecording()
+{
+ m_videoStatus = QMediaRecorder::FinalizingStatus;
+ emit videoStatusChanged(m_videoStatus);
+
+ const camera_error_t result = camera_stop_video(m_handle);
+ if (result != CAMERA_EOK) {
+ emit videoError(QMediaRecorder::ResourceError, tr("Unable to stop video recording"));
+ }
+
+ m_videoStatus = QMediaRecorder::LoadedStatus;
+ emit videoStatusChanged(m_videoStatus);
+
+ m_videoRecordingDuration.invalidate();
+}
+
+bool BbCameraSession::isCaptureModeSupported(camera_handle_t handle, QCamera::CaptureModes mode) const
+{
+ if (mode & QCamera::CaptureStillImage)
+ return camera_has_feature(handle, CAMERA_FEATURE_PHOTO);
+
+ if (mode & QCamera::CaptureVideo)
+ return camera_has_feature(handle, CAMERA_FEATURE_VIDEO);
+
+ return false;
+}
+
+QList<QSize> BbCameraSession::supportedResolutions(QCamera::CaptureMode mode) const
+{
+ Q_ASSERT(m_handle != CAMERA_HANDLE_INVALID);
+
+ QList<QSize> list;
+
+ camera_error_t result = CAMERA_EOK;
+ camera_res_t resolutions[20];
+ unsigned int supported = 0;
+
+ if (mode == QCamera::CaptureStillImage)
+ result = camera_get_photo_output_resolutions(m_handle, CAMERA_FRAMETYPE_JPEG, 20, &supported, resolutions);
+ else if (mode == QCamera::CaptureVideo)
+ result = camera_get_video_output_resolutions(m_handle, 20, &supported, resolutions);
+
+ if (result != CAMERA_EOK)
+ return list;
+
+ for (unsigned int i = 0; i < supported; ++i)
+ list << QSize(resolutions[i].width, resolutions[i].height);
+
+ return list;
+}
+
+QList<QSize> BbCameraSession::supportedViewfinderResolutions(QCamera::CaptureMode mode) const
+{
+ Q_ASSERT(m_handle != CAMERA_HANDLE_INVALID);
+
+ QList<QSize> list;
+
+ camera_error_t result = CAMERA_EOK;
+ camera_res_t resolutions[20];
+ unsigned int supported = 0;
+
+ if (mode == QCamera::CaptureStillImage)
+ result = camera_get_photo_vf_resolutions(m_handle, 20, &supported, resolutions);
+ else if (mode == QCamera::CaptureVideo)
+ result = camera_get_video_vf_resolutions(m_handle, 20, &supported, resolutions);
+
+ if (result != CAMERA_EOK)
+ return list;
+
+ for (unsigned int i = 0; i < supported; ++i)
+ list << QSize(resolutions[i].width, resolutions[i].height);
+
+ return list;
+}
+
+QSize BbCameraSession::currentViewfinderResolution(QCamera::CaptureMode mode) const
+{
+ Q_ASSERT(m_handle != CAMERA_HANDLE_INVALID);
+
+ camera_error_t result = CAMERA_EOK;
+ int width = 0;
+ int height = 0;
+
+ if (mode == QCamera::CaptureStillImage)
+ result = camera_get_photovf_property(m_handle, CAMERA_IMGPROP_WIDTH, &width,
+ CAMERA_IMGPROP_HEIGHT, &height);
+ else if (mode == QCamera::CaptureVideo)
+ result = camera_get_videovf_property(m_handle, CAMERA_IMGPROP_WIDTH, &width,
+ CAMERA_IMGPROP_HEIGHT, &height);
+
+ if (result != CAMERA_EOK)
+ return QSize();
+
+ return QSize(width, height);
+}
+
+QT_END_NAMESPACE