summaryrefslogtreecommitdiffstats
path: root/src/plugins/symbian/ecam/s60imagecapturesession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/symbian/ecam/s60imagecapturesession.cpp')
-rw-r--r--src/plugins/symbian/ecam/s60imagecapturesession.cpp1884
1 files changed, 1884 insertions, 0 deletions
diff --git a/src/plugins/symbian/ecam/s60imagecapturesession.cpp b/src/plugins/symbian/ecam/s60imagecapturesession.cpp
new file mode 100644
index 000000000..16d240c7b
--- /dev/null
+++ b/src/plugins/symbian/ecam/s60imagecapturesession.cpp
@@ -0,0 +1,1884 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qstring.h>
+#include <QtCore/qdir.h>
+
+#include "s60imagecapturesession.h"
+#include "s60videowidgetcontrol.h"
+#include "s60cameraservice.h"
+#include "s60cameraconstants.h"
+
+#include <fbs.h> // CFbsBitmap
+#include <pathinfo.h>
+#include <imageconversion.h> // ICL Decoder (for SnapShot) & Encoder (for Bitmap Images)
+
+S60ImageCaptureDecoder::S60ImageCaptureDecoder(S60ImageCaptureSession *imageSession,
+ RFs *fileSystemAccess,
+ const TDesC8 *data,
+ const TDesC16 *fileName) :
+ CActive(CActive::EPriorityStandard),
+ m_imageSession(imageSession),
+ m_fs(fileSystemAccess),
+ m_jpegImageData(data),
+ m_jpegImageFile(fileName),
+ m_fileInput(false)
+{
+ CActiveScheduler::Add(this);
+}
+
+S60ImageCaptureDecoder::~S60ImageCaptureDecoder()
+{
+ if (m_imageDecoder) {
+ delete m_imageDecoder;
+ m_imageDecoder = 0;
+ }
+}
+
+S60ImageCaptureDecoder *S60ImageCaptureDecoder::FileNewL(S60ImageCaptureSession *imageSession,
+ RFs *fileSystemAccess,
+ const TDesC16 *fileName)
+{
+ S60ImageCaptureDecoder* self = new (ELeave) S60ImageCaptureDecoder(imageSession,
+ fileSystemAccess,
+ 0,
+ fileName);
+ CleanupStack::PushL(self);
+ self->ConstructL(true);
+ CleanupStack::Pop(self);
+ return self;
+}
+
+S60ImageCaptureDecoder *S60ImageCaptureDecoder::DataNewL(S60ImageCaptureSession *imageSession,
+ RFs *fileSystemAccess,
+ const TDesC8 *data)
+{
+ S60ImageCaptureDecoder* self = new (ELeave) S60ImageCaptureDecoder(imageSession,
+ fileSystemAccess,
+ data,
+ 0);
+ CleanupStack::PushL(self);
+ self->ConstructL(false);
+ CleanupStack::Pop(self);
+ return self;
+}
+
+void S60ImageCaptureDecoder::ConstructL(const bool fileInput)
+{
+ if (fileInput) {
+ if (!m_imageSession || !m_fs || !m_jpegImageFile)
+ User::Leave(KErrGeneral);
+ m_imageDecoder = CImageDecoder::FileNewL(*m_fs, *m_jpegImageFile);
+ } else {
+ if (!m_imageSession || !m_fs || !m_jpegImageData)
+ User::Leave(KErrGeneral);
+ m_imageDecoder = CImageDecoder::DataNewL(*m_fs, *m_jpegImageData);
+ }
+}
+
+void S60ImageCaptureDecoder::decode(CFbsBitmap *destBitmap)
+{
+ if (m_imageDecoder) {
+ m_imageDecoder->Convert(&iStatus, *destBitmap, 0);
+ SetActive();
+ }
+ else
+ m_imageSession->setError(KErrGeneral, QLatin1String("Preview image creation failed."));
+}
+
+TFrameInfo *S60ImageCaptureDecoder::frameInfo()
+{
+ if (m_imageDecoder) {
+ m_frameInfo = m_imageDecoder->FrameInfo();
+ return &m_frameInfo;
+ }
+ else
+ return 0;
+}
+
+void S60ImageCaptureDecoder::RunL()
+{
+ m_imageSession->handleImageDecoded(iStatus.Int());
+}
+
+void S60ImageCaptureDecoder::DoCancel()
+{
+ if (m_imageDecoder)
+ m_imageDecoder->Cancel();
+}
+
+TInt S60ImageCaptureDecoder::RunError(TInt aError)
+{
+ m_imageSession->setError(aError, QLatin1String("Preview image creation failed."));
+ return KErrNone;
+}
+
+//=============================================================================
+
+S60ImageCaptureEncoder::S60ImageCaptureEncoder(S60ImageCaptureSession *imageSession,
+ RFs *fileSystemAccess,
+ const TDesC16 *fileName,
+ TInt jpegQuality) :
+ CActive(CActive::EPriorityStandard),
+ m_imageSession(imageSession),
+ m_fileSystemAccess(fileSystemAccess),
+ m_fileName(fileName),
+ m_jpegQuality(jpegQuality)
+{
+ CActiveScheduler::Add(this);
+}
+
+S60ImageCaptureEncoder::~S60ImageCaptureEncoder()
+{
+ if (m_frameImageData) {
+ delete m_frameImageData;
+ m_frameImageData = 0;
+ }
+ if (m_imageEncoder) {
+ delete m_imageEncoder;
+ m_imageEncoder = 0;
+ }
+}
+
+S60ImageCaptureEncoder *S60ImageCaptureEncoder::NewL(S60ImageCaptureSession *imageSession,
+ RFs *fileSystemAccess,
+ const TDesC16 *fileName,
+ TInt jpegQuality)
+{
+ S60ImageCaptureEncoder* self = new (ELeave) S60ImageCaptureEncoder(imageSession,
+ fileSystemAccess,
+ fileName,
+ jpegQuality);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+}
+
+void S60ImageCaptureEncoder::ConstructL()
+{
+ if (!m_imageSession || !m_fileSystemAccess || !m_fileName)
+ User::Leave(KErrGeneral);
+
+ m_imageEncoder = CImageEncoder::FileNewL(*m_fileSystemAccess,
+ *m_fileName,
+ CImageEncoder::EOptionNone,
+ KImageTypeJPGUid);
+ CleanupStack::PushL(m_imageEncoder);
+
+ // Set Jpeg Quality
+ m_frameImageData = CFrameImageData::NewL();
+ CleanupStack::PushL(m_frameImageData);
+
+ TJpegImageData* jpegFormat = new( ELeave ) TJpegImageData;
+ CleanupStack::PushL(jpegFormat);
+
+ jpegFormat->iQualityFactor = m_jpegQuality;
+
+ // jpegFormat (TJpegImageData) ownership transferred to m_frameImageData (CFrameImageData)
+ User::LeaveIfError( m_frameImageData->AppendImageData(jpegFormat));
+
+ CleanupStack::Pop(jpegFormat);
+ CleanupStack::Pop(m_frameImageData);
+ CleanupStack::Pop(m_imageEncoder);
+}
+
+void S60ImageCaptureEncoder::encode(CFbsBitmap *sourceBitmap)
+{
+ if (m_imageEncoder) {
+ m_imageEncoder->Convert(&iStatus, *sourceBitmap, m_frameImageData);
+ SetActive();
+ }
+ else
+ m_imageSession->setError(KErrGeneral, QLatin1String("Saving image to file failed."));
+}
+
+void S60ImageCaptureEncoder::RunL()
+{
+ m_imageSession->handleImageEncoded(iStatus.Int());
+}
+
+void S60ImageCaptureEncoder::DoCancel()
+{
+ if (m_imageEncoder)
+ m_imageEncoder->Cancel();
+}
+
+TInt S60ImageCaptureEncoder::RunError(TInt aError)
+{
+ m_imageSession->setError(aError, QLatin1String("Saving image to file failed."));
+ return KErrNone;
+}
+
+//=============================================================================
+
+S60ImageCaptureSession::S60ImageCaptureSession(QObject *parent) :
+ QObject(parent),
+ m_cameraEngine(0),
+ m_advancedSettings(0),
+ m_cameraInfo(0),
+ m_previewBitmap(0),
+ m_activeScheduler(0),
+ m_fileSystemAccess(0),
+ m_imageDecoder(0),
+ m_imageEncoder(0),
+ m_error(KErrNone),
+ m_activeDeviceIndex(KDefaultCameraDevice),
+ m_cameraStarted(false),
+ m_icState(EImageCaptureNotPrepared),
+ m_currentCodec(QString()),
+ m_captureSize(QSize()),
+ m_symbianImageQuality(QtMultimediaKit::HighQuality * KSymbianImageQualityCoefficient),
+ m_captureSettingsSet(false),
+ m_stillCaptureFileName(QString()),
+ m_requestedStillCaptureFileName(QString()),
+ m_currentImageId(0),
+ m_captureWhenReady(false),
+ m_previewDecodingOngoing(false),
+ m_previewInWaitLoop(false)
+{
+ // Define supported image codecs
+ m_supportedImageCodecs << "image/jpeg";
+
+ initializeImageCaptureSettings();
+
+ // Install ActiveScheduler if needed
+ if (!CActiveScheduler::Current()) {
+ m_activeScheduler = new CActiveScheduler;
+ CActiveScheduler::Install(m_activeScheduler);
+ }
+}
+
+S60ImageCaptureSession::~S60ImageCaptureSession()
+{
+ // Delete AdvancedSettings (Should already be destroyed by CameraControl)
+ deleteAdvancedSettings();
+
+ m_formats.clear();
+ m_supportedImageCodecs.clear();
+
+ if (m_imageDecoder) {
+ m_imageDecoder->Cancel();
+ delete m_imageDecoder;
+ m_imageDecoder = 0;
+ }
+ if (m_imageEncoder) {
+ m_imageEncoder->Cancel();
+ delete m_imageEncoder;
+ m_imageEncoder = 0;
+ }
+
+ if (m_previewBitmap) {
+ delete m_previewBitmap;
+ m_previewBitmap = 0;
+ }
+
+ // Uninstall ActiveScheduler if needed
+ if (m_activeScheduler) {
+ CActiveScheduler::Install(0);
+ delete m_activeScheduler;
+ m_activeScheduler = 0;
+ }
+}
+
+CCamera::TFormat S60ImageCaptureSession::defaultImageFormat()
+{
+ // Primary Camera
+ if (m_activeDeviceIndex == 0)
+ return KDefaultImageFormatPrimaryCam;
+
+ // Secondary Camera or other
+ else
+ return KDefaultImageFormatSecondaryCam;
+}
+
+bool S60ImageCaptureSession::isDeviceReady()
+{
+#ifdef Q_CC_NOKIAX86 // Emulator
+ return true;
+#endif
+
+ if (m_cameraEngine)
+ return m_cameraEngine->IsCameraReady();
+
+ return false;
+}
+
+void S60ImageCaptureSession::deleteAdvancedSettings()
+{
+ if (m_advancedSettings) {
+ delete m_advancedSettings;
+ m_advancedSettings = 0;
+ emit advancedSettingChanged();
+ }
+}
+
+void S60ImageCaptureSession::setCameraHandle(CCameraEngine* camerahandle)
+{
+ if (camerahandle) {
+ m_cameraEngine = camerahandle;
+ resetSession();
+
+ // Set default settings
+ initializeImageCaptureSettings();
+ }
+}
+
+void S60ImageCaptureSession::setCurrentDevice(TInt deviceindex)
+{
+ m_activeDeviceIndex = deviceindex;
+}
+
+void S60ImageCaptureSession::notifySettingsSet()
+{
+ m_captureSettingsSet = true;
+}
+
+void S60ImageCaptureSession::resetSession(bool errorHandling)
+{
+ // Delete old AdvancedSettings
+ deleteAdvancedSettings();
+
+ m_captureWhenReady = false;
+ m_previewDecodingOngoing = false;
+ m_previewInWaitLoop = false;
+ m_stillCaptureFileName = QString();
+ m_requestedStillCaptureFileName = QString();
+ m_icState = EImageCaptureNotPrepared;
+
+ m_error = KErrNone;
+ m_currentFormat = defaultImageFormat();
+
+ int err = KErrNone;
+ m_advancedSettings = S60CameraSettings::New(err, this, m_cameraEngine);
+ if (err == KErrNotSupported) {
+ m_advancedSettings = 0;
+#ifndef S60_31_PLATFORM // Post S60 3.1 Platform
+ // Adv. settings may not be supported for other than the Primary Camera
+ if (m_cameraEngine->CurrentCameraIndex() == 0)
+ setError(err, tr("Unexpected camera error."));
+#endif // !S60_31_PLATFORM
+ } else if (err != KErrNone) { // Other errors
+ m_advancedSettings = 0;
+ qWarning("Failed to create camera settings handler.");
+ if (errorHandling)
+ emit cameraError(QCamera::ServiceMissingError, tr("Failed to recover from error."));
+ else
+ setError(err, tr("Unexpected camera error."));
+ return;
+ }
+
+ if (m_advancedSettings) {
+ if (m_cameraEngine)
+ m_cameraEngine->SetAdvancedObserver(m_advancedSettings);
+ else
+ setError(KErrNotReady, tr("Unexpected camera error."));
+ }
+
+ updateImageCaptureFormats();
+
+ emit advancedSettingChanged();
+}
+
+S60CameraSettings* S60ImageCaptureSession::advancedSettings()
+{
+ return m_advancedSettings;
+}
+
+/*
+ * This function can be used both internally and from Control classes using
+ * this session. The error notification will go to the client application
+ * either through QCameraImageCapture (if captureError is true) or QCamera (if
+ * captureError is false, default) error signal.
+ */
+void S60ImageCaptureSession::setError(const TInt error,
+ const QString &description,
+ const bool captureError)
+{
+ if (error == KErrNone)
+ return;
+
+ m_error = error;
+ QCameraImageCapture::Error cameraError = fromSymbianErrorToQtMultimediaError(error);
+
+ if (captureError) {
+ emit this->captureError(m_currentImageId, cameraError, description);
+ if (cameraError != QCameraImageCapture::NotSupportedFeatureError)
+ resetSession(true);
+ } else {
+ emit this->cameraError(cameraError, description);
+ if (cameraError != QCamera::NotSupportedFeatureError)
+ resetSession(true);
+ }
+}
+
+QCameraImageCapture::Error S60ImageCaptureSession::fromSymbianErrorToQtMultimediaError(int aError)
+{
+ switch(aError) {
+ case KErrNone:
+ return QCameraImageCapture::NoError; // No errors have occurred
+ case KErrNotReady:
+ return QCameraImageCapture::NotReadyError; // Not ready for operation
+ case KErrNotSupported:
+ return QCameraImageCapture::NotSupportedFeatureError; // The feature is not supported
+ case KErrNoMemory:
+ return QCameraImageCapture::OutOfSpaceError; // Out of disk space
+ case KErrNotFound:
+ case KErrBadHandle:
+ return QCameraImageCapture::ResourceError; // No resources available
+
+ default:
+ return QCameraImageCapture::ResourceError; // Other error has occurred
+ }
+}
+
+int S60ImageCaptureSession::currentImageId() const
+{
+ return m_currentImageId;
+}
+
+void S60ImageCaptureSession::initializeImageCaptureSettings()
+{
+ if (m_captureSettingsSet)
+ return;
+
+ m_currentCodec = KDefaultImageCodec;
+ m_captureSize = QSize(-1, -1);
+ m_currentFormat = defaultImageFormat();
+
+ // Resolution
+ if (m_cameraEngine) {
+ QList<QSize> resolutions = supportedCaptureSizesForCodec(imageCaptureCodec());
+ foreach (QSize reso, resolutions) {
+ if ((reso.width() * reso.height()) > (m_captureSize.width() * m_captureSize.height()))
+ m_captureSize = reso;
+ }
+ } else {
+ m_captureSize = KDefaultImageResolution;
+ }
+
+ m_symbianImageQuality = KDefaultImageQuality;
+}
+
+/*
+ * This function selects proper format to be used for the captured image based
+ * on the requested image codec.
+ */
+CCamera::TFormat S60ImageCaptureSession::selectFormatForCodec(const QString &codec)
+{
+ CCamera::TFormat format = CCamera::EFormatMonochrome;
+
+ if (codec == "image/jpg" || codec == "image/jpeg") {
+ // Primary Camera
+ if (m_activeDeviceIndex == 0)
+ format = KDefaultImageFormatPrimaryCam;
+
+ // Secondary Camera or other
+ else
+ format = KDefaultImageFormatSecondaryCam;
+
+ return format;
+ }
+
+ setError(KErrNotSupported, tr("Failed to select color format to be used with image codec."));
+ return format;
+}
+
+int S60ImageCaptureSession::prepareImageCapture()
+{
+ if (m_cameraEngine) {
+ if (!m_cameraEngine->IsCameraReady()) {
+ // Reset state to make sure camera is prepared before capturing image
+ m_icState = EImageCaptureNotPrepared;
+ return KErrNotReady;
+ }
+
+ // First set the quality
+ CCamera *camera = m_cameraEngine->Camera();
+ if (camera)
+ camera->SetJpegQuality(m_symbianImageQuality);
+ else
+ setError(KErrNotReady, tr("Setting image quality failed."), true);
+
+ // Then prepare with correct resolution and format
+ TSize captureSize = TSize(m_captureSize.width(), m_captureSize.height());
+ TRAPD(symbianError, m_cameraEngine->PrepareL(captureSize, m_currentFormat));
+ if (!symbianError)
+ m_icState = EImageCapturePrepared;
+
+ // Check if CaptureSize was modified
+ if (captureSize.iWidth != m_captureSize.width() || captureSize.iHeight != m_captureSize.height())
+ m_captureSize = QSize(captureSize.iWidth, captureSize.iHeight);
+ emit captureSizeChanged(m_captureSize);
+
+#ifdef ECAM_PREVIEW_API
+ // Subscribe previews
+ MCameraPreviewObserver *observer = this;
+ m_cameraEngine->EnablePreviewProvider(observer);
+#endif // ECAM_PREVIEW_API
+
+ return symbianError;
+ }
+
+ return KErrGeneral;
+}
+
+void S60ImageCaptureSession::releaseImageCapture()
+{
+ // Make sure ImageCapture is prepared the next time it is being activated
+ m_icState = EImageCaptureNotPrepared;
+
+#ifdef ECAM_PREVIEW_API
+ // Cancel preview subscription
+ m_cameraEngine->DisablePreviewProvider();
+#endif // ECAM_PREVIEW_API
+}
+
+int S60ImageCaptureSession::capture(const QString &fileName)
+{
+ if (!m_cameraStarted) {
+ m_captureWhenReady = true;
+ m_requestedStillCaptureFileName = fileName; // Save name, it will be processed during actual capture
+ return 0;
+ }
+
+ if (m_icState < EImageCapturePrepared) {
+ int prepareSuccess = prepareImageCapture();
+ if (prepareSuccess) {
+ setError(prepareSuccess, tr("Failure during image capture preparation."), true);
+ return 0;
+ }
+ } else if (m_icState > EImageCapturePrepared) {
+ setError(KErrNotReady, tr("Previous operation is still ongoing."), true);
+ return 0;
+ }
+
+ m_icState = EImageCaptureCapturing;
+
+ // Give new ID for the new image
+ m_currentImageId += 1;
+
+ emit readyForCaptureChanged(false);
+
+ processFileName(fileName);
+
+ if (m_cameraEngine) {
+ TRAPD(err, m_cameraEngine->CaptureL());
+ setError(err, tr("Image capture failed."), true);
+ } else {
+ setError(KErrNotReady, tr("Unexpected camera error."), true);
+ }
+
+#ifdef Q_CC_NOKIAX86 // Emulator
+ QImage *snapImage = new QImage(QLatin1String("C:/Data/testimage.jpg"));
+ emit imageExposed(m_currentImageId);
+ emit imageCaptured(m_currentImageId, *snapImage);
+ emit imageSaved(m_currentImageId, m_stillCaptureFileName);
+#endif // Q_CC_NOKIAX86
+
+ return m_currentImageId;
+}
+
+void S60ImageCaptureSession::cancelCapture()
+{
+ if (m_icState != EImageCaptureCapturing)
+ return;
+
+ if (m_cameraEngine)
+ m_cameraEngine->CancelCapture();
+
+ m_icState = EImageCapturePrepared;
+}
+
+void S60ImageCaptureSession::processFileName(const QString &fileName)
+{
+ // Empty FileName - Use default file name and path (C:\Data\Images\image.jpg)
+ if (fileName.isEmpty()) {
+ // Make sure default directory exists
+ QDir videoDir(QDir::rootPath());
+ if (!videoDir.exists(KDefaultImagePath))
+ videoDir.mkpath(KDefaultImagePath);
+ QString defaultFile = KDefaultImagePath;
+ defaultFile.append("\\");
+ defaultFile.append(KDefaultImageFileName);
+ m_stillCaptureFileName = defaultFile;
+
+ } else { // Not empty
+
+ QString fullFileName;
+
+ // Relative FileName
+ if (!fileName.contains(":")) {
+ // Extract file name and path from the URL
+ fullFileName = KDefaultImagePath;
+ if (fileName.at(0) != '\\')
+ fullFileName.append("\\");
+ fullFileName.append(QDir::toNativeSeparators(QDir::cleanPath(fileName)));
+
+ // Absolute FileName
+ } else {
+ // Extract file name and path from the given location
+ fullFileName = QDir::toNativeSeparators(QDir::cleanPath(fileName));
+ }
+
+ QString fileNameOnly = fullFileName.right(fullFileName.length() - fullFileName.lastIndexOf("\\") - 1);
+ QString directory = fullFileName.left(fullFileName.lastIndexOf("\\"));
+ if (directory.lastIndexOf("\\") == (directory.length() - 1))
+ directory = directory.left(directory.length() - 1);
+
+ // URL is Absolute path, not including file name
+ if (!fileNameOnly.contains(".")) {
+ if (fileNameOnly != "") {
+ directory.append("\\");
+ directory.append(fileNameOnly);
+ }
+ fileNameOnly = KDefaultImageFileName;
+ }
+
+ // Make sure absolute directory exists
+ QDir imageDir(QDir::rootPath());
+ if (!imageDir.exists(directory))
+ imageDir.mkpath(directory);
+
+ QString resolvedFileName = directory;
+ resolvedFileName.append("\\");
+ resolvedFileName.append(fileNameOnly);
+ m_stillCaptureFileName = resolvedFileName;
+ }
+}
+
+void S60ImageCaptureSession::MceoFocusComplete()
+{
+ emit focusStatusChanged(QCamera::Locked, QCamera::LockAcquired);
+}
+
+void S60ImageCaptureSession::MceoCapturedDataReady(TDesC8* aData)
+{
+ emit imageExposed(m_currentImageId);
+
+ m_icState = EImageCaptureWritingImage;
+
+ TFileName path = convertImagePath();
+
+ // Try to save image and inform if it was succcesful
+ TRAPD(err, saveImageL(aData, path));
+ if (err) {
+ if (m_previewDecodingOngoing)
+ m_previewDecodingOngoing = false; // Reset
+
+ setError(err, tr("Writing captured image to a file failed."), true);
+ m_icState = EImageCapturePrepared;
+ return;
+ }
+
+ m_icState = EImageCapturePrepared;
+
+}
+
+void S60ImageCaptureSession::MceoCapturedBitmapReady(CFbsBitmap* aBitmap)
+{
+ emit imageExposed(m_currentImageId);
+
+ m_icState = EImageCaptureWritingImage;
+
+ if(aBitmap)
+ {
+#ifndef ECAM_PREVIEW_API
+ if (m_previewDecodingOngoing) {
+ m_previewInWaitLoop = true;
+ CActiveScheduler::Start(); // Wait for the completion of the previous Preview generation
+ }
+
+ // Delete old instances if needed
+ if (m_imageDecoder) {
+ delete m_imageDecoder;
+ m_imageDecoder = 0;
+ }
+ if (m_previewBitmap) {
+ delete m_previewBitmap;
+ m_previewBitmap = 0;
+ }
+#endif // ECAM_CAMERA_API
+ if (m_imageEncoder) {
+ delete m_imageEncoder;
+ m_imageEncoder = 0;
+ }
+ if (m_fileSystemAccess) {
+ m_fileSystemAccess->Close();
+ delete m_fileSystemAccess;
+ m_fileSystemAccess = 0;
+ }
+
+ TInt saveError = KErrNone;
+ TFileName path = convertImagePath();
+
+ // Create FileSystem access
+ m_fileSystemAccess = new RFs;
+ if (!m_fileSystemAccess) {
+ setError(KErrNoMemory, tr("Failed to write captured image to a file."));
+ return;
+ }
+ saveError = m_fileSystemAccess->Connect();
+ if (saveError) {
+ setError(saveError, tr("Failed to write captured image to a file."));
+ return;
+ }
+
+ TRAP(saveError, m_imageEncoder = S60ImageCaptureEncoder::NewL(this,
+ m_fileSystemAccess,
+ &path,
+ m_symbianImageQuality));
+ if (saveError)
+ setError(saveError, tr("Saving captured image failed."), true);
+ m_previewDecodingOngoing = true;
+ m_imageEncoder->encode(aBitmap);
+
+ } else {
+ setError(KErrBadHandle, tr("Unexpected camera error."), true);
+ }
+
+ m_icState = EImageCapturePrepared;
+}
+
+void S60ImageCaptureSession::MceoHandleError(TCameraEngineError aErrorType, TInt aError)
+{
+ Q_UNUSED(aErrorType);
+ setError(aError, tr("General camera error."));
+}
+
+TFileName S60ImageCaptureSession::convertImagePath()
+{
+ TFileName path = KNullDesC();
+
+ // Convert to Symbian path
+ TPtrC16 attachmentPath(KNullDesC);
+
+ // Path is already included in filename
+ attachmentPath.Set(reinterpret_cast<const TUint16*>(QDir::toNativeSeparators(m_stillCaptureFileName).utf16()));
+ path.Append(attachmentPath);
+
+ return path;
+}
+
+/*
+ * Creates (asynchronously) Preview Image from Jpeg ImageBuffer and also
+ * writes Jpeg (synchronously) to a file.
+ */
+void S60ImageCaptureSession::saveImageL(TDesC8 *aData, TFileName &aPath)
+{
+ if (aData == 0)
+ setError(KErrGeneral, tr("Captured image data is not available."), true);
+
+ if (aPath.Size() > 0) {
+#ifndef ECAM_PREVIEW_API
+ if (m_previewDecodingOngoing) {
+ m_previewInWaitLoop = true;
+ CActiveScheduler::Start(); // Wait for the completion of the previous Preview generation
+ }
+
+ // Delete old instances if needed
+ if (m_imageDecoder) {
+ delete m_imageDecoder;
+ m_imageDecoder = 0;
+ }
+ if (m_previewBitmap) {
+ delete m_previewBitmap;
+ m_previewBitmap = 0;
+ }
+#endif // ECAM_PREVIEW_API
+ if (m_fileSystemAccess) {
+ m_fileSystemAccess->Close();
+ delete m_fileSystemAccess;
+ m_fileSystemAccess = 0;
+ }
+
+ RFs *fileSystemAccess = new (ELeave) RFs;
+ User::LeaveIfError(fileSystemAccess->Connect());
+ CleanupClosePushL(*fileSystemAccess);
+
+#ifndef ECAM_PREVIEW_API
+ // Generate Thumbnail to be used as Preview
+ S60ImageCaptureDecoder *imageDecoder = S60ImageCaptureDecoder::DataNewL(this, fileSystemAccess, aData);
+ CleanupStack::PushL(imageDecoder);
+
+ // Set proper Preview Size
+ TSize scaledSize((m_captureSize.width() / KSnapshotDownScaleFactor), (m_captureSize.height() / KSnapshotDownScaleFactor));
+ if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight)
+ scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/2)), (m_captureSize.height() / (KSnapshotDownScaleFactor/2)));
+ if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight)
+ scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/4)), (m_captureSize.height() / (KSnapshotDownScaleFactor/4)));
+ if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight)
+ scaledSize.SetSize(m_captureSize.width(), m_captureSize.height());
+
+ TFrameInfo *info = imageDecoder->frameInfo();
+ if (!info) {
+ setError(KErrGeneral, tr("Preview image creation failed."));
+ return;
+ }
+
+ CFbsBitmap *previewBitmap = new (ELeave) CFbsBitmap;
+ CleanupStack::PushL(previewBitmap);
+ TInt bitmapCreationErr = previewBitmap->Create(scaledSize, info->iFrameDisplayMode);
+ if (bitmapCreationErr) {
+ setError(bitmapCreationErr, tr("Preview creation failed."));
+ return;
+ }
+
+ // Jpeg conversion completes in RunL
+ m_previewDecodingOngoing = true;
+ imageDecoder->decode(previewBitmap);
+#endif // ECAM_PREVIEW_API
+
+ RFile file;
+ TInt fileWriteErr = KErrNone;
+ fileWriteErr = file.Replace(*fileSystemAccess, aPath, EFileWrite);
+ if (fileWriteErr)
+ User::Leave(fileWriteErr);
+ CleanupClosePushL(file); // Close if Leaves
+
+ fileWriteErr = file.Write(*aData);
+ if (fileWriteErr)
+ User::Leave(fileWriteErr);
+
+ CleanupStack::PopAndDestroy(&file);
+#ifdef ECAM_PREVIEW_API
+ CleanupStack::PopAndDestroy(fileSystemAccess);
+#else // !ECAM_PREVIEW_API
+ // Delete when Image is decoded
+ CleanupStack::Pop(previewBitmap);
+ CleanupStack::Pop(imageDecoder);
+ CleanupStack::Pop(fileSystemAccess);
+
+ // Set member variables (Cannot leave any more)
+ m_previewBitmap = previewBitmap;
+ m_imageDecoder = imageDecoder;
+ m_fileSystemAccess = fileSystemAccess;
+#endif // ECAM_PREVIEW_API
+
+ emit imageSaved(m_currentImageId, m_stillCaptureFileName);
+
+ // Inform that we can continue taking more pictures
+ emit readyForCaptureChanged(true);
+
+ // For custom preview generation, image buffer gets released in RunL()
+#ifdef ECAM_PREVIEW_API
+ releaseImageBuffer();
+#endif // ECAM_PREVIEW_API
+
+ } else {
+ setError(KErrPathNotFound, tr("Invalid path given."), true);
+ }
+}
+
+void S60ImageCaptureSession::releaseImageBuffer()
+{
+ if (m_cameraEngine)
+ m_cameraEngine->ReleaseImageBuffer();
+ else
+ setError(KErrNotReady, tr("Unexpected camera error."), true);
+}
+
+/*
+ * Queries camera properties
+ * Results are returned to member variable m_info
+ *
+ * @return boolean indicating if querying the info was a success
+ */
+bool S60ImageCaptureSession::queryCurrentCameraInfo()
+{
+ if (m_cameraEngine) {
+ m_cameraInfo = m_cameraEngine->CameraInfo();
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This function handles different camera status changes
+ */
+void S60ImageCaptureSession::cameraStatusChanged(QCamera::Status status)
+{
+ if (status == QCamera::ActiveStatus) {
+ m_cameraStarted = true;
+ if (m_captureWhenReady)
+ capture(m_requestedStillCaptureFileName);
+ }else if (status == QCamera::UnloadedStatus) {
+ m_cameraStarted = false;
+ m_icState = EImageCaptureNotPrepared;
+ }
+ else
+ m_cameraStarted = false;
+}
+
+QSize S60ImageCaptureSession::captureSize() const
+{
+ return m_captureSize;
+}
+
+QSize S60ImageCaptureSession::minimumCaptureSize()
+{
+ return supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).first();
+}
+QSize S60ImageCaptureSession::maximumCaptureSize()
+{
+ return supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).last();
+}
+
+void S60ImageCaptureSession::setCaptureSize(const QSize &size)
+{
+ if (size.isNull() ||
+ size.isEmpty() ||
+ size == QSize(-1,-1)) {
+ // An empty QSize indicates the encoder should make an optimal choice based on what is
+ // available from the image source and the limitations of the codec.
+ m_captureSize = supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).last();
+ }
+ else
+ m_captureSize = size;
+}
+
+QList<QSize> S60ImageCaptureSession::supportedCaptureSizesForCodec(const QString &codecName)
+{
+ QList<QSize> list;
+
+ // If we have CameraEngine loaded and we can update CameraInfo
+ if (m_cameraEngine && queryCurrentCameraInfo()) {
+ CCamera::TFormat format;
+ if (codecName == "")
+ format = defaultImageFormat();
+ else
+ format = selectFormatForCodec(codecName);
+
+ CCamera *camera = m_cameraEngine->Camera();
+ TSize imageSize;
+ if (camera) {
+ for (int i = 0; i < m_cameraInfo->iNumImageSizesSupported; i++) {
+ camera->EnumerateCaptureSizes(imageSize, i, format);
+ list << QSize(imageSize.iWidth, imageSize.iHeight); // Add resolution to the list
+ }
+ }
+ }
+
+#ifdef Q_CC_NOKIAX86 // Emulator
+ // Add some for testing purposes
+ list << QSize(50, 50);
+ list << QSize(100, 100);
+ list << QSize(800,600);
+#endif
+
+ return list;
+}
+
+QMap<QString, int> S60ImageCaptureSession::formatMap()
+{
+ QMap<QString, int> formats;
+
+ // Format list copied from CCamera::TFormat (in ecam.h)
+ formats.insert("Monochrome", 0x0001);
+ formats.insert("16bitRGB444", 0x0002);
+ formats.insert("16BitRGB565", 0x0004);
+ formats.insert("32BitRGB888", 0x0008);
+ formats.insert("Jpeg", 0x0010);
+ formats.insert("Exif", 0x0020);
+ formats.insert("FbsBitmapColor4K", 0x0040);
+ formats.insert("FbsBitmapColor64K", 0x0080);
+ formats.insert("FbsBitmapColor16M", 0x0100);
+ formats.insert("UserDefined", 0x0200);
+ formats.insert("YUV420Interleaved", 0x0400);
+ formats.insert("YUV420Planar", 0x0800);
+ formats.insert("YUV422", 0x1000);
+ formats.insert("YUV422Reversed", 0x2000);
+ formats.insert("YUV444", 0x4000);
+ formats.insert("YUV420SemiPlanar", 0x8000);
+ formats.insert("FbsBitmapColor16MU", 0x00010000);
+ formats.insert("MJPEG", 0x00020000);
+ formats.insert("EncodedH264", 0x00040000);
+
+ return formats;
+}
+
+QMap<QString, QString> S60ImageCaptureSession::codecDescriptionMap()
+{
+ QMap<QString, QString> formats;
+
+ formats.insert("image/jpg", "JPEG image codec");
+
+ return formats;
+}
+
+QStringList S60ImageCaptureSession::supportedImageCaptureCodecs()
+{
+#ifdef Q_CC_NOKIAX86 // Emulator
+ return formatMap().keys();
+#endif
+
+ return m_supportedImageCodecs;
+}
+
+void S60ImageCaptureSession::updateImageCaptureFormats()
+{
+ m_formats.clear();
+ if (m_cameraEngine && queryCurrentCameraInfo()) {
+ TUint32 supportedFormats = m_cameraInfo->iImageFormatsSupported;
+
+#ifdef S60_3X_PLATFORM // S60 3.1 & 3.2
+ int maskEnd = CCamera::EFormatFbsBitmapColor16MU;
+#else // S60 5.0 or later
+ int maskEnd = CCamera::EFormatEncodedH264;
+#endif // S60_3X_PLATFORM
+
+ for (int mask = CCamera::EFormatMonochrome; mask <= maskEnd; mask <<= 1) {
+ if (supportedFormats & mask)
+ m_formats << mask; // Store mask of supported format
+ }
+ }
+}
+
+QString S60ImageCaptureSession::imageCaptureCodec()
+{
+ return m_currentCodec;
+}
+void S60ImageCaptureSession::setImageCaptureCodec(const QString &codecName)
+{
+ if (!codecName.isEmpty()) {
+ if (supportedImageCaptureCodecs().contains(codecName, Qt::CaseInsensitive) ||
+ codecName == "image/jpg") {
+ m_currentCodec = codecName;
+ m_currentFormat = selectFormatForCodec(m_currentCodec);
+ } else {
+ setError(KErrNotSupported, tr("Requested image codec is not supported"));
+ }
+ } else {
+ m_currentCodec = KDefaultImageCodec;
+ m_currentFormat = selectFormatForCodec(m_currentCodec);
+ }
+}
+
+QString S60ImageCaptureSession::imageCaptureCodecDescription(const QString &codecName)
+{
+ QString description = codecDescriptionMap().value(codecName);
+ return description;
+}
+
+QtMultimediaKit::EncodingQuality S60ImageCaptureSession::captureQuality() const
+{
+ switch (m_symbianImageQuality) {
+ case KJpegQualityVeryLow:
+ return QtMultimediaKit::VeryLowQuality;
+ case KJpegQualityLow:
+ return QtMultimediaKit::LowQuality;
+ case KJpegQualityNormal:
+ return QtMultimediaKit::NormalQuality;
+ case KJpegQualityHigh:
+ return QtMultimediaKit::HighQuality;
+ case KJpegQualityVeryHigh:
+ return QtMultimediaKit::VeryHighQuality;
+
+ default:
+ // Return normal as default
+ return QtMultimediaKit::NormalQuality;
+ }
+}
+
+void S60ImageCaptureSession::setCaptureQuality(const QtMultimediaKit::EncodingQuality &quality)
+{
+ // Use sensible presets
+ switch (quality) {
+ case QtMultimediaKit::VeryLowQuality:
+ m_symbianImageQuality = KJpegQualityVeryLow;
+ break;
+ case QtMultimediaKit::LowQuality:
+ m_symbianImageQuality = KJpegQualityLow;
+ break;
+ case QtMultimediaKit::NormalQuality:
+ m_symbianImageQuality = KJpegQualityNormal;
+ break;
+ case QtMultimediaKit::HighQuality:
+ m_symbianImageQuality = KJpegQualityHigh;
+ break;
+ case QtMultimediaKit::VeryHighQuality:
+ m_symbianImageQuality = KJpegQualityVeryHigh;
+ break;
+
+ default:
+ m_symbianImageQuality = quality * KSymbianImageQualityCoefficient;
+ break;
+ }
+}
+
+qreal S60ImageCaptureSession::maximumZoom()
+{
+ qreal maxZoomFactor = 1.0;
+
+ if (queryCurrentCameraInfo()) {
+ maxZoomFactor = m_cameraInfo->iMaxZoomFactor;
+
+ if (maxZoomFactor == 0.0 || maxZoomFactor == 1.0) {
+ return 1.0; // Not supported
+ } else {
+ return maxZoomFactor;
+ }
+ } else {
+ return 1.0;
+ }
+}
+
+qreal S60ImageCaptureSession::minZoom()
+{
+ qreal minZoomValue = 1.0;
+
+ if (queryCurrentCameraInfo()) {
+ minZoomValue = m_cameraInfo->iMinZoomFactor;
+ if (minZoomValue == 0.0 || minZoomValue == 1.0)
+ return 1.0; // Macro Zoom is not supported
+ else {
+ return minZoomValue;
+ }
+
+ } else {
+ return 1.0;
+ }
+}
+
+qreal S60ImageCaptureSession::maxDigitalZoom()
+{
+ qreal maxDigitalZoomFactor = 1.0;
+
+ if (queryCurrentCameraInfo()) {
+ maxDigitalZoomFactor = m_cameraInfo->iMaxDigitalZoomFactor;
+ return maxDigitalZoomFactor;
+ } else {
+ return 1.0;
+ }
+}
+
+void S60ImageCaptureSession::doSetZoomFactorL(qreal optical, qreal digital)
+{
+#if !defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) & !defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER)
+ // Convert Zoom Factor to Zoom Value if AdvSettings are not available
+ int digitalSymbian = (digital * m_cameraInfo->iMaxDigitalZoom) / maxDigitalZoom();
+ if (m_cameraInfo->iMaxDigitalZoom != 0 && digital == 1.0)
+ digitalSymbian = 1; // Make sure zooming out to initial value if requested
+#endif // !USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER & !USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER
+
+ if (m_cameraEngine && !m_cameraEngine->IsCameraReady())
+ return;
+
+ if (m_cameraEngine && queryCurrentCameraInfo()) {
+ CCamera *camera = m_cameraEngine->Camera();
+ if (camera) {
+
+ // Optical Zoom
+ if (!qFuzzyCompare(optical, qreal(1.0)) && !qFuzzyCompare(optical, qreal(0.0))) {
+ setError(KErrNotSupported, tr("Requested optical zoom factor is not supported."));
+ return;
+ }
+
+ // Digital Zoom (Smooth Zoom - Zoom value set in steps)
+ if (digital != digitalZoomFactor()) {
+ if ((digital > 1.0 || qFuzzyCompare(digital, qreal(1.0))) &&
+ digital <= m_cameraInfo->iMaxDigitalZoomFactor) {
+#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER)
+ if (m_advancedSettings) {
+ qreal currentZoomFactor = m_advancedSettings->digitalZoomFactorL();
+
+ QList<qreal> smoothZoomSetValues;
+ QList<qreal> factors = m_advancedSettings->supportedDigitalZoomFactors();
+ if (currentZoomFactor < digital) {
+ for (int i = 0; i < factors.count(); ++i) {
+ if (factors.at(i) > currentZoomFactor && factors.at(i) < digital)
+ smoothZoomSetValues << factors.at(i);
+ }
+
+ for (int i = 0; i < smoothZoomSetValues.count(); i = i + KSmoothZoomStep) {
+ m_advancedSettings->setDigitalZoomFactorL(smoothZoomSetValues[i]); // Using Zoom Factor
+ }
+
+ } else {
+ for (int i = 0; i < factors.count(); ++i) {
+ if (factors.at(i) < currentZoomFactor && factors.at(i) > digital)
+ smoothZoomSetValues << factors.at(i);
+ }
+
+ for (int i = (smoothZoomSetValues.count() - 1); i >= 0; i = i - KSmoothZoomStep) {
+ m_advancedSettings->setDigitalZoomFactorL(smoothZoomSetValues[i]); // Using Zoom Factor
+ }
+ }
+
+ // Set final value
+ m_advancedSettings->setDigitalZoomFactorL(digital);
+ }
+ else
+ setError(KErrNotReady, tr("Zooming failed."));
+#else // No advanced settigns
+ // Define zoom steps
+ int currentZoomFactor = camera->DigitalZoomFactor();
+ int difference = abs(currentZoomFactor - digitalSymbian);
+ int midZoomValue = currentZoomFactor;
+
+ if (currentZoomFactor < digitalSymbian) {
+ while (midZoomValue < (digitalSymbian - KSmoothZoomStep)) {
+ midZoomValue = midZoomValue + KSmoothZoomStep;
+ camera->SetDigitalZoomFactorL(midZoomValue);
+ }
+ } else {
+ while (midZoomValue > (digitalSymbian + KSmoothZoomStep)) {
+ midZoomValue = midZoomValue - KSmoothZoomStep;
+ camera->SetDigitalZoomFactorL(midZoomValue);
+ }
+ }
+
+ // Set final and emit signal
+ camera->SetDigitalZoomFactorL(digitalSymbian);
+#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER
+ } else {
+ setError(KErrNotSupported, tr("Requested digital zoom factor is not supported."));
+ return;
+ }
+ }
+ }
+ } else {
+ setError(KErrGeneral, tr("Unexpected camera error."));
+ }
+}
+
+qreal S60ImageCaptureSession::opticalZoomFactor()
+{
+ qreal factor = 1.0;
+
+#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER)
+ if (m_advancedSettings) {
+ TRAPD(err, factor = m_advancedSettings->opticalZoomFactorL());
+ if (err)
+ return 1.0;
+ }
+#else // No advanced settigns
+ if (m_cameraEngine && m_cameraInfo) {
+ if (m_cameraEngine->Camera()) {
+ if (m_cameraInfo->iMaxZoom != 0)
+ factor = (m_cameraEngine->Camera()->ZoomFactor()* maximumZoom()) / m_cameraInfo->iMaxZoom;
+ else
+ factor = 1.0;
+ }
+ }
+#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER
+
+ if (factor == 0.0) // If not supported
+ factor = 1.0;
+
+ return factor;
+}
+
+qreal S60ImageCaptureSession::digitalZoomFactor()
+{
+ qreal factor = 1.0;
+
+#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER)
+ if (m_advancedSettings) {
+ TRAPD(err, factor = m_advancedSettings->digitalZoomFactorL());
+ if (err)
+ return 1.0;
+ }
+#else // No advanced settigns
+ if (m_cameraEngine && m_cameraInfo) {
+ if (m_cameraEngine->Camera()) {
+ if (m_cameraInfo->iMaxDigitalZoom != 0)
+ factor = (m_cameraEngine->Camera()->DigitalZoomFactor()* maxDigitalZoom()) / m_cameraInfo->iMaxDigitalZoom;
+ else
+ factor = 1.0;
+ }
+ }
+#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER
+
+ if (factor == 0.0)
+ factor = 1.0;
+
+ return factor;
+}
+
+void S60ImageCaptureSession::setFlashMode(QCameraExposure::FlashModes mode)
+{
+ TRAPD(err, doSetFlashModeL(mode));
+ setError(err, tr("Failed to set flash mode."));
+}
+
+void S60ImageCaptureSession::doSetFlashModeL(QCameraExposure::FlashModes mode)
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ CCamera *camera = m_cameraEngine->Camera();
+ switch(mode) {
+ case QCameraExposure::FlashOff:
+ camera->SetFlashL(CCamera::EFlashNone);
+ break;
+ case QCameraExposure::FlashAuto:
+ camera->SetFlashL(CCamera::EFlashAuto);
+ break;
+ case QCameraExposure::FlashOn:
+ camera->SetFlashL(CCamera::EFlashForced);
+ break;
+ case QCameraExposure::FlashRedEyeReduction:
+ camera->SetFlashL(CCamera::EFlashRedEyeReduce);
+ break;
+ case QCameraExposure::FlashFill:
+ camera->SetFlashL(CCamera::EFlashFillIn);
+ break;
+
+ default:
+ setError(KErrNotSupported, tr("Requested flash mode is not suported"));
+ break;
+ }
+ } else {
+ setError(KErrNotReady, tr("Unexpected camera error."));
+ }
+}
+
+QCameraExposure::FlashMode S60ImageCaptureSession::flashMode()
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ CCamera *camera = m_cameraEngine->Camera();
+ switch(camera->Flash()) {
+ case CCamera::EFlashAuto:
+ return QCameraExposure::FlashAuto;
+ case CCamera::EFlashForced:
+ return QCameraExposure::FlashOn;
+ case CCamera::EFlashRedEyeReduce:
+ return QCameraExposure::FlashRedEyeReduction;
+ case CCamera::EFlashFillIn:
+ return QCameraExposure::FlashFill;
+ case CCamera::EFlashNone:
+ return QCameraExposure::FlashOff;
+
+ default:
+ return QCameraExposure::FlashAuto; // Most probable default
+ }
+ } else {
+ setError(KErrNotReady, tr("Unexpected camera error."));
+ }
+
+ return QCameraExposure::FlashOff;
+}
+
+QCameraExposure::FlashModes S60ImageCaptureSession::supportedFlashModes()
+{
+ QCameraExposure::FlashModes modes = QCameraExposure::FlashOff;
+
+ if (queryCurrentCameraInfo()) {
+ TInt supportedModes = m_cameraInfo->iFlashModesSupported;
+
+ if (supportedModes == 0)
+ return modes;
+
+ if (supportedModes & CCamera::EFlashManual)
+ modes |= QCameraExposure::FlashOff;
+ if (supportedModes & CCamera::EFlashForced)
+ modes |= QCameraExposure::FlashOn;
+ if (supportedModes & CCamera::EFlashAuto)
+ modes |= QCameraExposure::FlashAuto;
+ if (supportedModes & CCamera::EFlashFillIn)
+ modes |= QCameraExposure::FlashFill;
+ if (supportedModes & CCamera::EFlashRedEyeReduce)
+ modes |= QCameraExposure::FlashRedEyeReduction;
+ }
+
+ return modes;
+}
+
+QCameraExposure::ExposureMode S60ImageCaptureSession::exposureMode()
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ CCamera* camera = m_cameraEngine->Camera();
+ switch(camera->Exposure()) {
+ case CCamera::EExposureManual:
+ return QCameraExposure::ExposureManual;
+ case CCamera::EExposureAuto:
+ return QCameraExposure::ExposureAuto;
+ case CCamera::EExposureNight:
+ return QCameraExposure::ExposureNight;
+ case CCamera::EExposureBacklight:
+ return QCameraExposure::ExposureBacklight;
+ case CCamera::EExposureSport:
+ return QCameraExposure::ExposureSports;
+ case CCamera::EExposureSnow:
+ return QCameraExposure::ExposureSnow;
+ case CCamera::EExposureBeach:
+ return QCameraExposure::ExposureBeach;
+
+ default:
+ return QCameraExposure::ExposureAuto;
+ }
+ }
+
+ return QCameraExposure::ExposureAuto;
+}
+
+bool S60ImageCaptureSession::isExposureModeSupported(QCameraExposure::ExposureMode mode) const
+{
+ TInt supportedModes = m_cameraInfo->iExposureModesSupported;
+
+ if (supportedModes == 0)
+ return false;
+
+ switch (mode) {
+ case QCameraExposure::ExposureManual:
+ if(supportedModes & CCamera::EExposureManual)
+ return true;
+ else
+ return false;
+ case QCameraExposure::ExposureAuto:
+ return true; // Always supported
+ case QCameraExposure::ExposureNight:
+ if(supportedModes & CCamera::EExposureNight)
+ return true;
+ else
+ return false;
+ case QCameraExposure::ExposureBacklight:
+ if(supportedModes & CCamera::EExposureBacklight)
+ return true;
+ else
+ return false;
+ case QCameraExposure::ExposureSports:
+ if(supportedModes & CCamera::EExposureSport)
+ return true;
+ else
+ return false;
+ case QCameraExposure::ExposureSnow:
+ if(supportedModes & CCamera::EExposureSnow)
+ return true;
+ else
+ return false;
+ case QCameraExposure::ExposureBeach:
+ if(supportedModes & CCamera::EExposureBeach)
+ return true;
+ else
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+void S60ImageCaptureSession::setExposureMode(QCameraExposure::ExposureMode mode)
+{
+ TRAPD(err, doSetExposureModeL(mode));
+ setError(err, tr("Failed to set exposure mode."));
+}
+
+void S60ImageCaptureSession::doSetExposureModeL( QCameraExposure::ExposureMode mode)
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ CCamera *camera = m_cameraEngine->Camera();
+ switch(mode) {
+ case QCameraExposure::ExposureManual:
+ camera->SetExposureL(CCamera::EExposureManual);
+ break;
+ case QCameraExposure::ExposureAuto:
+ camera->SetExposureL(CCamera::EExposureAuto);
+ break;
+ case QCameraExposure::ExposureNight:
+ camera->SetExposureL(CCamera::EExposureNight);
+ break;
+ case QCameraExposure::ExposureBacklight:
+ camera->SetExposureL(CCamera::EExposureBacklight);
+ break;
+ case QCameraExposure::ExposureSports:
+ camera->SetExposureL(CCamera::EExposureSport);
+ break;
+ case QCameraExposure::ExposureSnow:
+ camera->SetExposureL(CCamera::EExposureSnow);
+ break;
+ case QCameraExposure::ExposureBeach:
+ camera->SetExposureL(CCamera::EExposureBeach);
+ break;
+ case QCameraExposure::ExposureLargeAperture:
+ case QCameraExposure::ExposureSmallAperture:
+ break;
+ case QCameraExposure::ExposurePortrait:
+ case QCameraExposure::ExposureSpotlight:
+ default:
+ setError(KErrNotSupported, tr("Requested exposure mode is not suported"));
+ break;
+ }
+ } else {
+ setError(KErrNotReady, tr("Unexpected camera error."));
+ }
+}
+
+int S60ImageCaptureSession::contrast() const
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ return m_cameraEngine->Camera()->Contrast();
+ } else {
+ return 0;
+ }
+}
+
+void S60ImageCaptureSession::setContrast(int value)
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ TRAPD(err, m_cameraEngine->Camera()->SetContrastL(value));
+ setError(err, tr("Failed to set contrast."));
+ } else {
+ setError(KErrNotReady, tr("Unexpected camera error."));
+ }
+}
+
+int S60ImageCaptureSession::brightness() const
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ return m_cameraEngine->Camera()->Brightness();
+ } else {
+ return 0;
+ }
+}
+
+void S60ImageCaptureSession::setBrightness(int value)
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ TRAPD(err, m_cameraEngine->Camera()->SetBrightnessL(value));
+ setError(err, tr("Failed to set brightness."));
+ } else {
+ setError(KErrNotReady, tr("Unexpected camera error."));
+ }
+}
+
+ QCameraImageProcessing::WhiteBalanceMode S60ImageCaptureSession::whiteBalanceMode()
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ CCamera::TWhiteBalance mode = m_cameraEngine->Camera()->WhiteBalance();
+ switch(mode) {
+ case CCamera::EWBAuto:
+ return QCameraImageProcessing::WhiteBalanceAuto;
+ case CCamera::EWBDaylight:
+ return QCameraImageProcessing::WhiteBalanceSunlight;
+ case CCamera::EWBCloudy:
+ return QCameraImageProcessing::WhiteBalanceCloudy;
+ case CCamera::EWBTungsten:
+ return QCameraImageProcessing::WhiteBalanceTungsten;
+ case CCamera::EWBFluorescent:
+ return QCameraImageProcessing::WhiteBalanceFluorescent;
+ case CCamera::EWBFlash:
+ return QCameraImageProcessing::WhiteBalanceFlash;
+ case CCamera::EWBBeach:
+ return QCameraImageProcessing::WhiteBalanceSunset;
+ case CCamera::EWBManual:
+ return QCameraImageProcessing::WhiteBalanceManual;
+ case CCamera::EWBShade:
+ return QCameraImageProcessing::WhiteBalanceShade;
+
+ default:
+ return QCameraImageProcessing::WhiteBalanceAuto;
+ }
+ }
+
+ return QCameraImageProcessing::WhiteBalanceAuto;
+}
+
+void S60ImageCaptureSession::setWhiteBalanceMode( QCameraImageProcessing::WhiteBalanceMode mode)
+{
+ TRAPD(err, doSetWhiteBalanceModeL(mode));
+ setError(err, tr("Failed to set white balance mode."));
+}
+
+void S60ImageCaptureSession::doSetWhiteBalanceModeL( QCameraImageProcessing::WhiteBalanceMode mode)
+{
+ if (m_cameraEngine && m_cameraEngine->Camera()) {
+ CCamera* camera = m_cameraEngine->Camera();
+ switch(mode) {
+ case QCameraImageProcessing::WhiteBalanceAuto:
+ camera->SetWhiteBalanceL(CCamera::EWBAuto);
+ break;
+ case QCameraImageProcessing::WhiteBalanceSunlight:
+ camera->SetWhiteBalanceL(CCamera::EWBDaylight);
+ break;
+ case QCameraImageProcessing::WhiteBalanceCloudy:
+ camera->SetWhiteBalanceL(CCamera::EWBCloudy);
+ break;
+ case QCameraImageProcessing::WhiteBalanceTungsten:
+ camera->SetWhiteBalanceL(CCamera::EWBTungsten);
+ break;
+ case QCameraImageProcessing::WhiteBalanceFluorescent:
+ camera->SetWhiteBalanceL(CCamera::EWBFluorescent);
+ break;
+ case QCameraImageProcessing::WhiteBalanceFlash:
+ camera->SetWhiteBalanceL(CCamera::EWBFlash);
+ break;
+ case QCameraImageProcessing::WhiteBalanceSunset:
+ camera->SetWhiteBalanceL(CCamera::EWBBeach);
+ break;
+ case QCameraImageProcessing::WhiteBalanceManual:
+ camera->SetWhiteBalanceL(CCamera::EWBManual);
+ break;
+ case QCameraImageProcessing::WhiteBalanceShade:
+ camera->SetWhiteBalanceL(CCamera::EWBShade);
+ break;
+
+ default:
+ setError(KErrNotSupported, tr("Requested white balance mode is not suported"));
+ break;
+ }
+ } else {
+ setError(KErrNotReady, tr("Unexpected camera error."));
+ }
+}
+
+bool S60ImageCaptureSession::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const
+{
+ if (m_cameraEngine) {
+ TInt supportedModes = m_cameraInfo->iWhiteBalanceModesSupported;
+ switch (mode) {
+ case QCameraImageProcessing::WhiteBalanceManual:
+ if (supportedModes & CCamera::EWBManual)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceAuto:
+ if (supportedModes & CCamera::EWBAuto)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceSunlight:
+ if (supportedModes & CCamera::EWBDaylight)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceCloudy:
+ if (supportedModes & CCamera::EWBCloudy)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceShade:
+ if (supportedModes & CCamera::EWBShade)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceTungsten:
+ if (supportedModes & CCamera::EWBTungsten)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceFluorescent:
+ if (supportedModes & CCamera::EWBFluorescent)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceIncandescent: // Not available in Symbian
+ return false;
+ case QCameraImageProcessing::WhiteBalanceFlash:
+ if (supportedModes & CCamera::EWBFlash)
+ return true;
+ else
+ return false;
+ case QCameraImageProcessing::WhiteBalanceSunset:
+ if (supportedModes & CCamera::EWBBeach)
+ return true;
+ else
+ return false;
+
+ default:
+ return false;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * ====================
+ * S60 3.1 AutoFocosing
+ * ====================
+ */
+bool S60ImageCaptureSession::isFocusSupported() const
+{
+ return m_cameraEngine->IsAutoFocusSupported();
+}
+
+void S60ImageCaptureSession::startFocus()
+{
+ if (m_cameraEngine) {
+ TRAPD(err, m_cameraEngine->StartFocusL());
+ setError(err, tr("Failed to start focusing."));
+ }
+ else
+ setError(KErrNotReady, tr("Unexpected camera error."));
+}
+
+void S60ImageCaptureSession::cancelFocus()
+{
+ if (m_cameraEngine) {
+ TRAPD(err, m_cameraEngine->FocusCancel());
+ setError(err, tr("Failed to cancel focusing."));
+ }
+ else
+ setError(KErrNotReady, tr("Unexpected camera error."));
+}
+
+void S60ImageCaptureSession::handleImageDecoded(int error)
+{
+ // Delete unneeded objects
+ if (m_imageDecoder) {
+ delete m_imageDecoder;
+ m_imageDecoder = 0;
+ }
+ if (m_fileSystemAccess) {
+ m_fileSystemAccess->Close();
+ delete m_fileSystemAccess;
+ m_fileSystemAccess = 0;
+ }
+
+ // Check status of decoding
+ if (error != KErrNone) {
+ if (m_previewBitmap) {
+ m_previewBitmap->Reset();
+ delete m_previewBitmap;
+ m_previewBitmap = 0;
+ }
+ releaseImageBuffer();
+ if (m_previewInWaitLoop) {
+ CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation
+ m_previewInWaitLoop = false; // Reset
+ }
+ setError(error, tr("Preview creation failed."));
+ return;
+ }
+
+ m_previewDecodingOngoing = false;
+
+ QPixmap prevPixmap = QPixmap::fromSymbianCFbsBitmap(m_previewBitmap);
+ QImage preview = prevPixmap.toImage();
+
+ if (m_previewBitmap) {
+ m_previewBitmap->Reset();
+ delete m_previewBitmap;
+ m_previewBitmap = 0;
+ }
+
+ QT_TRYCATCH_LEAVING( emit imageCaptured(m_currentImageId, preview) );
+
+ // Release image resources (if not already done)
+ releaseImageBuffer();
+
+ if (m_previewInWaitLoop) {
+ CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation
+ m_previewInWaitLoop = false; // Reset
+ }
+}
+
+void S60ImageCaptureSession::handleImageEncoded(int error)
+{
+ // Check status of encoding
+ if (error != KErrNone) {
+ releaseImageBuffer();
+ if (m_previewInWaitLoop) {
+ CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation
+ m_previewInWaitLoop = false; // Reset
+ }
+ setError(error, tr("Saving captured image to file failed."));
+ return;
+ } else {
+ QT_TRYCATCH_LEAVING( emit imageSaved(m_currentImageId, m_stillCaptureFileName) );
+ }
+
+ if (m_imageEncoder) {
+ delete m_imageEncoder;
+ m_imageEncoder = 0;
+ }
+
+#ifndef ECAM_PREVIEW_API
+ // Start preview generation
+ TInt previewError = KErrNone;
+ TFileName fileName = convertImagePath();
+ TRAP(previewError, m_imageDecoder = S60ImageCaptureDecoder::FileNewL(this, m_fileSystemAccess, &fileName));
+ if (previewError) {
+ setError(previewError, tr("Failed to create preview image."));
+ return;
+ }
+
+ // Set proper Preview Size
+ TSize scaledSize((m_captureSize.width() / KSnapshotDownScaleFactor), (m_captureSize.height() / KSnapshotDownScaleFactor));
+ if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight)
+ scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/2)), (m_captureSize.height() / (KSnapshotDownScaleFactor/2)));
+ if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight)
+ scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/4)), (m_captureSize.height() / (KSnapshotDownScaleFactor/4)));
+ if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight)
+ scaledSize.SetSize(m_captureSize.width(), m_captureSize.height());
+
+ TFrameInfo *info = m_imageDecoder->frameInfo();
+ if (!info) {
+ setError(KErrGeneral, tr("Preview image creation failed."));
+ return;
+ }
+
+ m_previewBitmap = new CFbsBitmap;
+ if (!m_previewBitmap) {
+ setError(KErrNoMemory, tr("Failed to create preview image."));
+ return;
+ }
+ previewError = m_previewBitmap->Create(scaledSize, info->iFrameDisplayMode);
+ if (previewError) {
+ setError(previewError, tr("Preview creation failed."));
+ return;
+ }
+
+ // Jpeg decoding completes in handleImageDecoded()
+ m_imageDecoder->decode(m_previewBitmap);
+#endif // ECAM_PREVIEW_API
+
+ // Buffer can be released since Preview is created from file
+ releaseImageBuffer();
+
+ // Inform that we can continue taking more pictures
+ QT_TRYCATCH_LEAVING( emit readyForCaptureChanged(true) );
+}
+
+#ifdef ECAM_PREVIEW_API
+void S60ImageCaptureSession::MceoPreviewReady(CFbsBitmap& aPreview)
+{
+ QPixmap previewPixmap = QPixmap::fromSymbianCFbsBitmap(&aPreview);
+ QImage preview = previewPixmap.toImage();
+
+ // Notify preview availability
+ emit imageCaptured(m_currentImageId, preview);
+}
+#endif // ECAM_PREVIEW_API
+
+// End of file
+