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