Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #18306 from davidflanagan/bug995432-v1.4
Browse files Browse the repository at this point in the history
Merge pull request #18249 from davidflanagan/bug995432
  • Loading branch information
David Flanagan committed Apr 14, 2014
2 parents 3534b48 + 9021261 commit 9b877e7
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 31 deletions.
5 changes: 5 additions & 0 deletions apps/camera/js/config/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ module.exports = {
zoom: {
disabled: false
},
caf: {
// Set this property to true if you want to disable continuous auto focus
// even on hardware that supports it.
disabled: false
},
viewfinder: {
scaleType: 'fill'
},
Expand Down
121 changes: 92 additions & 29 deletions apps/camera/js/lib/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ var model = require('vendor/model');
var recordSpaceMin = constants.RECORD_SPACE_MIN;
var recordSpacePadding = constants.RECORD_SPACE_PADDING;

// More explicit names for the focus modes we care about
var MANUAL_AUTO_FOCUS = 'auto';
var CONTINUOUS_AUTO_FOCUS = 'continuous-picture';

/**
* Locals
*/
Expand Down Expand Up @@ -50,13 +54,23 @@ function Camera(options) {
this.mozCamera = null;
this.cameraList = navigator.mozCameras.getListOfCameras();
this.orientation = options.orientation || orientation;
this.autoFocus = {};
this.video = {
storage: navigator.getDeviceStorage('videos'),
filepath: null,
minSpace: options.recordSpaceMin || recordSpaceMin,
spacePadding : options.recordSpacePadding || recordSpacePadding
};

// If the hardware supports continuous auto focus, we generally want to
// use it. But we do have a option in the settings file to disable it
// at build time.
if (options.cafEnabled !== undefined) {
this.cafEnabled = options.cafEnabled;
} else {
// If the option is not specified at all, assume true
this.cafEnabled = true;
}

debug('initialized');
}

Expand Down Expand Up @@ -182,7 +196,6 @@ Camera.prototype.configureCamera = function(mozCamera) {
this.mozCamera.onShutter = this.onShutter;
this.mozCamera.onPreviewStateChange = this.onPreviewStateChange;
this.mozCamera.onRecorderStateChange = this.onRecorderStateChange;
this.configureFocus(capabilities.focusModes);
this.set('capabilities', this.formatCapabilities(capabilities));
debug('configured camera');
};
Expand Down Expand Up @@ -215,6 +228,7 @@ Camera.prototype.configure = function() {
options.previewSize.height);

this.mozCamera.setConfiguration(options, success, error);
this.configureFocus(this.mode);
this.configureZoom(previewSize);
};

Expand Down Expand Up @@ -260,12 +274,6 @@ Camera.prototype.setRecorderProfile = function(key) {
return this;
};

Camera.prototype.configureFocus = function(modes) {
var supports = this.autoFocus = {};
(modes || []).forEach(function(mode) { supports[mode] = true; });
debug('focus configured', supports);
};

