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 .
*/
2013-01-18 13:06:28 -08:00
# include <time.h>
2012-07-30 14:59:05 -07:00
# include <string.h>
2012-09-28 22:30:52 -07:00
# include <sys/stat.h>
# include <fcntl.h>
# include <errno.h>
# include <libgen.h>
2012-08-17 03:56:55 -07:00
# include "base/basictypes.h"
2012-07-30 14:59:05 -07:00
# include "camera/CameraParameters.h"
# include "nsCOMPtr.h"
# include "nsDOMClassInfo.h"
# include "nsMemory.h"
# include "nsThread.h"
2012-09-28 22:30:52 -07:00
# include <media/MediaProfiles.h>
2012-10-29 16:16:42 -07:00
# include "mozilla/FileUtils.h"
2012-12-11 15:15:07 -08:00
# include "mozilla/Services.h"
2012-11-02 16:53:40 -07:00
# include "nsAlgorithm.h"
2012-11-02 13:11:50 -07:00
# include <media/mediaplayer.h>
2012-07-30 14:59:05 -07:00
# include "nsPrintfCString.h"
2012-12-04 18:00:39 -08:00
# include "nsIObserverService.h"
2013-05-11 02:10:18 -07:00
# include "nsIVolume.h"
# include "nsIVolumeService.h"
2012-07-30 14:59:05 -07:00
# include "DOMCameraManager.h"
# include "GonkCameraHwMgr.h"
2012-09-04 18:01:56 -07:00
# include "DOMCameraCapabilities.h"
# include "DOMCameraControl.h"
2012-10-23 15:30:28 -07:00
# include "GonkRecorderProfiles.h"
2012-07-30 14:59:05 -07:00
# include "GonkCameraControl.h"
# include "CameraCommon.h"
using namespace mozilla ;
2012-11-12 16:06:31 -08:00
using namespace mozilla : : dom ;
using namespace mozilla : : layers ;
2012-09-04 18:01:56 -07:00
using namespace android ;
2012-07-30 14:59:05 -07:00
2012-12-18 15:19:38 -08:00
/**
* See bug 783682. Most camera implementations , despite claiming they
* support ' yuv420p ' as a preview format , actually ignore this setting
* and return ' yuv420sp ' data anyway . We have come across a new implementation
* that , while reporting that ' yuv420p ' is supported * and * has been accepted ,
* still returns the frame data in ' yuv420sp ' anyway . So for now , since
* everyone seems to return this format , we just force it .
*/
# define FORCE_PREVIEW_FORMAT_YUV420SP 1
2013-03-14 14:30:38 -07:00
# define RETURN_IF_NO_CAMERA_HW() \
do { \
if ( ! mCameraHw . get ( ) ) { \
DOM_CAMERA_LOGE ( " %s:%d : mCameraHw is null \n " , __func__ , __LINE__ ) ; \
return NS_ERROR_NOT_AVAILABLE ; \
} \
} while ( 0 )
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 ;
2013-10-30 12:41:08 -07:00
case CAMERA_PARAM_PICTURESIZE :
return CameraParameters : : KEY_PICTURE_SIZE ;
2012-11-02 16:53:40 -07:00
case CAMERA_PARAM_THUMBNAILQUALITY :
return CameraParameters : : KEY_JPEG_THUMBNAIL_QUALITY ;
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 ;
2012-11-02 16:53:40 -07:00
case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES :
return CameraParameters : : KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES ;
2012-07-30 14:59:05 -07:00
default :
return nullptr ;
}
}
2012-09-04 18:01:56 -07:00
// nsDOMCameraControl implementation-specific constructor
2013-07-06 13:55:10 -07:00
nsDOMCameraControl : : nsDOMCameraControl ( uint32_t aCameraId , nsIThread * aCameraThread , nsICameraGetCameraCallback * onSuccess , nsICameraErrorCallback * onError , nsPIDOMWindow * aWindow )
: mDOMCapabilities ( nullptr ) , mWindow ( aWindow )
2012-09-04 18:01:56 -07:00
{
2013-07-06 13:55:10 -07:00
MOZ_ASSERT ( aWindow , " shouldn't be created with null window! " ) ;
2012-09-04 18:01:56 -07:00
DOM_CAMERA_LOGT ( " %s:%d : this=%p \n " , __func__ , __LINE__ , this ) ;
2013-08-29 06:57:53 -07:00
SetIsDOMBinding ( ) ;
2012-09-04 18:01:56 -07:00
/**
* 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 ( ) ;
2013-07-06 13:55:10 -07:00
nsRefPtr < nsGonkCameraControl > control = new nsGonkCameraControl ( aCameraId , aCameraThread , this , onSuccess , onError , aWindow - > WindowID ( ) ) ;
control - > DispatchInit ( this , onSuccess , onError , aWindow - > WindowID ( ) ) ;
2013-02-16 11:05:45 -08:00
mCameraControl = control ;
2012-09-04 18:01:56 -07:00
}
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 :
2012-09-30 17:37:47 -07:00
InitGonkCameraControl ( nsGonkCameraControl * aCameraControl , nsDOMCameraControl * aDOMCameraControl , nsICameraGetCameraCallback * onSuccess , nsICameraErrorCallback * onError , uint64_t aWindowId )
2012-09-04 18:01:56 -07:00
: mCameraControl ( aCameraControl )
, mDOMCameraControl ( aDOMCameraControl )
2013-06-17 08:59:53 -07:00
, mOnSuccessCb ( new nsMainThreadPtrHolder < nsICameraGetCameraCallback > ( onSuccess ) )
, mOnErrorCb ( new nsMainThreadPtrHolder < nsICameraErrorCallback > ( onError ) )
2012-09-30 17:37:47 -07:00
, mWindowId ( aWindowId )
2012-09-04 18:01:56 -07:00
{
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 ( ) ;
2012-09-30 17:37:47 -07:00
return mDOMCameraControl - > Result ( rv , mOnSuccessCb , mOnErrorCb , mWindowId ) ;
2012-09-04 18:01:56 -07:00
}
nsRefPtr < nsGonkCameraControl > mCameraControl ;
// Raw pointer to DOM-facing camera control--it must NS_ADDREF itself for us
nsDOMCameraControl * mDOMCameraControl ;
2013-06-17 08:59:53 -07:00
nsMainThreadPtrHandle < nsICameraGetCameraCallback > mOnSuccessCb ;
nsMainThreadPtrHandle < nsICameraErrorCallback > mOnErrorCb ;
2012-09-30 17:37:47 -07:00
uint64_t mWindowId ;
2012-09-04 18:01:56 -07:00
} ;
// Construct nsGonkCameraControl on the main thread.
2012-09-30 17:37:47 -07:00
nsGonkCameraControl : : nsGonkCameraControl ( uint32_t aCameraId , nsIThread * aCameraThread , nsDOMCameraControl * aDOMCameraControl , nsICameraGetCameraCallback * onSuccess , nsICameraErrorCallback * onError , uint64_t aWindowId )
: CameraControlImpl ( aCameraId , aCameraThread , aWindowId )
2012-07-30 14:59:05 -07:00
, mExposureCompensationMin ( 0.0 )
, mExposureCompensationStep ( 0.0 )
, mDeferConfigUpdate ( false )
2012-09-04 18:01:56 -07:00
, mWidth ( 0 )
, mHeight ( 0 )
2012-11-02 16:53:40 -07:00
, mLastPictureWidth ( 0 )
, mLastPictureHeight ( 0 )
2013-10-30 12:41:08 -07:00
, mLastThumbnailWidth ( 0 )
, mLastThumbnailHeight ( 0 )
2012-12-18 15:19:38 -08:00
# if !FORCE_PREVIEW_FORMAT_YUV420SP
2012-09-04 18:01:56 -07:00
, mFormat ( PREVIEW_FORMAT_UNKNOWN )
2012-12-18 15:19:38 -08:00
# else
, mFormat ( PREVIEW_FORMAT_YUV420SP )
# endif
2012-10-23 15:30:28 -07:00
, mFps ( 30 )
2012-09-04 18:01:56 -07:00
, mDiscardedFrameCount ( 0 )
2012-10-23 15:30:28 -07:00
, mMediaProfiles ( nullptr )
, mRecorder ( nullptr )
, mProfileManager ( nullptr )
, mRecorderProfile ( nullptr )
2012-12-04 18:00:39 -08:00
, mVideoFile ( nullptr )
2012-09-04 18:01:56 -07:00
{
// 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 " ) ;
2013-02-16 11:05:45 -08:00
}
2012-09-04 18:01:56 -07:00
2013-02-16 11:05:45 -08:00
void nsGonkCameraControl : : DispatchInit ( nsDOMCameraControl * aDOMCameraControl , nsICameraGetCameraCallback * onSuccess , nsICameraErrorCallback * onError , uint64_t aWindowId )
{
2012-09-04 18:01:56 -07:00
// ...but initialization is carried out on the camera thread.
2012-09-30 17:37:47 -07:00
nsCOMPtr < nsIRunnable > init = new InitGonkCameraControl ( this , aDOMCameraControl , onSuccess , onError , aWindowId ) ;
2012-09-04 18:01:56 -07:00
mCameraThread - > Dispatch ( init , NS_DISPATCH_NORMAL ) ;
}
nsresult
nsGonkCameraControl : : Init ( )
2012-07-30 14:59:05 -07:00
{
2013-03-08 11:43:33 -08:00
mCameraHw = GonkCameraHardware : : Connect ( this , mCameraId ) ;
2013-03-14 14:30:38 -07:00
if ( ! mCameraHw . get ( ) ) {
DOM_CAMERA_LOGE ( " Failed to connect to camera %d (this=%p) \n " , mCameraId , this ) ;
return NS_ERROR_FAILURE ;
}
2013-03-08 11:43:33 -08:00
DOM_CAMERA_LOGI ( " Initializing camera %d (this=%p, mCameraHw=%p) \n " , mCameraId , this , mCameraHw . get ( ) ) ;
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
2012-12-18 15:19:38 -08:00
# if !FORCE_PREVIEW_FORMAT_YUV420SP
2012-09-04 18:01:56 -07:00
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 ) ;
2012-12-18 15:19:38 -08:00
# else
mParams . setPreviewFormat ( " yuv420sp " ) ;
mParams . setPreviewFrameRate ( mFps ) ;
# endif
2012-11-02 16:53:40 -07:00
PushParametersImpl ( ) ;
2012-09-04 18:01:56 -07:00
// Check that our settings stuck
PullParametersImpl ( ) ;
2012-12-18 15:19:38 -08:00
# if !FORCE_PREVIEW_FORMAT_YUV420SP
2012-09-04 18:01:56 -07:00
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 ) ;
}
2012-12-18 15:19:38 -08:00
# endif
2012-09-04 18:01:56 -07:00
// 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 ) ;
2013-10-30 12:41:08 -07:00
mLastThumbnailWidth = mParams . getInt ( mParams . KEY_JPEG_THUMBNAIL_WIDTH ) ;
mLastThumbnailHeight = mParams . getInt ( mParams . KEY_JPEG_THUMBNAIL_HEIGHT ) ;
int w ;
int h ;
mParams . getPictureSize ( & w , & h ) ;
MOZ_ASSERT ( w > 0 & & h > 0 ) ; // make sure the driver returns sane values
mLastPictureWidth = static_cast < uint32_t > ( w ) ;
mLastPictureHeight = static_cast < uint32_t > ( h ) ;
2012-09-04 18:01:56 -07:00
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 ) ;
2013-10-30 12:41:08 -07:00
DOM_CAMERA_LOGI ( " - default picture size: %u x %u \n " , mLastPictureWidth , mLastPictureHeight ) ;
DOM_CAMERA_LOGI ( " - default thumbnail size: %u x %u \n " , mLastThumbnailWidth , mLastThumbnailHeight ) ;
2012-09-04 18:01:56 -07:00
2013-03-14 14:30:38 -07:00
return NS_OK ;
2012-07-30 14:59:05 -07:00
}
nsGonkCameraControl : : ~ nsGonkCameraControl ( )
{
2013-03-08 11:43:33 -08:00
DOM_CAMERA_LOGT ( " %s:%d : this=%p, mCameraHw = %p \n " , __func__ , __LINE__ , this , mCameraHw . get ( ) ) ;
2013-01-07 04:54:24 -08:00
2012-12-23 07:54:54 -08:00
ReleaseHardwareImpl ( nullptr ) ;
2012-07-30 14:59:05 -07:00
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
2013-02-11 11:37:50 -08:00
nsGonkCameraControl : : GetParameter ( uint32_t aKey ,
nsTArray < idl : : 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 ) ;
2013-02-11 11:37:50 -08:00
idl : : CameraRegion * r ;
2012-07-30 14:59:05 -07:00
// 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 ) ;
2012-11-02 16:53:40 -07:00
aRegions . Clear ( ) ;
return ;
2012-07-30 14:59:05 -07:00
}
}
return ;
2012-11-02 16:53:40 -07:00
}
2012-07-30 14:59:05 -07:00
2012-11-02 16:53:40 -07:00
void
2013-02-11 11:37:50 -08:00
nsGonkCameraControl : : GetParameter ( uint32_t aKey ,
nsTArray < idl : : CameraSize > & aSizes )
2012-11-02 16:53:40 -07:00
{
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 ;
2013-02-11 11:37:50 -08:00
idl : : CameraSize * s ;
2012-11-02 16:53:40 -07:00
// The 'value' string is in the format "w1xh1,w2xh2,w3xh3,..."
while ( p ) {
s = aSizes . AppendElement ( ) ;
if ( sscanf ( p , " %dx%d " , & s - > width , & s - > height ) ! = 2 ) {
DOM_CAMERA_LOGE ( " %s:%d : size tuple has bad format: '%s' \n " , __func__ , __LINE__ , p ) ;
aSizes . Clear ( ) ;
return ;
}
// Look for the next record...
p = strchr ( p , ' , ' ) ;
if ( p ) {
// ...skip the comma too
+ + p ;
}
}
return ;
2012-07-30 14:59:05 -07:00
}
2013-10-30 12:41:08 -07:00
void
nsGonkCameraControl : : GetParameter ( uint32_t aKey , idl : : CameraSize & aSize )
{
if ( aKey = = CAMERA_PARAM_THUMBNAILSIZE ) {
// This is a special case--for some reason the thumbnail size
// is accessed as two separate values instead of a tuple.
RwAutoLockRead lock ( mRwLock ) ;
aSize . width = mParams . getInt ( CameraParameters : : KEY_JPEG_THUMBNAIL_WIDTH ) ;
aSize . height = mParams . getInt ( CameraParameters : : KEY_JPEG_THUMBNAIL_HEIGHT ) ;
DOM_CAMERA_LOGI ( " thumbnail size --> value='%ux%u' \n " , aSize . width , aSize . height ) ;
return ;
}
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 ;
}
if ( sscanf ( value , " %ux%u " , & aSize . width , & aSize . height ) ! = 2 ) {
DOM_CAMERA_LOGE ( " %s:%d : size tuple has bad format: '%s' \n " , __func__ , __LINE__ , value ) ;
aSize . width = 0 ;
aSize . height = 0 ;
}
}
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 ( ) ) {
2013-10-30 12:41:08 -07:00
DOM_CAMERA_LOGT ( " %s:%d - dispatching to camera thread \n " , __func__ , __LINE__ ) ;
2012-09-04 18:01:56 -07:00
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
2013-02-11 11:37:50 -08:00
nsGonkCameraControl : : SetParameter ( uint32_t aKey ,
const nsTArray < idl : : 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.
2013-11-13 11:24:20 -08:00
{
RwAutoLockWrite lock ( mRwLock ) ;
mParams . set ( key , " (0,0,0,0,0) " ) ;
}
2012-07-30 14:59:05 -07:00
PushParameters ( ) ;
return ;
}
nsCString s ;
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 ; i < length ; + + i ) {
2013-02-11 11:37:50 -08:00
const idl : : CameraRegion * r = & aRegions [ i ] ;
2012-07-30 14:59:05 -07:00
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 ( ) ;
}
2012-11-02 16:53:40 -07:00
void
nsGonkCameraControl : : SetParameter ( uint32_t aKey , int aValue )
{
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
return ;
}
{
RwAutoLockWrite lock ( mRwLock ) ;
mParams . set ( key , aValue ) ;
}
PushParameters ( ) ;
}
2013-10-30 12:41:08 -07:00
void
nsGonkCameraControl : : SetParameter ( uint32_t aKey , const idl : : CameraSize & aSize )
{
switch ( aKey ) {
case CAMERA_PARAM_PICTURESIZE :
DOM_CAMERA_LOGI ( " setting picture size to %ux%u \n " , aSize . width , aSize . height ) ;
SetPictureSize ( aSize . width , aSize . height ) ;
break ;
case CAMERA_PARAM_THUMBNAILSIZE :
DOM_CAMERA_LOGI ( " setting thumbnail size to %ux%u \n " , aSize . width , aSize . height ) ;
SetThumbnailSize ( aSize . width , aSize . height ) ;
break ;
default :
{
const char * key = getKeyText ( aKey ) ;
if ( ! key ) {
return ;
}
nsCString s ;
s . AppendPrintf ( " %ux%u " , aSize . width , aSize . height ) ;
DOM_CAMERA_LOGI ( " setting '%s' to %s \n " , key , s . get ( ) ) ;
RwAutoLockWrite lock ( mRwLock ) ;
mParams . set ( key , s . get ( ) ) ;
}
break ;
}
PushParameters ( ) ;
}
2012-07-30 14:59:05 -07:00
nsresult
nsGonkCameraControl : : GetPreviewStreamImpl ( GetPreviewStreamTask * aGetPreviewStream )
{
2012-11-22 21:31:42 -08:00
// stop any currently running preview
StopPreviewInternal ( true /* forced */ ) ;
2012-07-30 14:59:05 -07:00
2012-12-23 07:56:59 -08:00
// remove any existing recorder profile
mRecorderProfile = nullptr ;
2012-11-22 21:31:42 -08:00
SetPreviewSize ( aGetPreviewStream - > mSize . width , aGetPreviewStream - > mSize . height ) ;
DOM_CAMERA_LOGI ( " picture preview: wanted %d x %d, got %d x %d (%d fps, format %d) \n " , aGetPreviewStream - > mSize . width , aGetPreviewStream - > mSize . height , mWidth , mHeight , mFps , mFormat ) ;
2012-09-04 18:01:56 -07:00
2013-01-08 15:43:50 -08:00
nsMainThreadPtrHandle < nsICameraPreviewStreamCallback > onSuccess = aGetPreviewStream - > mOnSuccessCb ;
nsCOMPtr < GetPreviewStreamResult > getPreviewStreamResult = new GetPreviewStreamResult ( this , mWidth , mHeight , mFps , onSuccess , mWindowId ) ;
2012-09-04 18:01:56 -07:00
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 ) {
2012-11-22 21:31:42 -08:00
StopPreviewInternal ( true /* forced */ ) ;
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 ) ;
2013-03-14 14:30:38 -07:00
RETURN_IF_NO_CAMERA_HW ( ) ;
2013-03-08 11:43:33 -08:00
if ( mCameraHw - > StartPreview ( ) ! = OK ) {
2012-09-04 18:01:56 -07:00
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 ( ) ;
}
2013-08-05 13:24:43 -07:00
OnPreviewStateChange ( PREVIEW_STARTED ) ;
2012-09-04 18:01:56 -07:00
return NS_OK ;
}
nsresult
2012-09-28 22:30:52 -07:00
nsGonkCameraControl : : StopPreviewInternal ( bool aForced )
2012-09-04 18:01:56 -07:00
{
2012-11-22 21:31:42 -08:00
DOM_CAMERA_LOGI ( " %s: stopping preview (mDOMPreview=%p) \n " , __func__ , mDOMPreview ) ;
2012-09-04 18:01:56 -07:00
// StopPreview() is a synchronous call--it doesn't return
// until the camera preview thread exits.
2012-09-28 22:30:52 -07:00
if ( mDOMPreview ) {
2013-03-14 14:30:38 -07:00
if ( mCameraHw . get ( ) ) {
mCameraHw - > StopPreview ( ) ;
}
2012-09-28 22:30:52 -07:00
mDOMPreview - > Stopped ( aForced ) ;
mDOMPreview = nullptr ;
}
2012-09-04 18:01:56 -07:00
2013-08-05 13:24:43 -07:00
OnPreviewStateChange ( PREVIEW_STOPPED ) ;
2012-09-04 18:01:56 -07:00
return NS_OK ;
2012-07-30 14:59:05 -07:00
}
2012-09-28 22:30:52 -07:00
nsresult
nsGonkCameraControl : : StopPreviewImpl ( StopPreviewTask * aStopPreview )
{
return StopPreviewInternal ( ) ;
}
2012-07-30 14:59:05 -07:00
nsresult
nsGonkCameraControl : : AutoFocusImpl ( AutoFocusTask * aAutoFocus )
{
2013-01-08 15:43:50 -08:00
if ( aAutoFocus - > mCancel ) {
2013-03-14 14:30:38 -07:00
if ( mCameraHw . get ( ) ) {
mCameraHw - > CancelAutoFocus ( ) ;
}
2012-07-30 14:59:05 -07:00
}
mAutoFocusOnSuccessCb = aAutoFocus - > mOnSuccessCb ;
mAutoFocusOnErrorCb = aAutoFocus - > mOnErrorCb ;
2013-03-14 14:30:38 -07:00
RETURN_IF_NO_CAMERA_HW ( ) ;
2013-03-08 11:43:33 -08:00
if ( mCameraHw - > AutoFocus ( ) ! = OK ) {
2012-07-30 14:59:05 -07:00
return NS_ERROR_FAILURE ;
}
return NS_OK ;
}
2012-11-02 16:53:40 -07:00
void
2013-10-30 12:41:08 -07:00
nsGonkCameraControl : : SetThumbnailSize ( uint32_t aWidth , uint32_t aHeight )
2012-11-02 16:53:40 -07:00
{
/**
2013-10-30 12:41:08 -07:00
* We keep a copy of the specified size so that if the picture size
* changes , we can choose a new thumbnail size close to what was asked for
* last time .
*/
mLastThumbnailWidth = aWidth ;
mLastThumbnailHeight = aHeight ;
/**
* If either of width or height is zero , set the other to zero as well .
* This should disable inclusion of a thumbnail in the final picture .
*/
if ( ! aWidth | | ! aHeight ) {
DOM_CAMERA_LOGW ( " Requested thumbnail size %ux%u, disabling thumbnail \n " , aWidth , aHeight ) ;
RwAutoLockWrite write ( mRwLock ) ;
mParams . set ( CameraParameters : : KEY_JPEG_THUMBNAIL_WIDTH , 0 ) ;
mParams . set ( CameraParameters : : KEY_JPEG_THUMBNAIL_HEIGHT , 0 ) ;
return ;
}
/**
* Choose the supported thumbnail size that is closest to the specified size .
* Some drivers will fail to take a picture if the thumbnail does not have
* the same aspect ratio as the set picture size , so we need to enforce that
* too .
2012-11-02 16:53:40 -07:00
*/
2013-10-30 12:41:08 -07:00
int smallestDelta = INT_MAX ;
uint32_t smallestDeltaIndex = UINT32_MAX ;
int targetArea = aWidth * aHeight ;
nsAutoTArray < idl : : CameraSize , 8 > supportedSizes ;
GetParameter ( CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES , supportedSizes ) ;
for ( uint32_t i = 0 ; i < supportedSizes . Length ( ) ; + + i ) {
int area = supportedSizes [ i ] . width * supportedSizes [ i ] . height ;
int delta = abs ( area - targetArea ) ;
2012-11-02 16:53:40 -07:00
if ( area ! = 0
2013-10-30 12:41:08 -07:00
& & delta < smallestDelta
& & supportedSizes [ i ] . width * mLastPictureHeight / supportedSizes [ i ] . height = = mLastPictureWidth
2012-11-02 16:53:40 -07:00
) {
2013-10-30 12:41:08 -07:00
smallestDelta = delta ;
smallestDeltaIndex = i ;
2012-11-02 16:53:40 -07:00
}
}
2013-10-30 12:41:08 -07:00
if ( smallestDeltaIndex = = UINT32_MAX ) {
DOM_CAMERA_LOGW ( " Unable to find a thumbnail size close to %ux%u \n " , aWidth , aHeight ) ;
return ;
}
2012-11-02 16:53:40 -07:00
2013-10-30 12:41:08 -07:00
uint32_t w = supportedSizes [ smallestDeltaIndex ] . width ;
uint32_t h = supportedSizes [ smallestDeltaIndex ] . height ;
DOM_CAMERA_LOGI ( " Requested thumbnail size %ux%u --> using supported size %ux%u \n " , aWidth , aHeight , w , h ) ;
if ( w > INT32_MAX | | h > INT32_MAX ) {
DOM_CAMERA_LOGE ( " Supported thumbnail size is too big, no change \n " ) ;
return ;
}
RwAutoLockWrite write ( mRwLock ) ;
mParams . set ( CameraParameters : : KEY_JPEG_THUMBNAIL_WIDTH , static_cast < int > ( w ) ) ;
mParams . set ( CameraParameters : : KEY_JPEG_THUMBNAIL_HEIGHT , static_cast < int > ( h ) ) ;
}
void
nsGonkCameraControl : : UpdateThumbnailSize ( )
{
SetThumbnailSize ( mLastThumbnailWidth , mLastThumbnailHeight ) ;
}
void
nsGonkCameraControl : : SetPictureSize ( uint32_t aWidth , uint32_t aHeight )
{
/**
* 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 ( ! aWidth | | ! aHeight ) {
DOM_CAMERA_LOGW ( " Ignoring requested picture size of %ux%u \n " , aWidth , aHeight ) ;
return ;
}
if ( aWidth = = mLastPictureWidth & & aHeight = = mLastPictureHeight ) {
DOM_CAMERA_LOGI ( " Requested picture size %ux%u unchanged \n " , aWidth , aHeight ) ;
return ;
}
/**
* Choose the supported picture size that is closest in area to the
* specified size . Some drivers will fail to take a picture if the
* thumbnail size is not the same aspect ratio , so we update that
* as well to a size closest to the last user - requested one .
*/
int smallestDelta = INT_MAX ;
uint32_t smallestDeltaIndex = UINT32_MAX ;
int targetArea = aWidth * aHeight ;
nsAutoTArray < idl : : CameraSize , 8 > supportedSizes ;
GetParameter ( CAMERA_PARAM_SUPPORTED_PICTURESIZES , supportedSizes ) ;
for ( uint32_t i = 0 ; i < supportedSizes . Length ( ) ; + + i ) {
int area = supportedSizes [ i ] . width * supportedSizes [ i ] . height ;
int delta = abs ( area - targetArea ) ;
if ( area ! = 0 & & delta < smallestDelta ) {
smallestDelta = delta ;
smallestDeltaIndex = i ;
2012-11-02 16:53:40 -07:00
}
}
2013-10-30 12:41:08 -07:00
if ( smallestDeltaIndex = = UINT32_MAX ) {
DOM_CAMERA_LOGW ( " Unable to find a picture size close to %ux%u \n " , aWidth , aHeight ) ;
return ;
}
uint32_t w = supportedSizes [ smallestDeltaIndex ] . width ;
uint32_t h = supportedSizes [ smallestDeltaIndex ] . height ;
DOM_CAMERA_LOGI ( " Requested picture size %ux%u --> using supported size %ux%u \n " , aWidth , aHeight , w , h ) ;
if ( w > INT32_MAX | | h > INT32_MAX ) {
DOM_CAMERA_LOGE ( " Supported picture size is too big, no change \n " ) ;
return ;
}
mLastPictureWidth = w ;
mLastPictureHeight = h ;
{
// We must release the write-lock before updating the thumbnail size
RwAutoLockWrite write ( mRwLock ) ;
mParams . setPictureSize ( static_cast < int > ( w ) , static_cast < int > ( h ) ) ;
}
// Finally, update the thumbnail size
UpdateThumbnailSize ( ) ;
2012-11-02 16:53:40 -07:00
}
2012-07-30 14:59:05 -07:00
nsresult
nsGonkCameraControl : : TakePictureImpl ( TakePictureTask * aTakePicture )
{
2013-01-08 15:43:50 -08:00
if ( aTakePicture - > mCancel ) {
2013-03-14 14:30:38 -07:00
if ( mCameraHw . get ( ) ) {
mCameraHw - > CancelTakePicture ( ) ;
}
2012-07-30 14:59:05 -07:00
}
mTakePictureOnSuccessCb = aTakePicture - > mOnSuccessCb ;
mTakePictureOnErrorCb = aTakePicture - > mOnErrorCb ;
2013-03-14 14:30:38 -07:00
RETURN_IF_NO_CAMERA_HW ( ) ;
2012-07-30 14:59:05 -07:00
// batch-update camera configuration
mDeferConfigUpdate = true ;
2013-10-30 12:41:08 -07:00
SetPictureSize ( aTakePicture - > mSize . width , aTakePicture - > mSize . height ) ;
2012-07-30 14:59:05 -07:00
// 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 ) ;
2013-03-08 11:43:33 -08:00
r + = mCameraHw - > GetSensorOrientation ( ) ;
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 ( ) ) ;
}
2013-01-18 13:06:28 -08:00
// Add the non-GPS timestamp. The EXIF date/time field is formatted as
// "YYYY:MM:DD HH:MM:SS", without room for a time-zone; as such, the time
// is meant to be stored as a local time. Since we are given seconds from
// Epoch GMT, we use localtime_r() to handle the conversion.
time_t time = aTakePicture - > mDateTime ;
if ( time ! = aTakePicture - > mDateTime ) {
DOM_CAMERA_LOGE ( " picture date/time '%llu' is too far in the future \n " , aTakePicture - > mDateTime ) ;
} else {
struct tm t ;
if ( localtime_r ( & time , & t ) ) {
char dateTime [ 20 ] ;
if ( strftime ( dateTime , sizeof ( dateTime ) , " %Y:%m:%d %T " , & t ) ) {
DOM_CAMERA_LOGI ( " setting picture date/time to %s \n " , dateTime ) ;
// Not every platform defines a CameraParameters::KEY_EXIF_DATETIME;
// for those who don't, we use the raw string key, and if the platform
// doesn't support it, it will be ignored.
//
// See bug 832494.
SetParameter ( " exif-datetime " , dateTime ) ;
} else {
DOM_CAMERA_LOGE ( " picture date/time couldn't be converted to string \n " ) ;
}
} else {
DOM_CAMERA_LOGE ( " picture date/time couldn't be converted to local time: (%d) %s \n " , errno , strerror ( errno ) ) ;
}
}
2012-07-30 14:59:05 -07:00
mDeferConfigUpdate = false ;
PushParameters ( ) ;
2013-03-08 11:43:33 -08:00
if ( mCameraHw - > TakePicture ( ) ! = OK ) {
2012-07-30 14:59:05 -07:00
return NS_ERROR_FAILURE ;
}
2013-08-05 13:24:43 -07:00
// In Gonk, taking a picture implicitly kills the preview stream,
// so we need to reflect that here.
OnPreviewStateChange ( PREVIEW_STOPPED ) ;
2012-07-30 14:59:05 -07:00
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 " ) ;
2013-03-14 14:30:38 -07:00
RETURN_IF_NO_CAMERA_HW ( ) ;
2012-07-30 14:59:05 -07:00
RwAutoLockRead lock ( mRwLock ) ;
2013-03-08 11:43:33 -08:00
if ( mCameraHw - > PushParameters ( mParams ) ! = OK ) {
2012-07-30 14:59:05 -07:00
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 " ) ;
2013-03-14 14:30:38 -07:00
RETURN_IF_NO_CAMERA_HW ( ) ;
2012-07-30 14:59:05 -07:00
RwAutoLockWrite lock ( mRwLock ) ;
2013-03-08 11:43:33 -08:00
mCameraHw - > PullParameters ( mParams ) ;
2012-07-30 14:59:05 -07:00
return NS_OK ;
}
nsresult
nsGonkCameraControl : : StartRecordingImpl ( StartRecordingTask * aStartRecording )
{
2012-12-23 07:56:59 -08:00
NS_ENSURE_TRUE ( mRecorderProfile , NS_ERROR_NOT_INITIALIZED ) ;
NS_ENSURE_FALSE ( mRecorder , NS_ERROR_FAILURE ) ;
2012-09-28 22:30:52 -07:00
/**
2012-10-10 03:32:37 -07:00
* Get the base path from device storage and append the app - specified
* filename to it . The filename may include a relative subpath
* ( e . g . ) " DCIM/IMG_0001.jpg " .
*
2012-09-30 17:37:47 -07:00
* The camera app needs to provide the file extension ' .3 gp ' for now .
2012-09-28 22:30:52 -07:00
* See bug 795202.
*/
2012-10-23 15:30:28 -07:00
nsCOMPtr < nsIFile > filename = aStartRecording - > mFolder ;
2012-10-10 03:32:37 -07:00
filename - > AppendRelativePath ( aStartRecording - > mFilename ) ;
2013-05-11 02:10:18 -07:00
nsString fullpath ;
filename - > GetPath ( fullpath ) ;
nsCOMPtr < nsIVolumeService > vs = do_GetService ( NS_VOLUMESERVICE_CONTRACTID ) ;
NS_ENSURE_TRUE ( vs , NS_ERROR_FAILURE ) ;
nsCOMPtr < nsIVolume > vol ;
nsresult rv = vs - > GetVolumeByPath ( fullpath , getter_AddRefs ( vol ) ) ;
NS_ENSURE_SUCCESS ( rv , NS_ERROR_INVALID_ARG ) ;
nsString volName ;
vol - > GetName ( volName ) ;
2013-04-18 07:13:23 -07:00
mVideoFile = new DeviceStorageFile ( NS_LITERAL_STRING ( " videos " ) ,
2013-05-11 02:10:18 -07:00
volName ,
2013-04-18 07:13:23 -07:00
aStartRecording - > mFilename ) ;
2012-09-28 22:30:52 -07:00
2012-10-10 03:32:37 -07:00
nsAutoCString nativeFilename ;
filename - > GetNativePath ( nativeFilename ) ;
DOM_CAMERA_LOGI ( " Video filename is '%s' \n " , nativeFilename . get ( ) ) ;
2012-09-30 17:37:47 -07:00
2012-12-04 18:00:39 -08:00
if ( ! mVideoFile - > IsSafePath ( ) ) {
DOM_CAMERA_LOGE ( " Invalid video file name \n " ) ;
return NS_ERROR_INVALID_ARG ;
}
2012-10-29 16:16:42 -07:00
ScopedClose fd ( open ( nativeFilename . get ( ) , O_RDWR | O_CREAT , 0644 ) ) ;
2012-09-28 22:30:52 -07:00
if ( fd < 0 ) {
2012-10-10 03:32:37 -07:00
DOM_CAMERA_LOGE ( " Couldn't create file '%s': (%d) %s \n " , nativeFilename . get ( ) , errno , strerror ( errno ) ) ;
2012-09-28 22:30:52 -07:00
return NS_ERROR_FAILURE ;
}
2013-10-21 15:38:50 -07:00
rv = SetupRecording ( fd , aStartRecording - > mOptions . rotation , aStartRecording - > mOptions . maxFileSizeBytes , aStartRecording - > mOptions . maxVideoLengthMs ) ;
2012-10-29 16:16:42 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-09-28 22:30:52 -07:00
if ( mRecorder - > start ( ) ! = OK ) {
DOM_CAMERA_LOGE ( " mRecorder->start() failed \n " ) ;
2013-01-08 01:11:32 -08:00
// important: we MUST destroy the recorder if start() fails!
mRecorder = nullptr ;
2012-09-28 22:30:52 -07:00
return NS_ERROR_FAILURE ;
}
return NS_OK ;
2012-07-30 14:59:05 -07:00
}
2012-12-04 18:00:39 -08:00
class RecordingComplete : public nsRunnable
{
public :
2013-01-23 13:35:06 -08:00
RecordingComplete ( DeviceStorageFile * aFile )
2012-12-04 18:00:39 -08:00
: mFile ( aFile )
{ }
~ RecordingComplete ( ) { }
NS_IMETHOD Run ( )
{
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
2013-01-23 13:35:06 -08:00
obs - > NotifyObservers ( mFile , " file-watcher-notify " , NS_LITERAL_STRING ( " modified " ) . get ( ) ) ;
2012-12-04 18:00:39 -08:00
return NS_OK ;
}
private :
nsRefPtr < DeviceStorageFile > mFile ;
} ;
2012-07-30 14:59:05 -07:00
nsresult
nsGonkCameraControl : : StopRecordingImpl ( StopRecordingTask * aStopRecording )
{
2012-12-23 07:56:59 -08:00
// nothing to do if we have no mRecorder
NS_ENSURE_TRUE ( mRecorder , NS_OK ) ;
2012-09-28 22:30:52 -07:00
mRecorder - > stop ( ) ;
mRecorder = nullptr ;
2012-12-04 18:00:39 -08:00
// notify DeviceStorage that the new video file is closed and ready
2013-01-23 13:35:06 -08:00
nsCOMPtr < nsIRunnable > recordingComplete = new RecordingComplete ( mVideoFile ) ;
2012-12-04 18:00:39 -08:00
return NS_DispatchToMainThread ( recordingComplete , NS_DISPATCH_NORMAL ) ;
2012-07-30 14:59:05 -07:00
}
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 .
*/
2012-09-30 17:37:47 -07:00
nsCOMPtr < nsIRunnable > autoFocusResult = new AutoFocusResult ( aSuccess , mAutoFocusOnSuccessCb , mWindowId ) ;
2012-09-04 18:01:56 -07:00
/**
* 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.
2013-01-08 15:43:50 -08:00
nsCOMPtr < nsIRunnable > takePictureResult = new TakePictureResult ( data , aLength , NS_LITERAL_STRING ( " image/jpeg " ) , mTakePictureOnSuccessCb , mWindowId ) ;
2012-09-04 18:01:56 -07:00
/**
* 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
2013-01-24 10:41:18 -08:00
void
nsGonkCameraControl : : TakePictureError ( )
{
nsCOMPtr < nsIRunnable > takePictureError = new CameraErrorResult ( mTakePictureOnErrorCb , NS_LITERAL_STRING ( " FAILURE " ) , mWindowId ) ;
mTakePictureOnSuccessCb = nullptr ;
mTakePictureOnErrorCb = nullptr ;
nsresult rv = NS_DispatchToMainThread ( takePictureError ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to dispatch takePicture() onError callback to main thread! " ) ;
}
}
2012-09-04 18:01:56 -07:00
void
nsGonkCameraControl : : SetPreviewSize ( uint32_t aWidth , uint32_t aHeight )
{
2013-07-09 16:33:29 -07:00
android : : Vector < Size > previewSizes ;
2012-09-04 18:01:56 -07:00
uint32_t bestWidth = aWidth ;
uint32_t bestHeight = aHeight ;
2012-09-27 23:57:33 -07:00
uint32_t minSizeDelta = UINT32_MAX ;
2012-09-04 18:01:56 -07:00
uint32_t delta ;
Size size ;
2013-11-13 11:24:20 -08:00
{
RwAutoLockRead lock ( mRwLock ) ;
mParams . getSupportedPreviewSizes ( previewSizes ) ;
}
2012-09-04 18:01:56 -07:00
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 ;
2013-11-13 11:24:20 -08:00
{
RwAutoLockWrite lock ( mRwLock ) ;
mParams . setPreviewSize ( mWidth , mHeight ) ;
}
2012-09-04 18:01:56 -07:00
PushParameters ( ) ;
2012-07-30 14:59:05 -07:00
}
2012-09-28 22:30:52 -07:00
nsresult
2012-10-23 15:30:28 -07:00
nsGonkCameraControl : : SetupVideoMode ( const nsAString & aProfile )
2012-09-28 22:30:52 -07:00
{
// read preferences for camcorder
mMediaProfiles = MediaProfiles : : getInstance ( ) ;
2012-10-23 15:30:28 -07:00
nsAutoCString profile = NS_ConvertUTF16toUTF8 ( aProfile ) ;
2013-10-21 15:38:50 -07:00
mRecorderProfile = GetGonkRecorderProfileManager ( ) . get ( ) - > Get ( profile . get ( ) ) ;
2012-10-23 15:30:28 -07:00
if ( ! mRecorderProfile ) {
DOM_CAMERA_LOGE ( " Recorder profile '%s' is not supported \n " , profile . get ( ) ) ;
return NS_ERROR_INVALID_ARG ;
}
const GonkRecorderVideoProfile * video = mRecorderProfile - > GetGonkVideoProfile ( ) ;
int width = video - > GetWidth ( ) ;
int height = video - > GetHeight ( ) ;
int fps = video - > GetFramerate ( ) ;
if ( fps = = - 1 | | width = = - 1 | | height = = - 1 ) {
DOM_CAMERA_LOGE ( " Can't configure preview with fps=%d, width=%d, height=%d \n " , fps , width , height ) ;
2012-09-28 22:30:52 -07:00
return NS_ERROR_FAILURE ;
}
PullParametersImpl ( ) ;
2012-10-23 15:30:28 -07:00
// configure camera video recording parameters
2012-09-28 22:30:52 -07:00
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
2013-11-13 11:24:20 -08:00
{
RwAutoLockWrite lock ( mRwLock ) ;
mParams . setPreviewSize ( width , height ) ;
mParams . setPreviewFrameRate ( fps ) ;
2012-09-28 22:30:52 -07:00
2013-11-13 11:24:20 -08:00
/**
* " record-size " is probably deprecated in later ICS ;
* might need to set " video-size " instead of " record-size " .
* See bug 795332.
*/
snprintf ( buffer , SIZE , " %dx%d " , width , height ) ;
mParams . set ( " record-size " , buffer ) ;
}
2012-09-28 22:30:52 -07:00
2012-10-23 15:30:28 -07:00
// push the updated camera configuration immediately
PushParameters ( ) ;
2012-09-28 22:30:52 -07:00
return NS_OK ;
}
2012-11-02 13:11:50 -07:00
class GonkRecorderListener : public IMediaRecorderClient
{
public :
GonkRecorderListener ( nsGonkCameraControl * aCameraControl )
: mCameraControl ( aCameraControl )
{
DOM_CAMERA_LOGT ( " %s:%d : this=%p, aCameraControl=%p \n " , __func__ , __LINE__ , this , mCameraControl . get ( ) ) ;
}
void notify ( int msg , int ext1 , int ext2 )
{
if ( mCameraControl ) {
mCameraControl - > HandleRecorderEvent ( msg , ext1 , ext2 ) ;
}
}
IBinder * onAsBinder ( )
{
DOM_CAMERA_LOGE ( " onAsBinder() called, should NEVER get called! \n " ) ;
return nullptr ;
}
protected :
~ GonkRecorderListener ( ) { }
nsRefPtr < nsGonkCameraControl > mCameraControl ;
} ;
void
nsGonkCameraControl : : HandleRecorderEvent ( int msg , int ext1 , int ext2 )
{
/**
* Refer to base / include / media / mediarecorder . h for a complete list
* of error and info message codes . There are duplicate values
* within the status / error code space , as determined by code inspection :
*
* + - - - - - - - msg
* | + - - - - - ext1
* | | + - - - ext2
* V V V
* 1 MEDIA_RECORDER_EVENT_ERROR
* 1 MEDIA_RECORDER_ERROR_UNKNOWN
* [ 3 ] ERROR_MALFORMED
* 100 mediaplayer . h : : MEDIA_ERROR_SERVER_DIED
* 0 < always zero >
* 2 MEDIA_RECORDER_EVENT_INFO
* 800 MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
* 0 < always zero >
* 801 MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
* 0 < always zero >
* 1000 MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS [ 1 b ]
* [ 3 ] UNKNOWN_ERROR , etc .
* 100 MEDIA_ERROR [ 4 ]
* 100 mediaplayer . h : : MEDIA_ERROR_SERVER_DIED
* 0 < always zero >
* 100 MEDIA_RECORDER_TRACK_EVENT_ERROR
* 100 MEDIA_RECORDER_TRACK_ERROR_GENERAL [ 1 a ]
* [ 3 ] UNKNOWN_ERROR , etc .
* 200 MEDIA_RECORDER_ERROR_VIDEO_NO_SYNC_FRAME [ 2 ]
* ? < unknown >
* 101 MEDIA_RECORDER_TRACK_EVENT_INFO
* 1000 MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS [ 1 a ]
* [ 3 ] UNKNOWN_ERROR , etc .
* N see mediarecorder . h : : media_recorder_info_type [ 5 ]
*
* 1. a ) High 4 bits are the track number , the next 12 bits are reserved ,
* and the final 16 bits are the actual error code ( above ) .
* b ) But not in this case .
* 2. Never actually used in AOSP code ?
* 3. Specific error codes are from utils / Errors . h and / or
* include / media / stagefright / MediaErrors . h .
* 4. Only in frameworks / base / media / libmedia / mediaplayer . cpp .
* 5. These are mostly informational and we can ignore them ; note that
* although the MEDIA_RECORDER_INFO_MAX_DURATION_REACHED and
* MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED values are defined in this
* enum , they are used with different ext1 codes . / o \
*/
int trackNum = - 1 ; // no track
switch ( msg ) {
// Recorder-related events
case MEDIA_RECORDER_EVENT_INFO :
switch ( ext1 ) {
case MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED :
DOM_CAMERA_LOGI ( " recorder-event : info: maximum file size reached \n " ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " FileSizeLimitReached " ) , ext2 , trackNum ) ;
return ;
case MEDIA_RECORDER_INFO_MAX_DURATION_REACHED :
DOM_CAMERA_LOGI ( " recorder-event : info: maximum video duration reached \n " ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " VideoLengthLimitReached " ) , ext2 , trackNum ) ;
return ;
case MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS :
DOM_CAMERA_LOGI ( " recorder-event : info: track completed \n " ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " TrackCompleted " ) , ext2 , trackNum ) ;
return ;
}
break ;
case MEDIA_RECORDER_EVENT_ERROR :
switch ( ext1 ) {
case MEDIA_RECORDER_ERROR_UNKNOWN :
DOM_CAMERA_LOGE ( " recorder-event : recorder-error: %d (0x%08x) \n " , ext2 , ext2 ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " MediaRecorderFailed " ) , ext2 , trackNum ) ;
return ;
case MEDIA_ERROR_SERVER_DIED :
DOM_CAMERA_LOGE ( " recorder-event : recorder-error: server died \n " ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " MediaServerFailed " ) , ext2 , trackNum ) ;
return ;
}
break ;
// Track-related events, see note 1(a) above.
case MEDIA_RECORDER_TRACK_EVENT_INFO :
trackNum = ( ext1 & 0xF0000000 ) > > 28 ;
ext1 & = 0xFFFF ;
switch ( ext1 ) {
case MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS :
if ( ext2 = = OK ) {
DOM_CAMERA_LOGI ( " recorder-event : track-complete: track %d, %d (0x%08x) \n " , trackNum , ext2 , ext2 ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " TrackCompleted " ) , ext2 , trackNum ) ;
return ;
}
DOM_CAMERA_LOGE ( " recorder-event : track-error: track %d, %d (0x%08x) \n " , trackNum , ext2 , ext2 ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " TrackFailed " ) , ext2 , trackNum ) ;
return ;
case MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME :
DOM_CAMERA_LOGI ( " recorder-event : track-info: progress in time: %d ms \n " , ext2 ) ;
return ;
}
break ;
case MEDIA_RECORDER_TRACK_EVENT_ERROR :
trackNum = ( ext1 & 0xF0000000 ) > > 28 ;
ext1 & = 0xFFFF ;
DOM_CAMERA_LOGE ( " recorder-event : track-error: track %d, %d (0x%08x) \n " , trackNum , ext2 , ext2 ) ;
OnRecorderStateChange ( NS_LITERAL_STRING ( " TrackFailed " ) , ext2 , trackNum ) ;
return ;
}
// All unhandled cases wind up here
DOM_CAMERA_LOGW ( " recorder-event : unhandled: msg=%d, ext1=%d, ext2=%d \n " , msg , ext1 , ext2 ) ;
}
2012-09-28 22:30:52 -07:00
nsresult
2012-11-06 19:32:01 -08:00
nsGonkCameraControl : : SetupRecording ( int aFd , int aRotation , int64_t aMaxFileSizeBytes , int64_t aMaxVideoLengthMs )
2012-09-28 22:30:52 -07:00
{
2013-03-14 14:30:38 -07:00
RETURN_IF_NO_CAMERA_HW ( ) ;
2012-09-28 22:30:52 -07:00
// choosing a size big enough to hold the params
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
mRecorder = new GonkRecorder ( ) ;
CHECK_SETARG ( mRecorder - > init ( ) ) ;
2012-10-23 15:30:28 -07:00
nsresult rv = mRecorderProfile - > ConfigureRecorder ( mRecorder ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2013-03-08 11:43:33 -08:00
CHECK_SETARG ( mRecorder - > setCamera ( mCameraHw ) ) ;
2012-10-23 15:30:28 -07:00
2012-11-02 13:11:50 -07:00
DOM_CAMERA_LOGI ( " maxVideoLengthMs=%lld \n " , aMaxVideoLengthMs ) ;
if ( aMaxVideoLengthMs = = 0 ) {
aMaxVideoLengthMs = - 1 ;
}
snprintf ( buffer , SIZE , " max-duration=%lld " , aMaxVideoLengthMs ) ;
2012-09-28 22:30:52 -07:00
CHECK_SETARG ( mRecorder - > setParameters ( String8 ( buffer ) ) ) ;
2012-10-23 15:30:28 -07:00
2012-11-02 13:11:50 -07:00
DOM_CAMERA_LOGI ( " maxFileSizeBytes=%lld \n " , aMaxFileSizeBytes ) ;
if ( aMaxFileSizeBytes = = 0 ) {
aMaxFileSizeBytes = - 1 ;
}
snprintf ( buffer , SIZE , " max-filesize=%lld " , aMaxFileSizeBytes ) ;
2012-09-28 22:30:52 -07:00
CHECK_SETARG ( mRecorder - > setParameters ( String8 ( buffer ) ) ) ;
2012-10-23 15:30:28 -07:00
2012-11-06 19:32:01 -08:00
// adjust rotation by camera sensor offset
int r = aRotation ;
2013-03-08 11:43:33 -08:00
r + = mCameraHw - > GetSensorOrientation ( GonkCameraHardware : : RAW_SENSOR_ORIENTATION ) ;
2012-11-06 19:32:01 -08:00
r % = 360 ;
r + = 45 ;
r / = 90 ;
r * = 90 ;
2012-11-09 17:32:10 -08:00
if ( r < 0 ) {
// the video recorder only supports positive rotations
r + = 360 ;
}
2012-11-06 19:32:01 -08:00
DOM_CAMERA_LOGI ( " setting video rotation to %d degrees (mapped from %d) \n " , r , aRotation ) ;
snprintf ( buffer , SIZE , " video-param-rotation-angle-degrees=%d " , r ) ;
2012-09-28 22:30:52 -07:00
CHECK_SETARG ( mRecorder - > setParameters ( String8 ( buffer ) ) ) ;
2012-11-02 13:11:50 -07:00
CHECK_SETARG ( mRecorder - > setListener ( new GonkRecorderListener ( this ) ) ) ;
2012-09-28 22:30:52 -07:00
// recording API needs file descriptor of output file
CHECK_SETARG ( mRecorder - > setOutputFile ( aFd , 0 , 0 ) ) ;
CHECK_SETARG ( mRecorder - > prepare ( ) ) ;
return NS_OK ;
}
nsresult
nsGonkCameraControl : : GetPreviewStreamVideoModeImpl ( GetPreviewStreamVideoModeTask * aGetPreviewStreamVideoMode )
{
// stop any currently running preview
StopPreviewInternal ( true /* forced */ ) ;
// setup the video mode
2013-10-21 15:38:50 -07:00
nsresult rv = SetupVideoMode ( aGetPreviewStreamVideoMode - > mOptions . profile ) ;
2012-09-28 22:30:52 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-10-23 15:30:28 -07:00
const RecorderVideoProfile * video = mRecorderProfile - > GetVideoProfile ( ) ;
int width = video - > GetWidth ( ) ;
int height = video - > GetHeight ( ) ;
int fps = video - > GetFramerate ( ) ;
2012-11-06 19:32:01 -08:00
DOM_CAMERA_LOGI ( " recording preview format: %d x %d (%d fps) \n " , width , height , fps ) ;
2012-09-28 22:30:52 -07:00
// create and return new preview stream object
2012-10-23 15:30:28 -07:00
nsCOMPtr < GetPreviewStreamResult > getPreviewStreamResult = new GetPreviewStreamResult ( this , width , height , fps , aGetPreviewStreamVideoMode - > mOnSuccessCb , mWindowId ) ;
2012-09-28 22:30:52 -07:00
rv = NS_DispatchToMainThread ( getPreviewStreamResult ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to dispatch GetPreviewStreamVideoMode() onSuccess callback to main thread! " ) ;
return rv ;
}
return NS_OK ;
}
2012-12-23 07:54:54 -08:00
nsresult
nsGonkCameraControl : : ReleaseHardwareImpl ( ReleaseHardwareTask * aReleaseHardware )
{
DOM_CAMERA_LOGT ( " %s:%d : this=%p \n " , __func__ , __LINE__ , this ) ;
// if we're recording, stop recording
if ( mRecorder ) {
DOM_CAMERA_LOGI ( " shutting down existing video recorder \n " ) ;
mRecorder - > stop ( ) ;
mRecorder = nullptr ;
}
// stop the preview
StopPreviewInternal ( true /* forced */ ) ;
// release the hardware handle
2013-03-08 11:43:33 -08:00
if ( mCameraHw . get ( ) ) {
mCameraHw - > Close ( ) ;
mCameraHw . clear ( ) ;
}
2012-12-23 07:54:54 -08:00
2013-01-08 15:43:50 -08:00
if ( aReleaseHardware ) {
2012-12-23 07:54:54 -08:00
nsCOMPtr < nsIRunnable > releaseHardwareResult = new ReleaseHardwareResult ( aReleaseHardware - > mOnSuccessCb , mWindowId ) ;
return NS_DispatchToMainThread ( releaseHardwareResult ) ;
}
return NS_OK ;
}
2012-10-23 15:30:28 -07:00
already_AddRefed < GonkRecorderProfileManager >
nsGonkCameraControl : : GetGonkRecorderProfileManager ( )
{
if ( ! mProfileManager ) {
2013-02-11 11:37:50 -08:00
nsTArray < idl : : CameraSize > sizes ;
2012-10-23 15:30:28 -07:00
nsresult rv = GetVideoSizes ( sizes ) ;
NS_ENSURE_SUCCESS ( rv , nullptr ) ;
mProfileManager = new GonkRecorderProfileManager ( mCameraId ) ;
mProfileManager - > SetSupportedResolutions ( sizes ) ;
}
nsRefPtr < GonkRecorderProfileManager > profileMgr = mProfileManager ;
return profileMgr . forget ( ) ;
}
already_AddRefed < RecorderProfileManager >
nsGonkCameraControl : : GetRecorderProfileManagerImpl ( )
{
nsRefPtr < RecorderProfileManager > profileMgr = GetGonkRecorderProfileManager ( ) ;
return profileMgr . forget ( ) ;
}
nsresult
2013-02-11 11:37:50 -08:00
nsGonkCameraControl : : GetVideoSizes ( nsTArray < idl : : CameraSize > & aVideoSizes )
2012-10-23 15:30:28 -07:00
{
aVideoSizes . Clear ( ) ;
2013-07-09 16:33:29 -07:00
android : : Vector < Size > sizes ;
2013-11-13 11:24:20 -08:00
{
RwAutoLockRead lock ( mRwLock ) ;
mParams . getSupportedVideoSizes ( sizes ) ;
if ( sizes . size ( ) = = 0 ) {
DOM_CAMERA_LOGI ( " Camera doesn't support video independent of the preview \n " ) ;
mParams . getSupportedPreviewSizes ( sizes ) ;
}
2012-10-23 15:30:28 -07:00
}
if ( sizes . size ( ) = = 0 ) {
DOM_CAMERA_LOGW ( " Camera doesn't report any supported video sizes at all \n " ) ;
return NS_OK ;
}
for ( size_t i = 0 ; i < sizes . size ( ) ; + + i ) {
2013-02-11 11:37:50 -08:00
idl : : CameraSize size ;
2012-10-23 15:30:28 -07:00
size . width = sizes [ i ] . width ;
size . height = sizes [ i ] . height ;
aVideoSizes . AppendElement ( size ) ;
}
return NS_OK ;
}
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 ) ;
}
2013-01-24 10:41:18 -08:00
void
ReceiveImageError ( nsGonkCameraControl * gc )
{
gc - > TakePictureError ( ) ;
}
2012-07-30 14:59:05 -07:00
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 .
*/
2013-07-24 19:13:35 -07:00
GrallocImage * videoImage = static_cast < GrallocImage * > ( aImage ) ;
GrallocImage : : GrallocData data ;
2012-09-04 18:01:56 -07:00
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
{
2013-07-24 19:13:35 -07:00
if ( ! gc - > ReceiveFrame ( aBuffer , ImageFormat : : GRALLOC_PLANAR_YCBCR , GonkFrameBuilder ) ) {
2012-09-07 13:23:01 -07:00
aBuffer - > Unlock ( ) ;
}
2012-07-30 14:59:05 -07:00
}
2012-09-30 17:37:47 -07:00
void
OnShutter ( nsGonkCameraControl * gc )
{
gc - > OnShutter ( ) ;
}
void
OnClosed ( nsGonkCameraControl * gc )
{
gc - > OnClosed ( ) ;
}
2012-07-30 14:59:05 -07:00
} // namespace mozilla