Bug 981047 - enable torch mode in low light when video recording, r=dhylands,ehsan

This commit is contained in:
Mike Habicher 2014-04-09 11:53:41 -04:00
parent a227ea0e70
commit 148549b192
7 changed files with 122 additions and 41 deletions

View File

@ -581,7 +581,7 @@ MediaEngineWebRTCVideoSource::StartImpl(webrtc::CaptureCapability aCapability) {
config.mPreviewSize.width = aCapability.width;
config.mPreviewSize.height = aCapability.height;
mCameraControl->Start(&config);
mCameraControl->Set(CAMERA_PARAM_PICTURESIZE, config.mPreviewSize);
mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, config.mPreviewSize);
hal::RegisterScreenConfigurationObserver(this);
}

View File

@ -500,7 +500,7 @@ nsDOMCameraControl::GetPictureSize(JSContext* cx, ErrorResult& aRv)
JS::Rooted<JS::Value> value(cx);
ICameraControl::Size size;
aRv = mCameraControl->Get(CAMERA_PARAM_PICTURESIZE, size);
aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size);
if (aRv.Failed()) {
return value;
}
@ -518,7 +518,7 @@ nsDOMCameraControl::SetPictureSize(JSContext* aCx, JS::Handle<JS::Value> aSize,
}
ICameraControl::Size s = { size.mWidth, size.mHeight };
aRv = mCameraControl->Set(CAMERA_PARAM_PICTURESIZE, s);
aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
}
/* attribute any thumbnailSize */
@ -764,6 +764,7 @@ nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
o.rotation = mOptions.mRotation;
o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes;
o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs;
o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch;
nsresult rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o);
if (NS_SUCCEEDED(rv)) {
return;

View File

@ -65,6 +65,9 @@ nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
, mLastThumbnailSize({0, 0})
, mPreviewFps(30)
, mResumePreviewAfterTakingPicture(false) // XXXmikeh - see bug 950102
, mFlashSupported(false)
, mLuminanceSupported(false)
, mAutoFlashModeOverridden(false)
, mDeferConfigUpdate(0)
, mMediaProfiles(nullptr)
, mRecorder(nullptr)
@ -153,6 +156,14 @@ nsGonkCameraControl::Initialize()
mParams.Get(CAMERA_PARAM_PREVIEWSIZE, mCurrentConfiguration.mPreviewSize);
mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
nsString luminance; // check for support
mParams.Get(CAMERA_PARAM_LUMINANCE, luminance);
mLuminanceSupported = !luminance.IsEmpty();
nsString flashMode;
mParams.Get(CAMERA_PARAM_FLASHMODE, flashMode);
mFlashSupported = !flashMode.IsEmpty();
DOM_CAMERA_LOGI(" - maximum metering areas: %u\n", mCurrentConfiguration.mMaxMeteringAreas);
DOM_CAMERA_LOGI(" - maximum focus areas: %u\n", mCurrentConfiguration.mMaxFocusAreas);
DOM_CAMERA_LOGI(" - default picture size: %u x %u\n",
@ -165,6 +176,14 @@ nsGonkCameraControl::Initialize()
mLastRecorderSize.width, mLastRecorderSize.height);
DOM_CAMERA_LOGI(" - default picture file format: %s\n",
NS_ConvertUTF16toUTF8(mFileFormat).get());
DOM_CAMERA_LOGI(" - luminance reporting: %ssupported\n",
mLuminanceSupported ? "" : "NOT ");
if (mFlashSupported) {
DOM_CAMERA_LOGI(" - flash: supported, default mode '%s'\n",
NS_ConvertUTF16toUTF8(flashMode).get());
} else {
DOM_CAMERA_LOGI(" - flash: NOT supported\n");
}
return NS_OK;
}
@ -382,9 +401,16 @@ nsGonkCameraControl::Set(uint32_t aKey, const nsAString& aValue)
return rv;
}
if (aKey == CAMERA_PARAM_PICTURE_FILEFORMAT) {
// Picture format -- need to keep it for the TakePicture() callback.
mFileFormat = aValue;
switch (aKey) {
case CAMERA_PARAM_PICTURE_FILEFORMAT:
// Picture format -- need to keep it for the TakePicture() callback.
mFileFormat = aValue;
break;
case CAMERA_PARAM_FLASHMODE:
// Explicit flash mode changes always win and stick.
mAutoFlashModeOverridden = false;
break;
}
return PushParameters();
@ -440,7 +466,7 @@ nsresult
nsGonkCameraControl::Set(uint32_t aKey, const Size& aSize)
{
switch (aKey) {
case CAMERA_PARAM_PICTURESIZE:
case CAMERA_PARAM_PICTURE_SIZE:
DOM_CAMERA_LOGI("setting picture size to %ux%u\n", aSize.width, aSize.height);
return SetPictureSize(aSize);
@ -752,7 +778,7 @@ nsGonkCameraControl::SetPictureSizeImpl(const Size& aSize)
return NS_ERROR_FAILURE;
}
nsresult rv = mParams.Set(CAMERA_PARAM_PICTURESIZE, size);
nsresult rv = mParams.Set(CAMERA_PARAM_PICTURE_SIZE, size);
if (NS_FAILED(rv)) {
return rv;
}
@ -865,10 +891,56 @@ nsGonkCameraControl::PullParametersImpl()
return mCameraHw->PullParameters(mParams);
}
nsresult
nsGonkCameraControl::SetupRecordingFlash(bool aAutoEnableLowLightTorch)
{
mAutoFlashModeOverridden = false;
if (!aAutoEnableLowLightTorch || !mLuminanceSupported || !mFlashSupported) {
return NS_OK;
}
DOM_CAMERA_LOGI("Luminance reporting and flash supported\n");
nsresult rv = PullParametersImpl();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsString luminance;
rv = mParams.Get(CAMERA_PARAM_LUMINANCE, luminance);
if (NS_WARN_IF(NS_FAILED(rv))) {
// If we failed to get the luminance, assume it's "high"
return NS_OK;
}
nsString flashMode;
rv = mParams.Get(CAMERA_PARAM_FLASHMODE, flashMode);
if (NS_WARN_IF(NS_FAILED(rv))) {
// If we failed to get the current flash mode, swallow the error
return NS_OK;
}
if (luminance.EqualsASCII("low") && flashMode.EqualsASCII("auto")) {
DOM_CAMERA_LOGI("Low luminance detected, turning on flash\n");
rv = SetAndPush(CAMERA_PARAM_FLASHMODE, NS_LITERAL_STRING("torch"));
if (NS_WARN_IF(NS_FAILED(rv))) {
// If we failed to turn on the flash, swallow the error
return NS_OK;
}
mAutoFlashModeOverridden = true;
}
return NS_OK;
}
nsresult
nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions)
{
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
NS_ENSURE_TRUE(mRecorderProfile, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_FALSE(mRecorder, NS_ERROR_FAILURE);
@ -905,15 +977,24 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri
if (aOptions) {
rv = SetupRecording(fd, aOptions->rotation, aOptions->maxFileSizeBytes,
aOptions->maxVideoLengthMs);
if (NS_SUCCEEDED(rv)) {
rv = SetupRecordingFlash(aOptions->autoEnableLowLightTorch);
}
} else {
rv = SetupRecording(fd, 0, 0, 0);
}
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (mRecorder->start() != OK) {
DOM_CAMERA_LOGE("mRecorder->start() failed\n");
// important: we MUST destroy the recorder if start() fails!
mRecorder = nullptr;
// put the flash back to the 'auto' state
if (mAutoFlashModeOverridden) {
SetAndPush(CAMERA_PARAM_FLASHMODE, NS_LITERAL_STRING("auto"));
}
return NS_ERROR_FAILURE;
}
@ -956,6 +1037,10 @@ nsGonkCameraControl::StopRecordingImpl()
mRecorder = nullptr;
OnRecorderStateChange(CameraControlListener::kRecorderStopped);
if (mAutoFlashModeOverridden) {
SetAndPush(CAMERA_PARAM_FLASHMODE, NS_LITERAL_STRING("auto"));
}
// notify DeviceStorage that the new video file is closed and ready
return NS_DispatchToMainThread(new RecordingComplete(mVideoFile), NS_DISPATCH_NORMAL);
}
@ -1430,7 +1515,9 @@ nsGonkCameraControl::OnRecorderEvent(int msg, int ext1, int ext2)
}
nsresult
nsGonkCameraControl::SetupRecording(int aFd, int aRotation, int64_t aMaxFileSizeBytes, int64_t aMaxVideoLengthMs)
nsGonkCameraControl::SetupRecording(int aFd, int aRotation,
int64_t aMaxFileSizeBytes,
int64_t aMaxVideoLengthMs)
{
RETURN_IF_NO_CAMERA_HW();
@ -1473,6 +1560,7 @@ nsGonkCameraControl::SetupRecording(int aFd, int aRotation, int64_t aMaxFileSize
// recording API needs file descriptor of output file
CHECK_SETARG(mRecorder->setOutputFile(aFd, 0, 0));
CHECK_SETARG(mRecorder->prepare());
return NS_OK;
}
@ -1482,12 +1570,7 @@ nsGonkCameraControl::StopImpl()
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
// if we're recording, stop recording
if (mRecorder) {
DOM_CAMERA_LOGI("Stopping existing video recorder\n");
mRecorder->stop();
mRecorder = nullptr;
OnRecorderStateChange(CameraControlListener::kRecorderStopped);
}
StopRecordingImpl();
// stop the preview
StopPreviewImpl();

View File

@ -117,7 +117,9 @@ protected:
virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() MOZ_OVERRIDE;
already_AddRefed<GonkRecorderProfileManager> GetGonkRecorderProfileManager();
nsresult SetupRecording(int aFd, int aRotation, int64_t aMaxFileSizeBytes, int64_t aMaxVideoLengthMs);
nsresult SetupRecording(int aFd, int aRotation, int64_t aMaxFileSizeBytes,
int64_t aMaxVideoLengthMs);
nsresult SetupRecordingFlash(bool aAutoEnableLowLightTorch);
nsresult SetupVideoMode(const nsAString& aProfile);
nsresult SetPreviewSize(const Size& aSize);
nsresult SetVideoSize(const Size& aSize);
@ -141,6 +143,9 @@ protected:
Size mLastRecorderSize;
uint32_t mPreviewFps;
bool mResumePreviewAfterTakingPicture;
bool mFlashSupported;
bool mLuminanceSupported;
bool mAutoFlashModeOverridden;
Atomic<uint32_t> mDeferConfigUpdate;
GonkCameraParameters mParams;

View File

@ -58,8 +58,6 @@ GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
return KEY_FOCUS_DISTANCES;
case CAMERA_PARAM_EXPOSURECOMPENSATION:
return KEY_EXPOSURE_COMPENSATION;
case CAMERA_PARAM_PICTURESIZE:
return KEY_PICTURE_SIZE;
case CAMERA_PARAM_THUMBNAILQUALITY:
return KEY_JPEG_THUMBNAIL_QUALITY;
case CAMERA_PARAM_PICTURE_SIZE:
@ -81,6 +79,8 @@ GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
// Not every platform defines KEY_ISO_MODE;
// for those that don't, we use the raw string key.
return "iso";
case CAMERA_PARAM_LUMINANCE:
return "luminance-condition";
case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
return KEY_SUPPORTED_PREVIEW_SIZES;
@ -266,8 +266,10 @@ GonkCameraParameters::GetTranslated(uint32_t aKey, nsAString& aValue)
}
if (aKey == CAMERA_PARAM_ISOMODE) {
rv = MapIsoFromGonk(val, aValue);
} else {
} else if(val) {
aValue.AssignASCII(val);
} else {
aValue.Truncate(0);
}
return rv;
}

