2012-07-30 14:59:05 -07:00
/*
* Copyright ( C ) 2012 Mozilla Foundation
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
# include <string.h>
2012-08-17 03:56:55 -07:00
# include "base/basictypes.h"
2012-07-30 14:59:05 -07:00
# include "libcameraservice/CameraHardwareInterface.h"
# include "camera/CameraParameters.h"
# include "nsCOMPtr.h"
# include "nsDOMClassInfo.h"
# include "nsMemory.h"
# include "jsapi.h"
# include "nsThread.h"
# include "nsPrintfCString.h"
# include "DOMCameraManager.h"
# include "GonkCameraHwMgr.h"
2012-09-04 18:01:56 -07:00
# include "DOMCameraCapabilities.h"
# include "DOMCameraControl.h"
2012-07-30 14:59:05 -07:00
# include "GonkCameraControl.h"
# include "CameraCommon.h"
using namespace mozilla ;
2012-09-04 18:01:56 -07:00
using namespace android ;
2012-07-30 14:59:05 -07:00
2012-08-22 08:56:38 -07:00
static const char * getKeyText ( uint32_t aKey )
2012-07-30 14:59:05 -07:00
{
switch ( aKey ) {
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_EFFECT :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_EFFECT ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_WHITEBALANCE :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_WHITE_BALANCE ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SCENEMODE :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SCENE_MODE ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_FLASHMODE :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_FLASH_MODE ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_FOCUSMODE :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_FOCUS_MODE ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_ZOOM :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_ZOOM ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_METERINGAREAS :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_METERING_AREAS ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_FOCUSAREAS :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_FOCUS_AREAS ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_FOCALLENGTH :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_FOCAL_LENGTH ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_FOCUSDISTANCENEAR :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_FOCUS_DISTANCES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_FOCUS_DISTANCES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_FOCUSDISTANCEFAR :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_FOCUS_DISTANCES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_EXPOSURECOMPENSATION :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_EXPOSURE_COMPENSATION ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_PREVIEW_SIZES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_VIDEOSIZES :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_VIDEO_SIZES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_PICTURESIZES :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_PICTURE_SIZES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_PICTURE_FORMATS ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_WHITEBALANCES :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_WHITE_BALANCE ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_SCENEMODES :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_SCENE_MODES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_EFFECTS :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_EFFECTS ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_FLASHMODES :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_FLASH_MODES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_FOCUSMODES :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_SUPPORTED_FOCUS_MODES ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_MAX_NUM_FOCUS_AREAS ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_MAX_NUM_METERING_AREAS ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_MIN_EXPOSURE_COMPENSATION ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_MAX_EXPOSURE_COMPENSATION ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_EXPOSURE_COMPENSATION_STEP ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_ZOOM :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_ZOOM_SUPPORTED ;
2012-09-04 18:01:56 -07:00
case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS :
2012-07-30 14:59:05 -07:00
return CameraParameters : : KEY_ZOOM_RATIOS ;
default :
return nullptr ;
}
}
2012-09-04 18:01:56 -07:00
// nsDOMCameraControl implementation-specific constructor
nsDOMCameraControl : : nsDOMCameraControl ( uint32_t aCameraId , nsIThread * aCameraThread , nsICameraGetCameraCallback * onSuccess , nsICameraErrorCallback * onError )
: mDOMCapabilities ( nullptr )
{
DOM_CAMERA_LOGT ( " %s:%d : this=%p \n " , __func__ , __LINE__ , this ) ;
/**
* nsDOMCameraControl is a cycle - collection participant , which means it is
* not threadsafe - - so we need to bump up its reference count here to make
* sure that it exists long enough to be initialized .
*
* Once it is initialized , the GetCameraResult main - thread runnable will
* decrement it again to make sure it can be cleaned up .
*
* nsGonkCameraControl MUST NOT hold a strong reference to this
* nsDOMCameraControl or memory will leak !
*/
NS_ADDREF_THIS ( ) ;
mCameraControl = new nsGonkCameraControl ( aCameraId , aCameraThread , this , onSuccess , onError ) ;
}
2012-07-30 14:59:05 -07:00
// Gonk-specific CameraControl implementation.
2012-09-04 18:01:56 -07:00
// Initialize nsGonkCameraControl instance--runs on camera thread.
class InitGonkCameraControl : public nsRunnable
{
public :
InitGonkCameraControl ( nsGonkCameraControl * aCameraControl , nsDOMCameraControl * aDOMCameraControl , nsICameraGetCameraCallback * onSuccess , nsICameraErrorCallback * onError )
: mCameraControl ( aCameraControl )
, mDOMCameraControl ( aDOMCameraControl )
, mOnSuccessCb ( onSuccess )
, mOnErrorCb ( onError )
{
DOM_CAMERA_LOGT ( " %s:%d : this=%p \n " , __func__ , __LINE__ , this ) ;
}
~ InitGonkCameraControl ( )
{
DOM_CAMERA_LOGT ( " %s:%d : this=%p \n " , __func__ , __LINE__ , this ) ;
}
NS_IMETHOD Run ( )
{
nsresult rv = mCameraControl - > Init ( ) ;
return mDOMCameraControl - > Result ( rv , mOnSuccessCb , mOnErrorCb ) ;
}
nsRefPtr < nsGonkCameraControl > mCameraControl ;
// Raw pointer to DOM-facing camera control--it must NS_ADDREF itself for us
nsDOMCameraControl * mDOMCameraControl ;
nsCOMPtr < nsICameraGetCameraCallback > mOnSuccessCb ;
nsCOMPtr < nsICameraErrorCallback > mOnErrorCb ;
} ;
// Construct nsGonkCameraControl on the main thread.
nsGonkCameraControl : : nsGonkCameraControl ( uint32_t aCameraId , nsIThread * aCameraThread , nsDOMCameraControl * aDOMCameraControl , nsICameraGetCameraCallback * onSuccess , nsICameraErrorCallback * onError )
: CameraControlImpl ( aCameraId , aCameraThread )
2012-07-30 14:59:05 -07:00
, mHwHandle ( 0 )
, mExposureCompensationMin ( 0.0 )
, mExposureCompensationStep ( 0.0 )
, mDeferConfigUpdate ( false )
2012-09-04 18:01:56 -07:00
, mWidth ( 0 )
, mHeight ( 0 )
, mFormat ( PREVIEW_FORMAT_UNKNOWN )
, mDiscardedFrameCount ( 0 )
{
// Constructor runs on the main thread...
DOM_CAMERA_LOGT ( " %s:%d : this=%p \n " , __func__ , __LINE__ , this ) ;
mRwLock = PR_NewRWLock ( PR_RWLOCK_RANK_NONE , " GonkCameraControl.Parameters.Lock " ) ;
// ...but initialization is carried out on the camera thread.
nsCOMPtr < nsIRunnable > init = new InitGonkCameraControl ( this , aDOMCameraControl , onSuccess , onError ) ;
mCameraThread - > Dispatch ( init , NS_DISPATCH_NORMAL ) ;
}
nsresult
nsGonkCameraControl : : Init ( )
2012-07-30 14:59:05 -07:00
{
mHwHandle = GonkCameraHardware : : GetHandle ( this , mCameraId ) ;
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGI ( " Initializing camera %d (this=%p, mHwHandle=%d) \n " , mCameraId , this , mHwHandle ) ;
2012-07-30 14:59:05 -07:00
// Initialize our camera configuration database.
2012-09-04 18:01:56 -07:00
PullParametersImpl ( ) ;
// Try to set preferred image format and frame rate
DOM_CAMERA_LOGI ( " Camera preview formats: %s \n " , mParams . get ( mParams . KEY_SUPPORTED_PREVIEW_FORMATS ) ) ;
const char * const PREVIEW_FORMAT = " yuv420p " ;
const char * const BAD_PREVIEW_FORMAT = " yuv420sp " ;
mParams . setPreviewFormat ( PREVIEW_FORMAT ) ;
mParams . setPreviewFrameRate ( mFps ) ;
// Check that our settings stuck
PullParametersImpl ( ) ;
const char * format = mParams . getPreviewFormat ( ) ;
if ( strcmp ( format , PREVIEW_FORMAT ) = = 0 ) {
mFormat = PREVIEW_FORMAT_YUV420P ; /* \o/ */
} else if ( strcmp ( format , BAD_PREVIEW_FORMAT ) = = 0 ) {
mFormat = PREVIEW_FORMAT_YUV420SP ;
DOM_CAMERA_LOGA ( " Camera ignored our request for '%s' preview, will have to convert (from %d) \n " , PREVIEW_FORMAT , mFormat ) ;
} else {
mFormat = PREVIEW_FORMAT_UNKNOWN ;
DOM_CAMERA_LOGE ( " Camera ignored our request for '%s' preview, returned UNSUPPORTED format '%s' \n " , PREVIEW_FORMAT , format ) ;
}
// Check the frame rate and log if the camera ignored our setting
uint32_t fps = mParams . getPreviewFrameRate ( ) ;
if ( fps ! = mFps ) {
DOM_CAMERA_LOGA ( " We asked for %d fps but camera returned %d fps, using that " , mFps , fps ) ;
mFps = fps ;
}
// Grab any other settings we'll need later.
mExposureCompensationMin = mParams . getFloat ( mParams . KEY_MIN_EXPOSURE_COMPENSATION ) ;
mExposureCompensationStep = mParams . getFloat ( mParams . KEY_EXPOSURE_COMPENSATION_STEP ) ;
mMaxMeteringAreas = mParams . getInt ( mParams . KEY_MAX_NUM_METERING_AREAS ) ;
mMaxFocusAreas = mParams . getInt ( mParams . KEY_MAX_NUM_FOCUS_AREAS ) ;
DOM_CAMERA_LOGI ( " - minimum exposure compensation: %f \n " , mExposureCompensationMin ) ;
DOM_CAMERA_LOGI ( " - exposure compensation step: %f \n " , mExposureCompensationStep ) ;
DOM_CAMERA_LOGI ( " - maximum metering areas: %d \n " , mMaxMeteringAreas ) ;
DOM_CAMERA_LOGI ( " - maximum focus areas: %d \n " , mMaxFocusAreas ) ;
return mHwHandle ! = 0 ? NS_OK : NS_ERROR_FAILURE ;
2012-07-30 14:59:05 -07:00
}
nsGonkCameraControl : : ~ nsGonkCameraControl ( )
{
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGT ( " %s:%d : this=%p, mHwHandle = %d \n " , __func__ , __LINE__ , this , mHwHandle ) ;
2012-07-30 14:59:05 -07:00
GonkCameraHardware : : ReleaseHandle ( mHwHandle ) ;
if ( mRwLock ) {
PRRWLock * lock = mRwLock ;
mRwLock = nullptr ;
PR_DestroyRWLock ( lock ) ;
}
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGT ( " %s:%d \n " , __func__ , __LINE__ ) ;
2012-07-30 14:59:05 -07:00
}
class RwAutoLockRead
{
public :
RwAutoLockRead ( PRRWLock * aRwLock )
: mRwLock ( aRwLock )
{
PR_RWLock_Rlock ( mRwLock ) ;
}
~ RwAutoLockRead ( )
{
PR_RWLock_Unlock ( mRwLock ) ;
}
protected :
PRRWLock * mRwLock ;
} ;
class RwAutoLockWrite
{
public :
RwAutoLockWrite ( PRRWLock * aRwLock )
: mRwLock ( aRwLock )
{
PR_RWLock_Wlock ( mRwLock ) ;
}
~ RwAutoLockWrite ( )
{
PR_RWLock_Unlock ( mRwLock ) ;
}
protected :
PRRWLock * mRwLock ;
} ;
const char *
nsGonkCameraControl : : GetParameter ( const char * aKey )
{
RwAutoLockRead lock ( mRwLock ) ;
return mParams . get ( aKey ) ;
}
const char *
2012-08-22 08:56:38 -07:00
nsGonkCameraControl : : GetParameterConstChar ( uint32_t aKey )
2012-07-30 14:59:05 -07:00
{
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
return nullptr ;
}
RwAutoLockRead lock ( mRwLock ) ;
return mParams . get ( key ) ;
}
double
2012-08-22 08:56:38 -07:00
nsGonkCameraControl : : GetParameterDouble ( uint32_t aKey )
2012-07-30 14:59:05 -07:00
{
double val ;
int index = 0 ;
double focusDistance [ 3 ] ;
const char * s ;
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
// return 1x when zooming is not supported
return aKey = = CAMERA_PARAM_ZOOM ? 1.0 : 0.0 ;
}
RwAutoLockRead lock ( mRwLock ) ;
switch ( aKey ) {
case CAMERA_PARAM_ZOOM :
val = mParams . getInt ( key ) ;
return val / 100 ;
/**
* The gonk camera parameters API only exposes one focus distance property
* that contains " Near,Optimum,Far " distances , in metres , where ' Far ' may
* be ' Infinity ' .
*/
case CAMERA_PARAM_FOCUSDISTANCEFAR :
+ + index ;
// intentional fallthrough
case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM :
+ + index ;
// intentional fallthrough
case CAMERA_PARAM_FOCUSDISTANCENEAR :
s = mParams . get ( key ) ;
if ( sscanf ( s , " %lf,%lf,%lf " , & focusDistance [ 0 ] , & focusDistance [ 1 ] , & focusDistance [ 2 ] ) = = 3 ) {
return focusDistance [ index ] ;
}
return 0.0 ;
case CAMERA_PARAM_EXPOSURECOMPENSATION :
index = mParams . getInt ( key ) ;
if ( ! index ) {
// NaN indicates automatic exposure compensation
return NAN ;
}
val = ( index - 1 ) * mExposureCompensationStep + mExposureCompensationMin ;
DOM_CAMERA_LOGI ( " index = %d --> compensation = %f \n " , index , val ) ;
return val ;
default :
return mParams . getFloat ( key ) ;
}
}
void
2012-08-22 08:56:38 -07:00
nsGonkCameraControl : : GetParameter ( uint32_t aKey , nsTArray < CameraRegion > & aRegions )
2012-07-30 14:59:05 -07:00
{
aRegions . Clear ( ) ;
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
return ;
}
RwAutoLockRead lock ( mRwLock ) ;
const char * value = mParams . get ( key ) ;
DOM_CAMERA_LOGI ( " key='%s' --> value='%s' \n " , key , value ) ;
if ( ! value ) {
return ;
}
const char * p = value ;
2012-08-22 08:56:38 -07:00
uint32_t count = 1 ;
2012-07-30 14:59:05 -07:00
// count the number of regions in the string
while ( ( p = strstr ( p , " ),( " ) ) ) {
+ + count ;
p + = 3 ;
}
aRegions . SetCapacity ( count ) ;
CameraRegion * r ;
// parse all of the region sets
2012-08-22 08:56:38 -07:00
uint32_t i ;
2012-07-30 14:59:05 -07:00
for ( i = 0 , p = value ; p & & i < count ; + + i , p = strchr ( p + 1 , ' ( ' ) ) {
r = aRegions . AppendElement ( ) ;
if ( sscanf ( p , " (%d,%d,%d,%d,%u) " , & r - > top , & r - > left , & r - > bottom , & r - > right , & r - > weight ) ! = 5 ) {
DOM_CAMERA_LOGE ( " %s:%d : region tuple has bad format: '%s' \n " , __func__ , __LINE__ , p ) ;
goto GetParameter_error ;
}
}
return ;
GetParameter_error :
aRegions . Clear ( ) ;
}
2012-09-04 18:01:56 -07:00
nsresult
2012-07-30 14:59:05 -07:00
nsGonkCameraControl : : PushParameters ( )
{
2012-09-04 18:01:56 -07:00
if ( mDeferConfigUpdate ) {
DOM_CAMERA_LOGT ( " %s:%d - defering config update \n " , __func__ , __LINE__ ) ;
return NS_OK ;
}
/**
* If we ' re already on the camera thread , call PushParametersImpl ( )
* directly , so that it executes synchronously . Some callers
* require this so that changes take effect immediately before
* we can proceed .
*/
if ( NS_IsMainThread ( ) ) {
DOM_CAMERA_LOGT ( " %s:%d - dispatching to main thread \n " , __func__ , __LINE__ ) ;
nsCOMPtr < nsIRunnable > pushParametersTask = NS_NewRunnableMethod ( this , & nsGonkCameraControl : : PushParametersImpl ) ;
return mCameraThread - > Dispatch ( pushParametersTask , NS_DISPATCH_NORMAL ) ;
2012-07-30 14:59:05 -07:00
}
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGT ( " %s:%d \n " , __func__ , __LINE__ ) ;
return PushParametersImpl ( ) ;
2012-07-30 14:59:05 -07:00
}
void
nsGonkCameraControl : : SetParameter ( const char * aKey , const char * aValue )
{
{
RwAutoLockWrite lock ( mRwLock ) ;
mParams . set ( aKey , aValue ) ;
}
PushParameters ( ) ;
}
void
2012-08-22 08:56:38 -07:00
nsGonkCameraControl : : SetParameter ( uint32_t aKey , const char * aValue )
2012-07-30 14:59:05 -07:00
{
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
return ;
}
{
RwAutoLockWrite lock ( mRwLock ) ;
mParams . set ( key , aValue ) ;
}
PushParameters ( ) ;
}
void
2012-08-22 08:56:38 -07:00
nsGonkCameraControl : : SetParameter ( uint32_t aKey , double aValue )
2012-07-30 14:59:05 -07:00
{
2012-08-22 08:56:38 -07:00
uint32_t index ;
2012-07-30 14:59:05 -07:00
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
return ;
}
{
RwAutoLockWrite lock ( mRwLock ) ;
if ( aKey = = CAMERA_PARAM_EXPOSURECOMPENSATION ) {
/**
* Convert from real value to a Gonk index , round
* to the nearest step ; index is 1 - based .
*/
index = ( aValue - mExposureCompensationMin + mExposureCompensationStep / 2 ) / mExposureCompensationStep + 1 ;
DOM_CAMERA_LOGI ( " compensation = %f --> index = %d \n " , aValue , index ) ;
mParams . set ( key , index ) ;
} else {
mParams . setFloat ( key , aValue ) ;
}
}
PushParameters ( ) ;
}
void
2012-08-22 08:56:38 -07:00
nsGonkCameraControl : : SetParameter ( uint32_t aKey , const nsTArray < CameraRegion > & aRegions )
2012-07-30 14:59:05 -07:00
{
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
return ;
}
2012-08-22 08:56:38 -07:00
uint32_t length = aRegions . Length ( ) ;
2012-07-30 14:59:05 -07:00
if ( ! length ) {
// This tells the camera driver to revert to automatic regioning.
mParams . set ( key , " (0,0,0,0,0) " ) ;
PushParameters ( ) ;
return ;
}
nsCString s ;
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 ; i < length ; + + i ) {
2012-07-30 14:59:05 -07:00
const CameraRegion * r = & aRegions [ i ] ;
s . AppendPrintf ( " (%d,%d,%d,%d,%d), " , r - > top , r - > left , r - > bottom , r - > right , r - > weight ) ;
}
// remove the trailing comma
s . Trim ( " , " , false , true , true ) ;
DOM_CAMERA_LOGI ( " camera region string '%s' \n " , s . get ( ) ) ;
{
RwAutoLockWrite lock ( mRwLock ) ;
mParams . set ( key , s . get ( ) ) ;
}
PushParameters ( ) ;
}
nsresult
nsGonkCameraControl : : GetPreviewStreamImpl ( GetPreviewStreamTask * aGetPreviewStream )
{
2012-09-04 18:01:56 -07:00
SetPreviewSize ( aGetPreviewStream - > mSize . width , aGetPreviewStream - > mSize . height ) ;
2012-07-30 14:59:05 -07:00
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGI ( " config preview: wated %d x %d, got %d x %d (%d fps, format %d) \n " , aGetPreviewStream - > mSize . width , aGetPreviewStream - > mSize . height , mWidth , mHeight , mFps , mFormat ) ;
nsCOMPtr < GetPreviewStreamResult > getPreviewStreamResult = new GetPreviewStreamResult ( this , mWidth , mHeight , mFps , aGetPreviewStream - > mOnSuccessCb ) ;
return NS_DispatchToMainThread ( getPreviewStreamResult ) ;
}
nsresult
nsGonkCameraControl : : StartPreviewImpl ( StartPreviewTask * aStartPreview )
{
/**
* If ' aStartPreview - > mDOMPreview ' is null , we are just restarting
* the preview after taking a picture . No need to monkey with the
* currently set DOM - facing preview object .
*/
if ( aStartPreview - > mDOMPreview ) {
if ( mDOMPreview ) {
mDOMPreview - > Stopped ( true ) ;
2012-07-30 14:59:05 -07:00
}
2012-09-04 18:01:56 -07:00
mDOMPreview = aStartPreview - > mDOMPreview ;
} else if ( ! mDOMPreview ) {
return NS_ERROR_INVALID_ARG ;
}
DOM_CAMERA_LOGI ( " %s: starting preview (mDOMPreview=%p) \n " , __func__ , mDOMPreview ) ;
if ( GonkCameraHardware : : StartPreview ( mHwHandle ) ! = OK ) {
DOM_CAMERA_LOGE ( " %s: failed to start preview \n " , __func__ ) ;
return NS_ERROR_FAILURE ;
2012-07-30 14:59:05 -07:00
}
2012-09-04 18:01:56 -07:00
if ( aStartPreview - > mDOMPreview ) {
mDOMPreview - > Started ( ) ;
}
return NS_OK ;
}
nsresult
nsGonkCameraControl : : StopPreviewImpl ( StopPreviewTask * aStopPreview )
{
DOM_CAMERA_LOGI ( " %s: stopping preview \n " , __func__ ) ;
// StopPreview() is a synchronous call--it doesn't return
// until the camera preview thread exits.
GonkCameraHardware : : StopPreview ( mHwHandle ) ;
mDOMPreview - > Stopped ( ) ;
mDOMPreview = nullptr ;
return NS_OK ;
2012-07-30 14:59:05 -07:00
}
nsresult
nsGonkCameraControl : : AutoFocusImpl ( AutoFocusTask * aAutoFocus )
{
nsCOMPtr < nsICameraAutoFocusCallback > cb = mAutoFocusOnSuccessCb ;
if ( cb ) {
/**
* We already have a callback , so someone has already
* called autoFocus ( ) - - cancel it .
*/
mAutoFocusOnSuccessCb = nullptr ;
nsCOMPtr < nsICameraErrorCallback > ecb = mAutoFocusOnErrorCb ;
mAutoFocusOnErrorCb = nullptr ;
if ( ecb ) {
nsresult rv = NS_DispatchToMainThread ( new CameraErrorResult ( ecb , NS_LITERAL_STRING ( " CANCELLED " ) ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
GonkCameraHardware : : CancelAutoFocus ( mHwHandle ) ;
}
mAutoFocusOnSuccessCb = aAutoFocus - > mOnSuccessCb ;
mAutoFocusOnErrorCb = aAutoFocus - > mOnErrorCb ;
if ( GonkCameraHardware : : AutoFocus ( mHwHandle ) ! = OK ) {
return NS_ERROR_FAILURE ;
}
return NS_OK ;
}
nsresult
nsGonkCameraControl : : TakePictureImpl ( TakePictureTask * aTakePicture )
{
2012-09-04 18:01:56 -07:00
nsCOMPtr < nsICameraTakePictureCallback > cb = mTakePictureOnSuccessCb ;
2012-07-30 14:59:05 -07:00
if ( cb ) {
/**
* We already have a callback , so someone has already
* called TakePicture ( ) - - cancel it .
*/
mTakePictureOnSuccessCb = nullptr ;
nsCOMPtr < nsICameraErrorCallback > ecb = mTakePictureOnErrorCb ;
mTakePictureOnErrorCb = nullptr ;
if ( ecb ) {
nsresult rv = NS_DispatchToMainThread ( new CameraErrorResult ( ecb , NS_LITERAL_STRING ( " CANCELLED " ) ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
GonkCameraHardware : : CancelTakePicture ( mHwHandle ) ;
}
mTakePictureOnSuccessCb = aTakePicture - > mOnSuccessCb ;
mTakePictureOnErrorCb = aTakePicture - > mOnErrorCb ;
// batch-update camera configuration
mDeferConfigUpdate = true ;
/**
* height and width : some drivers are less friendly about getting one of
* these set to zero , so if either is not specified , ignore both and go
* with current or default settings .
*/
if ( aTakePicture - > mSize . width & & aTakePicture - > mSize . height ) {
nsCString s ;
s . AppendPrintf ( " %dx%d " , aTakePicture - > mSize . width , aTakePicture - > mSize . height ) ;
DOM_CAMERA_LOGI ( " setting picture size to '%s' \n " , s . get ( ) ) ;
SetParameter ( CameraParameters : : KEY_PICTURE_SIZE , s . get ( ) ) ;
}
// Picture format -- need to keep it for the callback.
mFileFormat = aTakePicture - > mFileFormat ;
SetParameter ( CameraParameters : : KEY_PICTURE_FORMAT , NS_ConvertUTF16toUTF8 ( mFileFormat ) . get ( ) ) ;
// Convert 'rotation' to a positive value from 0..270 degrees, in steps of 90.
2012-08-22 08:56:38 -07:00
uint32_t r = static_cast < uint32_t > ( aTakePicture - > mRotation ) ;
2012-07-30 14:59:05 -07:00
r % = 360 ;
r + = 45 ;
r / = 90 ;
r * = 90 ;
DOM_CAMERA_LOGI ( " setting picture rotation to %d degrees (mapped from %d) \n " , r , aTakePicture - > mRotation ) ;
SetParameter ( CameraParameters : : KEY_ROTATION , nsPrintfCString ( " %u " , r ) . get ( ) ) ;
// Add any specified positional information -- don't care if these fail.
if ( ! isnan ( aTakePicture - > mPosition . latitude ) ) {
DOM_CAMERA_LOGI ( " setting picture latitude to %lf \n " , aTakePicture - > mPosition . latitude ) ;
SetParameter ( CameraParameters : : KEY_GPS_LATITUDE , nsPrintfCString ( " %lf " , aTakePicture - > mPosition . latitude ) . get ( ) ) ;
}
if ( ! isnan ( aTakePicture - > mPosition . longitude ) ) {
DOM_CAMERA_LOGI ( " setting picture longitude to %lf \n " , aTakePicture - > mPosition . longitude ) ;
SetParameter ( CameraParameters : : KEY_GPS_LONGITUDE , nsPrintfCString ( " %lf " , aTakePicture - > mPosition . longitude ) . get ( ) ) ;
}
if ( ! isnan ( aTakePicture - > mPosition . altitude ) ) {
DOM_CAMERA_LOGI ( " setting picture altitude to %lf \n " , aTakePicture - > mPosition . altitude ) ;
SetParameter ( CameraParameters : : KEY_GPS_ALTITUDE , nsPrintfCString ( " %lf " , aTakePicture - > mPosition . altitude ) . get ( ) ) ;
}
if ( ! isnan ( aTakePicture - > mPosition . timestamp ) ) {
DOM_CAMERA_LOGI ( " setting picture timestamp to %lf \n " , aTakePicture - > mPosition . timestamp ) ;
SetParameter ( CameraParameters : : KEY_GPS_TIMESTAMP , nsPrintfCString ( " %lf " , aTakePicture - > mPosition . timestamp ) . get ( ) ) ;
}
mDeferConfigUpdate = false ;
PushParameters ( ) ;
if ( GonkCameraHardware : : TakePicture ( mHwHandle ) ! = OK ) {
return NS_ERROR_FAILURE ;
}
return NS_OK ;
}
nsresult
2012-09-04 18:01:56 -07:00
nsGonkCameraControl : : PushParametersImpl ( )
2012-07-30 14:59:05 -07:00
{
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGI ( " Pushing camera parameters \n " ) ;
2012-07-30 14:59:05 -07:00
RwAutoLockRead lock ( mRwLock ) ;
if ( GonkCameraHardware : : PushParameters ( mHwHandle , mParams ) ! = OK ) {
return NS_ERROR_FAILURE ;
}
return NS_OK ;
}
nsresult
2012-09-04 18:01:56 -07:00
nsGonkCameraControl : : PullParametersImpl ( )
2012-07-30 14:59:05 -07:00
{
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGI ( " Pulling camera parameters \n " ) ;
2012-07-30 14:59:05 -07:00
RwAutoLockWrite lock ( mRwLock ) ;
GonkCameraHardware : : PullParameters ( mHwHandle , mParams ) ;
return NS_OK ;
}
nsresult
nsGonkCameraControl : : StartRecordingImpl ( StartRecordingTask * aStartRecording )
{
return NS_ERROR_NOT_IMPLEMENTED ;
}
nsresult
nsGonkCameraControl : : StopRecordingImpl ( StopRecordingTask * aStopRecording )
{
return NS_ERROR_NOT_IMPLEMENTED ;
}
void
2012-09-04 18:01:56 -07:00
nsGonkCameraControl : : AutoFocusComplete ( bool aSuccess )
{
/**
* Auto focusing can change some of the camera ' s parameters , so
* we need to pull a new set before sending the result to the
* main thread .
*/
PullParametersImpl ( ) ;
/**
* If we make it here , regardless of the value of ' aSuccess ' , we
* consider the autofocus _process_ to have succeeded . It is up
* to the onSuccess callback to determine how to handle the case
* where the camera wasn ' t actually able to acquire focus .
*/
nsCOMPtr < nsIRunnable > autoFocusResult = new AutoFocusResult ( aSuccess , mAutoFocusOnSuccessCb ) ;
/**
* Remember to set these to null so that we don ' t hold any extra
* references to our document ' s window .
*/
mAutoFocusOnSuccessCb = nullptr ;
mAutoFocusOnErrorCb = nullptr ;
nsresult rv = NS_DispatchToMainThread ( autoFocusResult ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to dispatch autoFocus() onSuccess callback to main thread! " ) ;
}
}
void
nsGonkCameraControl : : TakePictureComplete ( uint8_t * aData , uint32_t aLength )
2012-07-30 14:59:05 -07:00
{
2012-09-04 18:01:56 -07:00
uint8_t * data = new uint8_t [ aLength ] ;
memcpy ( data , aData , aLength ) ;
// TODO: see bug 779144.
nsIDOMBlob * blob = new nsDOMMemoryFile ( static_cast < void * > ( data ) , static_cast < uint64_t > ( aLength ) , NS_LITERAL_STRING ( " image/jpeg " ) ) ;
nsCOMPtr < nsIRunnable > takePictureResult = new TakePictureResult ( blob , mTakePictureOnSuccessCb ) ;
/**
* Remember to set these to null so that we don ' t hold any extra
* references to our document ' s window .
*/
mTakePictureOnSuccessCb = nullptr ;
mTakePictureOnErrorCb = nullptr ;
nsresult rv = NS_DispatchToMainThread ( takePictureResult ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to dispatch takePicture() onSuccess callback to main thread! " ) ;
}
}
2012-07-30 14:59:05 -07:00
2012-09-04 18:01:56 -07:00
void
nsGonkCameraControl : : SetPreviewSize ( uint32_t aWidth , uint32_t aHeight )
{
Vector < Size > previewSizes ;
uint32_t bestWidth = aWidth ;
uint32_t bestHeight = aHeight ;
uint32_t minSizeDelta = PR_UINT32_MAX ;
uint32_t delta ;
Size size ;
mParams . getSupportedPreviewSizes ( previewSizes ) ;
if ( ! aWidth & & ! aHeight ) {
// no size specified, take the first supported size
size = previewSizes [ 0 ] ;
bestWidth = size . width ;
bestHeight = size . height ;
} else if ( aWidth & & aHeight ) {
// both height and width specified, find the supported size closest to requested size
for ( uint32_t i = 0 ; i < previewSizes . size ( ) ; i + + ) {
Size size = previewSizes [ i ] ;
uint32_t delta = abs ( ( long int ) ( size . width * size . height - aWidth * aHeight ) ) ;
if ( delta < minSizeDelta ) {
minSizeDelta = delta ;
bestWidth = size . width ;
bestHeight = size . height ;
}
}
} else if ( ! aWidth ) {
// width not specified, find closest height match
for ( uint32_t i = 0 ; i < previewSizes . size ( ) ; i + + ) {
size = previewSizes [ i ] ;
delta = abs ( ( long int ) ( size . height - aHeight ) ) ;
if ( delta < minSizeDelta ) {
minSizeDelta = delta ;
bestWidth = size . width ;
bestHeight = size . height ;
}
}
} else if ( ! aHeight ) {
// height not specified, find closest width match
for ( uint32_t i = 0 ; i < previewSizes . size ( ) ; i + + ) {
size = previewSizes [ i ] ;
delta = abs ( ( long int ) ( size . width - aWidth ) ) ;
if ( delta < minSizeDelta ) {
minSizeDelta = delta ;
bestWidth = size . width ;
bestHeight = size . height ;
}
}
2012-07-30 14:59:05 -07:00
}
2012-09-04 18:01:56 -07:00
mWidth = bestWidth ;
mHeight = bestHeight ;
mParams . setPreviewSize ( mWidth , mHeight ) ;
PushParameters ( ) ;
2012-07-30 14:59:05 -07:00
}
// Gonk callback handlers.
namespace mozilla {
void
2012-08-22 08:56:38 -07:00
ReceiveImage ( nsGonkCameraControl * gc , uint8_t * aData , uint32_t aLength )
2012-07-30 14:59:05 -07:00
{
gc - > TakePictureComplete ( aData , aLength ) ;
}
void
2012-09-04 18:01:56 -07:00
AutoFocusComplete ( nsGonkCameraControl * gc , bool aSuccess )
{
gc - > AutoFocusComplete ( aSuccess ) ;
}
static void
GonkFrameBuilder ( Image * aImage , void * aBuffer , uint32_t aWidth , uint32_t aHeight )
2012-07-30 14:59:05 -07:00
{
2012-09-04 18:01:56 -07:00
/**
* Cast the generic Image back to our platform - specific type and
* populate it .
*/
GonkIOSurfaceImage * videoImage = static_cast < GonkIOSurfaceImage * > ( aImage ) ;
GonkIOSurfaceImage : : Data data ;
data . mGraphicBuffer = static_cast < layers : : GraphicBufferLocked * > ( aBuffer ) ;
data . mPicSize = gfxIntSize ( aWidth , aHeight ) ;
videoImage - > SetData ( data ) ;
2012-07-30 14:59:05 -07:00
}
void
2012-09-04 18:01:56 -07:00
ReceiveFrame ( nsGonkCameraControl * gc , layers : : GraphicBufferLocked * aBuffer )
2012-07-30 14:59:05 -07:00
{
2012-09-07 13:23:01 -07:00
if ( ! gc - > ReceiveFrame ( aBuffer , ImageFormat : : GONK_IO_SURFACE , GonkFrameBuilder ) ) {
aBuffer - > Unlock ( ) ;
}
2012-07-30 14:59:05 -07:00
}
} // namespace mozilla