/**
* Sets the current flash mode,
* both on the Camera instance
Expand Down Expand Up @@ -430,46 +438,70 @@ Camera.prototype.takePicture = function(options) {
function onSuccess(blob) {
var image = { blob: blob };
self.resumePreview();
self.set('focus', 'none');
self.emit('newimage', image);
debug('success taking picture');
complete();
}

function complete() {
// If we are in C-AF mode, we have to call resumeContinuousFocus() in
// order to get the camera to resume focusing on what we point it at.
if (self.mozCamera.focusMode === CONTINUOUS_AUTO_FOCUS) {
self.mozCamera.resumeContinuousFocus();
}

self.set('focus', 'none');
self.emit('ready');
}
};

/** Focus the camera, callback when done.
*
* If the camera don't support focus,
* callback is called (sync).
/**
* Focus the camera, invoke the callback asynchronously when done.
*
* If the focus fails, the 'focus' state
* is set, then reset after 1 second.
* If we only have fixed focus, then we call the callback right away
* (but still asynchronously). Otherwise, we call autoFocus to focus
* the camera and call the callback when focus is complete. In C-AF mode
* this process should be fast. In manual AF mode, focusing takes about
* a second and causes a noticeable delay before the picture is taken.
*
* @param {Function} done
* @private
*/
Camera.prototype.focus = function(done) {
if (!this.autoFocus.auto) { return done(); }
var reset = function() { self.set('focus', 'none'); };
var self = this;
var focusMode = this.mozCamera.focusMode;

this.set('focus', 'focusing');
this.mozCamera.autoFocus(onFocus);

function onFocus(success) {
if (success) {
self.set('focus', 'focused');
done();
return;
}
if (focusMode === MANUAL_AUTO_FOCUS || focusMode === CONTINUOUS_AUTO_FOCUS) {
//
// In either focus mode, we call autoFocus() to ensure that the user gets
// a sharp picture. The difference between the two modes is that if
// C-AF is on, it is likely that the camera is already focused, so the
// call to autoFocus() invokes its callback very quickly and we get much
// better response time.
//
// In either case, the callback is passed a boolean specifying whether
// focus was successful or not, and we display a green or red focus ring
// then call the done callback, which takes the picture and clears
// the focus ring.
//
this.set('focus', 'focusing'); // white focus ring

self.set('focus', 'fail');
setTimeout(reset, 1000);
done('failed');
this.mozCamera.autoFocus(function(success) {
if (success) {
self.set('focus', 'focused'); // green focus ring
done();
}
else {
self.set('focus', 'fail'); // red focus ring
done('failed');
}
});
}
else {
// This is fixed focus: there is nothing we can do here so we
// should just call the callback and take the photo. No focus
// happens so we don't display a focus ring.
setTimeout(done);
}
};

Expand Down Expand Up @@ -838,6 +870,37 @@ Camera.prototype.setSceneMode = function(value){
}
};

Camera.prototype.configureFocus = function(captureMode) {
var focusModes = this.get('capabilities').focusModes;

// If we're taking still pictures, and C-AF is enabled and supported
// (and gecko supports resumeContinuousFocus) then use C-AF.
// XXX: once bug 986024 has landed and been uplifted we can remove
// the check for resumeContinuousFocus support
if (captureMode === 'picture') {
if (this.cafEnabled &&
focusModes.indexOf(CONTINUOUS_AUTO_FOCUS) >= 0 &&
this.mozCamera.resumeContinuousFocus) {
this.mozCamera.focusMode = CONTINUOUS_AUTO_FOCUS;
return;
}
}

// Otherwise, we'll use 'auto' mode, if it is supported.
// We do this for video and still pictures. For videos, this mode
// actually does continous focus and it seems to work better than
// the actual 'continuous-video' mode.
if (focusModes.indexOf(MANUAL_AUTO_FOCUS) >= 0) {
this.mozCamera.focusMode = MANUAL_AUTO_FOCUS;
}
else {
// If auto mode is not supported then we presumably have a fixed focus
// camera. Just use the first available focus mode, and don't call
// auto focus. This happens with the front-facing camera, typically
this.mozCamera.focusMode = focusModes[0];
}
};

Camera.prototype.isZoomSupported = function() {
return this.mozCamera.capabilities.zoomRatios.length > 1;
};
Expand Down
5 changes: 4 additions & 1 deletion apps/camera/js/lib/sounds.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@ Sounds.prototype.player = function(name) {
*/
Sounds.prototype.playSound = function(sound) {
if (sound.enabled) {
sound.audio.play();
// cloneNode() lets us play overlapping sounds and is needed when the
// user takes pictures very rapidly.
// See http://robert.ocallahan.org/2011/11/latency-of-html5-sounds.html
sound.audio.cloneNode(true).play();
}
};

Expand Down
3 changes: 2 additions & 1 deletion apps/camera/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ require(['config/require', 'config'], function() {
maxFileSizeBytes: 0,
maxWidth: 0,
maxHeight: 0,
container: document.body
container: document.body,
cafEnabled: settings.caf.enabled()
});

/**
Expand Down

0 comments on commit 9b877e7

Please sign in to comment.