camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp
changeset 43 0e652f8f1fbd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp	Thu Jul 15 01:55:05 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 <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;
+
+    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<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 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<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));
+            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