camerauis/cameraxui/cxengine/src/cxesnapshotcontrolprivate.cpp
changeset 43 0e652f8f1fbd
equal deleted inserted replaced
28:3075d9b614e6 43:0e652f8f1fbd
       
     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     const QSize ASPECT_RATIO_SIZE_4BY3  = QSize(4,3);
       
    43     const QSize ASPECT_RATIO_SIZE_16BY9 = QSize(16, 9);
       
    44     const QSize ASPECT_RATIO_SIZE_11BY9 = QSize(11, 9);
       
    45 
       
    46 #ifdef Q_OS_SYMBIAN
       
    47     /*!
       
    48     * Helper class for cleaning up MCameraBuffer instances.
       
    49     */
       
    50     class CxeCameraBufferCleanup
       
    51     {
       
    52     public:
       
    53         explicit CxeCameraBufferCleanup(MCameraBuffer *buffer)
       
    54             : mBuffer(buffer)
       
    55         {
       
    56         }
       
    57 
       
    58         ~CxeCameraBufferCleanup()
       
    59         {
       
    60             if (mBuffer) {
       
    61                 CX_DEBUG(("CxeCameraBufferCleanup - releasing MCameraBuffer.."));
       
    62                 mBuffer->Release();
       
    63                 mBuffer = NULL;
       
    64             }
       
    65         }
       
    66     private:
       
    67         Q_DISABLE_COPY(CxeCameraBufferCleanup)
       
    68         MCameraBuffer *mBuffer;
       
    69     };
       
    70 #endif // Q_OS_SYMBIAN
       
    71 }
       
    72 
       
    73 
       
    74 /*!
       
    75 * Constructor.
       
    76 * @param parent Public interface of Snapshot control.
       
    77 * @param device Camera device interface, used for getting hold of adaptation snapshot API.
       
    78 */
       
    79 CxeSnapshotControlPrivate::CxeSnapshotControlPrivate(CxeSnapshotControl *parent,
       
    80                                                      CxeCameraDevice& device)
       
    81     : CxeStateMachine("CxeSnapshotControlPrivate"),
       
    82       q(parent),
       
    83       mDevice(device)
       
    84 {
       
    85     CX_DEBUG_ENTER_FUNCTION();
       
    86     CX_ASSERT_ALWAYS(q);
       
    87     initializeStates();
       
    88     CX_DEBUG_EXIT_FUNCTION();
       
    89 }
       
    90 
       
    91 /*!
       
    92 * Destructor.
       
    93 */
       
    94 CxeSnapshotControlPrivate::~CxeSnapshotControlPrivate()
       
    95 {
       
    96     CX_DEBUG_ENTER_FUNCTION();
       
    97     stop();
       
    98     CX_DEBUG_EXIT_FUNCTION();
       
    99 }
       
   100 
       
   101 /*!
       
   102 * Called when state changes.
       
   103 * @param newStateId Id of the new state.
       
   104 * @param error Error code or CxeError::None in successful case.
       
   105 */
       
   106 void CxeSnapshotControlPrivate::handleStateChanged(int newStateId, CxeError::Id error)
       
   107 {
       
   108     emit q->stateChanged(static_cast<CxeSnapshotControl::State>(newStateId), error);
       
   109 }
       
   110 
       
   111 
       
   112 /*!
       
   113 * Get the state of Snapshot Control.
       
   114 * @return The current state.
       
   115 */
       
   116 CxeSnapshotControl::State CxeSnapshotControlPrivate::state() const
       
   117 {
       
   118     return static_cast<CxeSnapshotControl::State> (stateId());
       
   119 }
       
   120 
       
   121 /*!
       
   122 * Initialize Snapshot Control states
       
   123 */
       
   124 void CxeSnapshotControlPrivate::initializeStates()
       
   125 {
       
   126     CX_DEBUG_ENTER_FUNCTION();
       
   127     // addState( id, name, allowed next states )
       
   128     addState(new CxeState(CxeSnapshotControl::Idle, "Idle", CxeSnapshotControl::Active));
       
   129     addState(new CxeState(CxeSnapshotControl::Active, "Active", CxeSnapshotControl::Idle));
       
   130 
       
   131     setInitialState(CxeSnapshotControl::Idle);
       
   132     CX_DEBUG_EXIT_FUNCTION();
       
   133 }
       
   134 
       
   135 /*!
       
   136 * Calculate snapshot size based on diplay size and image / video output resolution.
       
   137 * @param displaySize Display size in pixels.
       
   138 * @param Cxe::AspectRatio Aspect ratio of image/video resolution.
       
   139 * @return Proposed best snapshot size.
       
   140 */
       
   141 
       
   142 QSize CxeSnapshotControlPrivate::calculateSnapshotSize(const QSize& displaySize, Cxe::AspectRatio aspectRatio) const
       
   143 {
       
   144     CX_DEBUG_ENTER_FUNCTION();
       
   145     CX_DEBUG(("CxeSnapshotControlPrivate - display size      (%d,%d)", displaySize.width(), displaySize.height()));
       
   146 
       
   147     // Take resolution as reference for aspect ratio.
       
   148     // Scale keeping aspect ratio to just fit display.
       
   149     QSize size;
       
   150     
       
   151     if (aspectRatio == Cxe::AspectRatio4to3) {
       
   152         size = ASPECT_RATIO_SIZE_4BY3;
       
   153     } else if (aspectRatio == Cxe::AspectRatio16to9) {
       
   154         size = ASPECT_RATIO_SIZE_16BY9;
       
   155     } else if (aspectRatio == Cxe::AspectRatio11to9) {
       
   156         size = ASPECT_RATIO_SIZE_11BY9;
       
   157     }
       
   158     size.scale(displaySize, Qt::KeepAspectRatio);
       
   159 
       
   160     CX_DEBUG(("CxeSnapshotControlPrivate - adjusted final size, (%d,%d)", size.width(), size.height()));
       
   161 
       
   162     CX_DEBUG_EXIT_FUNCTION();
       
   163 
       
   164     return size;
       
   165 }
       
   166 
       
   167 
       
   168 /*!
       
   169 * Start getting snapshots from camera.
       
   170 * Throws CxeException with CxeError::Id if error encountered.
       
   171 * @param size Size of the snapshot in pixels.
       
   172 */
       
   173 void CxeSnapshotControlPrivate::start(const QSize &size)
       
   174 {
       
   175     CX_DEBUG_ENTER_FUNCTION();
       
   176 #ifdef Q_OS_SYMBIAN
       
   177     CCamera::CCameraSnapshot *ss = mDevice.cameraSnapshot();
       
   178     CX_ASSERT_ALWAYS(ss);
       
   179 
       
   180     if (ss->IsSnapshotActive()) {
       
   181         CX_DEBUG(("Stop currently active snapshot.."));
       
   182         ss->StopSnapshot();
       
   183     }
       
   184 
       
   185     // Prepare snapshot
       
   186     CCamera::TFormat snapFormat = CCamera::EFormatFbsBitmapColor16MU;
       
   187     TSize snapSize = TSize(size.width(), size.height());
       
   188 
       
   189     CX_DEBUG(("Prepare snapshot, size (%d x %d)..", size.width(), size.height()));
       
   190     TRAPD(status, ss->PrepareSnapshotL(snapFormat, snapSize, MAINTAIN_ASPECT));
       
   191     CxeException::throwIfError(CxeErrorHandlingSymbian::map(status));
       
   192     CX_DEBUG(("After prepare ECAM modified size to (%d x %d)..", size.width(), size.height()));
       
   193 
       
   194     CX_DEBUG(("Start snapshot.."));
       
   195     ss->StartSnapshot();
       
   196 #else
       
   197     Q_UNUSED(size);
       
   198 #endif // Q_OS_SYMBIAN
       
   199     setState(CxeSnapshotControl::Active);
       
   200 
       
   201     CX_DEBUG_EXIT_FUNCTION();
       
   202 }
       
   203 
       
   204 /*!
       
   205 * Stop getting snapshots from camera.
       
   206 */
       
   207 void CxeSnapshotControlPrivate::stop()
       
   208 {
       
   209     CX_DEBUG_ENTER_FUNCTION();
       
   210 #ifdef Q_OS_SYMBIAN
       
   211     if (mDevice.cameraSnapshot()) {
       
   212         mDevice.cameraSnapshot()->StopSnapshot();
       
   213     }
       
   214 #endif // Q_OS_SYMBIAN
       
   215     setState(CxeSnapshotControl::Idle);
       
   216     CX_DEBUG_EXIT_FUNCTION();
       
   217 }
       
   218 
       
   219 /*!
       
   220 * Helper method for getting the snapshot.
       
   221 * Throws exception if fetching the snapshot fails.
       
   222 * @return QImage containing the snapshot.
       
   223 */
       
   224 QImage CxeSnapshotControlPrivate::snapshot()
       
   225 {
       
   226     CX_DEBUG_ENTER_FUNCTION();
       
   227     QImage image;
       
   228 
       
   229     #ifdef Q_OS_SYMBIAN
       
   230 
       
   231         CFbsBitmap *snapshot = NULL;
       
   232         TRAPD(status, {
       
   233             RArray<TInt> frameIndex;
       
   234             CleanupClosePushL(frameIndex);
       
   235 
       
   236             MCameraBuffer &buffer(mDevice.cameraSnapshot()->SnapshotDataL(frameIndex));
       
   237             // Make sure buffer is released on leave / exception.
       
   238             // Buffer is released once the cleanup item goes out of scope.
       
   239             CxeCameraBufferCleanup cleaner(&buffer);
       
   240 
       
   241             TInt firstImageIndex(frameIndex.Find(0));
       
   242             snapshot = &buffer.BitmapL(firstImageIndex);
       
   243 
       
   244             CleanupStack::PopAndDestroy(); // frameIndex
       
   245 
       
   246             TSize size = snapshot->SizeInPixels();
       
   247             TInt sizeInWords = size.iHeight * CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU) / sizeof(TUint32);
       
   248             CX_DEBUG(("size %d x %d, sizeInWords = %d", size.iWidth, size.iHeight, sizeInWords ));
       
   249 
       
   250             CX_DEBUG(("Creating QImage"));
       
   251             image = QImage(size.iWidth, size.iHeight, QImage::Format_RGB32);
       
   252 
       
   253             // Convert to QImage
       
   254             snapshot->LockHeap();
       
   255             const uchar *dataPtr = (const uchar*) snapshot->DataAddress();
       
   256             uchar *dst = image.bits();
       
   257             memcpy(dst, dataPtr, image.numBytes());
       
   258             snapshot->UnlockHeap();
       
   259 
       
   260         });
       
   261         // We throw error with the Symbian error code if there was problems.
       
   262         CxeException::throwIfError(status);
       
   263 
       
   264 
       
   265     #endif // Q_OS_SYMBIAN
       
   266 
       
   267         CX_DEBUG_EXIT_FUNCTION();
       
   268         return image;
       
   269 }
       
   270 
       
   271 /*!
       
   272 * Handle camera snapshot events.
       
   273 * @param id Event uid.
       
   274 * @param error Status code of the event.
       
   275 */
       
   276 void CxeSnapshotControlPrivate::handleCameraEvent(int id, int error)
       
   277 {
       
   278     CX_DEBUG_ENTER_FUNCTION();
       
   279 
       
   280     // Ignoring all events if not active.
       
   281     if (state() == CxeSnapshotControl::Active) {
       
   282 #ifdef Q_OS_SYMBIAN
       
   283         if (id == KUidECamEventSnapshotUidValue) {
       
   284             QImage ss;
       
   285 
       
   286             if (!error) {
       
   287                 try {
       
   288                     ss = snapshot();
       
   289                 } catch (const CxeException& e) {
       
   290                     // Note: Normally CxeException carries CxeError::Id,
       
   291                     // but we intentionally use Symbian code in getSnapshot
       
   292                     // as it's easier to handle here.
       
   293                     error = e.error();
       
   294                 } catch (...) {
       
   295                     error = KErrGeneral;
       
   296                 }
       
   297             }
       
   298 
       
   299             // Emit snapshot ready signal through the public interface.
       
   300             emit q->snapshotReady(CxeErrorHandlingSymbian::map(error), ss);
       
   301         }
       
   302 #else
       
   303         Q_UNUSED(id)
       
   304         Q_UNUSED(error)
       
   305 #endif // Q_OS_SYMBIAN
       
   306     }
       
   307     CX_DEBUG_EXIT_FUNCTION();
       
   308 }
       
   309 
       
   310 // end of file