camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp
changeset 38 0f0b4c1d7744
child 37 64817133cd1d
equal deleted inserted replaced
28:3075d9b614e6 38:0f0b4c1d7744
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 #include <QSize>
       
    19 #include <QPixmap>
       
    20 // Note: Keep atleast one Qt include before preprocessor flags
       
    21 #ifdef Q_OS_SYMBIAN
       
    22 #include <e32base.h>
       
    23 #include <fbs.h>
       
    24 #include <ecam.h>
       
    25 #include <ecam/camerasnapshot.h>
       
    26 #endif // Q_OS_SYMBIAN
       
    27 
       
    28 #include "cxutils.h"
       
    29 #include "cxeerror.h"
       
    30 #include "cxeexception.h"
       
    31 #include "cxeerrormappingsymbian.h"
       
    32 #include "cxecameradevice.h"
       
    33 #include "cxestate.h"
       
    34 #include "cxesnapshotcontrol.h"
       
    35 #include "cxesnapshotcontrolprivate.h"
       
    36 
       
    37 
       
    38 namespace
       
    39 {
       
    40     const int MAINTAIN_ASPECT = false;
       
    41 
       
    42 #ifdef Q_OS_SYMBIAN
       
    43     /*!
       
    44     * Helper class for cleaning up MCameraBuffer instances.
       
    45     */
       
    46     class CxeCameraBufferCleanup
       
    47     {
       
    48     public:
       
    49         explicit CxeCameraBufferCleanup(MCameraBuffer *buffer)
       
    50             : mBuffer(buffer)
       
    51         {
       
    52         }
       
    53 
       
    54         ~CxeCameraBufferCleanup()
       
    55         {
       
    56             if (mBuffer) {
       
    57                 CX_DEBUG(("CxeCameraBufferCleanup - releasing MCameraBuffer.."));
       
    58                 mBuffer->Release();
       
    59                 mBuffer = NULL;
       
    60             }
       
    61         }
       
    62     private:
       
    63         Q_DISABLE_COPY(CxeCameraBufferCleanup)
       
    64         MCameraBuffer *mBuffer;
       
    65     };
       
    66 #endif // Q_OS_SYMBIAN
       
    67 }
       
    68 
       
    69 
       
    70 /*!
       
    71 * Constructor.
       
    72 * @param parent Public interface of Snapshot control.
       
    73 * @param device Camera device interface, used for getting hold of adaptation snapshot API.
       
    74 */
       
    75 CxeSnapshotControlPrivate::CxeSnapshotControlPrivate(CxeSnapshotControl *parent,
       
    76                                                      CxeCameraDevice& device)
       
    77     : CxeStateMachine("CxeSnapshotControlPrivate"),
       
    78       q(parent),
       
    79       mDevice(device)
       
    80 {
       
    81     CX_DEBUG_ENTER_FUNCTION();
       
    82     CX_ASSERT_ALWAYS(q);
       
    83     initializeStates();
       
    84     CX_DEBUG_EXIT_FUNCTION();
       
    85 }
       
    86 
       
    87 /*!
       
    88 * Destructor.
       
    89 */
       
    90 CxeSnapshotControlPrivate::~CxeSnapshotControlPrivate()
       
    91 {
       
    92     CX_DEBUG_ENTER_FUNCTION();
       
    93     stop();
       
    94     CX_DEBUG_EXIT_FUNCTION();
       
    95 }
       
    96 
       
    97 /*!
       
    98 * Called when state changes.
       
    99 * @param newStateId Id of the new state.
       
   100 * @param error Error code or CxeError::None in successful case.
       
   101 */
       
   102 void CxeSnapshotControlPrivate::handleStateChanged(int newStateId, CxeError::Id error)
       
   103 {
       
   104     emit q->stateChanged(static_cast<CxeSnapshotControl::State>(newStateId), error);
       
   105 }
       
   106 
       
   107 
       
   108 /*!
       
   109 * Get the state of Snapshot Control.
       
   110 * @return The current state.
       
   111 */
       
   112 CxeSnapshotControl::State CxeSnapshotControlPrivate::state() const
       
   113 {
       
   114     return static_cast<CxeSnapshotControl::State> (stateId());
       
   115 }
       
   116 
       
   117 /*!
       
   118 * Initialize Snapshot Control states
       
   119 */
       
   120 void CxeSnapshotControlPrivate::initializeStates()
       
   121 {
       
   122     CX_DEBUG_ENTER_FUNCTION();
       
   123     // addState( id, name, allowed next states )
       
   124     addState(new CxeState(CxeSnapshotControl::Idle, "Idle", CxeSnapshotControl::Active));
       
   125     addState(new CxeState(CxeSnapshotControl::Active, "Active", CxeSnapshotControl::Idle));
       
   126 
       
   127     setInitialState(CxeSnapshotControl::Idle);
       
   128     CX_DEBUG_EXIT_FUNCTION();
       
   129 }
       
   130 
       
   131 /*!
       
   132 * Calculate snapshot size based on diplay size and image / video output resolution.
       
   133 * @param displaySize Display size in pixels.
       
   134 * @param outputResolution Resolution of the output image / video in pixels.
       
   135 * @return Proposed best snapshot size.
       
   136 */
       
   137 QSize CxeSnapshotControlPrivate::calculateSnapshotSize(const QSize &displaySize, const QSize &outputResolution) const
       
   138 {
       
   139     CX_DEBUG_ENTER_FUNCTION();
       
   140     CX_DEBUG(("CxeSnapshotControlPrivate - output resolution (%d,%d)", outputResolution.width(), outputResolution.height()));
       
   141     CX_DEBUG(("CxeSnapshotControlPrivate - display size      (%d,%d)", displaySize.width(), displaySize.height()));
       
   142 
       
   143     // Take resolution as reference for aspect ratio.
       
   144     // Scale keeping aspect ratio to just fit display.
       
   145     QSize size(outputResolution);
       
   146     size.scale(displaySize, Qt::KeepAspectRatio);
       
   147     CX_DEBUG(("CxeSnapshotControlPrivate - calculated size, (%d,%d)", size.width(), size.height()));
       
   148     size.setHeight(displaySize.height());
       
   149     CX_DEBUG(("CxeSnapshotControlPrivate - adjusted final size, (%d,%d)", size.width(), size.height()));
       
   150     CX_DEBUG_EXIT_FUNCTION();
       
   151     return size;
       
   152 }
       
   153 
       
   154 /*!
       
   155 * Start getting snapshots from camera.
       
   156 * Throws CxeException with CxeError::Id if error encountered.
       
   157 * @param size Size of the snapshot in pixels.
       
   158 */
       
   159 void CxeSnapshotControlPrivate::start(const QSize &size)
       
   160 {
       
   161     CX_DEBUG_ENTER_FUNCTION();
       
   162 #ifdef Q_OS_SYMBIAN
       
   163     CCamera::CCameraSnapshot *ss = mDevice.cameraSnapshot();
       
   164     CX_ASSERT_ALWAYS(ss);
       
   165 
       
   166     if (ss->IsSnapshotActive()) {
       
   167         CX_DEBUG(("Stop currently active snapshot.."));
       
   168         ss->StopSnapshot();
       
   169     }
       
   170 
       
   171     // Prepare snapshot
       
   172     CCamera::TFormat snapFormat = CCamera::EFormatFbsBitmapColor16MU;
       
   173     TSize snapSize = TSize(size.width(), size.height());
       
   174 
       
   175     CX_DEBUG(("Prepare snapshot, size (%d x %d)..", size.width(), size.height()));
       
   176     TRAPD(status, ss->PrepareSnapshotL(snapFormat, snapSize, MAINTAIN_ASPECT));
       
   177     CxeException::throwIfError(CxeErrorHandlingSymbian::map(status));
       
   178     CX_DEBUG(("After prepare ECAM modified size to (%d x %d)..", size.width(), size.height()));
       
   179 
       
   180     CX_DEBUG(("Start snapshot.."));
       
   181     ss->StartSnapshot();
       
   182 #else
       
   183     Q_UNUSED(size);
       
   184 #endif // Q_OS_SYMBIAN
       
   185     setState(CxeSnapshotControl::Active);
       
   186 
       
   187     CX_DEBUG_EXIT_FUNCTION();
       
   188 }
       
   189 
       
   190 /*!
       
   191 * Stop getting snapshots from camera.
       
   192 */
       
   193 void CxeSnapshotControlPrivate::stop()
       
   194 {
       
   195     CX_DEBUG_ENTER_FUNCTION();
       
   196 #ifdef Q_OS_SYMBIAN
       
   197     if (mDevice.cameraSnapshot()) {
       
   198         mDevice.cameraSnapshot()->StopSnapshot();
       
   199     }
       
   200 #endif // Q_OS_SYMBIAN
       
   201     setState(CxeSnapshotControl::Idle);
       
   202     CX_DEBUG_EXIT_FUNCTION();
       
   203 }
       
   204 
       
   205 /*!
       
   206 * Helper method for getting the snapshot.
       
   207 * Throws exception if fetching the snapshot fails.
       
   208 * @return QPixmap containing the snapshot.
       
   209 */
       
   210 QPixmap CxeSnapshotControlPrivate::snapshot()
       
   211 {
       
   212     CX_DEBUG_ENTER_FUNCTION();
       
   213     QPixmap pixmap;
       
   214 
       
   215 #ifdef Q_OS_SYMBIAN
       
   216     TRAPD(status, {
       
   217         RArray<TInt> frameIndex;
       
   218         CleanupClosePushL(frameIndex);
       
   219 
       
   220         MCameraBuffer &buffer(mDevice.cameraSnapshot()->SnapshotDataL(frameIndex));
       
   221         // Make sure buffer is released on leave / exception.
       
   222         // Buffer is released once the cleanup item goes out of scope.
       
   223         CxeCameraBufferCleanup cleaner(&buffer);
       
   224 
       
   225         TInt firstImageIndex(frameIndex.Find(0));
       
   226         CFbsBitmap &snapshot(buffer.BitmapL(firstImageIndex));
       
   227 
       
   228         CleanupStack::PopAndDestroy(); // frameIndex
       
   229 
       
   230         TSize size = snapshot.SizeInPixels();
       
   231         TInt sizeInWords = size.iHeight * CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU) / sizeof(TUint32);
       
   232         CX_DEBUG(("size %d x %d, sizeInWords = %d", size.iWidth, size.iHeight, sizeInWords ));
       
   233 
       
   234         TUint32 *pixelData = new (ELeave) TUint32[ sizeInWords ];
       
   235         // Convert to QImage
       
   236         snapshot.LockHeap();
       
   237         TUint32 *dataPtr = snapshot.DataAddress();
       
   238         memcpy(pixelData, dataPtr, sizeof(TUint32)*sizeInWords);
       
   239         snapshot.UnlockHeap();
       
   240 
       
   241         CX_DEBUG(("Creating QImage"));
       
   242         QImage *snapImage = new QImage((uchar*)pixelData, size.iWidth, size.iHeight,
       
   243                                        CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU),
       
   244                                        QImage::Format_RGB32);
       
   245 
       
   246         pixmap = QPixmap::fromImage(*snapImage);
       
   247         delete [] pixelData;
       
   248         delete snapImage;
       
   249     });
       
   250     // We throw error with the Symbian error code if there was problems.
       
   251     CxeException::throwIfError(status);
       
   252 #endif // Q_OS_SYMBIAN
       
   253 
       
   254     CX_DEBUG_EXIT_FUNCTION();
       
   255     return pixmap;
       
   256 }
       
   257 
       
   258 /*!
       
   259 * Handle camera snapshot events.
       
   260 * @param id Event uid.
       
   261 * @param error Status code of the event.
       
   262 */
       
   263 void CxeSnapshotControlPrivate::handleCameraEvent(int id, int error)
       
   264 {
       
   265     CX_DEBUG_ENTER_FUNCTION();
       
   266 
       
   267     // Ignoring all events if not active.
       
   268     if (state() == CxeSnapshotControl::Active) {
       
   269 #ifdef Q_OS_SYMBIAN
       
   270         if (id == KUidECamEventSnapshotUidValue) {
       
   271             QPixmap ss;
       
   272 
       
   273             if (!error) {
       
   274                 try {
       
   275                     ss = snapshot();
       
   276                 } catch (const CxeException& e) {
       
   277                     // Note: Normally CxeException carries CxeError::Id,
       
   278                     // but we intentionally use Symbian code in getSnapshot
       
   279                     // as it's easier to handle here.
       
   280                     error = e.error();
       
   281                 } catch (...) {
       
   282                     error = KErrGeneral;
       
   283                 }
       
   284             }
       
   285 
       
   286             // Emit snapshot ready signal through the public interface.
       
   287             emit q->snapshotReady(CxeErrorHandlingSymbian::map(error), ss);
       
   288         }
       
   289 #else
       
   290         Q_UNUSED(id)
       
   291         Q_UNUSED(error)
       
   292 #endif // Q_OS_SYMBIAN
       
   293     }
       
   294     CX_DEBUG_EXIT_FUNCTION();
       
   295 }
       
   296 
       
   297 // end of file