Commit 6663e0d0 authored by Kuo Jen Wei's avatar Kuo Jen Wei Committed by Commit Bot

[CCA] Convert modes.js into ES6 module.

Bug: 141518780
Test: Pass closure compiler check, tast run <DUT> 'camera.CCAUI*' on
both HALv1 and v3 devices.

Change-Id: Iac9a59809856274b86b0bca1c182576449d37133
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1988086
Commit-Queue: Kuo Jen Wei <inker@chromium.org>
Auto-Submit: Kuo Jen Wei <inker@chromium.org>
Reviewed-by: default avatarShik Chen <shik@chromium.org>
Cr-Commit-Position: refs/heads/master@{#728477}
parent 86fed075
...@@ -2,34 +2,38 @@ ...@@ -2,34 +2,38 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
'use strict'; import {assert, assertInstanceof} from '../../chrome_util.js';
import {CaptureCandidate, // eslint-disable-line no-unused-vars
/** ConstraintsPreferrer, // eslint-disable-line no-unused-vars
* Namespace for the Camera app. PhotoConstraintsPreferrer, // eslint-disable-line no-unused-vars
*/ VideoConstraintsPreferrer, // eslint-disable-line no-unused-vars
var cca = cca || {}; } from '../../device/constraints_preferrer.js';
import {Filenamer} from '../../models/filenamer.js';
/** import * as filesystem from '../../models/filesystem.js';
* Namespace for views. // eslint-disable-next-line no-unused-vars
*/ import {VideoSaver} from '../../models/video_saver_interface.js';
cca.views = cca.views || {}; import {DeviceOperator, parseMetadata} from '../../mojo/device_operator.js';
import {CrosImageCapture} from '../../mojo/image_capture.js';
/** import {PerfEvent} from '../../perf.js';
* Namespace for Camera view. import * as sound from '../../sound.js';
*/ import * as state from '../../state.js';
cca.views.camera = cca.views.camera || {}; import * as toast from '../../toast.js';
import {Resolution,
/* eslint-disable no-unused-vars */ ResolutionList, // eslint-disable-line no-unused-vars
} from '../../type.js';
import {Mode} from '../../type.js';
import * as util from '../../util.js';
import {RecordTime} from './recordtime.js';
/** /**
* Contains video recording result. * Contains video recording result.
* @typedef {{ * @typedef {{
* resolution: {width: number, height: number}, * resolution: {width: number, height: number},
* duration: number, * duration: number,
* videoSaver: !cca.models.VideoSaver, * videoSaver: !VideoSaver,
* }} * }}
*/ */
cca.views.camera.VideoResult; export let VideoResult;
/** /**
* Contains photo taking result. * Contains photo taking result.
...@@ -38,55 +42,55 @@ cca.views.camera.VideoResult; ...@@ -38,55 +42,55 @@ cca.views.camera.VideoResult;
* blob: !Blob, * blob: !Blob,
* }} * }}
*/ */
cca.views.camera.PhotoResult; export let PhotoResult;
/** /**
* Callback to trigger mode switching. * Callback to trigger mode switching.
* return {!Promise} * return {!Promise}
* @typedef {function(): !Promise} * @typedef {function(): !Promise}
*/ */
cca.views.camera.DoSwitchMode; export let DoSwitchMode;
/** /**
* Callback for saving photo capture result. * Callback for saving photo capture result.
* param {!cca.views.camera.PhotoResult} Captured photo result. * param {!PhotoResult} Captured photo result.
* param {string} Name of the photo result to be saved as. * param {string} Name of the photo result to be saved as.
* return {!Promise} * return {!Promise}
* @typedef {function(cca.views.camera.PhotoResult, string): !Promise} * @typedef {function(PhotoResult, string): !Promise}
*/ */
cca.views.camera.DoSavePhoto; export let DoSavePhoto;
/** /**
* Callback for allocating VideoSaver to save video capture result. * Callback for allocating VideoSaver to save video capture result.
* @typedef {function(): !Promise<!cca.models.VideoSaver>} * @typedef {function(): !Promise<!VideoSaver>}
*/ */
cca.views.camera.CreateVideoSaver; export let CreateVideoSaver;
/** /**
* Callback for saving video capture result. * Callback for saving video capture result.
* param {!cca.views.camera.VideoResult} Captured video result. * param {!VideoResult} Captured video result.
* param {string} Name of the video result to be saved as. * param {string} Name of the video result to be saved as.
* return {!Promise} * return {!Promise}
* @typedef {function(!cca.views.camera.VideoResult, string): !Promise} * @typedef {function(!VideoResult, string): !Promise}
*/ */
cca.views.camera.DoSaveVideo; export let DoSaveVideo;
/** /**
* Callback for playing shutter effect. * Callback for playing shutter effect.
* @typedef {function()} * @typedef {function()}
*/ */
cca.views.camera.PlayShutterEffect; export let PlayShutterEffect;
/* eslint-enable no-unused-vars */ /* eslint-disable no-unused-vars */
/** /**
* The abstract interface for the mode configuration. * The abstract interface for the mode configuration.
* @interface * @interface
*/ */
cca.views.camera.ModeConfig = class { class ModeConfig {
/** /**
* Factory function to create capture object for this mode. * Factory function to create capture object for this mode.
* @return {!cca.views.camera.ModeBase} * @return {!ModeBase}
* @abstract * @abstract
*/ */
captureFactory() {} captureFactory() {}
...@@ -111,14 +115,14 @@ cca.views.camera.ModeConfig = class { ...@@ -111,14 +115,14 @@ cca.views.camera.ModeConfig = class {
/** /**
* HALv3 constraints preferrer for this mode. * HALv3 constraints preferrer for this mode.
* @return {!cca.device.ConstraintsPreferrer} * @return {!ConstraintsPreferrer}
* @abstract * @abstract
*/ */
get constraintsPreferrer() {} get constraintsPreferrer() {}
/** /**
* Mode to be fallbacked to when fail to configure this mode. * Mode to be fallbacked to when fail to configure this mode.
* @return {!cca.Mode} * @return {!Mode}
* @abstract * @abstract
*/ */
get nextMode() {} get nextMode() {}
...@@ -131,34 +135,36 @@ cca.views.camera.ModeConfig = class { ...@@ -131,34 +135,36 @@ cca.views.camera.ModeConfig = class {
get captureIntent() {} get captureIntent() {}
/* eslint-enable getter-return */ /* eslint-enable getter-return */
}; }
/* eslint-enable no-unused-vars */
/** /**
* Mode controller managing capture sequence of different camera mode. * Mode controller managing capture sequence of different camera mode.
*/ */
cca.views.camera.Modes = class { export class Modes {
/** /**
* @param {!cca.Mode} defaultMode Default mode to be switched to. * @param {!Mode} defaultMode Default mode to be switched to.
* @param {!cca.device.PhotoConstraintsPreferrer} photoPreferrer * @param {!PhotoConstraintsPreferrer} photoPreferrer
* @param {!cca.device.VideoConstraintsPreferrer} videoPreferrer * @param {!VideoConstraintsPreferrer} videoPreferrer
* @param {!cca.views.camera.DoSwitchMode} doSwitchMode * @param {!DoSwitchMode} doSwitchMode
* @param {!cca.views.camera.DoSavePhoto} doSavePhoto * @param {!DoSavePhoto} doSavePhoto
* @param {!cca.views.camera.CreateVideoSaver} createVideoSaver * @param {!CreateVideoSaver} createVideoSaver
* @param {!cca.views.camera.DoSaveVideo} doSaveVideo * @param {!DoSaveVideo} doSaveVideo
* @param {!cca.views.camera.PlayShutterEffect} playShutterEffect * @param {!PlayShutterEffect} playShutterEffect
*/ */
constructor( constructor(
defaultMode, photoPreferrer, videoPreferrer, doSwitchMode, doSavePhoto, defaultMode, photoPreferrer, videoPreferrer, doSwitchMode, doSavePhoto,
createVideoSaver, doSaveVideo, playShutterEffect) { createVideoSaver, doSaveVideo, playShutterEffect) {
/** /**
* @type {!cca.views.camera.DoSwitchMode} * @type {!DoSwitchMode}
* @private * @private
*/ */
this.doSwitchMode_ = doSwitchMode; this.doSwitchMode_ = doSwitchMode;
/** /**
* Capture controller of current camera mode. * Capture controller of current camera mode.
* @type {?cca.views.camera.ModeBase} * @type {?ModeBase}
*/ */
this.current = null; this.current = null;
...@@ -174,10 +180,10 @@ cca.views.camera.Modes = class { ...@@ -174,10 +180,10 @@ cca.views.camera.Modes = class {
* @private * @private
*/ */
this.modesGroup_ = this.modesGroup_ =
/** @type {!HTMLElement} */ (document.querySelector('#modes-group')); assertInstanceof(document.querySelector('#modes-group'), HTMLElement);
/** /**
* @type {?cca.Resolution} * @type {?Resolution}
* @private * @private
*/ */
this.captureResolution_ = null; this.captureResolution_ = null;
...@@ -190,7 +196,7 @@ cca.views.camera.Modes = class { ...@@ -190,7 +196,7 @@ cca.views.camera.Modes = class {
* constraints-candidates. * constraints-candidates.
*/ */
const getV1Constraints = async function(videoMode, deviceId) { const getV1Constraints = async function(videoMode, deviceId) {
const defaultFacing = await cca.util.getDefaultFacing(); const defaultFacing = await util.getDefaultFacing();
return [ return [
{ {
aspectRatio: {ideal: videoMode ? 1.7777777778 : 1.3333333333}, aspectRatio: {ideal: videoMode ? 1.7777777778 : 1.3333333333},
...@@ -201,7 +207,7 @@ cca.views.camera.Modes = class { ...@@ -201,7 +207,7 @@ cca.views.camera.Modes = class {
width: {min: 640}, width: {min: 640},
frameRate: {min: 24}, frameRate: {min: 24},
}, },
].map((constraint) => { ].map((/** !MediaTrackConstraints */ constraint) => {
if (deviceId) { if (deviceId) {
constraint.deviceId = {exact: deviceId}; constraint.deviceId = {exact: deviceId};
} else { } else {
...@@ -219,49 +225,49 @@ cca.views.camera.Modes = class { ...@@ -219,49 +225,49 @@ cca.views.camera.Modes = class {
/** /**
* Mode classname and related functions and attributes. * Mode classname and related functions and attributes.
* @type {!Object<!cca.Mode, !cca.views.camera.ModeConfig>} * @type {!Object<!Mode, !ModeConfig>}
* @private * @private
*/ */
this.allModes_ = { this.allModes_ = {
[cca.Mode.VIDEO]: { [Mode.VIDEO]: {
captureFactory: () => new cca.views.camera.Video( captureFactory: () => new Video(
/** @type {!MediaStream} */ (this.stream_), createVideoSaver, assertInstanceof(this.stream_, MediaStream), createVideoSaver,
doSaveVideo), doSaveVideo),
isSupported: async () => true, isSupported: async () => true,
constraintsPreferrer: videoPreferrer, constraintsPreferrer: videoPreferrer,
getV1Constraints: getV1Constraints.bind(this, true), getV1Constraints: getV1Constraints.bind(this, true),
nextMode: cca.Mode.PHOTO, nextMode: Mode.PHOTO,
captureIntent: cros.mojom.CaptureIntent.VIDEO_RECORD, captureIntent: cros.mojom.CaptureIntent.VIDEO_RECORD,
}, },
[cca.Mode.PHOTO]: { [Mode.PHOTO]: {
captureFactory: () => new cca.views.camera.Photo( captureFactory: () => new Photo(
/** @type {!MediaStream} */ (this.stream_), doSavePhoto, assertInstanceof(this.stream_, MediaStream), doSavePhoto,
this.captureResolution_, playShutterEffect), this.captureResolution_, playShutterEffect),
isSupported: async () => true, isSupported: async () => true,
constraintsPreferrer: photoPreferrer, constraintsPreferrer: photoPreferrer,
getV1Constraints: getV1Constraints.bind(this, false), getV1Constraints: getV1Constraints.bind(this, false),
nextMode: cca.Mode.SQUARE, nextMode: Mode.SQUARE,
captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE, captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
}, },
[cca.Mode.SQUARE]: { [Mode.SQUARE]: {
captureFactory: () => new cca.views.camera.Square( captureFactory: () => new Square(
/** @type {!MediaStream} */ (this.stream_), doSavePhoto, assertInstanceof(this.stream_, MediaStream), doSavePhoto,
this.captureResolution_, playShutterEffect), this.captureResolution_, playShutterEffect),
isSupported: async () => true, isSupported: async () => true,
constraintsPreferrer: photoPreferrer, constraintsPreferrer: photoPreferrer,
getV1Constraints: getV1Constraints.bind(this, false), getV1Constraints: getV1Constraints.bind(this, false),
nextMode: cca.Mode.PHOTO, nextMode: Mode.PHOTO,
captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE, captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
}, },
[cca.Mode.PORTRAIT]: { [Mode.PORTRAIT]: {
captureFactory: () => new cca.views.camera.Portrait( captureFactory: () => new Portrait(
/** @type {!MediaStream} */ (this.stream_), doSavePhoto, assertInstanceof(this.stream_, MediaStream), doSavePhoto,
this.captureResolution_, playShutterEffect), this.captureResolution_, playShutterEffect),
isSupported: async (deviceId) => { isSupported: async (deviceId) => {
if (deviceId === null) { if (deviceId === null) {
return false; return false;
} }
const deviceOperator = await cca.mojo.DeviceOperator.getInstance(); const deviceOperator = await DeviceOperator.getInstance();
if (deviceOperator === null) { if (deviceOperator === null) {
return false; return false;
} }
...@@ -269,40 +275,40 @@ cca.views.camera.Modes = class { ...@@ -269,40 +275,40 @@ cca.views.camera.Modes = class {
}, },
constraintsPreferrer: photoPreferrer, constraintsPreferrer: photoPreferrer,
getV1Constraints: getV1Constraints.bind(this, false), getV1Constraints: getV1Constraints.bind(this, false),
nextMode: cca.Mode.PHOTO, nextMode: Mode.PHOTO,
captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE, captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
}, },
}; };
document.querySelectorAll('.mode-item>input').forEach((element) => { document.querySelectorAll('.mode-item>input').forEach((element) => {
element.addEventListener('click', (event) => { element.addEventListener('click', (event) => {
if (!cca.state.get(cca.state.State.STREAMING) || if (!state.get(state.State.STREAMING) ||
cca.state.get(cca.state.State.TAKING)) { state.get(state.State.TAKING)) {
event.preventDefault(); event.preventDefault();
} }
}); });
element.addEventListener('change', async (event) => { element.addEventListener('change', async (event) => {
if (element.checked) { if (element.checked) {
var mode = element.dataset.mode; const mode = element.dataset.mode;
this.updateModeUI_(mode); this.updateModeUI_(mode);
cca.state.set(cca.state.State.MODE_SWITCHING, true); state.set(state.State.MODE_SWITCHING, true);
const isSuccess = await this.doSwitchMode_(); const isSuccess = await this.doSwitchMode_();
cca.state.set( state.set(state.State.MODE_SWITCHING, false, {hasError: !isSuccess});
cca.state.State.MODE_SWITCHING, false, {hasError: !isSuccess});
} }
}); });
}); });
[cca.state.State.EXPERT, cca.state.State.SAVE_METADATA].forEach((state) => { [state.State.EXPERT, state.State.SAVE_METADATA].forEach(
cca.state.addObserver(state, this.updateSaveMetadata_.bind(this)); (/** state.State */ s) => {
}); state.addObserver(s, this.updateSaveMetadata_.bind(this));
});
// Set default mode when app started. // Set default mode when app started.
this.updateModeUI_(defaultMode); this.updateModeUI_(defaultMode);
} }
/** /**
* @return {!Array<cca.Mode>} * @return {!Array<Mode>}
* @private * @private
*/ */
get allModeNames_() { get allModeNames_() {
...@@ -311,11 +317,11 @@ cca.views.camera.Modes = class { ...@@ -311,11 +317,11 @@ cca.views.camera.Modes = class {
/** /**
* Updates state of mode related UI to the target mode. * Updates state of mode related UI to the target mode.
* @param {!cca.Mode} mode Mode to be toggled. * @param {!Mode} mode Mode to be toggled.
* @private * @private
*/ */
updateModeUI_(mode) { updateModeUI_(mode) {
this.allModeNames_.forEach((m) => cca.state.set(m, m === mode)); this.allModeNames_.forEach((m) => state.set(m, m === mode));
const element = const element =
document.querySelector(`.mode-item>input[data-mode=${mode}]`); document.querySelector(`.mode-item>input[data-mode=${mode}]`);
element.checked = true; element.checked = true;
...@@ -324,7 +330,7 @@ cca.views.camera.Modes = class { ...@@ -324,7 +330,7 @@ cca.views.camera.Modes = class {
wrapper.offsetHeight / 2; wrapper.offsetHeight / 2;
// Make photo mode scroll slightly upper so that the third mode item falls // Make photo mode scroll slightly upper so that the third mode item falls
// in blur area: crbug.com/988869 // in blur area: crbug.com/988869
if (mode === cca.Mode.PHOTO) { if (mode === Mode.PHOTO) {
scrollTop -= 16; scrollTop -= 16;
} }
this.modesGroup_.scrollTo({ this.modesGroup_.scrollTo({
...@@ -337,13 +343,13 @@ cca.views.camera.Modes = class { ...@@ -337,13 +343,13 @@ cca.views.camera.Modes = class {
/** /**
* Gets all mode candidates. Desired trying sequence of candidate modes is * Gets all mode candidates. Desired trying sequence of candidate modes is
* reflected in the order of the returned array. * reflected in the order of the returned array.
* @return {!Array<!cca.Mode>} Mode candidates to be tried out. * @return {!Array<!Mode>} Mode candidates to be tried out.
*/ */
getModeCandidates() { getModeCandidates() {
const tried = {}; const tried = {};
const results = []; const /** !Array<Mode> */ results = [];
let mode = this.allModeNames_.find(cca.state.get); let mode = this.allModeNames_.find(state.get);
cca.assert(mode !== undefined); assert(mode !== undefined);
while (!tried[mode]) { while (!tried[mode]) {
tried[mode] = true; tried[mode] = true;
results.push(mode); results.push(mode);
...@@ -355,10 +361,10 @@ cca.views.camera.Modes = class { ...@@ -355,10 +361,10 @@ cca.views.camera.Modes = class {
/** /**
* Gets all available capture resolution and its corresponding preview * Gets all available capture resolution and its corresponding preview
* constraints for the given mode. * constraints for the given mode.
* @param {!cca.Mode} mode * @param {!Mode} mode
* @param {string} deviceId * @param {string} deviceId
* @param {!cca.ResolutionList} previewResolutions * @param {!ResolutionList} previewResolutions
* @return {!Array<!cca.CaptureCandidate>} * @return {!Array<!CaptureCandidate>}
*/ */
getResolutionCandidates(mode, deviceId, previewResolutions) { getResolutionCandidates(mode, deviceId, previewResolutions) {
return this.allModes_[mode].constraintsPreferrer.getSortedCandidates( return this.allModes_[mode].constraintsPreferrer.getSortedCandidates(
...@@ -368,9 +374,9 @@ cca.views.camera.Modes = class { ...@@ -368,9 +374,9 @@ cca.views.camera.Modes = class {
/** /**
* Gets capture resolution and its corresponding preview constraints for the * Gets capture resolution and its corresponding preview constraints for the
* given mode on camera HALv1 device. * given mode on camera HALv1 device.
* @param {!cca.Mode} mode * @param {!Mode} mode
* @param {?string} deviceId * @param {?string} deviceId
* @return {!Promise<!Array<!cca.CaptureCandidate>>} * @return {!Promise<!Array<!CaptureCandidate>>}
*/ */
async getResolutionCandidatesV1(mode, deviceId) { async getResolutionCandidatesV1(mode, deviceId) {
const previewCandidates = const previewCandidates =
...@@ -380,7 +386,7 @@ cca.views.camera.Modes = class { ...@@ -380,7 +386,7 @@ cca.views.camera.Modes = class {
/** /**
* Gets capture intent for the given mode. * Gets capture intent for the given mode.
* @param {!cca.Mode} mode * @param {!Mode} mode
* @return {cros.mojom.CaptureIntent} Capture intent for the given mode. * @return {cros.mojom.CaptureIntent} Capture intent for the given mode.
*/ */
getCaptureIntent(mode) { getCaptureIntent(mode) {
...@@ -390,12 +396,13 @@ cca.views.camera.Modes = class { ...@@ -390,12 +396,13 @@ cca.views.camera.Modes = class {
/** /**
* Gets supported modes for video device of given device id. * Gets supported modes for video device of given device id.
* @param {?string} deviceId Device id of the video device. * @param {?string} deviceId Device id of the video device.
* @return {!Promise<!Array<!cca.Mode>>} All supported mode for * @return {!Promise<!Array<!Mode>>} All supported mode for
* the video device. * the video device.
*/ */
async getSupportedModes(deviceId) { async getSupportedModes(deviceId) {
let supportedModes = []; const /** !Array<Mode> */ supportedModes = [];
for (const [mode, obj] of Object.entries(this.allModes_)) { for (const mode of this.allModeNames_) {
const obj = this.allModes_[mode];
if (await obj.isSupported(deviceId)) { if (await obj.isSupported(deviceId)) {
supportedModes.push(mode); supportedModes.push(mode);
} }
...@@ -421,10 +428,10 @@ cca.views.camera.Modes = class { ...@@ -421,10 +428,10 @@ cca.views.camera.Modes = class {
/** /**
* Creates and updates new current mode object. * Creates and updates new current mode object.
* @param {!cca.Mode} mode Classname of mode to be updated. * @param {!Mode} mode Classname of mode to be updated.
* @param {!MediaStream} stream Stream of the new switching mode. * @param {!MediaStream} stream Stream of the new switching mode.
* @param {?string} deviceId Device id of currently working video device. * @param {?string} deviceId Device id of currently working video device.
* @param {?cca.Resolution} captureResolution Capturing resolution width and * @param {?Resolution} captureResolution Capturing resolution width and
* height. * height.
* @return {!Promise} * @return {!Promise}
*/ */
...@@ -449,8 +456,7 @@ cca.views.camera.Modes = class { ...@@ -449,8 +456,7 @@ cca.views.camera.Modes = class {
* @private * @private
*/ */
async updateSaveMetadata_() { async updateSaveMetadata_() {
if (cca.state.get(cca.state.State.EXPERT) && if (state.get(state.State.EXPERT) && state.get(state.State.SAVE_METADATA)) {
cca.state.get(cca.state.State.SAVE_METADATA)) {
await this.enableSaveMetadata_(); await this.enableSaveMetadata_();
} else { } else {
await this.disableSaveMetadata_(); await this.disableSaveMetadata_();
...@@ -478,16 +484,16 @@ cca.views.camera.Modes = class { ...@@ -478,16 +484,16 @@ cca.views.camera.Modes = class {
await this.current.removeMetadataObserver(); await this.current.removeMetadataObserver();
} }
} }
}; }
/** /**
* Base class for controlling capture sequence in different camera modes. * Base class for controlling capture sequence in different camera modes.
* @abstract * @abstract
*/ */
cca.views.camera.ModeBase = class { class ModeBase {
/** /**
* @param {!MediaStream} stream * @param {!MediaStream} stream
* @param {?cca.Resolution} captureResolution Capturing resolution width and * @param {?Resolution} captureResolution Capturing resolution width and
* height. * height.
*/ */
constructor(stream, captureResolution) { constructor(stream, captureResolution) {
...@@ -501,7 +507,7 @@ cca.views.camera.ModeBase = class { ...@@ -501,7 +507,7 @@ cca.views.camera.ModeBase = class {
/** /**
* Capture resolution. May be null on device not support of setting * Capture resolution. May be null on device not support of setting
* resolution. * resolution.
* @type {?cca.Resolution} * @type {?Resolution}
* @private * @private
*/ */
this.captureResolution_ = captureResolution; this.captureResolution_ = captureResolution;
...@@ -559,30 +565,34 @@ cca.views.camera.ModeBase = class { ...@@ -559,30 +565,34 @@ cca.views.camera.ModeBase = class {
* @protected * @protected
*/ */
stop_() {} stop_() {}
}; }
/**
* Video recording MIME type. Mkv with AVC1 is the only preferred format.
* @type {string}
*/
const VIDEO_MIMETYPE = 'video/x-matroska;codecs=avc1';
/** /**
* Video mode capture controller. * Video mode capture controller.
* @constructor
* @extends {cca.views.camera.ModeBase}
*/ */
cca.views.camera.Video = class extends cca.views.camera.ModeBase { class Video extends ModeBase {
/** /**
* @param {!MediaStream} stream * @param {!MediaStream} stream
* @param {!cca.views.camera.CreateVideoSaver} createVideoSaver * @param {!CreateVideoSaver} createVideoSaver
* @param {!cca.views.camera.DoSaveVideo} doSaveVideo * @param {!DoSaveVideo} doSaveVideo
*/ */
constructor(stream, createVideoSaver, doSaveVideo) { constructor(stream, createVideoSaver, doSaveVideo) {
super(stream, null); super(stream, null);
/** /**
* @type {!cca.views.camera.CreateVideoSaver} * @type {!CreateVideoSaver}
* @private * @private
*/ */
this.createVideoSaver_ = createVideoSaver; this.createVideoSaver_ = createVideoSaver;
/** /**
* @type {!cca.views.camera.DoSaveVideo} * @type {!DoSaveVideo}
* @private * @private
*/ */
this.doSaveVideo_ = doSaveVideo; this.doSaveVideo_ = doSaveVideo;
...@@ -603,17 +613,17 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase { ...@@ -603,17 +613,17 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase {
/** /**
* Record-time for the elapsed recording time. * Record-time for the elapsed recording time.
* @type {!cca.views.camera.RecordTime} * @type {!RecordTime}
* @private * @private
*/ */
this.recordTime_ = new cca.views.camera.RecordTime(); this.recordTime_ = new RecordTime();
} }
/** /**
* @override * @override
*/ */
async start_() { async start_() {
this.startSound_ = cca.sound.play('#sound-rec-start'); this.startSound_ = sound.play('#sound-rec-start');
try { try {
await this.startSound_; await this.startSound_;
} finally { } finally {
...@@ -622,43 +632,40 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase { ...@@ -622,43 +632,40 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase {
if (this.mediaRecorder_ === null) { if (this.mediaRecorder_ === null) {
try { try {
if (!MediaRecorder.isTypeSupported( if (!MediaRecorder.isTypeSupported(VIDEO_MIMETYPE)) {
cca.views.camera.Video.VIDEO_MIMETYPE)) {
throw new Error('The preferred mimeType is not supported.'); throw new Error('The preferred mimeType is not supported.');
} }
this.mediaRecorder_ = new MediaRecorder( this.mediaRecorder_ =
this.stream_, {mimeType: cca.views.camera.Video.VIDEO_MIMETYPE}); new MediaRecorder(this.stream_, {mimeType: VIDEO_MIMETYPE});
} catch (e) { } catch (e) {
cca.toast.show('error_msg_record_start_failed'); toast.show('error_msg_record_start_failed');
throw e; throw e;
} }
} }
this.recordTime_.start(); this.recordTime_.start();
let /** ?VideoSaver */ videoSaver = null;
let /** number */ duration = 0;
try { try {
var videoSaver = await this.captureVideo_(); videoSaver = await this.captureVideo_();
} catch (e) { } catch (e) {
cca.toast.show('error_msg_empty_recording'); toast.show('error_msg_empty_recording');
throw e; throw e;
} finally { } finally {
var duration = this.recordTime_.stop(); duration = this.recordTime_.stop();
} }
cca.sound.play('#sound-rec-end'); sound.play('#sound-rec-end');
const settings = this.stream_.getVideoTracks()[0].getSettings(); const settings = this.stream_.getVideoTracks()[0].getSettings();
const resolution = new cca.Resolution(settings.width, settings.height); const resolution = new Resolution(settings.width, settings.height);
cca.state.set(cca.perf.PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, true); state.set(PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, true);
try { try {
await this.doSaveVideo_( await this.doSaveVideo_(
{resolution, duration, videoSaver}, {resolution, duration, videoSaver}, (new Filenamer()).newVideoName());
(new cca.models.Filenamer()).newVideoName()); state.set(PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {resolution});
cca.state.set(
cca.perf.PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false,
{resolution});
} catch (e) { } catch (e) {
cca.state.set( state.set(
cca.perf.PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {hasError: true});
{hasError: true});
throw e; throw e;
} }
} }
...@@ -678,7 +685,7 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase { ...@@ -678,7 +685,7 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase {
/** /**
* Starts recording and waits for stop recording event triggered by stop * Starts recording and waits for stop recording event triggered by stop
* shutter. * shutter.
* @return {!Promise<!cca.models.VideoSaver>} Saves recorded video. * @return {!Promise<!VideoSaver>} Saves recorded video.
* @private * @private
*/ */
async captureVideo_() { async captureVideo_() {
...@@ -687,13 +694,13 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase { ...@@ -687,13 +694,13 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let noChunk = true; let noChunk = true;
var ondataavailable = (event) => { const ondataavailable = (event) => {
if (event.data && event.data.size > 0) { if (event.data && event.data.size > 0) {
noChunk = false; noChunk = false;
saver.write(event.data); saver.write(event.data);
} }
}; };
var onstop = (event) => { const onstop = (event) => {
this.mediaRecorder_.removeEventListener( this.mediaRecorder_.removeEventListener(
'dataavailable', ondataavailable); 'dataavailable', ondataavailable);
this.mediaRecorder_.removeEventListener('stop', onstop); this.mediaRecorder_.removeEventListener('stop', onstop);
...@@ -710,39 +717,31 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase { ...@@ -710,39 +717,31 @@ cca.views.camera.Video = class extends cca.views.camera.ModeBase {
this.mediaRecorder_.start(3000); this.mediaRecorder_.start(3000);
}); });
} }
}; }
/**
* Video recording MIME type. Mkv with AVC1 is the only preferred
* format.
* @type {string}
* @const
*/
cca.views.camera.Video.VIDEO_MIMETYPE = 'video/x-matroska;codecs=avc1';
/** /**
* Photo mode capture controller. * Photo mode capture controller.
*/ */
cca.views.camera.Photo = class extends cca.views.camera.ModeBase { class Photo extends ModeBase {
/** /**
* @param {!MediaStream} stream * @param {!MediaStream} stream
* @param {!cca.views.camera.DoSavePhoto} doSavePhoto * @param {!DoSavePhoto} doSavePhoto
* @param {?cca.Resolution} captureResolution * @param {?Resolution} captureResolution
* @param {!cca.views.camera.PlayShutterEffect} playShutterEffect * @param {!PlayShutterEffect} playShutterEffect
*/ */
constructor(stream, doSavePhoto, captureResolution, playShutterEffect) { constructor(stream, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, captureResolution); super(stream, captureResolution);
/** /**
* Callback for saving picture. * Callback for saving picture.
* @type {!cca.views.camera.DoSavePhoto} * @type {!DoSavePhoto}
* @protected * @protected
*/ */
this.doSavePhoto_ = doSavePhoto; this.doSavePhoto_ = doSavePhoto;
/** /**
* ImageCapture object to capture still photos. * CrosImageCapture object to capture still photos.
* @type {?cca.mojo.ImageCapture} * @type {?CrosImageCapture}
* @private * @private
*/ */
this.crosImageCapture_ = null; this.crosImageCapture_ = null;
...@@ -763,7 +762,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -763,7 +762,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
/** /**
* Callback for playing shutter effect. * Callback for playing shutter effect.
* @type {!cca.views.camera.PlayShutterEffect} * @type {!PlayShutterEffect}
* @protected * @protected
*/ */
this.playShutterEffect_ = playShutterEffect; this.playShutterEffect_ = playShutterEffect;
...@@ -775,7 +774,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -775,7 +774,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
async start_() { async start_() {
if (this.crosImageCapture_ === null) { if (this.crosImageCapture_ === null) {
this.crosImageCapture_ = this.crosImageCapture_ =
new cca.mojo.ImageCapture(this.stream_.getVideoTracks()[0]); new CrosImageCapture(this.stream_.getVideoTracks()[0]);
} }
await this.takePhoto_(); await this.takePhoto_();
...@@ -787,9 +786,9 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -787,9 +786,9 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
* @private * @private
*/ */
async takePhoto_() { async takePhoto_() {
const imageName = (new cca.models.Filenamer()).newImageName(); const imageName = (new Filenamer()).newImageName();
if (this.metadataObserverId_ !== null) { if (this.metadataObserverId_ !== null) {
this.metadataNames_.push(cca.models.Filenamer.getMetadataName(imageName)); this.metadataNames_.push(Filenamer.getMetadataName(imageName));
} }
let photoSettings; let photoSettings;
...@@ -810,19 +809,16 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -810,19 +809,16 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
const results = await this.crosImageCapture_.takePhoto(photoSettings); const results = await this.crosImageCapture_.takePhoto(photoSettings);
this.playShutterEffect_(); this.playShutterEffect_();
cca.state.set(cca.perf.PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, true); state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, true);
const blob = await results[0]; const blob = await results[0];
const image = await cca.util.blobToImage(blob); const image = await util.blobToImage(blob);
const resolution = new cca.Resolution(image.width, image.height); const resolution = new Resolution(image.width, image.height);
await this.doSavePhoto_({resolution, blob}, imageName); await this.doSavePhoto_({resolution, blob}, imageName);
cca.state.set( state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {resolution});
cca.perf.PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false,
{resolution});
} catch (e) { } catch (e) {
cca.state.set( state.set(
cca.perf.PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {hasError: true});
{hasError: true}); toast.show('error_msg_take_photo_failed');
cca.toast.show('error_msg_take_photo_failed');
throw e; throw e;
} }
} }
...@@ -836,7 +832,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -836,7 +832,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
return; return;
} }
const deviceOperator = await cca.mojo.DeviceOperator.getInstance(); const deviceOperator = await DeviceOperator.getInstance();
if (!deviceOperator) { if (!deviceOperator) {
return; return;
} }
...@@ -858,11 +854,11 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -858,11 +854,11 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
continue; continue;
} }
const val = cca.mojo.parseMetadata(entry); const val = parseMetadata(entry);
parsedMetadata[key] = val; parsedMetadata[key] = val;
} }
cca.models.FileSystem.saveBlob( filesystem.saveBlob(
new Blob( new Blob(
[JSON.stringify(parsedMetadata, null, 2)], [JSON.stringify(parsedMetadata, null, 2)],
{type: 'application/json'}), {type: 'application/json'}),
...@@ -883,7 +879,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -883,7 +879,7 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
return; return;
} }
const deviceOperator = await cca.mojo.DeviceOperator.getInstance(); const deviceOperator = await DeviceOperator.getInstance();
if (!deviceOperator) { if (!deviceOperator) {
return; return;
} }
...@@ -897,17 +893,17 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase { ...@@ -897,17 +893,17 @@ cca.views.camera.Photo = class extends cca.views.camera.ModeBase {
} }
this.metadataObserverId_ = null; this.metadataObserverId_ = null;
} }
}; }
/** /**
* Square mode capture controller. * Square mode capture controller.
*/ */
cca.views.camera.Square = class extends cca.views.camera.Photo { class Square extends Photo {
/** /**
* @param {!MediaStream} stream * @param {!MediaStream} stream
* @param {!cca.views.camera.DoSavePhoto} doSavePhoto * @param {!DoSavePhoto} doSavePhoto
* @param {?cca.Resolution} captureResolution * @param {?Resolution} captureResolution
* @param {!cca.views.camera.PlayShutterEffect} playShutterEffect * @param {!PlayShutterEffect} playShutterEffect
*/ */
constructor(stream, doSavePhoto, captureResolution, playShutterEffect) { constructor(stream, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, doSavePhoto, captureResolution, playShutterEffect); super(stream, doSavePhoto, captureResolution, playShutterEffect);
...@@ -917,8 +913,7 @@ cca.views.camera.Square = class extends cca.views.camera.Photo { ...@@ -917,8 +913,7 @@ cca.views.camera.Square = class extends cca.views.camera.Photo {
// orientation information. Corrects the orientation before the square // orientation information. Corrects the orientation before the square
// cut. // cut.
result.blob = await new Promise( result.blob = await new Promise(
(resolve, reject) => (resolve, reject) => util.orientPhoto(result.blob, resolve, reject));
cca.util.orientPhoto(result.blob, resolve, reject));
result.blob = await this.cropSquare(result.blob); result.blob = await this.cropSquare(result.blob);
await doSavePhoto(result, ...args); await doSavePhoto(result, ...args);
}; };
...@@ -930,7 +925,7 @@ cca.views.camera.Square = class extends cca.views.camera.Photo { ...@@ -930,7 +925,7 @@ cca.views.camera.Square = class extends cca.views.camera.Photo {
* @return {!Promise<!Blob>} Promise with result cropped square image. * @return {!Promise<!Blob>} Promise with result cropped square image.
*/ */
async cropSquare(blob) { async cropSquare(blob) {
const img = await cca.util.blobToImage(blob); const img = await util.blobToImage(blob);
let side = Math.min(img.width, img.height); let side = Math.min(img.width, img.height);
let canvas = document.createElement('canvas'); let canvas = document.createElement('canvas');
canvas.width = side; canvas.width = side;
...@@ -945,17 +940,17 @@ cca.views.camera.Square = class extends cca.views.camera.Photo { ...@@ -945,17 +940,17 @@ cca.views.camera.Square = class extends cca.views.camera.Photo {
croppedBlob.resolution = blob.resolution; croppedBlob.resolution = blob.resolution;
return croppedBlob; return croppedBlob;
} }
}; }
/** /**
* Portrait mode capture controller. * Portrait mode capture controller.
*/ */
cca.views.camera.Portrait = class extends cca.views.camera.Photo { class Portrait extends Photo {
/** /**
* @param {!MediaStream} stream * @param {!MediaStream} stream
* @param {!cca.views.camera.DoSavePhoto} doSavePhoto * @param {!DoSavePhoto} doSavePhoto
* @param {?cca.Resolution} captureResolution * @param {?Resolution} captureResolution
* @param {!cca.views.camera.PlayShutterEffect} playShutterEffect * @param {!PlayShutterEffect} playShutterEffect
*/ */
constructor(stream, doSavePhoto, captureResolution, playShutterEffect) { constructor(stream, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, doSavePhoto, captureResolution, playShutterEffect); super(stream, doSavePhoto, captureResolution, playShutterEffect);
...@@ -967,7 +962,7 @@ cca.views.camera.Portrait = class extends cca.views.camera.Photo { ...@@ -967,7 +962,7 @@ cca.views.camera.Portrait = class extends cca.views.camera.Photo {
async start_() { async start_() {
if (this.crosImageCapture_ === null) { if (this.crosImageCapture_ === null) {
this.crosImageCapture_ = this.crosImageCapture_ =
new cca.mojo.ImageCapture(this.stream_.getVideoTracks()[0]); new CrosImageCapture(this.stream_.getVideoTracks()[0]);
} }
let photoSettings; let photoSettings;
...@@ -984,46 +979,54 @@ cca.views.camera.Portrait = class extends cca.views.camera.Photo { ...@@ -984,46 +979,54 @@ cca.views.camera.Portrait = class extends cca.views.camera.Photo {
}); });
} }
const filenamer = new cca.models.Filenamer(); const filenamer = new Filenamer();
const refImageName = filenamer.newBurstName(false); const refImageName = filenamer.newBurstName(false);
const portraitImageName = filenamer.newBurstName(true); const portraitImageName = filenamer.newBurstName(true);
if (this.metadataObserverId_ !== null) { if (this.metadataObserverId_ !== null) {
[refImageName, portraitImageName].forEach((imageName) => { [refImageName, portraitImageName].forEach((/** string */ imageName) => {
this.metadataNames_.push( this.metadataNames_.push(Filenamer.getMetadataName(imageName));
cca.models.Filenamer.getMetadataName(imageName));
}); });
} }
let /** ?Promise<!Blob> */ reference;
let /** ?Promise<!Blob> */ portrait;
try { try {
var [reference, portrait] = await this.crosImageCapture_.takePhoto( [reference, portrait] = await this.crosImageCapture_.takePhoto(
photoSettings, [cros.mojom.Effect.PORTRAIT_MODE]); photoSettings, [cros.mojom.Effect.PORTRAIT_MODE]);
this.playShutterEffect_(); this.playShutterEffect_();
} catch (e) { } catch (e) {
cca.toast.show('error_msg_take_photo_failed'); toast.show('error_msg_take_photo_failed');
throw e; throw e;
} }
cca.state.set( state.set(PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, true);
cca.perf.PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, true);
let hasError = false; let hasError = false;
const [refSave, portraitSave] = [
[reference, refImageName], /**
[portrait, portraitImageName], * @param {!Promise<!Blob>} p
].map(async ([p, imageName]) => { * @param {string} imageName
* @return {!Promise}
*/
const saveResult = async (p, imageName) => {
const isPortrait = Object.is(p, portrait); const isPortrait = Object.is(p, portrait);
let /** ?Blob */ blob = null;
try { try {
var blob = await p; blob = await p;
} catch (e) { } catch (e) {
hasError = true; hasError = true;
cca.toast.show( toast.show(
isPortrait ? 'error_msg_take_portrait_photo_failed' : isPortrait ? 'error_msg_take_portrait_photo_failed' :
'error_msg_take_photo_failed'); 'error_msg_take_photo_failed');
throw e; throw e;
} }
const {width, height} = await cca.util.blobToImage(blob); const {width, height} = await util.blobToImage(blob);
await this.doSavePhoto_({resolution: {width, height}, blob}, imageName); await this.doSavePhoto_({resolution: {width, height}, blob}, imageName);
}); };
const refSave = saveResult(reference, refImageName);
const portraitSave = saveResult(portrait, portraitImageName);
try { try {
await portraitSave; await portraitSave;
} catch (e) { } catch (e) {
...@@ -1032,8 +1035,24 @@ cca.views.camera.Portrait = class extends cca.views.camera.Photo { ...@@ -1032,8 +1035,24 @@ cca.views.camera.Portrait = class extends cca.views.camera.Photo {
// TODO(inker): Log non-intended error. // TODO(inker): Log non-intended error.
} }
await refSave; await refSave;
cca.state.set( state.set(
cca.perf.PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false, PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false, {hasError});
{hasError});
} }
}; }
/** @const */
cca.views.camera.VideoResult = VideoResult;
/** @const */
cca.views.camera.PhotoResult = PhotoResult;
/** @const */
cca.views.camera.DoSwitchMode = DoSwitchMode;
/** @const */
cca.views.camera.DoSavePhoto = DoSavePhoto;
/** @const */
cca.views.camera.CreateVideoSaver = CreateVideoSaver;
/** @const */
cca.views.camera.DoSaveVideo = DoSaveVideo;
/** @const */
cca.views.camera.PlayShutterEffect = PlayShutterEffect;
/** @const */
cca.views.camera.Modes = Modes;
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
<script type="module" src="../js/views/camera/recordtime.js"></script> <script type="module" src="../js/views/camera/recordtime.js"></script>
<script type="module" src="../js/views/camera/review_result.js"></script> <script type="module" src="../js/views/camera/review_result.js"></script>
<script type="module" src="../js/views/camera/timertick.js"></script> <script type="module" src="../js/views/camera/timertick.js"></script>
<script defer src="../js/views/camera/modes.js"></script> <script type="module" src="../js/views/camera/modes.js"></script>
<script type="module" src="../js/views/dialog.js"></script> <script type="module" src="../js/views/dialog.js"></script>
<script type="module" src="../js/views/settings.js"></script> <script type="module" src="../js/views/settings.js"></script>
<script type="module" src="../js/views/warning.js"></script> <script type="module" src="../js/views/warning.js"></script>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment