--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp Thu May 27 12:43:29 2010 +0300
@@ -0,0 +1,297 @@
+/*
+* 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 <QSize>
+#include <QPixmap>
+// Note: Keep atleast one Qt include before preprocessor flags
+#ifdef Q_OS_SYMBIAN
+#include <e32base.h>
+#include <fbs.h>
+#include <ecam.h>
+#include <ecam/camerasnapshot.h>
+#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;
+
+#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<CxeSnapshotControl::State>(newStateId), error);
+}
+
+
+/*!
+* Get the state of Snapshot Control.
+* @return The current state.
+*/
+CxeSnapshotControl::State CxeSnapshotControlPrivate::state() const
+{
+ return static_cast<CxeSnapshotControl::State> (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 outputResolution Resolution of the output image / video in pixels.
+* @return Proposed best snapshot size.
+*/
+QSize CxeSnapshotControlPrivate::calculateSnapshotSize(const QSize &displaySize, const QSize &outputResolution) const
+{
+ CX_DEBUG_ENTER_FUNCTION();
+ CX_DEBUG(("CxeSnapshotControlPrivate - output resolution (%d,%d)", outputResolution.width(), outputResolution.height()));
+ 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(outputResolution);
+ size.scale(displaySize, Qt::KeepAspectRatio);
+ CX_DEBUG(("CxeSnapshotControlPrivate - calculated size, (%d,%d)", size.width(), size.height()));
+ size.setHeight(displaySize.height());
+ 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 QPixmap containing the snapshot.
+*/
+QPixmap CxeSnapshotControlPrivate::snapshot()
+{
+ CX_DEBUG_ENTER_FUNCTION();
+ QPixmap pixmap;
+
+#ifdef Q_OS_SYMBIAN
+ TRAPD(status, {
+ RArray<TInt> 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));
+ CFbsBitmap &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 ));
+
+ TUint32 *pixelData = new (ELeave) TUint32[ sizeInWords ];
+ // Convert to QImage
+ snapshot.LockHeap();
+ TUint32 *dataPtr = snapshot.DataAddress();
+ memcpy(pixelData, dataPtr, sizeof(TUint32)*sizeInWords);
+ snapshot.UnlockHeap();
+
+ CX_DEBUG(("Creating QImage"));
+ QImage *snapImage = new QImage((uchar*)pixelData, size.iWidth, size.iHeight,
+ CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU),
+ QImage::Format_RGB32);
+
+ pixmap = QPixmap::fromImage(*snapImage);
+ delete [] pixelData;
+ delete snapImage;
+ });
+ // We throw error with the Symbian error code if there was problems.
+ CxeException::throwIfError(status);
+#endif // Q_OS_SYMBIAN
+
+ CX_DEBUG_EXIT_FUNCTION();
+ return pixmap;
+}
+
+/*!
+* 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) {
+ QPixmap 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