camerauis/cameraxui/cxengine/src/cxestillcapturecontroldesktop.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:03:46 +0300
branchRCL_3
changeset 53 61bc0f252b2b
child 55 0da2a5b56583
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* 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 <QPixmap>

#include "cxestillcapturecontroldesktop.h"
#include "cxeimagedataitemdesktop.h"
#include "cxeimagedataqueuedesktop.h"
#include "cxefilenamegenerator.h"
#include "cxefilesavethreaddesktop.h"
#include "cxutils.h"
#include "cxecameradevicecontrol.h"
#include "cxestillimagedesktop.h"
#include "cxeviewfindercontrol.h"
#include "cxeviewfindercontroldesktop.h"
#include "cxeautofocuscontrol.h"
#include "cxestate.h"
#include "cxecameradevicedesktop.h"

// constants
const int KMaintainAspectRatio = false;



/**
 * Constructor.
 */
CxeStillCaptureControlDesktop::CxeStillCaptureControlDesktop(
        CxeCameraDeviceDesktop &cameraDevice,
        CxeViewfinderControl &viewfinderControl,
        CxeCameraDeviceControl &cameraDeviceControl,
        CxeFilenameGenerator &nameGenerator,
        CxeAutoFocusControl &autoFocusControl,
        CxeFileSaveThread &saveThread) :
  mCameraDevice(cameraDevice),
  mState(CxeStillCaptureControl::Uninitialized),
  mViewfinderControl(viewfinderControl),
  mCameraDeviceControl(cameraDeviceControl),
  mFilenameGenerator(nameGenerator),
  mAutoFocusControl(autoFocusControl),
  mMode(SingleImageCapture),
  mAfState(CxeAutoFocusControl::Unknown),
  mSaveThread(saveThread)
{
    CX_DEBUG_ENTER_FUNCTION();

    qRegisterMetaType<CxeStillCaptureControl::State>();
    initializeStates();
    reset();

    mImageDataQueue = new CxeImageDataQueueDesktop();

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * Destructor.
 */
CxeStillCaptureControlDesktop::~CxeStillCaptureControlDesktop()
{
    CX_DEBUG_ENTER_FUNCTION();

    deinit();
    reset();
    mSupportedImageQualities.clear();
    delete mImageDataQueue;

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * Return the current state.
 */
CxeStillCaptureControl::State CxeStillCaptureControlDesktop::state() const
{
    return mState;
}

/**
 * Initialize the control states.
 */
void CxeStillCaptureControlDesktop::initializeStates()
{

    // addState( id, name, allowed next states )
}

/**
 * Initialize the still image capture control.
 */
void CxeStillCaptureControlDesktop::init()
{
    CX_DEBUG_ENTER_FUNCTION();

    if (state() == Uninitialized) {
        CxeImageDetails dummyDetails;
        dummyDetails.mAspectRatio = Cxe::AspectRatio4to3;
        dummyDetails.mEstimatedSize = 10000;
        dummyDetails.mHeight = 360;
        dummyDetails.mWidth = 640;
        mSupportedImageQualities.append(dummyDetails);
        prepare();
    }

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * Un-initialize the image mode.
 */
void CxeStillCaptureControlDesktop::deinit()
{
    CX_DEBUG_ENTER_FUNCTION();

    if (state() == Uninitialized) {
        // nothing to do
        CX_DEBUG_EXIT_FUNCTION();
        return;
    }
    mState = Uninitialized;
    CX_DEBUG_EXIT_FUNCTION();
}


/*!
 * Prepare still capture mode.
 */
void CxeStillCaptureControlDesktop::prepare()
{
    CX_DEBUG_ENTER_FUNCTION();

    if (state() != Uninitialized) {
        // wrong state and we return
        return;
    }

    int err = 0;
    CxeError::Id cxErr = getImageQualityDetails(mCurrentImageDetails);
    int ecamStillResolutionIndex = 0;

    if (cxErr == CxeError::None) {
        int imageWidth =  mCurrentImageDetails.mWidth;
        int imageHeight = mCurrentImageDetails.mHeight;
        CX_DEBUG(("CxeStillCaptureControlSymbian::prepare <> resolution = (%d, %d)", imageWidth, imageHeight));

        if (ecamStillResolutionIndex < 0) {
            CX_DEBUG(("CxeStillCaptureControlSymbian::prepare - WARNING! resolution not supported, falling back to index 0"));
            ecamStillResolutionIndex = 0;
        }

        CX_DEBUG(("PrepareImageCaptureL done, err=%d, resolution index = %d", err, ecamStillResolutionIndex));

        if (!err) {
            // still capture prepare went fine, try preparing snapshot
            err = prepareStillSnapshot();
        }
    } else {
        err = 0;
    }

    if (!err) {
        // If viewfinder is already running, this call does nothing
        mViewfinderControl.start();
        // inform zoom control to prepare zoom
        emit prepareZoomForStill(ecamStillResolutionIndex);
    } else {
        CX_DEBUG(("Image Prepare FAILED! symbian error = %d", err));
    }
    mState = Ready;
    emit imagePrepareComplete(CxeError::None);
    CX_DEBUG_EXIT_FUNCTION();
}



/*!
 Prepare still snapshot
 Returns symbian error code.
 */
int CxeStillCaptureControlDesktop::prepareStillSnapshot()
{
    CX_DEBUG_ENTER_FUNCTION();

    handleSnapshotEvent(CxeError::None);

    CX_DEBUG_EXIT_FUNCTION();

    return 0;
}


/*!
 imageInfo contains image qualities details
 Returns CxeError error code.
 */
CxeError::Id CxeStillCaptureControlDesktop::getImageQualityDetails(CxeImageDetails &imageInfo)
{
    CX_DEBUG_ENTER_FUNCTION();

    int imageQuality = 0;
    CxeError::Id err = CxeError::None;
    if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex) {
        bool validQuality = (imageQuality >= 0 && imageQuality < mSupportedImageQualities.count());

        if (err == CxeError::None && validQuality ) {
            // get image quality details
            imageInfo = mSupportedImageQualities.at(imageQuality);
        } else {
            err = CxeError::NotFound;
            CX_DEBUG(("Invalid ImageQuality = %d", imageQuality));
        }
    } else {
        // we are in secondary camera
        // get secondary camera image quality details
       imageInfo = mSupportedImageQualities.at(imageQuality);
    }

    CX_DEBUG_EXIT_FUNCTION();
    return err;
}


/**
 * Command to start image capture now.
 */
void CxeStillCaptureControlDesktop::capture()
{
    CX_DEBUG_ENTER_FUNCTION();

    //! @todo: NOTE: This call may not stay here. It can move depending on the implementation for burst capture.
    if (mMode == BurstCapture) {
        // Start a new filename sequence
        mFilenameGenerator.startNewImageFilenameSequence();
    }
    emit imageCaptured(CxeError::None, 0);
    handleSnapshotEvent(CxeError::None);
    CX_DEBUG_EXIT_FUNCTION();
}


/**
 * Snapshot ready notification. Ask the snapshot from snapshot interface.
 * NB: Typically snapshot arrives before image data but can be in reverse
 * order as well.
 */
void CxeStillCaptureControlDesktop::handleSnapshotEvent(CxeError::Id error)
{
    CX_DEBUG_ENTER_FUNCTION();

    if (state() == CxeStillCaptureControl::Uninitialized) {
        // we ignore this event, when we are not active
        return;
    }

    if (error) {
        emit snapshotReady(error, QImage(), 0);
    }

    // Get image container for current snapshot index.
    // Remember to increment counter.
    CxeStillImageDesktop* stillImage = getImageForIndex(mNextSnapshotIndex++);

    // When the snapshot ready event is handled, prepare new filename.
    if (stillImage->filename().isEmpty()) {
        // Error ignored at this point, try again when image data arrives.
        prepareFilename(stillImage);
    }

    CxeImageDataItem* dataItem = new CxeImageDataItemDesktop(mNextImageDataIndex++, stillImage->snapshot(), stillImage->filename(), stillImage->id());

    stillImage->setDataItem(dataItem);

    mSaveThread.save(dataItem);

    emit snapshotReady(CxeError::None, QImage(), stillImage->id());
    emit imageCaptured(CxeError::None, stillImage->id());

    mState = Ready;
    emit stateChanged(mState, CxeError::None);

    CX_DEBUG_EXIT_FUNCTION();
}



/**
 * Settings changed, needs updated
 */
void CxeStillCaptureControlDesktop::handleSettingValueChanged(const QString& settingId,QVariant newValue)
{
    CX_DEBUG_ENTER_FUNCTION();

    if (settingId == CxeSettingIds::FLASH_MODE) {
        updateFlashSetting(newValue);
    } else if (settingId == CxeSettingIds::LIGHT_SENSITIVITY) {
        updateISOSetting(newValue);
    } else if (settingId == CxeSettingIds::EV_COMPENSATION_VALUE) {
        updateEVCompensationSetting(newValue);
    } else if (settingId == CxeSettingIds::IMAGE_QUALITY) {
        // re-prepare for still
        deinit();
        init();
    } else {
        // do nothing
    }
    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * Image Scene mode changed, needs updated
 */
void CxeStillCaptureControlDesktop::handleSceneChanged(CxeScene& scene)
{
    CX_DEBUG_ENTER_FUNCTION();

    if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex){
        CX_DEBUG_ASSERT(scene.count() != 0);
        // we are interested only in the following settings in this class scope

        if(scene.contains(CxeSettingIds::FLASH_MODE)) {
            CX_DEBUG(("CxeStillCaptureControlSymbian::handleSceneChanged scene->mFlashMode = %d", scene[CxeSettingIds::FLASH_MODE].toInt()));
            updateFlashSetting(scene[CxeSettingIds::FLASH_MODE]);
        }

        if(scene.contains(CxeSettingIds::LIGHT_SENSITIVITY)) {
            updateISOSetting(scene[CxeSettingIds::LIGHT_SENSITIVITY]);
        }

        if(scene.contains(CxeSettingIds::EV_COMPENSATION_VALUE)) {
            updateEVCompensationSetting(scene[CxeSettingIds::EV_COMPENSATION_VALUE]);
        }
    }

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * UpdateFlashSetting
 */
void CxeStillCaptureControlDesktop::updateFlashSetting(QVariant newValue)
{
    CX_DEBUG_ENTER_FUNCTION();

    Q_UNUSED(newValue);

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * UpdateISOSetting
 */
void CxeStillCaptureControlDesktop::updateISOSetting(QVariant newValue)
{
    CX_DEBUG_ENTER_FUNCTION();

    Q_UNUSED(newValue);

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * UpdateEVCompensationSetting
 */
void CxeStillCaptureControlDesktop::updateEVCompensationSetting(QVariant newValue)
{
    CX_DEBUG_ENTER_FUNCTION();

    Q_UNUSED(newValue);


    CX_DEBUG_EXIT_FUNCTION();
}


/**
 * ECam reference changing, release resources
 */
void CxeStillCaptureControlDesktop::prepareForCameraDelete()
{
    CX_DEBUG_ENTER_FUNCTION();
    deinit();
    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * Camera being released. Cancel ongoing capture, if any.
 */
void CxeStillCaptureControlDesktop::prepareForRelease()
{
    CX_DEBUG_ENTER_FUNCTION();
    deinit();
    CX_DEBUG_EXIT_FUNCTION();
}

/**
 *  New camera available,
 */
void CxeStillCaptureControlDesktop::handleCameraAllocated(CxeError::Id error)
{
    CX_DEBUG_ENTER_FUNCTION();

    if (error == CxeError::None) {
        // load all still resoultions supported by ecam
        // load all still qualities supported by icm
        mSupportedImageQualities.clear();
        // get list of supported image qualities based on camera index

    }

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * Return number of images captured (during current capture operation only).
 */
int CxeStillCaptureControlDesktop::imageCount() const
{
    return mImages.count();
}

/**
 * Reset the image array.
 */
void CxeStillCaptureControlDesktop::reset()
{
    CX_DEBUG_ENTER_FUNCTION();

    qDeleteAll(mImages);
    mImages.clear();

    mNextSnapshotIndex = 0;
    mNextImageDataIndex = 0;

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * This should cancel any ongoing image captures.
 */
void CxeStillCaptureControlDesktop::cancelAll()
{
    mImageDataQueue->clear();
    reset();
}

/**
 * Sets the current capture mode: SingleImageCapture / BurstCapture.
 */
void CxeStillCaptureControlDesktop::setMode(CaptureMode mode)
{
    mMode = mode;
}

/**
 * Returns the current capture mode.
 */
CxeStillCaptureControl::CaptureMode CxeStillCaptureControlDesktop::mode() const
{
    return mMode;
}

/**
 * Operator [] - returns the indexed image from capture array.
 */
CxeStillImage &CxeStillCaptureControlDesktop::operator[](int index)
{
    return *mImages[ index ];
}

/**
 * Getter for image data queue.
 */
CxeImageDataQueue &CxeStillCaptureControlDesktop::imageDataQueue()
{
    return *mImageDataQueue;
}

/**
 * Generates a filename and sets it in the still image object.
 * Skips the process if filename already copied exists in the object. This
 * behaviour is required in rare cases where image data arrives before snapshot.
 */
CxeError::Id CxeStillCaptureControlDesktop::prepareFilename(CxeStillImageDesktop *stillImage)
{
    CxeError::Id err = CxeError::None;
    if (stillImage->filename().isEmpty()) {
        QString path;

        QString fileExt = mCurrentImageDetails.mImageFileExtension;

        if (mMode == SingleImageCapture) {
            err = mFilenameGenerator.generateFilename(path, fileExt);
        }
        else {
            err = mFilenameGenerator.nextImageFilenameInSequence(path, fileExt);
        }

        if (!err) {
            CX_DEBUG(( "Next image file path: %s", path.toAscii().constData() ));
            stillImage->setFilename(path);
        }
        else {
            //! @todo: Error ID can be returned by this function.
            // Also error can be detected from empty filename string.
            CX_DEBUG(("ERROR in filename generation. err:%d", err));
        }
    }
    return err;
}

/*!
* Helper method to set orientation data from the orientation sensor
*/
void CxeStillCaptureControlDesktop::setOrientation(QVariant sensorData)
{
    CX_DEBUG_ENTER_FUNCTION();

    Q_UNUSED(sensorData);

    CX_DEBUG_EXIT_FUNCTION();
}

/**
 * Get the image container at given index or create a new one if needed.
 */
CxeStillImageDesktop* CxeStillCaptureControlDesktop::getImageForIndex(int index)
{
    CxeStillImageDesktop* image(NULL);

    if (mImages.count() <= index) {
        image = new CxeStillImageDesktop();
        image->setSnapshot(mCameraDevice.currentSnaphot());
        mImages.append(image);
    } else {
        CX_DEBUG_ASSERT( mNextImageDataIndex >= 0 && index < mImages.count() );
        image = mImages[index];
    }
    return image;
}


/*!
* Slot to handle Autofocus events.
*/
void CxeStillCaptureControlDesktop::handleAutofocusStateChanged(
                                         CxeAutoFocusControl::State newState,
                                         CxeError::Id /*error*/ )
{
    CX_DEBUG_ENTER_FUNCTION();

    mAfState = newState;
    CxeAutoFocusControl::Mode mode = mAutoFocusControl.mode();

    // if focused and in correct mode, play sound
    if  (newState == CxeAutoFocusControl::Ready &&
         mode != CxeAutoFocusControl::Hyperfocal &&
         mode != CxeAutoFocusControl::Infinity) {
    }
    CX_DEBUG_EXIT_FUNCTION();
}


/*!
* Returns supported image qualities based on the camera index
* (primary/secondary).
*/
QList<CxeImageDetails> CxeStillCaptureControlDesktop::supportedImageQualities()
{
    return QList<CxeImageDetails>();
}

/*!
* Returns the number of images left for the current image quality setting
*/
int CxeStillCaptureControlDesktop::imagesLeft()
{
    return 100; // Stub: Dummy value
}

// end of file