camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp
changeset 29 699651f2666f
child 37 64817133cd1d
--- /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