diff -r f54ad444594d -r 61bc0f252b2b camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp Tue Aug 31 15:03:46 2010 +0300 @@ -0,0 +1,310 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include +#include +// Note: Keep atleast one Qt include before preprocessor flags +#ifdef Q_OS_SYMBIAN +#include +#include +#include +#include +#endif // Q_OS_SYMBIAN + +#include "cxutils.h" +#include "cxeerror.h" +#include "cxeexception.h" +#include "cxeerrormappingsymbian.h" +#include "cxecameradevice.h" +#include "cxestate.h" +#include "cxesnapshotcontrol.h" +#include "cxesnapshotcontrolprivate.h" + + +namespace +{ + const int MAINTAIN_ASPECT = false; + + const QSize ASPECT_RATIO_SIZE_4BY3 = QSize(4,3); + const QSize ASPECT_RATIO_SIZE_16BY9 = QSize(16, 9); + const QSize ASPECT_RATIO_SIZE_11BY9 = QSize(11, 9); + +#ifdef Q_OS_SYMBIAN + /*! + * Helper class for cleaning up MCameraBuffer instances. + */ + class CxeCameraBufferCleanup + { + public: + explicit CxeCameraBufferCleanup(MCameraBuffer *buffer) + : mBuffer(buffer) + { + } + + ~CxeCameraBufferCleanup() + { + if (mBuffer) { + CX_DEBUG(("CxeCameraBufferCleanup - releasing MCameraBuffer..")); + mBuffer->Release(); + mBuffer = NULL; + } + } + private: + Q_DISABLE_COPY(CxeCameraBufferCleanup) + MCameraBuffer *mBuffer; + }; +#endif // Q_OS_SYMBIAN +} + + +/*! +* Constructor. +* @param parent Public interface of Snapshot control. +* @param device Camera device interface, used for getting hold of adaptation snapshot API. +*/ +CxeSnapshotControlPrivate::CxeSnapshotControlPrivate(CxeSnapshotControl *parent, + CxeCameraDevice& device) + : CxeStateMachine("CxeSnapshotControlPrivate"), + q(parent), + mDevice(device) +{ + CX_DEBUG_ENTER_FUNCTION(); + CX_ASSERT_ALWAYS(q); + initializeStates(); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Destructor. +*/ +CxeSnapshotControlPrivate::~CxeSnapshotControlPrivate() +{ + CX_DEBUG_ENTER_FUNCTION(); + stop(); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Called when state changes. +* @param newStateId Id of the new state. +* @param error Error code or CxeError::None in successful case. +*/ +void CxeSnapshotControlPrivate::handleStateChanged(int newStateId, CxeError::Id error) +{ + emit q->stateChanged(static_cast(newStateId), error); +} + + +/*! +* Get the state of Snapshot Control. +* @return The current state. +*/ +CxeSnapshotControl::State CxeSnapshotControlPrivate::state() const +{ + return static_cast (stateId()); +} + +/*! +* Initialize Snapshot Control states +*/ +void CxeSnapshotControlPrivate::initializeStates() +{ + CX_DEBUG_ENTER_FUNCTION(); + // addState( id, name, allowed next states ) + addState(new CxeState(CxeSnapshotControl::Idle, "Idle", CxeSnapshotControl::Active)); + addState(new CxeState(CxeSnapshotControl::Active, "Active", CxeSnapshotControl::Idle)); + + setInitialState(CxeSnapshotControl::Idle); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Calculate snapshot size based on diplay size and image / video output resolution. +* @param displaySize Display size in pixels. +* @param Cxe::AspectRatio Aspect ratio of image/video resolution. +* @return Proposed best snapshot size. +*/ + +QSize CxeSnapshotControlPrivate::calculateSnapshotSize(const QSize& displaySize, Cxe::AspectRatio aspectRatio) const +{ + CX_DEBUG_ENTER_FUNCTION(); + CX_DEBUG(("CxeSnapshotControlPrivate - display size (%d,%d)", displaySize.width(), displaySize.height())); + + // Take resolution as reference for aspect ratio. + // Scale keeping aspect ratio to just fit display. + QSize size; + + if (aspectRatio == Cxe::AspectRatio4to3) { + size = ASPECT_RATIO_SIZE_4BY3; + } else if (aspectRatio == Cxe::AspectRatio16to9) { + size = ASPECT_RATIO_SIZE_16BY9; + } else if (aspectRatio == Cxe::AspectRatio11to9) { + size = ASPECT_RATIO_SIZE_11BY9; + } + size.scale(displaySize, Qt::KeepAspectRatio); + + CX_DEBUG(("CxeSnapshotControlPrivate - adjusted final size, (%d,%d)", size.width(), size.height())); + + CX_DEBUG_EXIT_FUNCTION(); + + return size; +} + + +/*! +* Start getting snapshots from camera. +* Throws CxeException with CxeError::Id if error encountered. +* @param size Size of the snapshot in pixels. +*/ +void CxeSnapshotControlPrivate::start(const QSize &size) +{ + CX_DEBUG_ENTER_FUNCTION(); +#ifdef Q_OS_SYMBIAN + CCamera::CCameraSnapshot *ss = mDevice.cameraSnapshot(); + CX_ASSERT_ALWAYS(ss); + + if (ss->IsSnapshotActive()) { + CX_DEBUG(("Stop currently active snapshot..")); + ss->StopSnapshot(); + } + + // Prepare snapshot + CCamera::TFormat snapFormat = CCamera::EFormatFbsBitmapColor16MU; + TSize snapSize = TSize(size.width(), size.height()); + + CX_DEBUG(("Prepare snapshot, size (%d x %d)..", size.width(), size.height())); + TRAPD(status, ss->PrepareSnapshotL(snapFormat, snapSize, MAINTAIN_ASPECT)); + CxeException::throwIfError(CxeErrorHandlingSymbian::map(status)); + CX_DEBUG(("After prepare ECAM modified size to (%d x %d)..", size.width(), size.height())); + + CX_DEBUG(("Start snapshot..")); + ss->StartSnapshot(); +#else + Q_UNUSED(size); +#endif // Q_OS_SYMBIAN + setState(CxeSnapshotControl::Active); + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Stop getting snapshots from camera. +*/ +void CxeSnapshotControlPrivate::stop() +{ + CX_DEBUG_ENTER_FUNCTION(); +#ifdef Q_OS_SYMBIAN + if (mDevice.cameraSnapshot()) { + mDevice.cameraSnapshot()->StopSnapshot(); + } +#endif // Q_OS_SYMBIAN + setState(CxeSnapshotControl::Idle); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Helper method for getting the snapshot. +* Throws exception if fetching the snapshot fails. +* @return QImage containing the snapshot. +*/ +QImage CxeSnapshotControlPrivate::snapshot() +{ + CX_DEBUG_ENTER_FUNCTION(); + QImage image; + + #ifdef Q_OS_SYMBIAN + + CFbsBitmap *snapshot = NULL; + TRAPD(status, { + RArray frameIndex; + CleanupClosePushL(frameIndex); + + MCameraBuffer &buffer(mDevice.cameraSnapshot()->SnapshotDataL(frameIndex)); + // Make sure buffer is released on leave / exception. + // Buffer is released once the cleanup item goes out of scope. + CxeCameraBufferCleanup cleaner(&buffer); + + TInt firstImageIndex(frameIndex.Find(0)); + snapshot = &buffer.BitmapL(firstImageIndex); + + CleanupStack::PopAndDestroy(); // frameIndex + + TSize size = snapshot->SizeInPixels(); + TInt sizeInWords = size.iHeight * CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU) / sizeof(TUint32); + CX_DEBUG(("size %d x %d, sizeInWords = %d", size.iWidth, size.iHeight, sizeInWords )); + + CX_DEBUG(("Creating QImage")); + image = QImage(size.iWidth, size.iHeight, QImage::Format_RGB32); + + // Convert to QImage + snapshot->LockHeap(); + const uchar *dataPtr = (const uchar*) snapshot->DataAddress(); + uchar *dst = image.bits(); + memcpy(dst, dataPtr, image.numBytes()); + snapshot->UnlockHeap(); + + }); + // We throw error with the Symbian error code if there was problems. + CxeException::throwIfError(status); + + + #endif // Q_OS_SYMBIAN + + CX_DEBUG_EXIT_FUNCTION(); + return image; +} + +/*! +* Handle camera snapshot events. +* @param id Event uid. +* @param error Status code of the event. +*/ +void CxeSnapshotControlPrivate::handleCameraEvent(int id, int error) +{ + CX_DEBUG_ENTER_FUNCTION(); + + // Ignoring all events if not active. + if (state() == CxeSnapshotControl::Active) { +#ifdef Q_OS_SYMBIAN + if (id == KUidECamEventSnapshotUidValue) { + QImage ss; + + if (!error) { + try { + ss = snapshot(); + } catch (const CxeException& e) { + // Note: Normally CxeException carries CxeError::Id, + // but we intentionally use Symbian code in getSnapshot + // as it's easier to handle here. + error = e.error(); + } catch (...) { + error = KErrGeneral; + } + } + + // Emit snapshot ready signal through the public interface. + emit q->snapshotReady(CxeErrorHandlingSymbian::map(error), ss); + } +#else + Q_UNUSED(id) + Q_UNUSED(error) +#endif // Q_OS_SYMBIAN + } + CX_DEBUG_EXIT_FUNCTION(); +} + +// end of file