/*
* Copyright (c) 2002-2009 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: This class is used for playing camera.
*
*/
// INCLUDE FILES
#include <logger.h>
#include <fbs.h>
#include <e32svr.h>
#include "cmmacameraplayer.h"
#include "tmmaparametervalidator.h"
#include "mmmadisplay.h"
#include "cmmacamerasound.h"
#if defined( __WINS__ )
#include <w32std.h>
#endif
// CONSTANTS
_LIT8(KImageJpegMime, "image/jpeg");
_LIT8(KJpegMime, "jpeg");
_LIT(KVideoControlName, "VideoControl");
CMMACameraPlayer* CMMACameraPlayer::NewLC(TInt aCameraIndex)
{
CMMACameraPlayer* self = new(ELeave) CMMACameraPlayer;
CleanupStack::PushL(self);
self->ConstructL(aCameraIndex);
return self;
}
CMMACameraPlayer::~CMMACameraPlayer()
{
LOG(EJavaMMAPI, EInfo, "CMMACameraPlayer::~CMMACameraPlayer");
// Free (duplicated) UI camera resources first.
// Window is not able to send any
// callback requests to UI from now.
if (iWindow)
{
iWindow->SetDisplay(NULL);
}
if (iCamera)
{
iCamera->CancelCaptureImage();
iCamera->Release();
delete iCamera;
}
delete iSnapshotEncoded;
delete iSnapshotBitmap;
delete iRealizeWait;
if (iDisplay && iDisplay->HasContainer())
{
// Window will delete itself
// after all pending events are processed
// (lazy delete)
// iDisplay->UIGetCallback(
// *iWindow, CMMACameraWindow::EDestroyWindow);
}
else
{
delete iWindow;
}
iWindow = NULL;
}
CMMACameraPlayer::CMMACameraPlayer():
iDisplay(NULL),
iSourceSizeIndex(KErrNotFound),
iStartTime(KErrNotFound)
{
iStopViewFinder = ETrue;
}
void CMMACameraPlayer::ConstructL(TInt aCameraIndex)
{
CMMAPlayer::ConstructL();
if (aCameraIndex >= CCamera::CamerasAvailable())
{
// image capture is not supported
User::Leave(KErrNotFound);
}
iCamera = CCamera::NewL(*this, aCameraIndex);
iWindow = CMMACameraWindow::NewL(iCamera->Handle());
TCameraInfo cameraInfo;
iCamera->CameraInfo(cameraInfo);
if (cameraInfo.iNumImageSizesSupported < 1)
{
// image capture is not supported
User::Leave(KErrNotFound);
}
// default snapshot size
iSourceSizeIndex = cameraInfo.iNumImageSizesSupported - 1;
iRealizeWait = new(ELeave)CRealizeWait;
}
TInt64 CMMACameraPlayer::CurrentTime()
{
TTime time;
time.HomeTime();
return time.Int64();
}
void CMMACameraPlayer::ResolveViewFinderSizeL(TSize& aSize)
{
LOG(EJavaMMAPI, EInfo, "CMMACameraPlayer::ResolveViewFinderSizeL");
TSize resultSize;
// The only way to find out the size is to start the view finder
// with a proper size (screen size).
ResolveScreenSizeL(resultSize);
// StartViewFinderBitmapsL changes resultSize to
// the used view finder size.
// Used to get the source size only.
iCamera->StartViewFinderBitmapsL(resultSize);
// Bitmap viewfinder is not used anymore.
iCamera->StopViewFinder();
aSize = resultSize;
}
void CMMACameraPlayer::ResolveScreenSizeL(TSize& aSize)
{
LOG(EJavaMMAPI, EInfo, "CMMACameraPlayer::ResolveScreenSizeL");
#if defined( __WINS__ )
TSize size(0,0);
RWsSession ws;
if (ws.Connect() == KErrNone)
{
CleanupClosePushL(ws);
CWsScreenDevice* wsScreenDevice = new(ELeave)CWsScreenDevice(ws);
CleanupStack::PushL(wsScreenDevice);
User::LeaveIfError(wsScreenDevice->Construct());
size = wsScreenDevice->SizeInPixels();
CleanupStack::PopAndDestroy(2); // wsScreenDevice, ws.Close()
}
aSize = size;
#else
TScreenInfoV01 info;
TPckgBuf< TScreenInfoV01 > buf(info);
UserSvr::ScreenInfo(buf);
info = buf();
aSize = info.iScreenSize;
#endif
}
void CMMACameraPlayer::ResolveCaptureSizes(const CCamera::TFormat aFormat,
const TInt aNumImageSizesSupported,
const TSize& aRequestSize,
TSize& aSourceSize,
TInt& aSourceIndex,
TInt& aLargestIndex)
{
// Largest image size
TSize largestSize;
// Index to largest image size
TInt largestSizeIndex = 0;
// Source size
TSize sourceSize;
// Default source size index not set
TInt sourceSizeIndex = KErrNotFound;
// Temporary size for iterating capture sizes
TSize tmpSize;
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::ResolveCaptureSizes: aFormat = 0x%x", aFormat);
// go through all supported sizes.
// Notice: Capture sizes are assumed to be in order from smaller to larger sizes
for (TInt i = 0; i < aNumImageSizesSupported; i++)
{
iCamera->EnumerateCaptureSizes(tmpSize,
i,
aFormat);
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::ResolveCaptureSizes: tmpSize.iWidth = %d", tmpSize.iWidth);
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::ResolveCaptureSizes: tmpSize.iHeight = %d", tmpSize.iHeight);
// Check if current is the largest
if ((largestSize.iWidth < tmpSize.iWidth) &&
(largestSize.iHeight < tmpSize.iHeight))
{
largestSize = tmpSize;
largestSizeIndex = i;
}
// If wanted size is smaller than tmpSize we can use it
if ((aRequestSize.iWidth <= tmpSize.iWidth) &&
(aRequestSize.iHeight <= tmpSize.iHeight))
{
sourceSize = tmpSize;
sourceSizeIndex = i;
}
}
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::ResolveCaptureSizes: sourceSizeIndex = %d", sourceSizeIndex);
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::ResolveCaptureSizes: largestSizeIndex = %d", largestSizeIndex);
aSourceSize = sourceSize;
aSourceIndex = sourceSizeIndex;
aLargestIndex = largestSizeIndex;
}
void CMMACameraPlayer::StartL()
{
LOG1(EJavaMMAPI, EInfo, "CMMACameraPlayer:StartL iState %d", iState);
// start can't be called to not ready player
if (iState == EPrefetched)
{
// camera passes ready images through
// ViewFinderFrameReady method
// set time when started
iStartTime = CurrentTime();
// inform java side
ChangeState(EStarted);
TInt64 time;
GetMediaTime(&time);
// Notify the camera window
// about the status change
iWindow->SetStarted(ETrue);
// inform java side
PostLongEvent(CMMAPlayerEvent::EStarted, time);
}
PostActionCompletedStart();
PostActionCompleted(KErrNone); // java start return
}
void CMMACameraPlayer::StopL(TBool aPostEvent)
{
LOG1(EJavaMMAPI, EInfo, "CMMACameraPlayer::StopL", iState);
if (iState == EStarted)
{
TInt64 time;
GetMediaTime(&time); // add played time to media time
if (iStopViewFinder && iWindow->ViewFinderActive())
{
iWindow->SetStarted(EFalse);
}
iStartTime = KErrNotFound;
if (aPostEvent)
{
PostLongEvent(CMMAPlayerEvent::EStopped, time);
}
// go back to prefetched state
ChangeState(EPrefetched);
}
}
void CMMACameraPlayer::DeallocateL()
{
// If player is started when deallocate is called,
// player is stopped from java side -> state is changed to
// prefetched.
// In prefetched state only reserved resource is
// camera reserve( released with iCamera->Release() )
// In realized state no resources have been reserved.
// CHANGED: not releasing camera anymore, since it is already
// done in realized state
if (iState == EPrefetched)
{
ChangeState(ERealized);
}
}
void CMMACameraPlayer::RealizeL()
{
iCamera->Reserve();
// this lock will be released when power on is completed (or error)
if (!iRealizeWait->IsStarted())
{
iRealizeWait->Start();
}
User::LeaveIfError(iRealizeWait->iError);
CMMAPlayer::RealizeL();
}
void CMMACameraPlayer::PrefetchL()
{
LOG(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::PrefetchL");
// nothing to do here
ChangeState(EPrefetched);
PostActionCompleted(KErrNone);
}
void CMMACameraPlayer::GetDuration(TInt64* aDuration)
{
// camera viewer has no duration.
*aDuration = KTimeUnknown;
}
void CMMACameraPlayer::SetMediaTimeL(TInt64* /*aTime*/)
{
LOG(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::SetMediaTimeL ");
// with camera media time is not supported.
}
void CMMACameraPlayer::GetMediaTime(TInt64* aMediaTime)
{
if (iState == EStarted)
{
// add play time to media time
iMediaTime += CurrentTime() - iStartTime;
// set new start time
iStartTime = CurrentTime();
}
// set value to parameter
(*aMediaTime) = iMediaTime;
}
void CMMACameraPlayer::CloseL()
{
LOG(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::CloseL()");
// cancel all activity
iCamera->CancelCaptureImage();
// Stop and release UI Camera instance
iWindow->SetDisplay(NULL);
// we don't need reserve camera anymore
iCamera->Release();
CMMAPlayer::CloseL();
}
const TDesC& CMMACameraPlayer::Type()
{
return KMMACameraPlayer;
}
// MCameraObserver
void CMMACameraPlayer::ReserveComplete(TInt aError)
{
ELOG1(EJavaMMAPI, "MMA::CMMACameraPlayer::ReserveComplete %d", aError);
if (aError == KErrNone)
{
// camera will notify completion with PowerOnComplete method.
iCamera->PowerOn();
}
else
{
// release lock and store error. State doesn't change.
iRealizeWait->iError = aError;
iRealizeWait->AsyncStop();
}
}
void CMMACameraPlayer::PowerOnComplete(TInt aError)
{
ELOG1(EJavaMMAPI, "MMA::CMMACameraPlayer::PowerOnComplete %d", aError);
TSize viewFinderSize;
TInt error = aError;
if (error == KErrNone)
{
// The view finder size must be known after prefetching.
TRAP(error, ResolveViewFinderSizeL(viewFinderSize));
}
if (error == KErrNone)
{
iSize = viewFinderSize;
if (iDisplay)
{
iDisplay->SourceSizeChanged(iSize);
NotifyWithStringEvent(CMMAPlayerEvent::ESizeChanged, KVideoControlName);
}
}
iRealizeWait->iError = error;
iRealizeWait->AsyncStop();
}
void CMMACameraPlayer::ViewFinderFrameReady(CFbsBitmap& /*aFrame*/)
{
// Empty implementation of an interface method.
// DirectViewFinder is used
// instead of BitmapViewFinder
}
void CMMACameraPlayer::ImageReady(CFbsBitmap* aBitmap,
HBufC8* aData,
TInt aError)
{
ELOG1(EJavaMMAPI, "MMA::CMMACameraPlayer::ImageReady %d", aError);
// This method should never be called,
// unless we are taking snapshot
__ASSERT_DEBUG(iSnapshotStatus, User::Invariant());
__ASSERT_DEBUG(!iSnapshotBitmap, User::Invariant());
__ASSERT_DEBUG(!iSnapshotEncoded, User::Invariant());
if (aError == KErrNone)
{
// this class has ownership of the bitmap until
// snapshot bitmap is got from this class.
iSnapshotBitmap = aBitmap;
iSnapshotEncoded = aData;
}
// notify the caller, error code or KErrNone
User::RequestComplete(iSnapshotStatus, aError);
iWindow->SetStarted(ETrue);
// Status is not needed anymore
// and this class don't own the status.
iSnapshotStatus = NULL;
}
void CMMACameraPlayer::FrameBufferReady(MFrameBuffer* /*aFrameBuffer*/,
TInt /*aError*/)
{
LOG(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::FrameBufferReady");
// this callback will never be called
// Asserted in debug build to be sure.
__ASSERT_DEBUG(EFalse, User::Invariant());
}
void CMMACameraPlayer::SetDisplayL(MMMADisplay* aDisplay)
{
LOG(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::SetDisplay");
// now it is ready to draw
iDisplay = aDisplay;
// Passes display into iWindow.
// Allocates all resources needed to use a camera DirectViewFinder.
iWindow->SetDisplay(aDisplay);
iDisplay->SetWindowL(iWindow);
// Set view finder size to the display only if the view finder
// size has been resolved.
if (iSize != TSize(0, 0))
{
iDisplay->SourceSizeChanged(iSize);
NotifyWithStringEvent(CMMAPlayerEvent::ESizeChanged, KVideoControlName);
}
}
TSize CMMACameraPlayer::SourceSize()
{
return iSize;
}
MMMASnapshot::TEncoding CMMACameraPlayer::TakeSnapshotL(TRequestStatus* aStatus,
const TSize& aSize,
const CMMAImageSettings& aSettings)
{
__ASSERT_DEBUG(!iSnapshotStatus, User::Invariant());
__ASSERT_DEBUG(!iSnapshotBitmap, User::Invariant());
__ASSERT_DEBUG(!iSnapshotEncoded, User::Invariant());
// snapshots can not be taken if player is not realized
if (iState < ERealized)
{
User::Leave(KErrNotReady);
}
// save status which will be notified
iSnapshotStatus = aStatus;
// changing status to pending
*iSnapshotStatus = KRequestPending;
// Source size not set in the beginning
TSize sourceSize;
// Use default if size is not specified.
TInt sourceSizeIndex = iSourceSizeIndex;
// Largest image size index
TInt largestSizeIndex = 0;
// Get camera characteristics
TCameraInfo cameraInfo;
iCamera->CameraInfo(cameraInfo);
// Set default snapshot encoding type
TEncoding encoding = EBitmap;
// Set default image capture format
CCamera::TFormat format = CCamera::EFormatFbsBitmapColor16M;
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::TakeSnapshotL: cameraInfo.iImageFormatsSupported = 0x%x", cameraInfo.iImageFormatsSupported);
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::TakeSnapshotL: cameraInfo.iNumImageSizesSupported = %d", cameraInfo.iNumImageSizesSupported);
// Check if size was set in Java
if (aSize.iWidth != KErrNotFound &&
aSize.iHeight != KErrNotFound)
{
// Determine if jpeg capture was requested
if ((*aSettings.iMimeType == KJpegMime) ||
(*aSettings.iMimeType == KImageJpegMime))
{
// Shortcut for supported image formats
TUint32 imageFormats = cameraInfo.iImageFormatsSupported;
// Jpeg subtype constants
_LIT8(KJpegJfif, "jfif");
_LIT8(KJpegExif, "exif");
// Resolve requested jpeg subtype from settings and camerainfo
if ((imageFormats & CCamera::EFormatJpeg) &&
(*aSettings.iType == KJpegJfif))
{
// JFIF JPEG
format = CCamera::EFormatJpeg;
encoding = EEncoded;
}
else if ((imageFormats & CCamera::EFormatExif) &&
(*aSettings.iType == KJpegExif))
{
// EXIF JPEG
format = CCamera::EFormatExif;
encoding = EEncoded;
}
}
// Try to resolve nearest source size to the one requested,
// except for the JFIF and EXIF jpeg subtypes the match has
// to be exact otherwise non-encode capture format will be
// used
ResolveCaptureSizes(format,
cameraInfo.iNumImageSizesSupported,
aSize,
sourceSize,
sourceSizeIndex,
largestSizeIndex);
// Format was either of the jpeg formats and requested size
// didn't match the source size
if ((format >= CCamera::EFormatJpeg &&
format <= CCamera::EFormatExif) &&
(aSize != sourceSize))
{
// Try again with an non-encoded format
format = CCamera::EFormatFbsBitmapColor16M;
encoding = EBitmap;
ResolveCaptureSizes(format,
cameraInfo.iNumImageSizesSupported,
aSize,
sourceSize,
sourceSizeIndex,
largestSizeIndex);
}
if (sourceSizeIndex == KErrNotFound)
{
// If correct index was not found use the largest.
sourceSizeIndex = largestSizeIndex;
}
}
// else use default iSourceSizeIndex and default image capture format
iCamera->PrepareImageCaptureL(format,
sourceSizeIndex);
// play sound when capturing image
CMMACameraSound::PlayImageCaptureSoundL();
// start capture, ImageReady will be called when ready
iWindow->SetStarted(EFalse);
iCamera->CaptureImage();
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::TakeSnapshotL: format = 0x%x", format);
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::TakeSnapshotL: sourceSizeIndex = %d", sourceSizeIndex);
LOG1(EJavaMMAPI, EInfo, "MMA::CMMACameraPlayer::TakeSnapshotL: encoding = %d", encoding);
// Inform caller which snapshot encoding was ultimately used
return encoding;
}
CFbsBitmap* CMMACameraPlayer::SnapshotBitmap()
{
CFbsBitmap* bitmap = iSnapshotBitmap;
// ownership transfers to the caller
iSnapshotBitmap = NULL;
return bitmap;
}
HBufC8* CMMACameraPlayer::SnapshotEncoded()
{
HBufC8* encoded = iSnapshotEncoded;
// ownership transfers to the caller
iSnapshotEncoded = NULL;
return encoded;
}
void CMMACameraPlayer::NotifyWithStringEvent(
CMMAPlayerEvent::TEventType aEventType,
const TDesC& aStringEventData)
{
PostStringEvent(aEventType, aStringEventData);
}
MMMASnapshot* CMMACameraPlayer::SnapshoterL()
{
return this;
}
TInt CMMACameraPlayer::CameraHandle()
{
return iCamera->Handle();
}
void CMMACameraPlayer::SetViewFinderMode(TBool aStopViewFinder)
{
iStopViewFinder = aStopViewFinder;
}
// END OF FILE