View File

@ -46,11 +46,11 @@ enum {
CAMERA_PARAM_FOCUSDISTANCEOPTIMUM,
CAMERA_PARAM_FOCUSDISTANCEFAR,
CAMERA_PARAM_EXPOSURECOMPENSATION,
CAMERA_PARAM_PICTURESIZE,
CAMERA_PARAM_THUMBNAILSIZE,
CAMERA_PARAM_THUMBNAILQUALITY,
CAMERA_PARAM_SENSORANGLE,
CAMERA_PARAM_ISOMODE,
CAMERA_PARAM_LUMINANCE,
// supported features
CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
@ -113,6 +113,7 @@ public:
uint32_t rotation;
uint32_t maxFileSizeBytes;
uint32_t maxVideoLengthMs;
bool autoEnableLowLightTorch;
};
struct Configuration {

View File

@ -72,26 +72,6 @@ dictionary CameraPictureOptions
long long dateTime = 0;
};
/* These properties affect the video recording preview, e.g.
{
profile: "1080p",
rotation: 0
}
'profile' is one of the profiles returned by
CameraCapabilities.recorderProfiles'; if this profile is missing,
an arbitrary profile will be chosen.
'rotation' is the degrees clockwise to rotate the preview; if
this option is not supported, it will be ignored; if this option
is missing, the default is 0.
*/
dictionary CameraRecorderOptions
{
DOMString profile;
long rotation;
};
/* These properties affect the actual video recording, e.g.
{
rotation: 0,
@ -117,6 +97,15 @@ dictionary CameraStartRecordingOptions
long rotation = 0;
long long maxFileSizeBytes = 0;
long long maxVideoLengthMs = 0;
/* If startRecording() is called with flashMode set to "auto" and the
camera has determined that the scene is poorly lit, the flash mode
will be automatically changed to "torch" until stopRecording() is
called. During this time, flashMode will reflect the new setting. If
flashMode is changed while recording is in progress, the new setting
will be left as-is on stopRecording(). If the camera does not
support this setting, it will be ignored. */
boolean autoEnableLowLightTorch = false;
};
callback CameraSetConfigurationCallback = void (CameraConfiguration configuration);