Conflicts: src/plugins/blackberry/camera/bbcamerasession.cpp Change-Id: I7c86e10140ab86fd2a07e2f034dec38ae9112559
1305 lines
43 KiB
C++
1305 lines
43 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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 "windowgrabber.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_EUNINIT:
|
|
return QLatin1String("Camera library not initialized");
|
|
case CAMERA_EREGFAULT:
|
|
return QLatin1String("Callback registration failed");
|
|
case CAMERA_EMICINUSE:
|
|
return QLatin1String("Microphone in use already");
|
|
#ifndef Q_OS_BLACKBERRY_TABLET
|
|
case CAMERA_ENODATA:
|
|
return QLatin1String("Data does not exist");
|
|
case CAMERA_EBUSY:
|
|
return QLatin1String("Camera busy");
|
|
case CAMERA_EDESKTOPCAMERAINUSE:
|
|
return QLatin1String("Desktop camera in use already");
|
|
case CAMERA_ENOSPC:
|
|
return QLatin1String("Disk is full");
|
|
case CAMERA_EPOWERDOWN:
|
|
return QLatin1String("Camera in power down state");
|
|
case CAMERA_3ALOCKED:
|
|
return QLatin1String("3A have been locked");
|
|
case CAMERA_EVIEWFINDERFROZEN:
|
|
return QLatin1String("Freeze flag set");
|
|
#endif
|
|
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)
|
|
, m_windowGrabber(new WindowGrabber(this))
|
|
{
|
|
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)));
|
|
|
|
connect(m_windowGrabber, SIGNAL(frameGrabbed(QImage)), SLOT(viewfinderFrameGrabbed(QImage)));
|
|
}
|
|
|
|
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, BbCameraSession::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 = BbCameraSession::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());
|
|
|
|
const QByteArray windowId = QString().sprintf("qcamera_vf_%p", this).toLatin1();
|
|
m_windowGrabber->setWindowId(windowId);
|
|
|
|
const QByteArray windowGroupId = m_windowGrabber->windowGroupId();
|
|
|
|
camera_error_t result = CAMERA_EOK;
|
|
result = camera_set_videovf_property(m_handle,
|
|
CAMERA_IMGPROP_WIN_GROUPID, windowGroupId.data(),
|
|
CAMERA_IMGPROP_WIN_ID, windowId.data(),
|
|
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;
|
|
}
|
|
|
|
const QSize resolution = m_videoEncoderSettings.resolution();
|
|
|
|
#ifndef Q_OS_BLACKBERRY_TABLET
|
|
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;
|
|
|
|
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);
|
|
#else
|
|
result = camera_set_video_property(m_handle,
|
|
CAMERA_IMGPROP_WIDTH, resolution.width(),
|
|
CAMERA_IMGPROP_HEIGHT, resolution.height());
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
void BbCameraSession::viewfinderFrameGrabbed(const QImage &image)
|
|
{
|
|
QTransform transform;
|
|
|
|
transform.rotate(m_nativeCameraOrientation);
|
|
|
|
QImage frame = image.copy().transformed(transform);
|
|
if (m_device == cameraIdentifierFront())
|
|
frame = frame.mirrored(true, false);
|
|
|
|
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_ARGB32));
|
|
}
|
|
|
|
QVideoFrame videoFrame(frame);
|
|
|
|
m_surface->present(videoFrame);
|
|
}
|
|
}
|
|
|
|
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 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));
|
|
return;
|
|
}
|
|
#ifndef Q_OS_BLACKBERRY_TABLET
|
|
else if (status == CAMERA_STATUS_POWERUP) {
|
|
BbCameraSession *session = static_cast<BbCameraSession*>(context);
|
|
QMetaObject::invokeMethod(session, "handleCameraPowerUp", Qt::QueuedConnection);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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, 0, viewFinderStatusCallback, this);
|
|
viewfinderResolution = currentViewfinderResolution(QCamera::CaptureStillImage);
|
|
} else if (m_captureMode & QCamera::CaptureVideo) {
|
|
result = camera_start_video_viewfinder(m_handle, 0, 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_ARGB32));
|
|
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_windowGrabber->stop();
|
|
|
|
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());
|
|
|
|
const QByteArray windowId = QString().sprintf("qcamera_vf_%p", this).toLatin1();
|
|
m_windowGrabber->setWindowId(windowId);
|
|
|
|
const QByteArray windowGroupId = m_windowGrabber->windowGroupId();
|
|
|
|
camera_error_t result = camera_set_photovf_property(m_handle,
|
|
CAMERA_IMGPROP_WIN_GROUPID, windowGroupId.data(),
|
|
CAMERA_IMGPROP_WIN_ID, windowId.data(),
|
|
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)
|
|
|
|
#ifndef Q_OS_BLACKBERRY_TABLET
|
|
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);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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
|