Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2016-10-17 11:34:49 +02:00
Родитель e6711537be d6850a3a86
Коммит c481713ead
279 изменённых файлов: 15293 добавлений и 42311 удалений

Просмотреть файл

@ -130,7 +130,7 @@ SettingsListener.observe('language.current', 'en-US', function(value) {
// =================== RIL ====================
(function RILSettingsToPrefs() {
// DSDS default service IDs
['mms', 'sms', 'telephony', 'voicemail'].forEach(function(key) {
['mms', 'sms', 'telephony'].forEach(function(key) {
SettingsListener.observe('ril.' + key + '.defaultServiceId', 0,
function(value) {
if (value != null) {

Просмотреть файл

@ -165,9 +165,6 @@
#ifdef MOZ_B2G_BT
@RESPATH@/components/dom_bluetooth.xpt
#endif
#ifdef MOZ_B2G_CAMERA
@RESPATH@/components/dom_camera.xpt
#endif
@RESPATH@/components/dom_canvas.xpt
@RESPATH@/components/dom_contacts.xpt
@RESPATH@/components/dom_core.xpt
@ -206,7 +203,6 @@
@RESPATH@/components/dom_tv.xpt
@RESPATH@/components/dom_inputport.xpt
@RESPATH@/components/dom_views.xpt
@RESPATH@/components/dom_voicemail.xpt
#ifdef MOZ_WEBSPEECH
@RESPATH@/components/dom_webspeechrecognition.xpt
#endif
@ -446,12 +442,6 @@
@RESPATH@/components/WifiWorker.manifest
#endif // MOZ_WIDGET_GONK
; Camera
#ifdef MOZ_B2G_CAMERA
@RESPATH@/components/CameraTestHardware.js
@RESPATH@/components/CameraTestHardware.manifest
#endif // MOZ_B2G_CAMERA
; Tethering
#ifdef MOZ_WIDGET_GONK
@RESPATH@/components/TetheringManager.js
@ -499,8 +489,6 @@
#ifndef DISABLE_MOZ_RIL_GEOLOC
@RESPATH@/components/TelephonyService.js
@RESPATH@/components/TelephonyService.manifest
@RESPATH@/components/VoicemailService.js
@RESPATH@/components/VoicemailService.manifest
#endif
#endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL

Просмотреть файл

@ -1659,13 +1659,17 @@
if (isRemote == aShouldBeRemote)
return false;
let tab = this.getTabForBrowser(aBrowser);
let evt = document.createEvent("Events");
evt.initEvent("BeforeTabRemotenessChange", true, false);
tab.dispatchEvent(evt);
let wasActive = document.activeElement == aBrowser;
// Unmap the old outerWindowID.
this._outerWindowIDBrowserMap.delete(aBrowser.outerWindowID);
// Unhook our progress listener.
let tab = this.getTabForBrowser(aBrowser);
let filter = this._tabFilters.get(tab);
let listener = this._tabListeners.get(tab);
aBrowser.webProgress.removeProgressListener(filter);
@ -1749,7 +1753,7 @@
this.getFindBar(tab).browser = aBrowser;
}
let evt = document.createEvent("Events");
evt = document.createEvent("Events");
evt.initEvent("TabRemotenessChange", true, false);
tab.dispatchEvent(evt);

Просмотреть файл

@ -1,81 +1,49 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This test ensures that autoFilled values are not trimmed, unless the user
// selects from the autocomplete popup.
function test() {
waitForExplicitFinish();
add_task(function* setup() {
const PREF_TRIMURL = "browser.urlbar.trimURLs";
const PREF_AUTOFILL = "browser.urlbar.autoFill";
registerCleanupFunction(function () {
registerCleanupFunction(function* () {
Services.prefs.clearUserPref(PREF_TRIMURL);
Services.prefs.clearUserPref(PREF_AUTOFILL);
yield PlacesTestUtils.clearHistory();
gURLBar.handleRevert();
});
Services.prefs.setBoolPref(PREF_TRIMURL, true);
Services.prefs.setBoolPref(PREF_AUTOFILL, true);
// Adding a tab would hit switch-to-tab, so it's safer to just add a visit.
let callback = {
handleError: function () {},
handleResult: function () {},
handleCompletion: continue_test
};
let history = Cc["@mozilla.org/browser/history;1"]
.getService(Ci.mozIAsyncHistory);
history.updatePlaces({ uri: NetUtil.newURI("http://www.autofilltrimurl.com/whatever")
, visits: [ { transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED
, visitDate: Date.now() * 1000
} ]
}, callback);
}
function continue_test() {
function test_autoFill(aTyped, aExpected, aCallback) {
info(`Testing with input: ${aTyped}`);
gURLBar.inputField.value = aTyped.substr(0, aTyped.length - 1);
gURLBar.focus();
gURLBar.selectionStart = aTyped.length - 1;
gURLBar.selectionEnd = aTyped.length - 1;
EventUtils.synthesizeKey(aTyped.substr(-1), {});
waitForSearchComplete(function () {
info(`Got value: ${gURLBar.textValue}`);
is(gURLBar.textValue, aExpected, "Autofilled value is as expected");
aCallback();
});
}
test_autoFill("http://", "http://", function () {
test_autoFill("http://au", "http://autofilltrimurl.com/", function () {
test_autoFill("http://www.autofilltrimurl.com", "http://www.autofilltrimurl.com/", function () {
// Now ensure selecting from the popup correctly trims.
is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
EventUtils.synthesizeKey("VK_DOWN", {});
is(gURLBar.textValue, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
gURLBar.closePopup();
PlacesTestUtils.clearHistory().then(finish);
});
});
yield PlacesTestUtils.addVisits({
uri: "http://www.autofilltrimurl.com/whatever",
transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
});
});
function* promiseSearch(searchtext) {
gURLBar.focus();
gURLBar.inputField.value = searchtext.substr(0, searchtext.length -1);
EventUtils.synthesizeKey(searchtext.substr(-1, 1), {});
yield promiseSearchComplete();
}
var gOnSearchComplete = null;
function waitForSearchComplete(aCallback) {
info("Waiting for onSearchComplete");
if (!gOnSearchComplete) {
gOnSearchComplete = gURLBar.onSearchComplete;
registerCleanupFunction(() => {
gURLBar.onSearchComplete = gOnSearchComplete;
});
}
gURLBar.onSearchComplete = function () {
ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
gOnSearchComplete.apply(gURLBar);
aCallback();
}
}
add_task(function* () {
yield promiseSearch("http://");
is(gURLBar.inputField.value, "http://", "Autofilled value is as expected");
});
add_task(function* () {
yield promiseSearch("http://au");
is(gURLBar.inputField.value, "http://autofilltrimurl.com/", "Autofilled value is as expected");
});
add_task(function* () {
yield promiseSearch("http://www.autofilltrimurl.com");
is(gURLBar.inputField.value, "http://www.autofilltrimurl.com/", "Autofilled value is as expected");
// Now ensure selecting from the popup correctly trims.
is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
EventUtils.synthesizeKey("VK_DOWN", {});
is(gURLBar.inputField.value, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
});

Просмотреть файл

@ -25,9 +25,11 @@ add_task(function* injectJSON() {
});
add_task(function losslessDecode() {
let url = "http://example.com/\u30a2\u30a4\u30a6\u30a8\u30aa";
let urlNoScheme = "example.com/\u30a2\u30a4\u30a6\u30a8\u30aa";
let url = "http://" + urlNoScheme;
gURLBar.textValue = url;
Assert.equal(gURLBar.inputField.value, url,
// Since this is directly setting textValue, it is expected to be trimmed.
Assert.equal(gURLBar.inputField.value, urlNoScheme,
"The string displayed in the textbox should not be escaped");
gURLBar.value = "";
gURLBar.handleRevert();

Просмотреть файл

@ -147,7 +147,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<method name="onBeforeValueGet">
<body><![CDATA[
return {value: this._value};
return { value: this._value };
]]></body>
</method>
@ -919,12 +919,24 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
]]></body>
</method>
<property name="textValue">
<getter><![CDATA[
return this.inputField.value;
]]></getter>
<setter>
<![CDATA[
<!--
onBeforeTextValueSet is called by the base-binding's .textValue getter.
It should return the value that the getter should use.
-->
<method name="onBeforeTextValueGet">
<body><![CDATA[
return { value: this.inputField.value };
]]></body>
</method>
<!--
onBeforeTextValueSet is called by the base-binding's .textValue setter.
It should return the value that the setter should use.
-->
<method name="onBeforeTextValueSet">
<parameter name="aValue"/>
<body><![CDATA[
let val = aValue;
let uri;
try {
uri = makeURI(val);
@ -939,33 +951,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
}
}
// Trim popup selected values, but never trim results coming from
// autofill.
let styles = new Set(
this.popup.selectedIndex == -1 ? [] :
this.mController.getStyleAt(this.popup.selectedIndex).split(/\s+/)
);
if (this.popup.selectedIndex == -1 ||
this.mController
.getStyleAt(this.popup.selectedIndex)
.split(/\s+/).indexOf("autofill") >= 0) {
this._disableTrim = true;
}
this.value = val;
this._disableTrim = false;
// Completing a result should simulate the user typing the result, so
// fire an input event.
let evt = document.createEvent("UIEvents");
evt.initUIEvent("input", true, false, window, 0);
this.mIgnoreInput = true;
this.dispatchEvent(evt);
this.mIgnoreInput = false;
return this.value;
]]>
</setter>
</property>
return val;
]]></body>
</method>
<method name="_parseActionUrl">
<parameter name="aUrl"/>

Просмотреть файл

@ -40,3 +40,58 @@ add_task(function* () {
}
yield BrowserTestUtils.closeWindow(window1);
});
add_task(function* test_currentWindowAfterTabMoved() {
const files = {
"current.html": "<meta charset=utf-8><script src=current.js></script>",
"current.js": function() {
browser.test.onMessage.addListener(msg => {
if (msg === "current") {
browser.windows.getCurrent(win => {
browser.test.sendMessage("id", win.id);
});
}
});
browser.test.sendMessage("ready");
},
};
function background() {
let tabId;
const url = browser.extension.getURL("current.html");
browser.tabs.create({url}).then(tab => {
tabId = tab.id;
});
browser.test.onMessage.addListener(msg => {
if (msg === "move") {
browser.windows.create({tabId}).then(() => {
browser.test.sendMessage("moved");
});
} else if (msg === "close") {
browser.tabs.remove(tabId).then(() => {
browser.test.sendMessage("done");
});
}
});
}
const extension = ExtensionTestUtils.loadExtension({files, background});
yield extension.startup();
yield extension.awaitMessage("ready");
extension.sendMessage("current");
const first = yield extension.awaitMessage("id");
extension.sendMessage("move");
yield extension.awaitMessage("moved");
extension.sendMessage("current");
const second = yield extension.awaitMessage("id");
isnot(first, second, "current window id is different after moving the tab");
extension.sendMessage("close");
yield extension.awaitMessage("done");
yield extension.unload();
});

Просмотреть файл

@ -17,9 +17,10 @@ Cu.import("resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm");
var navigatorBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
this.RecentlyClosedTabsAndWindowsMenuUtils = {
@ -40,8 +41,8 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
aRestoreAllLabel="menuRestoreAllTabs.label") {
let doc = aWindow.document;
let fragment = doc.createDocumentFragment();
if (ss.getClosedTabCount(aWindow) != 0) {
let closedTabs = JSON.parse(ss.getClosedTabData(aWindow));
if (SessionStore.getClosedTabCount(aWindow) != 0) {
let closedTabs = SessionStore.getClosedTabData(aWindow, false);
for (let i = 0; i < closedTabs.length; i++) {
let element = doc.createElementNS(kNSXUL, aTagName);
element.setAttribute("label", closedTabs[i].title);
@ -99,7 +100,7 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
*/
getWindowsFragment: function(aWindow, aTagName, aPrefixRestoreAll=false,
aRestoreAllLabel="menuRestoreAllWindows.label") {
let closedWindowData = JSON.parse(ss.getClosedWindowData());
let closedWindowData = SessionStore.getClosedWindowData(false);
let fragment = aWindow.document.createDocumentFragment();
if (closedWindowData.length != 0) {
let menuLabelString = navigatorBundle.GetStringFromName("menuUndoCloseWindowLabel");

Просмотреть файл

@ -246,8 +246,8 @@ this.SessionStore = {
return SessionStoreInternal.getClosedTabCount(aWindow);
},
getClosedTabData: function ss_getClosedTabDataAt(aWindow) {
return SessionStoreInternal.getClosedTabData(aWindow);
getClosedTabData: function ss_getClosedTabData(aWindow, aAsString = true) {
return SessionStoreInternal.getClosedTabData(aWindow, aAsString);
},
undoCloseTab: function ss_undoCloseTab(aWindow, aIndex) {
@ -262,8 +262,8 @@ this.SessionStore = {
return SessionStoreInternal.getClosedWindowCount();
},
getClosedWindowData: function ss_getClosedWindowData() {
return SessionStoreInternal.getClosedWindowData();
getClosedWindowData: function ss_getClosedWindowData(aAsString = true) {
return SessionStoreInternal.getClosedWindowData(aAsString);
},
undoCloseWindow: function ss_undoCloseWindow(aIndex) {
@ -2184,9 +2184,11 @@ var SessionStoreInternal = {
return DyingWindowCache.get(aWindow)._closedTabs.length;
},
getClosedTabData: function ssi_getClosedTabDataAt(aWindow) {
getClosedTabData: function ssi_getClosedTabData(aWindow, aAsString = true) {
if ("__SSi" in aWindow) {
return JSON.stringify(this._windows[aWindow.__SSi]._closedTabs);
return aAsString ?
JSON.stringify(this._windows[aWindow.__SSi]._closedTabs) :
Cu.cloneInto(this._windows[aWindow.__SSi]._closedTabs, {});
}
if (!DyingWindowCache.has(aWindow)) {
@ -2194,7 +2196,7 @@ var SessionStoreInternal = {
}
let data = DyingWindowCache.get(aWindow);
return JSON.stringify(data._closedTabs);
return aAsString ? JSON.stringify(data._closedTabs) : Cu.cloneInto(data._closedTabs, {});
},
undoCloseTab: function ssi_undoCloseTab(aWindow, aIndex) {
@ -2250,8 +2252,8 @@ var SessionStoreInternal = {
return this._closedWindows.length;
},
getClosedWindowData: function ssi_getClosedWindowData() {
return JSON.stringify(this._closedWindows);
getClosedWindowData: function ssi_getClosedWindowData(aAsString = true) {
return aAsString ? JSON.stringify(this._closedWindows) : Cu.cloneInto(this._closedWindows, {});
},
undoCloseWindow: function ssi_undoCloseWindow(aIndex) {

Просмотреть файл

@ -7,6 +7,8 @@
const TEST_URL = "data:text/html;charset=utf-8,<input%20id=txt>" +
"<input%20type=checkbox%20id=chk>";
Cu.import("resource:///modules/sessionstore/SessionStore.jsm");
/**
* This test ensures that closing a window is a reversible action. We will
* close the the window, restore it and check that all data has been restored.
@ -25,7 +27,7 @@ function test() {
provideWindow(function onTestURLLoaded(newWin) {
newWin.gBrowser.addTab().linkedBrowser.stop();
// mark the window with some unique data to be restored later on
// Mark the window with some unique data to be restored later on.
ss.setWindowValue(newWin, uniqueKey, uniqueValue);
let [txt, chk] = newWin.content.document.querySelectorAll("#txt, #chk");
txt.value = uniqueText;
@ -35,11 +37,17 @@ function test() {
BrowserTestUtils.closeWindow(newWin).then(() => {
is(ss.getClosedWindowCount(), 1,
"The closed window was added to Recently Closed Windows");
let data = JSON.parse(ss.getClosedWindowData())[0];
ok(data.title == TEST_URL && JSON.stringify(data).indexOf(uniqueText) > -1,
let data = SessionStore.getClosedWindowData(false);
// Verify that non JSON serialized data is the same as JSON serialized data.
is(JSON.stringify(data), ss.getClosedWindowData(),
"Non-serialized data is the same as serialized data")
ok(data[0].title == TEST_URL && JSON.stringify(data[0]).indexOf(uniqueText) > -1,
"The closed window data was stored correctly");
// reopen the closed window and ensure its integrity
// Reopen the closed window and ensure its integrity.
let newWin2 = ss.undoCloseWindow(0);
ok(newWin2 instanceof ChromeWindow,
@ -47,9 +55,9 @@ function test() {
is(ss.getClosedWindowCount(), 0,
"The reopened window was removed from Recently Closed Windows");
// SSTabRestored will fire more than once, so we need to make sure we count them
// SSTabRestored will fire more than once, so we need to make sure we count them.
let restoredTabs = 0;
let expectedTabs = data.tabs.length;
let expectedTabs = data[0].tabs.length;
newWin2.addEventListener("SSTabRestored", function sstabrestoredListener(aEvent) {
++restoredTabs;
info("Restored tab " + restoredTabs + "/" + expectedTabs);
@ -57,7 +65,7 @@ function test() {
return;
}
is(restoredTabs, expectedTabs, "correct number of tabs restored");
is(restoredTabs, expectedTabs, "Correct number of tabs restored");
newWin2.removeEventListener("SSTabRestored", sstabrestoredListener, true);
is(newWin2.gBrowser.tabs.length, 2,
@ -71,7 +79,7 @@ function test() {
is(ss.getWindowValue(newWin2, uniqueKey), uniqueValue,
"The window correctly restored the data associated with it");
// clean up
// Clean up.
BrowserTestUtils.closeWindow(newWin2).then(finish);
}, true);
});

Просмотреть файл

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Cu.import("resource:///modules/sessionstore/SessionStore.jsm");
function test() {
/** Test for Bug 461634 **/
@ -30,23 +32,28 @@ function test() {
}
}
// open a window and add the above closed tab list
// Open a window and add the above closed tab list.
let newWin = openDialog(location, "", "chrome,all,dialog=no");
promiseWindowLoaded(newWin).then(() => {
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo",
test_state.windows[0]._closedTabs.length);
ss.setWindowState(newWin, JSON.stringify(test_state), true);
let closedTabs = JSON.parse(ss.getClosedTabData(newWin));
let closedTabs = SessionStore.getClosedTabData(newWin, false);
// Verify that non JSON serialized data is the same as JSON serialized data.
is(JSON.stringify(closedTabs), SessionStore.getClosedTabData(newWin),
"Non-serialized data is the same as serialized data")
is(closedTabs.length, test_state.windows[0]._closedTabs.length,
"Closed tab list has the expected length");
is(countByTitle(closedTabs, FORGET),
test_state.windows[0]._closedTabs.length - remember_count,
"The correct amout of tabs are to be forgotten");
is(countByTitle(closedTabs, REMEMBER), remember_count,
"Everything is set up.");
"Everything is set up");
// all of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE
// All of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE.
ok(testForError(() => ss.forgetClosedTab({}, 0)),
"Invalid window for forgetClosedTab throws");
ok(testForError(() => ss.forgetClosedTab(newWin, -1)),
@ -54,19 +61,24 @@ function test() {
ok(testForError(() => ss.forgetClosedTab(newWin, test_state.windows[0]._closedTabs.length + 1)),
"Invalid tab for forgetClosedTab throws");
// Remove third tab, then first tab
// Remove third tab, then first tab.
ss.forgetClosedTab(newWin, 2);
ss.forgetClosedTab(newWin, null);
closedTabs = JSON.parse(ss.getClosedTabData(newWin));
closedTabs = SessionStore.getClosedTabData(newWin, false);
// Verify that non JSON serialized data is the same as JSON serialized data.
is(JSON.stringify(closedTabs), SessionStore.getClosedTabData(newWin),
"Non-serialized data is the same as serialized data")
is(closedTabs.length, remember_count,
"The correct amout of tabs was removed");
is(countByTitle(closedTabs, FORGET), 0,
"All tabs specifically forgotten were indeed removed");
is(countByTitle(closedTabs, REMEMBER), remember_count,
"... and tabs not specifically forgetten weren't.");
"... and tabs not specifically forgetten weren't");
// clean up
// Clean up.
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
BrowserTestUtils.closeWindow(newWin).then(finish);
});

Просмотреть файл

@ -144,17 +144,30 @@ function* runScenarios(scenarios) {
// Hook up an event listener to make sure that the right
// tabs flip remoteness, and only once.
let flipListener = {
seenTabs: new Set(),
seenBeforeTabs: new Set(),
seenAfterTabs: new Set(),
handleEvent(e) {
let index = Array.from(tabbrowser.tabs).indexOf(e.target);
info(`Saw a tab at index ${index} flip remoteness`);
if (this.seenTabs.has(e.target)) {
Assert.ok(false, "Saw a tab flip remoteness more than once");
switch (e.type) {
case "BeforeTabRemotenessChange":
info(`Saw tab at index ${index} before remoteness flip`);
if (this.seenBeforeTabs.has(e.target)) {
Assert.ok(false, "Saw tab before remoteness flip more than once");
}
this.seenBeforeTabs.add(e.target);
break;
case "TabRemotenessChange":
info(`Saw tab at index ${index} after remoteness flip`);
if (this.seenAfterTabs.has(e.target)) {
Assert.ok(false, "Saw tab after remoteness flip more than once");
}
this.seenAfterTabs.add(e.target);
break;
}
this.seenTabs.add(e.target);
},
};
win.addEventListener("BeforeTabRemotenessChange", flipListener);
win.addEventListener("TabRemotenessChange", flipListener);
// Okay, time to test!
@ -163,6 +176,7 @@ function* runScenarios(scenarios) {
SessionStore.setWindowState(win, state, true);
win.removeEventListener("BeforeTabRemotenessChange", flipListener);
win.removeEventListener("TabRemotenessChange", flipListener);
// Because we know that scenario.expectedFlips and
@ -173,11 +187,15 @@ function* runScenarios(scenarios) {
let expectedRemoteness = scenario.expectedRemoteness[i];
let tab = tabbrowser.tabs[i];
if (expectedToFlip) {
Assert.ok(flipListener.seenTabs.has(tab),
`We should have seen tab at index ${i} flip remoteness`);
Assert.ok(flipListener.seenBeforeTabs.has(tab),
`We should have seen tab at index ${i} before remoteness flip`);
Assert.ok(flipListener.seenAfterTabs.has(tab),
`We should have seen tab at index ${i} after remoteness flip`);
} else {
Assert.ok(!flipListener.seenTabs.has(tab),
`We should not have seen tab at index ${i} flip remoteness`);
Assert.ok(!flipListener.seenBeforeTabs.has(tab),
`We should not have seen tab at index ${i} before remoteness flip`);
Assert.ok(!flipListener.seenAfterTabs.has(tab),
`We should not have seen tab at index ${i} after remoteness flip`);
}
Assert.equal(tab.linkedBrowser.isRemoteBrowser, expectedRemoteness,

Просмотреть файл

@ -1,3 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.6.221
Current extension version is: 1.6.234

Просмотреть файл

@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdf = {}));
// Use strict in our context only - users might not want it
'use strict';
var pdfjsVersion = '1.6.221';
var pdfjsBuild = 'f8bd3d4';
var pdfjsVersion = '1.6.234';
var pdfjsBuild = 'bc3bceb';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?

Просмотреть файл

@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdfWorker = {}));
// Use strict in our context only - users might not want it
'use strict';
var pdfjsVersion = '1.6.221';
var pdfjsBuild = 'f8bd3d4';
var pdfjsVersion = '1.6.234';
var pdfjsBuild = 'bc3bceb';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?
@ -37498,7 +37498,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
for (var j = 0, jj = items.length; j < jj; j++) {
if (typeof items[j] === 'string') {
buildTextContentItem(items[j]);
} else {
} else if (isNum(items[j])) {
ensureTextContentItem();
// PDF Specification 5.3.2 states:

Просмотреть файл

@ -1925,11 +1925,11 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
display: none;
}
/* Rules for browsers that support mozPrintCallback */
body[data-mozPrintCallback] #outerContainer {
/* Rules for browsers that support PDF.js printing */
body[data-pdfjsprinting] #outerContainer {
display: none;
}
body[data-mozPrintCallback] #printContainer {
body[data-pdfjsprinting] #printContainer {
display: block;
}
#printContainer {
@ -1946,7 +1946,8 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
page-break-after: always;
page-break-inside: avoid;
}
#printContainer canvas {
#printContainer canvas,
#printContainer img {
display: block;
}
}

Просмотреть файл

@ -148,7 +148,6 @@ var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
this.element.addEventListener('scroll', this._endPan, true);
event.preventDefault();
event.stopPropagation();
this.document.documentElement.classList.add(this.CSS_CLASS_GRABBING);
var focusedElement = document.activeElement;
if (focusedElement && !focusedElement.contains(event.target)) {
@ -167,8 +166,18 @@ var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
}
var xDiff = event.clientX - this.clientXStart;
var yDiff = event.clientY - this.clientYStart;
this.element.scrollTop = this.scrollTopStart - yDiff;
this.element.scrollLeft = this.scrollLeftStart - xDiff;
var scrollTop = this.scrollTopStart - yDiff;
var scrollLeft = this.scrollLeftStart - xDiff;
if (this.element.scrollTo) {
this.element.scrollTo({
top: scrollTop,
left: scrollLeft,
behavior: 'instant',
});
} else {
this.element.scrollTop = scrollTop;
this.element.scrollLeft = scrollLeft;
}
if (!this.overlay.parentNode) {
document.body.appendChild(this.overlay);
}
@ -3644,8 +3653,9 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
this.linkService = linkService;
this.renderingQueue = renderingQueue;
this.resume = null;
this.renderTask = null;
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
this.disableCanvasToImageConversion = disableCanvasToImageConversion;
this.pageWidth = this.viewport.width;
@ -3697,11 +3707,7 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
},
reset: function PDFThumbnailView_reset() {
if (this.renderTask) {
this.renderTask.cancel();
}
this.resume = null;
this.renderingState = RenderingStates.INITIAL;
this.cancelRendering();
this.pageWidth = this.viewport.width;
this.pageHeight = this.viewport.height;
@ -3745,6 +3751,15 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
this.reset();
},
cancelRendering: function PDFThumbnailView_cancelRendering() {
if (this.renderTask) {
this.renderTask.cancel();
this.renderTask = null;
}
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
},
/**
* @private
*/
@ -5216,6 +5231,7 @@ var PDFPageView = (function PDFPageViewClosure() {
this.textLayerFactory = textLayerFactory;
this.annotationLayerFactory = annotationLayerFactory;
this.renderTask = null;
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
@ -5259,11 +5275,7 @@ var PDFPageView = (function PDFPageViewClosure() {
},
reset: function PDFPageView_reset(keepZoomLayer, keepAnnotations) {
if (this.renderTask) {
this.renderTask.cancel();
}
this.resume = null;
this.renderingState = RenderingStates.INITIAL;
this.cancelRendering();
var div = this.div;
div.style.width = Math.floor(this.viewport.width) + 'px';
@ -5349,6 +5361,20 @@ var PDFPageView = (function PDFPageViewClosure() {
this.reset(/* keepZoomLayer = */ true, /* keepAnnotations = */ true);
},
cancelRendering: function PDFPageView_cancelRendering() {
if (this.renderTask) {
this.renderTask.cancel();
this.renderTask = null;
}
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
if (this.textLayer) {
this.textLayer.cancel();
this.textLayer = null;
}
},
/**
* Called when moved in the parent's container.
*/
@ -5444,6 +5470,7 @@ var PDFPageView = (function PDFPageViewClosure() {
draw: function PDFPageView_draw() {
if (this.renderingState !== RenderingStates.INITIAL) {
console.error('Must be in new state before drawing');
this.reset(); // Ensure that we reset all state to prevent issues.
}
this.renderingState = RenderingStates.RUNNING;
@ -5662,59 +5689,6 @@ var PDFPageView = (function PDFPageViewClosure() {
}
return promise;
},
beforePrint: function PDFPageView_beforePrint(printContainer) {
var CustomStyle = pdfjsLib.CustomStyle;
var pdfPage = this.pdfPage;
var viewport = pdfPage.getViewport(1);
var canvas = document.createElement('canvas');
// The size of the canvas in pixels for printing.
var PRINT_RESOLUTION = 150;
var PRINT_UNITS = PRINT_RESOLUTION / 72.0;
canvas.width = Math.floor(viewport.width * PRINT_UNITS);
canvas.height = Math.floor(viewport.height * PRINT_UNITS);
// The physical size of the canvas as specified by the PDF document.
canvas.style.width = Math.floor(viewport.width * CSS_UNITS) + 'px';
canvas.style.height = Math.floor(viewport.height * CSS_UNITS) + 'px';
var canvasWrapper = document.createElement('div');
canvasWrapper.appendChild(canvas);
printContainer.appendChild(canvasWrapper);
canvas.mozPrintCallback = function(obj) {
var ctx = obj.context;
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
var renderContext = {
canvasContext: ctx,
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
viewport: viewport,
intent: 'print'
};
pdfPage.render(renderContext).promise.then(function() {
// Tell the printEngine that rendering this canvas/page has finished.
obj.done();
}, function(error) {
console.error(error);
// Tell the printEngine that rendering this canvas/page has failed.
// This will make the print process stop.
if ('abort' in obj) {
obj.abort();
} else {
obj.done();
}
});
};
},
};
return PDFPageView;
@ -5838,15 +5812,14 @@ var PDFThumbnailViewer = (function PDFThumbnailViewerClosure() {
this.thumbnails = [];
this._pagesRotation = 0;
this._pagesRequests = [];
// Remove the thumbnails from the DOM.
this.container.textContent = '';
},
setDocument: function PDFThumbnailViewer_setDocument(pdfDocument) {
if (this.pdfDocument) {
// cleanup of the elements and views
var thumbsView = this.container;
while (thumbsView.hasChildNodes()) {
thumbsView.removeChild(thumbsView.lastChild);
}
this._cancelRendering();
this._resetView();
}
@ -5872,6 +5845,17 @@ var PDFThumbnailViewer = (function PDFThumbnailViewerClosure() {
}.bind(this));
},
/**
* @private
*/
_cancelRendering: function PDFThumbnailViewer_cancelRendering() {
for (var i = 0, ii = this.thumbnails.length; i < ii; i++) {
if (this.thumbnails[i]) {
this.thumbnails[i].cancelRendering();
}
}
},
/**
* @param {PDFThumbnailView} thumbView
* @returns {PDFPage}
@ -5949,8 +5933,8 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
function TextLayerBuilder(options) {
this.textLayerDiv = options.textLayerDiv;
this.eventBus = options.eventBus || domEvents.getGlobalEventBus();
this.textContent = null;
this.renderingDone = false;
this.divContentDone = false;
this.pageIdx = options.pageIndex;
this.pageNumber = this.pageIdx + 1;
this.matches = [];
@ -5963,6 +5947,9 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
}
TextLayerBuilder.prototype = {
/**
* @private
*/
_finishRendering: function TextLayerBuilder_finishRendering() {
this.renderingDone = true;
@ -5974,7 +5961,8 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
this.eventBus.dispatch('textlayerrendered', {
source: this,
pageNumber: this.pageNumber
pageNumber: this.pageNumber,
numTextDivs: this.textDivs.length,
});
},
@ -5984,14 +5972,10 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
* for specified amount of ms.
*/
render: function TextLayerBuilder_render(timeout) {
if (!this.divContentDone || this.renderingDone) {
if (!this.textContent || this.renderingDone) {
return;
}
if (this.textLayerRenderTask) {
this.textLayerRenderTask.cancel();
this.textLayerRenderTask = null;
}
this.cancel();
this.textDivs = [];
var textLayerFrag = document.createDocumentFragment();
@ -6008,17 +5992,23 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
this._finishRendering();
this.updateMatches();
}.bind(this), function (reason) {
// canceled or failed to render text layer -- skipping errors
// cancelled or failed to render text layer -- skipping errors
});
},
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
/**
* Cancels rendering of the text layer.
*/
cancel: function TextLayerBuilder_cancel() {
if (this.textLayerRenderTask) {
this.textLayerRenderTask.cancel();
this.textLayerRenderTask = null;
}
},
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
this.cancel();
this.textContent = textContent;
this.divContentDone = true;
},
convertMatches: function TextLayerBuilder_convertMatches(matches,
@ -6221,6 +6211,7 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
var div = this.textLayerDiv;
var self = this;
var expandDivsTimer = null;
div.addEventListener('mousedown', function (e) {
if (self.enhanceTextSelection && self.textLayerRenderTask) {
self.textLayerRenderTask.expandTextDivs(true);
@ -6232,6 +6223,7 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
}
end.classList.add('active');
});
div.addEventListener('mouseup', function (e) {
if (self.enhanceTextSelection && self.textLayerRenderTask) {
self.textLayerRenderTask.expandTextDivs(false);
@ -6536,6 +6528,13 @@ var PDFViewer = (function pdfViewer() {
return this._pages[index];
},
/**
* @returns {boolean} true if all {PDFPageView} objects are initialized.
*/
get pageViewsReady() {
return this._pageViewsReady;
},
/**
* @returns {number}
*/
@ -6667,6 +6666,7 @@ var PDFViewer = (function pdfViewer() {
*/
setDocument: function (pdfDocument) {
if (this.pdfDocument) {
this._cancelRendering();
this._resetView();
}
@ -6684,6 +6684,7 @@ var PDFViewer = (function pdfViewer() {
});
this.pagesPromise = pagesPromise;
pagesPromise.then(function () {
self._pageViewsReady = true;
self.eventBus.dispatch('pagesloaded', {
source: self,
pagesCount: pagesCount
@ -6789,11 +6790,10 @@ var PDFViewer = (function pdfViewer() {
this._location = null;
this._pagesRotation = 0;
this._pagesRequests = [];
this._pageViewsReady = false;
var container = this.viewer;
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
// Remove the pages from the DOM.
this.viewer.textContent = '';
},
_scrollUpdate: function PDFViewer_scrollUpdate() {
@ -7155,6 +7155,17 @@ var PDFViewer = (function pdfViewer() {
}
},
/**
* @private
*/
_cancelRendering: function PDFViewer_cancelRendering() {
for (var i = 0, ii = this._pages.length; i < ii; i++) {
if (this._pages[i]) {
this._pages[i].cancelRendering();
}
}
},
/**
* @param {PDFPageView} pageView
* @returns {PDFPage}
@ -7239,6 +7250,17 @@ var PDFViewer = (function pdfViewer() {
setFindController: function (findController) {
this.findController = findController;
},
/**
* Returns sizes of the pages.
* @returns {Array} Array of objects with width/height fields.
*/
getPagesOverview: function () {
return this._pages.map(function (pageView) {
var viewport = pageView.pdfPage.getViewport(1);
return {width: viewport.width, height: viewport.height};
});
},
};
return PDFViewer;
@ -7343,7 +7365,7 @@ var PDFViewerApplication = {
appConfig: null,
pdfDocument: null,
pdfLoadingTask: null,
printing: false,
printService: null,
/** @type {PDFViewer} */
pdfViewer: null,
/** @type {PDFThumbnailViewer} */
@ -7628,11 +7650,12 @@ var PDFViewerApplication = {
return this.pdfViewer.currentPageNumber;
},
get supportsPrinting() {
var canvas = document.createElement('canvas');
var value = 'mozPrintCallback' in canvas;
get printing() {
return !!this.printService;
},
return pdfjsLib.shadow(this, 'supportsPrinting', value);
get supportsPrinting() {
return PDFPrintServiceFactory.instance.supportsPrinting;
},
get supportsFullscreen() {
@ -8221,6 +8244,13 @@ var PDFViewerApplication = {
},
beforePrint: function pdfViewSetupBeforePrint() {
if (this.printService) {
// There is no way to suppress beforePrint/afterPrint events,
// but PDFPrintService may generate double events -- this will ignore
// the second event that will be coming from native window.print().
return;
}
if (!this.supportsPrinting) {
var printMessage = mozL10n.get('printing_not_supported', null,
'Warning: Printing is not fully supported by this browser.');
@ -8228,59 +8258,23 @@ var PDFViewerApplication = {
return;
}
var alertNotReady = false;
var i, ii;
if (!this.pdfDocument || !this.pagesCount) {
alertNotReady = true;
} else {
for (i = 0, ii = this.pagesCount; i < ii; ++i) {
if (!this.pdfViewer.getPageView(i).pdfPage) {
alertNotReady = true;
break;
}
}
}
if (alertNotReady) {
// The beforePrint is a sync method and we need to know layout before
// returning from this method. Ensure that we can get sizes of the pages.
if (!this.pdfViewer.pageViewsReady) {
var notReadyMessage = mozL10n.get('printing_not_ready', null,
'Warning: The PDF is not fully loaded for printing.');
window.alert(notReadyMessage);
return;
}
this.printing = true;
var pagesOverview = this.pdfViewer.getPagesOverview();
var printContainer = this.appConfig.printContainer;
var printService = PDFPrintServiceFactory.instance.createPrintService(
this.pdfDocument, pagesOverview, printContainer);
this.printService = printService;
this.forceRendering();
var printContainer = this.appConfig.printContainer;
var body = document.querySelector('body');
body.setAttribute('data-mozPrintCallback', true);
if (!this.hasEqualPageSizes) {
console.warn('Not all pages have the same size. The printed result ' +
'may be incorrect!');
}
// Insert a @page + size rule to make sure that the page size is correctly
// set. Note that we assume that all pages have the same size, because
// variable-size pages are not supported yet (at least in Chrome & Firefox).
// TODO(robwu): Use named pages when size calculation bugs get resolved
// (e.g. https://crbug.com/355116) AND when support for named pages is
// added (http://www.w3.org/TR/css3-page/#using-named-pages).
// In browsers where @page + size is not supported (such as Firefox,
// https://bugzil.la/851441), the next stylesheet will be ignored and the
// user has to select the correct paper size in the UI if wanted.
this.pageStyleSheet = document.createElement('style');
var pageSize = this.pdfViewer.getPageView(0).pdfPage.getViewport(1);
this.pageStyleSheet.textContent =
// "size:<width> <height>" is what we need. But also add "A4" because
// Firefox incorrectly reports support for the other value.
'@supports ((size:A4) and (size:1pt 1pt)) {' +
'@page { size: ' + pageSize.width + 'pt ' + pageSize.height + 'pt;}' +
'}';
body.appendChild(this.pageStyleSheet);
for (i = 0, ii = this.pagesCount; i < ii; ++i) {
this.pdfViewer.getPageView(i).beforePrint(printContainer);
}
printService.layout();
this.externalServices.reportTelemetry({
type: 'print'
@ -8301,17 +8295,10 @@ var PDFViewerApplication = {
},
afterPrint: function pdfViewSetupAfterPrint() {
var div = this.appConfig.printContainer;
while (div.hasChildNodes()) {
div.removeChild(div.lastChild);
if (this.printService) {
this.printService.destroy();
this.printService = null;
}
if (this.pageStyleSheet && this.pageStyleSheet.parentNode) {
this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet);
this.pageStyleSheet = null;
}
this.printing = false;
this.forceRendering();
},
@ -8618,6 +8605,19 @@ function webViewerPageRendered(e) {
var pageIndex = pageNumber - 1;
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
// If the page is still visible when it has finished rendering,
// ensure that the page number input loading indicator is hidden.
if (pageNumber === PDFViewerApplication.page) {
var pageNumberInput = PDFViewerApplication.appConfig.toolbar.pageNumber;
pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
}
// Prevent errors in the edge-case where the PDF document is removed *before*
// the 'pagerendered' event handler is invoked.
if (!pageView) {
return;
}
// Use the rendered page to set the corresponding thumbnail image.
if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
var thumbnailView = PDFViewerApplication.pdfThumbnailViewer.
@ -8634,13 +8634,6 @@ function webViewerPageRendered(e) {
'An error occurred while rendering the page.'), pageView.error);
}
// If the page is still visible when it has finished rendering,
// ensure that the page number input loading indicator is hidden.
if (pageNumber === PDFViewerApplication.page) {
var pageNumberInput = PDFViewerApplication.appConfig.toolbar.pageNumber;
pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
}
PDFViewerApplication.externalServices.reportTelemetry({
type: 'pageInfo'
});
@ -8654,12 +8647,7 @@ function webViewerPageRendered(e) {
}
function webViewerTextLayerRendered(e) {
var pageIndex = e.pageNumber - 1;
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
if (pageView.textLayer && pageView.textLayer.textDivs &&
pageView.textLayer.textDivs.length > 0 &&
!PDFViewerApplication.supportsDocumentColors) {
if (e.numTextDivs > 0 && !PDFViewerApplication.supportsDocumentColors) {
console.error(mozL10n.get('document_colors_not_allowed', null,
'PDF documents are not allowed to use their own colors: ' +
'\'Allow pages to choose their own colors\' ' +
@ -9268,8 +9256,120 @@ window.addEventListener('afterprint', function afterPrint(evt) {
});
})();
/* Abstract factory for the print service. */
var PDFPrintServiceFactory = {
instance: {
supportsPrinting: false,
createPrintService: function () {
throw new Error('Not implemented: createPrintService');
}
}
};
exports.PDFViewerApplication = PDFViewerApplication;
exports.DefaultExernalServices = DefaultExernalServices;
exports.PDFPrintServiceFactory = PDFPrintServiceFactory;
}));
(function (root, factory) {
{
factory((root.pdfjsWebFirefoxPrintService = {}), root.pdfjsWebUIUtils,
root.pdfjsWebApp, root.pdfjsWebPDFJS);
}
}(this, function (exports, uiUtils, app, pdfjsLib) {
var CSS_UNITS = uiUtils.CSS_UNITS;
var PDFPrintServiceFactory = app.PDFPrintServiceFactory;
// Creates a placeholder with div and canvas with right size for the page.
function composePage(pdfDocument, pageNumber, size, printContainer) {
var canvas = document.createElement('canvas');
// The size of the canvas in pixels for printing.
var PRINT_RESOLUTION = 150;
var PRINT_UNITS = PRINT_RESOLUTION / 72.0;
canvas.width = Math.floor(size.width * PRINT_UNITS);
canvas.height = Math.floor(size.height * PRINT_UNITS);
// The physical size of the canvas as specified by the PDF document.
canvas.style.width = Math.floor(size.width * CSS_UNITS) + 'px';
canvas.style.height = Math.floor(size.height * CSS_UNITS) + 'px';
var canvasWrapper = document.createElement('div');
canvasWrapper.appendChild(canvas);
printContainer.appendChild(canvasWrapper);
canvas.mozPrintCallback = function(obj) {
// Printing/rendering the page.
var ctx = obj.context;
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
pdfDocument.getPage(pageNumber).then(function (pdfPage) {
var renderContext = {
canvasContext: ctx,
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
viewport: pdfPage.getViewport(1),
intent: 'print'
};
return pdfPage.render(renderContext).promise;
}).then(function() {
// Tell the printEngine that rendering this canvas/page has finished.
obj.done();
}, function(error) {
console.error(error);
// Tell the printEngine that rendering this canvas/page has failed.
// This will make the print process stop.
if ('abort' in obj) {
obj.abort();
} else {
obj.done();
}
});
};
}
function FirefoxPrintService(pdfDocument, pagesOverview, printContainer) {
this.pdfDocument = pdfDocument;
this.pagesOverview = pagesOverview;
this.printContainer = printContainer;
}
FirefoxPrintService.prototype = {
layout: function () {
var pdfDocument = this.pdfDocument;
var printContainer = this.printContainer;
var body = document.querySelector('body');
body.setAttribute('data-pdfjsprinting', true);
for (var i = 0, ii = this.pagesOverview.length; i < ii; ++i) {
composePage(pdfDocument, i + 1, this.pagesOverview[i], printContainer);
}
},
destroy: function () {
this.printContainer.textContent = '';
}
};
PDFPrintServiceFactory.instance = {
get supportsPrinting() {
var canvas = document.createElement('canvas');
var value = 'mozPrintCallback' in canvas;
return pdfjsLib.shadow(this, 'supportsPrinting', value);
},
createPrintService: function (pdfDocument, pagesOverview, printContainer) {
return new FirefoxPrintService(pdfDocument, pagesOverview,
printContainer);
}
};
exports.FirefoxPrintService = FirefoxPrintService;
}));

Просмотреть файл

@ -213,7 +213,6 @@
@RESPATH@/components/dom_stylesheets.xpt
@RESPATH@/components/dom_telephony.xpt
@RESPATH@/components/dom_traversal.xpt
@RESPATH@/components/dom_voicemail.xpt
#ifdef MOZ_WEBSPEECH
@RESPATH@/components/dom_webspeechrecognition.xpt
#endif

Просмотреть файл

@ -88,6 +88,12 @@ document_properties_version=PDF Version:
document_properties_page_count=Page Count:
document_properties_close=Close
print_progress_message=Preparing document for printing…
# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by
# a numerical per cent value.
print_progress_percent={{progress}}%
print_progress_close=Cancel
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)

Просмотреть файл

@ -133,10 +133,14 @@ var AnimationsController = {
initialize: Task.async(function* () {
if (this.initialized) {
yield this.initialized.promise;
yield this.initialized;
return;
}
this.initialized = promise.defer();
let resolver;
this.initialized = new Promise(resolve => {
resolver = resolve;
});
this.onPanelVisibilityChange = this.onPanelVisibilityChange.bind(this);
this.onNewNodeFront = this.onNewNodeFront.bind(this);
@ -162,7 +166,7 @@ var AnimationsController = {
this.startListeners();
yield this.onNewNodeFront();
this.initialized.resolve();
resolver();
}),
destroy: Task.async(function* () {
@ -171,10 +175,14 @@ var AnimationsController = {
}
if (this.destroyed) {
yield this.destroyed.promise;
yield this.destroyed;
return;
}
this.destroyed = promise.defer();
let resolver;
this.destroyed = new Promise(resolve => {
resolver = resolve;
});
this.stopListeners();
this.destroyAnimationPlayers();
@ -184,8 +192,7 @@ var AnimationsController = {
this.animationsFront.destroy();
this.animationsFront = null;
}
this.destroyed.resolve();
resolver();
}),
startListeners: function () {

Просмотреть файл

@ -30,10 +30,14 @@ var AnimationsPanel = {
return;
}
if (this.initialized) {
yield this.initialized.promise;
yield this.initialized;
return;
}
this.initialized = promise.defer();
let resolver;
this.initialized = new Promise(resolve => {
resolver = resolve;
});
this.playersEl = $("#players");
this.errorMessageEl = $("#error-message");
@ -78,7 +82,7 @@ var AnimationsPanel = {
yield this.refreshAnimationsUI();
this.initialized.resolve();
resolver();
this.emit(this.PANEL_INITIALIZED);
}),
@ -88,10 +92,14 @@ var AnimationsPanel = {
}
if (this.destroyed) {
yield this.destroyed.promise;
yield this.destroyed;
return;
}
this.destroyed = promise.defer();
let resolver;
this.destroyed = new Promise(resolve => {
resolver = resolve;
});
this.stopListeners();
@ -108,7 +116,7 @@ var AnimationsPanel = {
this.playTimelineButtonEl = this.rewindTimelineButtonEl = null;
this.timelineCurrentTimeEl = this.rateSelectorEl = null;
this.destroyed.resolve();
resolver();
}),
startListeners: function () {

Просмотреть файл

@ -189,12 +189,12 @@ function waitForContentMessage(name) {
let mm = gBrowser.selectedBrowser.messageManager;
let def = promise.defer();
mm.addMessageListener(name, function onMessage(msg) {
mm.removeMessageListener(name, onMessage);
def.resolve(msg.data);
return new Promise(resolve => {
mm.addMessageListener(name, function onMessage(msg) {
mm.removeMessageListener(name, onMessage);
resolve(msg.data);
});
});
return def.promise;
}
/**

Просмотреть файл

@ -2,27 +2,28 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/inspector.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/rules.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/computed.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/fonts.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/boxmodel.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/animationinspector.css" type="text/css"?>
<?xml-stylesheet href="resource://devtools/client/shared/components/sidebar-toggle.css" type="text/css"?>
<?xml-stylesheet href="resource://devtools/client/shared/components/tabs/tabs.css" type="text/css"?>
<?xml-stylesheet href="resource://devtools/client/shared/components/tabs/tabbar.css" type="text/css"?>
<?xml-stylesheet href="resource://devtools/client/inspector/components/side-panel.css" type="text/css"?>
<?xml-stylesheet href="resource://devtools/client/inspector/components/inspector-tab-panel.css" type="text/css"?>
<?xml-stylesheet href="resource://devtools/client/shared/components/splitter/split-box.css" type="text/css"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" dir="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://global/skin/"/>
<link rel="stylesheet" href="resource://devtools/client/shared/widgets/widgets.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/widgets.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/inspector.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/rules.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/computed.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/fonts.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/boxmodel.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/animationinspector.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/sidebar-toggle.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/tabs.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/tabbar.css"/>
<link rel="stylesheet" href="resource://devtools/client/inspector/components/side-panel.css"/>
<link rel="stylesheet" href="resource://devtools/client/inspector/components/inspector-tab-panel.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/splitter/split-box.css"/>
<script type="application/javascript;version=1.8"
src="chrome://devtools/content/shared/theme-switching.js"></script>
<script type="application/javascript;version=1.8" src="inspector.js" defer="true"></script>
@ -35,9 +36,9 @@
<div id="inspector-toolbar" class="devtools-toolbar" nowindowdrag="true"
data-localization-bundle="devtools/locale/inspector.properties">
<button id="inspector-element-add-button" class="devtools-button"
data-localization="title=inspectorAddNode.label"/>
<div class="devtools-toolbar-spacer" />
<span id="inspector-searchlabel" />
data-localization="title=inspectorAddNode.label"></button>
<div class="devtools-toolbar-spacer"></div>
<span id="inspector-searchlabel"></span>
<div id="inspector-search" class="devtools-searchbox has-clear-btn">
<input id="inspector-searchbox" class="devtools-searchinput"
type="search"
@ -46,13 +47,13 @@
</div>
<button id="inspector-eyedropper-toggle"
data-localization="title=inspector.eyedropper.label"
class="devtools-button command-button-invertable" />
<div id="inspector-sidebar-toggle-box" />
class="devtools-button command-button-invertable"></button>
<div id="inspector-sidebar-toggle-box"></div>
</div>
<div id="markup-box" />
<div id="markup-box"></div>
<div id="inspector-breadcrumbs-toolbar" class="devtools-toolbar">
<div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"
role="group" data-localization="aria-label=inspector.breadcrumbs.label" tabindex="0" />
role="group" data-localization="aria-label=inspector.breadcrumbs.label" tabindex="0"></div>
</div>
</div>
@ -67,7 +68,7 @@
<div
xmlns="http://www.w3.org/1999/xhtml"
id="inspector-sidebar"
hidden="true" />
hidden="true"></div>
</div>
<!-- Sidebar panel definitions -->
@ -115,7 +116,7 @@
type="checkbox"
class="includebrowserstyles"/>
<label id="browser-style-checkbox-label" for="browser-style-checkbox"
data-localization="content=inspector.browserStyles.label"/>
data-localization="content=inspector.browserStyles.label"></label>
</div>
<div id="computedview-container">
@ -124,16 +125,16 @@
data-localization-bundle="devtools/locale/boxmodel.properties">
<div id="boxmodel-header">
<div id="boxmodel-expander" class="expander theme-twisty expandable" open=""></div>
<span data-localization="content=boxmodel.title"/>
<span data-localization="content=boxmodel.title"></span>
</div>
<div id="boxmodel-container">
<div id="boxmodel-main">
<span class="boxmodel-legend" data-box="margin" data-localization="content=boxmodel.margin;title=boxmodel.margin"/>
<span class="boxmodel-legend" data-box="margin" data-localization="content=boxmodel.margin;title=boxmodel.margin"></span>
<div id="boxmodel-margins" data-box="margin" data-localization="title=boxmodel.margin">
<span class="boxmodel-legend" data-box="border" data-localization="content=boxmodel.border;title=boxmodel.border"/>
<span class="boxmodel-legend" data-box="border" data-localization="content=boxmodel.border;title=boxmodel.border"></span>
<div id="boxmodel-borders" data-box="border" data-localization="title=boxmodel.border">
<span class="boxmodel-legend" data-box="padding" data-localization="content=boxmodel.padding;title=boxmodel.padding"/>
<span class="boxmodel-legend" data-box="padding" data-localization="content=boxmodel.padding;title=boxmodel.padding"></span>
<div id="boxmodel-padding" data-box="padding" data-localization="title=boxmodel.padding">
<div id="boxmodel-content" data-box="content" data-localization="title=boxmodel.content">
</div>
@ -179,7 +180,7 @@
<div id="propertyContainer" class="theme-separator" tabindex="0">
</div>
<div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"/>
<div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"></div>
</div>
</div>
</div>
@ -198,7 +199,7 @@
</div>
<label id="font-showall" class="theme-link"
data-localization="content=fontinspector.seeAll;
title=fontinspector.seeAll.tooltip"/>
title=fontinspector.seeAll.tooltip"></label>
</div>
<div id="font-container">
@ -212,14 +213,14 @@
</div>
<div class="font-info">
<h1 class="font-name"></h1>
<span class="font-is-local" data-localization="content=fontinspector.system"/>
<span class="font-is-remote" data-localization="content=fontinspector.remote"/>
<span class="font-is-local" data-localization="content=fontinspector.system"></span>
<span class="font-is-remote" data-localization="content=fontinspector.remote"></span>
<p class="font-format-url">
<input readonly="readonly" class="font-url"></input>
<span class="font-format"></span>
</p>
<p class="font-css">
<span data-localization="content=fontinspector.usedAs"/> "<span class="font-css-name"></span>"
<span data-localization="content=fontinspector.usedAs"></span> "<span class="font-css-name"></span>"
</p>
<pre class="font-css-code"></pre>
</div>
@ -228,7 +229,7 @@
</div>
<div id="sidebar-panel-animationinspector" class="devtools-monospace theme-sidebar inspector-tabpanel">
<iframe class="devtools-inspector-tab-frame" />
<iframe class="devtools-inspector-tab-frame"></iframe>
</div>
</div>

Просмотреть файл

@ -453,6 +453,7 @@ TextPropertyEditor.prototype = {
_onStartEditing: function () {
this.element.classList.remove("ruleview-overridden");
this.filterProperty.hidden = true;
this.enable.style.visibility = "hidden";
},

Просмотреть файл

@ -164,7 +164,7 @@ const JITOptimizationsItem = createClass({
return dom.div(
{
className: `optimization-tree-item optimization-tree-item-${type}`,
style: { marginLeft: depth * TREE_ROW_HEIGHT }
style: { marginInlineStart: depth * TREE_ROW_HEIGHT }
},
arrow,
content

Просмотреть файл

@ -246,7 +246,7 @@ PrefBranch.prototype = {
userValue: this._userValue,
};
localStorage.setItem(PREFIX + this.fullName, JSON.stringify(store));
localStorage.setItem(PREFIX + this._fullName, JSON.stringify(store));
this._parent._notify(this._name);
},
@ -341,8 +341,9 @@ PrefBranch.prototype = {
let parent = this;
for (let branch of branchList) {
if (!parent._children[branch]) {
parent._children[branch] = new PrefBranch(parent, branch,
parent.root + "." + branch);
let isParentRoot = !parent.parent;
let branchName = (isParentRoot ? "" : parent.root + ".") + branch;
parent._children[branch] = new PrefBranch(parent, branch, branchName);
}
parent = parent._children[branch];
}
@ -356,12 +357,15 @@ PrefBranch.prototype = {
* @param {String} keyName the full-qualified name of the preference.
* This is also the name of the key in local storage.
* @param {Any} userValue the user value to use if the pref does not exist
* @param {Any} defaultValue the default value to use if the pref
* does not exist
* @param {Boolean} hasUserValue if a new pref is created, whether
* the default value is also a user value
* @param {Any} defaultValue the default value to use if the pref
* does not exist
* @param {Boolean} init if true, then this call is initialization
* from local storage and should override the default prefs
*/
_findOrCreatePref: function (keyName, userValue, hasUserValue, defaultValue) {
_findOrCreatePref: function (keyName, userValue, hasUserValue, defaultValue,
init = false) {
let branch = this._createBranch(keyName.split("."));
if (hasUserValue && typeof (userValue) !== typeof (defaultValue)) {
@ -383,7 +387,7 @@ PrefBranch.prototype = {
throw new Error("unhandled argument type: " + typeof (defaultValue));
}
if (branch._type === PREF_INVALID) {
if (init || branch._type === PREF_INVALID) {
branch._storageUpdated(type, userValue, hasUserValue, defaultValue);
} else if (branch._type !== type) {
throw new Error("attempt to change type of pref " + keyName);
@ -422,7 +426,7 @@ PrefBranch.prototype = {
* Helper function to initialize the root PrefBranch.
*/
_initializeRoot: function () {
if (localStorage.length === 0 && Services._defaultPrefsEnabled) {
if (Services._defaultPrefsEnabled) {
/* eslint-disable no-eval */
let devtools = require("raw!prefs!devtools/client/preferences/devtools");
eval(devtools);
@ -439,7 +443,7 @@ PrefBranch.prototype = {
let {userValue, hasUserValue, defaultValue} =
JSON.parse(localStorage.getItem(keyName));
this._findOrCreatePref(keyName.slice(PREFIX.length), userValue,
hasUserValue, defaultValue);
hasUserValue, defaultValue, true);
}
}

Просмотреть файл

@ -5,3 +5,4 @@ support-files =
[test_service_appinfo.html]
[test_service_focus.html]
[test_service_prefs.html]
[test_service_prefs_defaults.html]

Просмотреть файл

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1309384
-->
<head>
<title>Test for Bug 1309384 - Services.prefs replacement defaults handling</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript;version=1.8">
"use strict";
var exports = {}
var module = {exports};
// Allow one require("raw!prefs...") to return some defaults, with the
// others being ignored.
var firstTime = true;
function require(something) {
if (!something.startsWith("raw!prefs!")) {
throw new Error("whoops");
}
if (!firstTime) {
return "";
}
firstTime = false;
return "pref('pref1', 'pref1default');\n" +
"pref('pref2', 'pref2default');\n" +
"pref('pref3', 'pref3default');\n";
}
// Pretend that one of the prefs was modifed by the user in an earlier session.
localStorage.setItem("Services.prefs:pref3", JSON.stringify({
// string
type: 32,
defaultValue: "pref3default",
hasUserValue: true,
userValue: "glass winged butterfly"
}));
</script>
<script type="application/javascript;version=1.8"
src="resource://devtools/client/shared/shim/Services.js"></script>
</head>
<body>
<script type="application/javascript;version=1.8">
"use strict";
is(Services.prefs.getCharPref("pref1"), "pref1default", "pref1 value");
is(Services.prefs.getCharPref("pref2"), "pref2default", "pref2 value");
is(Services.prefs.getCharPref("pref3"), "glass winged butterfly", "pref3 value");
// Only pref3 should be in local storage at this point.
is(localStorage.length, 1, "local storage is correct");
Services.prefs.setCharPref("pref2", "pref2override");
// Check that a default pref can be overridden properly
// Workaround to reset the prefs helper and force it to read defaults & overrides again.
Services._prefs = null;
is(Services.prefs.getCharPref("pref2"), "pref2override", "pref2 value overridden");
// Clean up.
localStorage.clear();
</script>
</body>

Просмотреть файл

@ -43,7 +43,14 @@ add_task(function* () {
info("Run tests for a Tooltip with a XUL panel");
useXulWrapper = true;
yield runTests(doc);
let isLinux = Services.appinfo.OS === "Linux";
if (!isLinux) {
// Skip these tests on linux when using a XUL Panel wrapper because some linux window
// manager don't support nicely XUL Panels with noautohide _and_ noautofocus.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1301342#c11
yield runTests(doc);
}
});
function* runTests(doc) {

Просмотреть файл

@ -572,6 +572,7 @@ HTMLTooltip.prototype = {
panel.setAttribute("animate", false);
panel.setAttribute("consumeoutsideclicks", false);
panel.setAttribute("noautofocus", true);
panel.setAttribute("noautohide", true);
panel.setAttribute("ignorekeys", true);
// Use type="arrow" to prevent side effects (see Bug 1285206)

Просмотреть файл

@ -746,10 +746,18 @@ checkbox:-moz-focusring {
border: 0;
padding: 0;
outline: none;
background-position: 0 0;
}
.theme-dark .theme-checkbox {
background-position: -28px 0;
}
.theme-checkbox[checked] {
background-position: -14px 0;
}
.theme-dark .theme-checkbox[checked] {
background-position: -42px 0;
}

Просмотреть файл

@ -253,11 +253,6 @@ this.PermissionsTable = { geolocation: {
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"voicemail": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"idle": {
app: DENY_ACTION,
privileged: DENY_ACTION,

Просмотреть файл

@ -49,7 +49,6 @@
#include "mozilla/dom/StorageManager.h"
#include "mozilla/dom/TCPSocket.h"
#include "mozilla/dom/Telephony.h"
#include "mozilla/dom/Voicemail.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/dom/workers/RuntimeService.h"
#include "mozilla/Hal.h"
@ -84,7 +83,6 @@
#ifdef MOZ_B2G_BT
#include "BluetoothManager.h"
#endif
#include "DOMCameraManager.h"
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
#include "AudioChannelManager.h"
@ -220,7 +218,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
@ -233,7 +230,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
#endif
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
@ -305,11 +301,6 @@ Navigator::Invalidate()
mTelephony = nullptr;
}
if (mVoicemail) {
mVoicemail->Shutdown();
mVoicemail = nullptr;
}
if (mInputPortManager) {
mInputPortManager = nullptr;
}
@ -331,7 +322,6 @@ Navigator::Invalidate()
}
#endif
mCameraManager = nullptr;
mMediaDevices = nullptr;
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
@ -1710,21 +1700,6 @@ Navigator::GetMozMobileConnections(ErrorResult& aRv)
#endif // MOZ_B2G_RIL
Voicemail*
Navigator::GetMozVoicemail(ErrorResult& aRv)
{
if (!mVoicemail) {
if (!mWindow) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
mVoicemail = Voicemail::Create(mWindow, aRv);
}
return mVoicemail;
}
IccManager*
Navigator::GetMozIccManager(ErrorResult& aRv)
{
@ -1902,23 +1877,6 @@ Navigator::GetMozTime(ErrorResult& aRv)
}
#endif
nsDOMCameraManager*
Navigator::GetMozCameras(ErrorResult& aRv)
{
if (!mCameraManager) {
if (!mWindow ||
!mWindow->GetOuterWindow() ||
mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
mCameraManager = nsDOMCameraManager::CreateInstance(mWindow);
}
return mCameraManager;
}
already_AddRefed<ServiceWorkerContainer>
Navigator::ServiceWorker()
{
@ -1965,9 +1923,6 @@ Navigator::OnNavigation()
if (manager) {
manager->OnNavigation(mWindow->WindowID());
}
if (mCameraManager) {
mCameraManager->OnNavigation(mWindow->WindowID());
}
}
bool
@ -2021,14 +1976,6 @@ Navigator::HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */)
return !!pmService;
}
/* static */
bool
Navigator::HasCameraSupport(JSContext* /* unused */, JSObject* aGlobal)
{
nsCOMPtr<nsPIDOMWindowInner> win = GetWindowFromGlobal(aGlobal);
return win && nsDOMCameraManager::CheckPermission(win);
}
/* static */
bool
Navigator::HasWifiManagerSupport(JSContext* /* unused */,

Просмотреть файл

@ -24,7 +24,6 @@ class nsPluginArray;
class nsMimeTypeArray;
class nsPIDOMWindowInner;
class nsIDOMNavigatorSystemMessages;
class nsDOMCameraManager;
class nsDOMDeviceStorage;
class nsIPrincipal;
class nsIURI;
@ -87,7 +86,6 @@ class MobileConnectionArray;
class PowerManager;
class IccManager;
class Telephony;
class Voicemail;
class InputPortManager;
class DeviceStorageAreaListener;
class Presentation;
@ -226,11 +224,9 @@ public:
IccManager* GetMozIccManager(ErrorResult& aRv);
MobileMessageManager* GetMozMobileMessage();
Telephony* GetMozTelephony(ErrorResult& aRv);
Voicemail* GetMozVoicemail(ErrorResult& aRv);
InputPortManager* GetInputPortManager(ErrorResult& aRv);
already_AddRefed<LegacyMozTCPSocket> MozTCPSocket();
network::Connection* GetConnection(ErrorResult& aRv);
nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
MediaDevices* GetMediaDevices(ErrorResult& aRv);
#ifdef MOZ_B2G_RIL
@ -281,8 +277,6 @@ public:
// WebIDL helper methods
static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
static bool HasCameraSupport(JSContext* /* unused */,
JSObject* aGlobal);
static bool HasWifiManagerSupport(JSContext* /* unused */,
JSObject* aGlobal);
#ifdef MOZ_NFC
@ -335,7 +329,6 @@ private:
RefPtr<IccManager> mIccManager;
RefPtr<MobileMessageManager> mMobileMessageManager;
RefPtr<Telephony> mTelephony;
RefPtr<Voicemail> mVoicemail;
RefPtr<InputPortManager> mInputPortManager;
RefPtr<network::Connection> mConnection;
#ifdef MOZ_B2G_RIL
@ -347,7 +340,6 @@ private:
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
RefPtr<system::AudioChannelManager> mAudioChannelManager;
#endif
RefPtr<nsDOMCameraManager> mCameraManager;
RefPtr<MediaDevices> mMediaDevices;
nsTArray<nsWeakPtr> mDeviceStorageStores;
RefPtr<time::TimeManager> mTimeManager;

Просмотреть файл

@ -686,22 +686,6 @@ nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
return NS_ERROR_FAILURE;
}
#ifdef MOZ_WIDGET_GONK
uint32_t len = mPermissionRequests.Length();
for (uint32_t i = 0; i < len; i++) {
if (mPermissionRequests[i].type().EqualsLiteral("audio-capture")) {
GonkPermissionService::GetInstance()->addGrantInfo(
"android.permission.RECORD_AUDIO",
static_cast<ContentParent*>(mParent->Manager())->Pid());
}
if (mPermissionRequests[i].type().EqualsLiteral("video-capture")) {
GonkPermissionService::GetInstance()->addGrantInfo(
"android.permission.CAMERA",
static_cast<ContentParent*>(mParent->Manager())->Pid());
}
}
#endif
nsTArray<PermissionChoice> choices;
if (aChoices.isNullOrUndefined()) {
// No choice is specified.

Просмотреть файл

@ -1307,6 +1307,7 @@ nsIDocument::nsIDocument()
mFontFaceSetDirty(true),
mGetUserFontSetCalled(false),
mPostedFlushUserFontSet(false),
mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
mPartID(0),
mDidFireDOMContentLoaded(true),
mHasScrollLinkedEffect(false),

Просмотреть файл

@ -734,7 +734,6 @@ GK_ATOM(oncomplete, "oncomplete")
GK_ATOM(oncompositionend, "oncompositionend")
GK_ATOM(oncompositionstart, "oncompositionstart")
GK_ATOM(oncompositionupdate, "oncompositionupdate")
GK_ATOM(onconfigurationchange, "onconfigurationchange")
GK_ATOM(onconnect, "onconnect")
GK_ATOM(onconnected, "onconnected")
GK_ATOM(onconnecting, "onconnecting")
@ -791,7 +790,6 @@ GK_ATOM(onenterpincodereq, "onenterpincodereq")
GK_ATOM(onemergencycbmodechange, "onemergencycbmodechange")
GK_ATOM(onerror, "onerror")
GK_ATOM(onevicted, "onevicted")
GK_ATOM(onfacesdetected, "onfacesdetected")
GK_ATOM(onfailed, "onfailed")
GK_ATOM(onfetch, "onfetch")
GK_ATOM(onfinish, "onfinish")
@ -882,7 +880,6 @@ GK_ATOM(onpairingconsentreq, "onpairingconsentreq")
GK_ATOM(onpaste, "onpaste")
GK_ATOM(onpendingchange, "onpendingchange")
GK_ATOM(onpichange, "onpichange")
GK_ATOM(onpicture, "onpicture")
GK_ATOM(onpointerlockchange, "onpointerlockchange")
GK_ATOM(onpointerlockerror, "onpointerlockerror")
GK_ATOM(onpopuphidden, "onpopuphidden")
@ -890,8 +887,6 @@ GK_ATOM(onpopuphiding, "onpopuphiding")
GK_ATOM(onpopuppositioned, "onpopuppositioned")
GK_ATOM(onpopupshowing, "onpopupshowing")
GK_ATOM(onpopupshown, "onpopupshown")
GK_ATOM(onposter, "onposter")
GK_ATOM(onpreviewstatechange, "onpreviewstatechange")
GK_ATOM(onpullphonebookreq, "onpullphonebookreq")
GK_ATOM(onpullvcardentryreq, "onpullvcardentryreq")
GK_ATOM(onpullvcardlistingreq, "onpullvcardlistingreq")
@ -907,7 +902,6 @@ GK_ATOM(onreadsuccess, "onreadsuccess")
GK_ATOM(onready, "onready")
GK_ATOM(onreadystatechange, "onreadystatechange")
GK_ATOM(onreceived, "onreceived")
GK_ATOM(onrecorderstatechange, "onrecorderstatechange")
GK_ATOM(onremoteheld, "onremoteheld")
GK_ATOM(onremoteresumed, "onremoteresumed")
GK_ATOM(onresourcetimingbufferfull, "onresourcetimingbufferfull")
@ -928,7 +922,6 @@ GK_ATOM(onsending, "onsending")
GK_ATOM(onsent, "onsent")
GK_ATOM(onset, "onset")
GK_ATOM(onshow, "onshow")
GK_ATOM(onshutter, "onshutter")
GK_ATOM(onstatechange, "onstatechange")
GK_ATOM(onstatuschanged, "onstatuschanged")
GK_ATOM(onstkcommand, "onstkcommand")

Просмотреть файл

@ -189,45 +189,6 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::cache::CacheStorage',
},
'CameraCapabilities': {
'nativeType': 'mozilla::dom::CameraCapabilities',
'headerFile': 'DOMCameraCapabilities.h'
},
'CameraControl': {
'nativeType': 'mozilla::nsDOMCameraControl',
'headerFile': 'DOMCameraControl.h',
'binaryNames': {
"release": "ReleaseHardware"
}
},
'CameraDetectedFace': {
'nativeType': 'mozilla::dom::DOMCameraDetectedFace',
'headerFile': 'DOMCameraDetectedFace.h'
},
'CameraManager': {
'nativeType': 'nsDOMCameraManager',
'headerFile': 'DOMCameraManager.h'
},
'CameraRecorderAudioProfile': {
'headerFile': 'DOMCameraCapabilities.h'
},
'CameraRecorderProfile': {
'headerFile': 'DOMCameraCapabilities.h'
},
'CameraRecorderProfiles': {
'headerFile': 'DOMCameraCapabilities.h'
},
'CameraRecorderVideoProfile': {
'headerFile': 'DOMCameraCapabilities.h'
},
'CanvasRenderingContext2D': {
'implicitJSContext': [
'createImageData', 'getImageData'
@ -750,14 +711,6 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::time::TimeManager',
},
'MozVoicemail': {
'nativeType': 'mozilla::dom::Voicemail',
},
'MozVoicemailStatus': {
'nativeType': 'mozilla::dom::VoicemailStatus',
},
'MutationObserver': {
'nativeType': 'nsDOMMutationObserver',
},

Просмотреть файл

@ -60,7 +60,6 @@ LOCAL_INCLUDES += [
'/dom/base',
'/dom/battery',
'/dom/bluetooth/common/webapi',
'/dom/camera',
'/dom/canvas',
'/dom/geolocation',
'/dom/html',

Просмотреть файл

@ -1,49 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef RWLOCK_AUTO_ENTER_H
#define RWLOCK_AUTO_ENTER_H
#include "prrwlock.h"
#include "mozilla/Assertions.h"
class RwLockAutoEnterRead
{
public:
explicit RwLockAutoEnterRead(PRRWLock* aRwLock)
: mRwLock(aRwLock)
{
MOZ_ASSERT(mRwLock);
PR_RWLock_Rlock(mRwLock);
}
~RwLockAutoEnterRead()
{
PR_RWLock_Unlock(mRwLock);
}
protected:
PRRWLock* mRwLock;
};
class RwLockAutoEnterWrite
{
public:
explicit RwLockAutoEnterWrite(PRRWLock* aRwLock)
: mRwLock(aRwLock)
{
MOZ_ASSERT(mRwLock);
PR_RWLock_Wlock(mRwLock);
}
~RwLockAutoEnterWrite()
{
PR_RWLock_Unlock(mRwLock);
}
protected:
PRRWLock* mRwLock;
};
#endif // RWLOCK_AUTO_ENTER_H

Просмотреть файл

@ -1,44 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_CAMERACOMMON_H
#define DOM_CAMERA_CAMERACOMMON_H
#include "mozilla/Logging.h"
extern mozilla::LogModule* GetCameraLog();
#define DOM_CAMERA_LOG( type, ... ) MOZ_LOG(GetCameraLog(), (mozilla::LogLevel)type, ( __VA_ARGS__ ))
#define DOM_CAMERA_LOGA( ... ) DOM_CAMERA_LOG( mozilla::LogLevel::Error, __VA_ARGS__ )
/**
* From the least to the most output.
*/
enum {
DOM_CAMERA_LOG_NOTHING,
DOM_CAMERA_LOG_ERROR,
DOM_CAMERA_LOG_WARNING,
DOM_CAMERA_LOG_INFO,
DOM_CAMERA_LOG_TRACE,
DOM_CAMERA_LOG_REFERENCES
};
/**
* DOM_CAMERA_LOGR() can be called before 'gCameraLog' is set, so
* we need to handle this one a little differently.
*/
#define DOM_CAMERA_LOGR( ... ) \
do { \
if (GetCameraLog()) { \
DOM_CAMERA_LOG( DOM_CAMERA_LOG_REFERENCES, __VA_ARGS__ ); \
} \
} while (0)
#define DOM_CAMERA_LOGT( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_TRACE, __VA_ARGS__ )
#define DOM_CAMERA_LOGI( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_INFO, __VA_ARGS__ )
#define DOM_CAMERA_LOGW( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_WARNING, __VA_ARGS__ )
#define DOM_CAMERA_LOGE( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_ERROR, __VA_ARGS__ )
#endif // DOM_CAMERA_CAMERACOMMON_H

Просмотреть файл

@ -1,795 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CameraControlImpl.h"
#include "base/basictypes.h"
#include "mozilla/Assertions.h"
#include "mozilla/Unused.h"
#include "nsPrintfCString.h"
#include "nsIWeakReferenceUtils.h"
#include "CameraCommon.h"
#include "nsGlobalWindow.h"
#include "DeviceStorageFileDescriptor.h"
#include "CameraControlListener.h"
using namespace mozilla;
/* static */ StaticRefPtr<nsIThread> CameraControlImpl::sCameraThread;
CameraControlImpl::CameraControlImpl()
: mListenerLock("mozilla::camera::CameraControlImpl.Listeners")
, mPreviewState(CameraControlListener::kPreviewStopped)
, mHardwareState(CameraControlListener::kHardwareUninitialized)
, mHardwareStateChangeReason(NS_OK)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
mCurrentConfiguration.mMode = ICameraControl::kUnspecifiedMode;
class Delegate : public Runnable
{
public:
NS_IMETHOD
Run() override
{
char stackBaseGuess;
profiler_register_thread("CameraThread", &stackBaseGuess);
return NS_OK;
}
};
// reuse the same camera thread to conserve resources
nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
if (ct) {
mCameraThread = ct.forget();
} else {
nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
if (NS_FAILED(rv)) {
MOZ_CRASH("Failed to create new Camera Thread");
}
mCameraThread->Dispatch(new Delegate(), NS_DISPATCH_NORMAL);
sCameraThread = mCameraThread;
}
}
CameraControlImpl::~CameraControlImpl()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
void
CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState,
nsresult aReason)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread. On Gonk, it may be called from the camera's
// local binder thread, should the mediaserver process die.
MutexAutoLock lock(mListenerLock);
if (aNewState == mHardwareState) {
DOM_CAMERA_LOGI("OnHardwareStateChange: state did not change from %d\n", mHardwareState);
return;
}
const char* state[] = { "uninitialized", "closed", "open", "failed" };
MOZ_ASSERT(aNewState >= 0);
if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
DOM_CAMERA_LOGI("New hardware state is '%s' (reason=0x%x)\n",
state[aNewState], aReason);
} else {
DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState);
}
mHardwareState = aNewState;
mHardwareStateChangeReason = aReason;
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnHardwareStateChange(mHardwareState, mHardwareStateChangeReason);
}
}
void
CameraControlImpl::OnConfigurationChange()
{
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
MutexAutoLock lock(mListenerLock);
DOM_CAMERA_LOGI("OnConfigurationChange : %zu listeners\n", mListeners.Length());
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnConfigurationChange(mCurrentConfiguration);
}
}
void
CameraControlImpl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread. On Gonk, it is called from the camera
// library's auto focus thread.
MutexAutoLock lock(mListenerLock);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnAutoFocusComplete(aAutoFocusSucceeded);
}
}
void
CameraControlImpl::OnAutoFocusMoving(bool aIsMoving)
{
MutexAutoLock lock(mListenerLock);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnAutoFocusMoving(aIsMoving);
}
}
void
CameraControlImpl::OnFacesDetected(const nsTArray<Face>& aFaces)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread. On Gonk, it is called from the camera
// library's face detection thread.
MutexAutoLock lock(mListenerLock);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnFacesDetected(aFaces);
}
}
void
CameraControlImpl::OnTakePictureComplete(const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread. On Gonk, it is called from the camera
// library's snapshot thread.
MutexAutoLock lock(mListenerLock);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnTakePictureComplete(aData, aLength, aMimeType);
}
}
void
CameraControlImpl::OnPoster(dom::BlobImpl* aBlobImpl)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread.
MutexAutoLock lock(mListenerLock);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnPoster(aBlobImpl);
}
}
void
CameraControlImpl::OnShutter()
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread. On Gonk, it is called from the camera driver's
// preview thread.
MutexAutoLock lock(mListenerLock);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnShutter();
}
}
void
CameraControlImpl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
int32_t aStatus, int32_t aTrackNumber)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread. On Gonk, it is called from the media encoder
// thread.
MutexAutoLock lock(mListenerLock);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnRecorderStateChange(aState, aStatus, aTrackNumber);
}
}
void
CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNewState)
{
// This callback runs on the Main Thread and the Camera Thread, and
// may run on the local binder thread, should the mediaserver
// process die.
MutexAutoLock lock(mListenerLock);
if (aNewState == mPreviewState) {
DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState);
return;
}
const char* state[] = { "stopped", "paused", "started" };
MOZ_ASSERT(aNewState >= 0);
if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
DOM_CAMERA_LOGI("New preview state is '%s'\n", state[aNewState]);
} else {
DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState);
}
mPreviewState = aNewState;
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnPreviewStateChange(mPreviewState);
}
}
void
CameraControlImpl::OnRateLimitPreview(bool aLimit)
{
// This function runs on neither the Main Thread nor the Camera Thread.
MutexAutoLock lock(mListenerLock);
DOM_CAMERA_LOGI("OnRateLimitPreview: %d\n", aLimit);
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnRateLimitPreview(aLimit);
}
}
bool
CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
{
// This function runs on neither the Main Thread nor the Camera Thread.
// On Gonk, it is called from the camera driver's preview thread.
MutexAutoLock lock(mListenerLock);
DOM_CAMERA_LOGI("OnNewPreviewFrame: we have %zu preview frame listener(s)\n",
mListeners.Length());
bool consumed = false;
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
consumed = l->OnNewPreviewFrame(aImage, aWidth, aHeight) || consumed;
}
return consumed;
}
void
CameraControlImpl::OnUserError(CameraControlListener::UserContext aContext,
nsresult aError)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread.
MutexAutoLock lock(mListenerLock);
const char* context[] = {
"StartCamera",
"StopCamera",
"AutoFocus",
"StartFaceDetection",
"StopFaceDetection",
"TakePicture",
"StartRecording",
"StopRecording",
"PauseRecording",
"ResumeRecording",
"SetConfiguration",
"StartPreview",
"StopPreview",
"SetPictureSize",
"SetThumbnailSize",
"ResumeContinuousFocus",
"Unspecified"
};
if (static_cast<size_t>(aContext) < sizeof(context) / sizeof(context[0])) {
DOM_CAMERA_LOGW("CameraControlImpl::OnUserError : aContext='%s' (%d), aError=0x%x\n",
context[aContext], aContext, aError);
} else {
DOM_CAMERA_LOGE("CameraControlImpl::OnUserError : aContext=%d, aError=0x%x\n",
aContext, aError);
}
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnUserError(aContext, aError);
}
}
void
CameraControlImpl::OnSystemError(CameraControlListener::SystemContext aContext,
nsresult aError)
{
// This callback can run on threads other than the Main Thread and
// the Camera Thread.
MutexAutoLock lock(mListenerLock);
const char* context[] = {
"Camera Service"
};
if (static_cast<size_t>(aContext) < sizeof(context) / sizeof(context[0])) {
DOM_CAMERA_LOGW("CameraControlImpl::OnSystemError : aContext='%s' (%d), aError=0x%x\n",
context[aContext], aContext, aError);
} else {
DOM_CAMERA_LOGE("CameraControlImpl::OnSystemError : aContext=%d, aError=0x%x\n",
aContext, aError);
}
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
CameraControlListener* l = mListeners[i];
l->OnSystemError(aContext, aError);
}
}
// Camera control asynchronous message; these are dispatched from
// the Main Thread to the Camera Thread, where they are consumed.
class CameraControlImpl::ControlMessage : public Runnable
{
public:
ControlMessage(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: mCameraControl(aCameraControl)
, mContext(aContext)
{ }
virtual nsresult RunImpl() = 0;
NS_IMETHOD
Run() override
{
MOZ_ASSERT(mCameraControl);
MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl->mCameraThread);
nsresult rv = RunImpl();
if (NS_FAILED(rv)) {
nsPrintfCString msg("Camera control API(%d) failed with 0x%x", mContext, rv);
NS_WARNING(msg.get());
mCameraControl->OnUserError(mContext, rv);
}
return NS_OK;
}
protected:
virtual ~ControlMessage() { }
RefPtr<CameraControlImpl> mCameraControl;
CameraControlListener::UserContext mContext;
};
nsresult
CameraControlImpl::Dispatch(ControlMessage* aMessage)
{
nsresult rv = mCameraThread->Dispatch(aMessage, NS_DISPATCH_NORMAL);
if (NS_SUCCEEDED(rv)) {
return NS_OK;
}
nsPrintfCString msg("Failed to dispatch camera control message (0x%x)", rv);
NS_WARNING(msg.get());
return NS_ERROR_FAILURE;
}
nsresult
CameraControlImpl::Start(const Configuration* aConfig)
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext,
const Configuration* aConfig)
: ControlMessage(aCameraControl, aContext)
, mHaveInitialConfig(false)
{
if (aConfig) {
mConfig = *aConfig;
mHaveInitialConfig = true;
}
}
nsresult
RunImpl() override
{
if (mHaveInitialConfig) {
return mCameraControl->StartImpl(&mConfig);
}
return mCameraControl->StartImpl();
}
protected:
bool mHaveInitialConfig;
Configuration mConfig;
};
return Dispatch(new Message(this, CameraControlListener::kInStartCamera, aConfig));
}
nsresult
CameraControlImpl::SetConfiguration(const Configuration& aConfig)
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext,
const Configuration& aConfig)
: ControlMessage(aCameraControl, aContext)
, mConfig(aConfig)
{ }
nsresult
RunImpl() override
{
return mCameraControl->SetConfigurationImpl(mConfig);
}
protected:
Configuration mConfig;
};
return Dispatch(new Message(this, CameraControlListener::kInSetConfiguration, aConfig));
}
nsresult
CameraControlImpl::AutoFocus()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->AutoFocusImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInAutoFocus));
}
nsresult
CameraControlImpl::StartFaceDetection()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->StartFaceDetectionImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInStartFaceDetection));
}
nsresult
CameraControlImpl::StopFaceDetection()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->StopFaceDetectionImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInStopFaceDetection));
}
nsresult
CameraControlImpl::TakePicture()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->TakePictureImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInTakePicture));
}
nsresult
CameraControlImpl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions)
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext,
const StartRecordingOptions* aOptions,
DeviceStorageFileDescriptor* aFileDescriptor)
: ControlMessage(aCameraControl, aContext)
, mOptionsPassed(false)
, mFileDescriptor(aFileDescriptor)
{
if (aOptions) {
mOptions = *aOptions;
mOptionsPassed = true;
}
}
nsresult
RunImpl() override
{
return mCameraControl->StartRecordingImpl(mFileDescriptor,
mOptionsPassed ? &mOptions : nullptr);
}
protected:
StartRecordingOptions mOptions;
bool mOptionsPassed;
RefPtr<DeviceStorageFileDescriptor> mFileDescriptor;
};
if (!aFileDescriptor) {
return NS_ERROR_INVALID_ARG;
}
return Dispatch(new Message(this, CameraControlListener::kInStartRecording,
aOptions, aFileDescriptor));
}
nsresult
CameraControlImpl::StopRecording()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->StopRecordingImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInStopRecording));
}
nsresult
CameraControlImpl::PauseRecording()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->PauseRecordingImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInPauseRecording));
}
nsresult
CameraControlImpl::ResumeRecording()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->ResumeRecordingImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInResumeRecording));
}
nsresult
CameraControlImpl::StartPreview()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->StartPreviewImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInStartPreview));
}
nsresult
CameraControlImpl::StopPreview()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->StopPreviewImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInStopPreview));
}
nsresult
CameraControlImpl::ResumeContinuousFocus()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->ResumeContinuousFocusImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInResumeContinuousFocus));
}
nsresult
CameraControlImpl::Stop()
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::UserContext aContext)
: ControlMessage(aCameraControl, aContext)
{ }
nsresult
RunImpl() override
{
return mCameraControl->StopImpl();
}
};
return Dispatch(new Message(this, CameraControlListener::kInStopCamera));
}
class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage
{
public:
ListenerMessage(CameraControlImpl* aCameraControl,
CameraControlListener* aListener)
: ControlMessage(aCameraControl, CameraControlListener::kInUnspecified)
, mListener(aListener)
{ }
protected:
RefPtr<CameraControlListener> mListener;
};
void
CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aListener)
{
MutexAutoLock lock(mListenerLock);
CameraControlListener* l = *mListeners.AppendElement() = aListener;
DOM_CAMERA_LOGI("Added camera control listener %p\n", l);
// Update the newly-added listener's state
l->OnConfigurationChange(mCurrentConfiguration);
l->OnHardwareStateChange(mHardwareState, mHardwareStateChangeReason);
l->OnPreviewStateChange(mPreviewState);
}
void
CameraControlImpl::AddListener(CameraControlListener* aListener)
{
class Message : public ListenerMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener* aListener)
: ListenerMessage(aCameraControl, aListener)
{ }
nsresult
RunImpl() override
{
mCameraControl->AddListenerImpl(mListener.forget());
return NS_OK;
}
};
if (aListener) {
Dispatch(new Message(this, aListener));
}
}
void
CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener)
{
MutexAutoLock lock(mListenerLock);
RefPtr<CameraControlListener> l(aListener);
mListeners.RemoveElement(l);
DOM_CAMERA_LOGI("Removed camera control listener %p\n", l.get());
// XXXmikeh - do we want to notify the listener that it has been removed?
}
void
CameraControlImpl::RemoveListener(CameraControlListener* aListener)
{
class Message : public ListenerMessage
{
public:
Message(CameraControlImpl* aCameraControl, CameraControlListener* aListener)
: ListenerMessage(aCameraControl, aListener)
{ }
nsresult
RunImpl() override
{
mCameraControl->RemoveListenerImpl(mListener);
return NS_OK;
}
};
if (aListener) {
Dispatch(new Message(this, aListener));
}
}

Просмотреть файл

@ -1,148 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_CAMERACONTROLIMPL_H
#define DOM_CAMERA_CAMERACONTROLIMPL_H
#include "nsTArray.h"
#include "nsWeakPtr.h"
#include "mozilla/Attributes.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Mutex.h"
#include "nsIFile.h"
#include "nsProxyRelease.h"
#include "ICameraControl.h"
#include "CameraCommon.h"
#include "DeviceStorage.h"
#include "DeviceStorageFileDescriptor.h"
#include "CameraControlListener.h"
namespace mozilla {
namespace dom {
class BlobImpl;
} // namespace dom
namespace layers {
class Image;
} // namespace layers
class CameraControlImpl : public ICameraControl
{
public:
explicit CameraControlImpl();
virtual void AddListener(CameraControlListener* aListener) override;
virtual void RemoveListener(CameraControlListener* aListener) override;
// See ICameraControl.h for these methods' return values.
virtual nsresult Start(const Configuration* aConfig = nullptr) override;
virtual nsresult Stop() override;
virtual nsresult SetConfiguration(const Configuration& aConfig) override;
virtual nsresult StartPreview() override;
virtual nsresult StopPreview() override;
virtual nsresult AutoFocus() override;
virtual nsresult StartFaceDetection() override;
virtual nsresult StopFaceDetection() override;
virtual nsresult TakePicture() override;
virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions) override;
virtual nsresult StopRecording() override;
virtual nsresult PauseRecording() override;
virtual nsresult ResumeRecording() override;
virtual nsresult ResumeContinuousFocus() override;
// Event handlers called directly from outside this class.
void OnShutter();
void OnUserError(CameraControlListener::UserContext aContext, nsresult aError);
void OnSystemError(CameraControlListener::SystemContext aContext, nsresult aError);
void OnAutoFocusMoving(bool aIsMoving);
protected:
// Event handlers.
void OnAutoFocusComplete(bool aAutoFocusSucceeded);
void OnFacesDetected(const nsTArray<Face>& aFaces);
void OnTakePictureComplete(const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
void OnPoster(dom::BlobImpl* aBlobImpl);
void OnRateLimitPreview(bool aLimit);
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
void OnRecorderStateChange(CameraControlListener::RecorderState aState,
int32_t aStatus = -1, int32_t aTrackNumber = -1);
void OnPreviewStateChange(CameraControlListener::PreviewState aState);
void OnHardwareStateChange(CameraControlListener::HardwareState aState,
nsresult aReason);
void OnConfigurationChange();
// When we create a new CameraThread, we keep a static reference to it so
// that multiple CameraControl instances can find and reuse it; but we
// don't want that reference to keep the thread object around unnecessarily,
// so we make it a weak reference. The strong dynamic references will keep
// the thread object alive as needed.
static StaticRefPtr<nsIThread> sCameraThread;
nsCOMPtr<nsIThread> mCameraThread;
virtual ~CameraControlImpl();
virtual void BeginBatchParameterSet() override { }
virtual void EndBatchParameterSet() override { }
// Manage camera event listeners.
void AddListenerImpl(already_AddRefed<CameraControlListener> aListener);
void RemoveListenerImpl(CameraControlListener* aListener);
nsTArray<RefPtr<CameraControlListener> > mListeners;
mutable Mutex mListenerLock;
class ControlMessage;
class ListenerMessage;
nsresult Dispatch(ControlMessage* aMessage);
// Asynchronous method implementations, invoked on the Camera Thread.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_INVALID_ARG if one or more arguments is invalid;
// - NS_ERROR_NOT_INITIALIZED if the underlying hardware is not initialized,
// failed to initialize (in the case of StartImpl()), or has been stopped;
// for StartRecordingImpl(), this indicates that no recorder has been
// configured (either by calling StartImpl() or SetConfigurationImpl());
// - NS_ERROR_ALREADY_INITIALIZED if the underlying hardware is already
// initialized;
// - NS_ERROR_NOT_IMPLEMENTED if the method is not implemented;
// - NS_ERROR_FAILURE on general failures.
virtual nsresult StartImpl(const Configuration* aConfig = nullptr) = 0;
virtual nsresult StopImpl() = 0;
virtual nsresult SetConfigurationImpl(const Configuration& aConfig) = 0;
virtual nsresult StartPreviewImpl() = 0;
virtual nsresult StopPreviewImpl() = 0;
virtual nsresult AutoFocusImpl() = 0;
virtual nsresult StartFaceDetectionImpl() = 0;
virtual nsresult StopFaceDetectionImpl() = 0;
virtual nsresult TakePictureImpl() = 0;
virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions) = 0;
virtual nsresult StopRecordingImpl() = 0;
virtual nsresult PauseRecordingImpl() = 0;
virtual nsresult ResumeRecordingImpl() = 0;
virtual nsresult ResumeContinuousFocusImpl() = 0;
virtual nsresult PushParametersImpl() = 0;
virtual nsresult PullParametersImpl() = 0;
void OnShutterInternal();
void OnClosedInternal();
CameraControlListener::CameraListenerConfiguration mCurrentConfiguration;
CameraControlListener::PreviewState mPreviewState;
CameraControlListener::HardwareState mHardwareState;
nsresult mHardwareStateChangeReason;
private:
CameraControlImpl(const CameraControlImpl&) = delete;
CameraControlImpl& operator=(const CameraControlImpl&) = delete;
};
} // namespace mozilla
#endif // DOM_CAMERA_CAMERACONTROLIMPL_H

Просмотреть файл

@ -1,138 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_CAMERACONTROLLISTENER_H
#define DOM_CAMERA_CAMERACONTROLLISTENER_H
#include <stdint.h>
#include "ICameraControl.h"
namespace mozilla {
namespace dom {
class BlobImpl;
} // namespace dom
namespace layers {
class Image;
} // namespace layers
class CameraControlListener
{
public:
CameraControlListener()
{
MOZ_COUNT_CTOR(CameraControlListener);
}
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~CameraControlListener()
{
MOZ_COUNT_DTOR(CameraControlListener);
}
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CameraControlListener);
enum HardwareState
{
kHardwareUninitialized,
kHardwareClosed,
kHardwareOpen,
kHardwareOpenFailed
};
// aReason:
// NS_OK : state change was expected and normal;
// NS_ERROR_FAILURE : one or more system-level components failed and
// the camera was closed;
// NS_ERROR_NOT_AVAILABLE : the hardware is in use by another process
// and cannot be acquired, or another process
// was given access to the camera hardware.
virtual void OnHardwareStateChange(HardwareState aState, nsresult aReason) { }
enum PreviewState
{
kPreviewStopped,
kPreviewPaused,
kPreviewStarted
};
virtual void OnPreviewStateChange(PreviewState aState) { }
enum RecorderState
{
kRecorderStopped,
kRecorderStarted,
kRecorderPaused,
kRecorderResumed,
kPosterCreated,
kPosterFailed,
#ifdef MOZ_B2G_CAMERA
kFileSizeLimitReached,
kVideoLengthLimitReached,
kTrackCompleted,
kTrackFailed,
kMediaRecorderFailed,
kMediaServerFailed
#endif
};
enum { kNoTrackNumber = -1 };
virtual void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum) { }
virtual void OnShutter() { }
virtual void OnRateLimitPreview(bool aLimit) { }
virtual bool OnNewPreviewFrame(layers::Image* aFrame, uint32_t aWidth, uint32_t aHeight)
{
return false;
}
class CameraListenerConfiguration : public ICameraControl::Configuration
{
public:
uint32_t mMaxMeteringAreas;
uint32_t mMaxFocusAreas;
};
virtual void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration) { }
virtual void OnAutoFocusComplete(bool aAutoFocusSucceeded) { }
virtual void OnAutoFocusMoving(bool aIsMoving) { }
virtual void OnTakePictureComplete(const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) { }
virtual void OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces) { }
virtual void OnPoster(dom::BlobImpl* aBlobImpl) { }
enum UserContext
{
kInStartCamera,
kInStopCamera,
kInAutoFocus,
kInStartFaceDetection,
kInStopFaceDetection,
kInTakePicture,
kInStartRecording,
kInStopRecording,
kInPauseRecording,
kInResumeRecording,
kInSetConfiguration,
kInStartPreview,
kInStopPreview,
kInSetPictureSize,
kInSetThumbnailSize,
kInResumeContinuousFocus,
kInUnspecified
};
// Error handler for problems arising due to user-initiated actions.
virtual void OnUserError(UserContext aContext, nsresult aError) { }
enum SystemContext
{
kSystemService
};
// Error handler for problems arising due to system failures, not triggered
// by something the CameraControl API user did.
virtual void OnSystemError(SystemContext aContext, nsresult aError) { }
};
} // namespace mozilla
#endif // DOM_CAMERA_CAMERACONTROLLISTENER_H

Просмотреть файл

@ -1,425 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CameraPreferences.h"
#include "CameraCommon.h"
#include "DOMCameraManager.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Preferences.h"
#ifdef MOZ_WIDGET_GONK
#include "mozilla/Services.h"
#include "nsIObserverService.h"
#endif
using namespace mozilla;
/* statics */
static StaticAutoPtr<Monitor> sPrefMonitor;
StaticAutoPtr<nsCString> CameraPreferences::sPrefTestEnabled;
StaticAutoPtr<nsCString> CameraPreferences::sPrefHardwareTest;
StaticAutoPtr<nsCString> CameraPreferences::sPrefGonkParameters;
nsresult CameraPreferences::sPrefCameraControlMethodErrorOverride = NS_OK;
nsresult CameraPreferences::sPrefCameraControlAsyncErrorOverride = NS_OK;
uint32_t CameraPreferences::sPrefCameraControlLowMemoryThresholdMB = 0;
bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
bool CameraPreferences::sPrefCameraParametersPermission = false;
#ifdef MOZ_WIDGET_GONK
StaticRefPtr<CameraPreferences> CameraPreferences::sObserver;
NS_IMPL_ISUPPORTS(CameraPreferences, nsIObserver);
#endif
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
{
uint32_t val;
nsresult rv = Preferences::GetUint(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = static_cast<nsresult>(val);
} else if(rv == NS_ERROR_UNEXPECTED) {
// Preference does not exist
rv = NS_OK;
aVal = NS_OK;
}
return rv;
}
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, uint32_t& aVal)
{
uint32_t val;
nsresult rv = Preferences::GetUint(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = val;
} else if(rv == NS_ERROR_UNEXPECTED) {
// Preference does not exist
rv = NS_OK;
aVal = 0;
}
return rv;
}
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, nsACString& aVal)
{
nsCString val;
nsresult rv = Preferences::GetCString(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = val;
} else if(rv == NS_ERROR_UNEXPECTED) {
// Preference does not exist
rv = NS_OK;
aVal.Truncate();
}
return rv;
}
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, bool& aVal)
{
bool val;
nsresult rv = Preferences::GetBool(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = val;
} else if(rv == NS_ERROR_UNEXPECTED) {
// Preference does not exist
rv = NS_OK;
aVal = false;
}
return rv;
}
/* static */
CameraPreferences::Pref CameraPreferences::sPrefs[] = {
{
"camera.control.test.enabled",
kPrefValueIsCString,
{ &sPrefTestEnabled }
},
{
"camera.control.test.hardware",
kPrefValueIsCString,
{ &sPrefHardwareTest }
},
{
"camera.control.test.permission",
kPrefValueIsBoolean,
{ &sPrefCameraParametersPermission }
},
#ifdef MOZ_B2G
{
"camera.control.test.hardware.gonk.parameters",
kPrefValueIsCString,
{ &sPrefGonkParameters }
},
#endif
{
"camera.control.test.method.error",
kPrefValueIsNsResult,
{ &sPrefCameraControlMethodErrorOverride }
},
{
"camera.control.test.async.error",
kPrefValueIsNsResult,
{ &sPrefCameraControlAsyncErrorOverride }
},
{
"camera.control.test.is_low_memory",
kPrefValueIsBoolean,
{ &sPrefCameraParametersIsLowMemory }
},
{
"camera.control.low_memory_thresholdMB",
kPrefValueIsUint32,
{ &sPrefCameraControlLowMemoryThresholdMB }
},
};
/* static */
uint32_t
CameraPreferences::PrefToIndex(const char* aPref)
{
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
if (strcmp(aPref, sPrefs[i].mPref) == 0) {
return i;
}
}
return kPrefNotFound;
}
/* static */
void
CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
{
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound) {
DOM_CAMERA_LOGE("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return;
}
Pref& p = sPrefs[i];
nsresult rv;
switch (p.mValueType) {
case kPrefValueIsNsResult:
{
nsresult& v = *p.mValue.mAsNsResult;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, 0x%x\n", aPref, v);
}
}
break;
case kPrefValueIsUint32:
{
uint32_t& v = *p.mValue.mAsUint32;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, %u\n", aPref, v);
}
}
break;
case kPrefValueIsCString:
{
nsCString& v = **p.mValue.mAsCString;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, '%s'\n", aPref, v.get());
}
}
break;
case kPrefValueIsBoolean:
{
bool& v = *p.mValue.mAsBoolean;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, %s\n",
aPref, v ? "true" : "false");
}
}
break;
default:
MOZ_ASSERT_UNREACHABLE("Unhandled preference value type!");
return;
}
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGE("Failed to get pref '%s' (0x%x)\n", aPref, rv);
}
}
/* static */
bool
CameraPreferences::Initialize()
{
DOM_CAMERA_LOGI("Initializing camera preference callbacks\n");
nsresult rv;
#ifdef MOZ_WIDGET_GONK
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
sObserver = new CameraPreferences();
rv = obs->AddObserver(sObserver, "init-camera-hw", false);
if (NS_WARN_IF(NS_FAILED(rv))) {
sObserver = nullptr;
}
} else {
DOM_CAMERA_LOGE("Could not get observer service\n");
}
#endif
sPrefMonitor = new Monitor("CameraPreferences.sPrefMonitor");
sPrefTestEnabled = new nsCString();
sPrefHardwareTest = new nsCString();
sPrefGonkParameters = new nsCString();
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
rv = Preferences::RegisterCallbackAndCall(CameraPreferences::PreferenceChanged,
sPrefs[i].mPref);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
}
DOM_CAMERA_LOGI("Camera preferences initialized\n");
return true;
}
/* static */
void
CameraPreferences::Shutdown()
{
DOM_CAMERA_LOGI("Shutting down camera preference callbacks\n");
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
Preferences::UnregisterCallback(CameraPreferences::PreferenceChanged,
sPrefs[i].mPref);
}
sPrefTestEnabled = nullptr;
sPrefHardwareTest = nullptr;
sPrefGonkParameters = nullptr;
sPrefMonitor = nullptr;
#ifdef MOZ_WIDGET_GONK
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
nsresult rv = obs->RemoveObserver(sObserver , "init-camera-hw");
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGE("Failed to remove CameraPreferences observer (0x%x)\n", rv);
}
sObserver = nullptr;
} else {
DOM_CAMERA_LOGE("Could not get observer service\n");
}
#endif
DOM_CAMERA_LOGI("Camera preferences shut down\n");
}
#ifdef MOZ_WIDGET_GONK
nsresult
CameraPreferences::PreinitCameraHardware()
{
nsDOMCameraManager::PreinitCameraHardware();
return NS_OK;
}
NS_IMETHODIMP
CameraPreferences::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
{
if (strcmp(aTopic, "init-camera-hw") == 0) {
return PreinitCameraHardware();
}
DOM_CAMERA_LOGE("Got unhandled topic '%s'\n", aTopic);
return NS_OK;
}
#endif
/* static */
bool
CameraPreferences::GetPref(const char* aPref, nsACString& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsCString) {
DOM_CAMERA_LOGW("Preference '%s' is not a string type\n", aPref);
return false;
}
StaticAutoPtr<nsCString>* s = sPrefs[i].mValue.mAsCString;
if (!*s) {
DOM_CAMERA_LOGE("Preference '%s' cache is not initialized\n", aPref);
return false;
}
if ((*s)->IsEmpty()) {
DOM_CAMERA_LOGI("Preference '%s' is not set\n", aPref);
return false;
}
DOM_CAMERA_LOGI("Preference '%s', got '%s'\n", aPref, (*s)->get());
aVal = **s;
return true;
}
/* static */
bool
CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsNsResult) {
DOM_CAMERA_LOGW("Preference '%s' is not an nsresult type\n", aPref);
return false;
}
nsresult v = *sPrefs[i].mValue.mAsNsResult;
if (v == NS_OK) {
DOM_CAMERA_LOGW("Preference '%s' is not set\n", aPref);
return false;
}
DOM_CAMERA_LOGI("Preference '%s', got 0x%x\n", aPref, v);
aVal = v;
return true;
}
/* static */
bool
CameraPreferences::GetPref(const char* aPref, uint32_t& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsUint32) {
DOM_CAMERA_LOGW("Preference '%s' is not a uint32_t type\n", aPref);
return false;
}
uint32_t v = *sPrefs[i].mValue.mAsUint32;
DOM_CAMERA_LOGI("Preference '%s', got %u\n", aPref, v);
aVal = v;
return true;
}
/* static */
bool
CameraPreferences::GetPref(const char* aPref, bool& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsBoolean) {
DOM_CAMERA_LOGW("Preference '%s' is not a boolean type\n", aPref);
return false;
}
bool v = *sPrefs[i].mValue.mAsBoolean;
DOM_CAMERA_LOGI("Preference '%s', got %s\n", aPref, v ? "true" : "false");
aVal = v;
return true;
}

Просмотреть файл

@ -1,104 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_CAMERAPREFERENCES_H
#define DOM_CAMERA_CAMERAPREFERENCES_H
#include "nsString.h"
#include "nsIObserver.h"
#ifdef MOZ_WIDGET_GONK
#include "mozilla/StaticPtr.h"
#endif
namespace mozilla {
template<class T> class StaticAutoPtr;
class CameraPreferences
#ifdef MOZ_WIDGET_GONK
: public nsIObserver
#endif
{
public:
#ifdef MOZ_WIDGET_GONK
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
#endif
static bool Initialize();
static void Shutdown();
static bool GetPref(const char* aPref, nsACString& aVal);
static bool GetPref(const char* aPref, nsresult& aVal);
static bool GetPref(const char* aPref, uint32_t& aVal);
static bool GetPref(const char* aPref, bool& aVal);
protected:
static const uint32_t kPrefNotFound = UINT32_MAX;
static uint32_t PrefToIndex(const char* aPref);
static void PreferenceChanged(const char* aPref, void* aClosure);
static nsresult UpdatePref(const char* aPref, nsresult& aVar);
static nsresult UpdatePref(const char* aPref, uint32_t& aVar);
static nsresult UpdatePref(const char* aPref, nsACString& aVar);
static nsresult UpdatePref(const char* aPref, bool& aVar);
enum PrefValueType {
kPrefValueIsNsResult,
kPrefValueIsUint32,
kPrefValueIsCString,
kPrefValueIsBoolean
};
struct Pref {
const char* const mPref;
PrefValueType mValueType;
union {
// The 'mAsVoid' member must be first and is required to allow 'mValue'
// to be initialized with any pointer type, as not all of our platforms
// support the use of designated initializers; in their absence, only
// the first element of a union can be statically initialized, and
// 'void*' lets us stuff any pointer type into it.
void* mAsVoid;
StaticAutoPtr<nsCString>* mAsCString;
nsresult* mAsNsResult;
uint32_t* mAsUint32;
bool* mAsBoolean;
} mValue;
};
static Pref sPrefs[];
static StaticAutoPtr<nsCString> sPrefTestEnabled;
static StaticAutoPtr<nsCString> sPrefHardwareTest;
static StaticAutoPtr<nsCString> sPrefGonkParameters;
static nsresult sPrefCameraControlMethodErrorOverride;
static nsresult sPrefCameraControlAsyncErrorOverride;
static uint32_t sPrefCameraControlLowMemoryThresholdMB;
static bool sPrefCameraParametersIsLowMemory;
static bool sPrefCameraParametersPermission;
#ifdef MOZ_WIDGET_GONK
static StaticRefPtr<CameraPreferences> sObserver;
nsresult PreinitCameraHardware();
protected:
// Objects may be instantiated for use as observers.
CameraPreferences() { }
virtual ~CameraPreferences() { }
#else
private:
// Static class only.
CameraPreferences();
~CameraPreferences();
#endif
};
} // namespace mozilla
#endif // DOM_CAMERA_CAMERAPREFERENCES_H

Просмотреть файл

@ -1,200 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CameraPreviewMediaStream.h"
#include "CameraCommon.h"
#include "MediaStreamListener.h"
#include "VideoFrameContainer.h"
/**
* Maximum number of outstanding invalidates before we start to drop frames;
* if we hit this threshold, it is an indicator that the main thread is
* either very busy or the device is busy elsewhere (e.g. encoding or
* persisting video data).
*/
#define MAX_INVALIDATE_PENDING 4
using namespace mozilla::layers;
using namespace mozilla::dom;
namespace mozilla {
static const TrackID TRACK_VIDEO = 2;
void
FakeMediaStreamGraph::DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
{
nsCOMPtr<nsIRunnable> task = aRunnable;
NS_DispatchToMainThread(task);
}
CameraPreviewMediaStream::CameraPreviewMediaStream()
: ProcessedMediaStream()
, mMutex("mozilla::camera::CameraPreviewMediaStream")
, mInvalidatePending(0)
, mDiscardedFrames(0)
, mRateLimit(false)
, mTrackCreated(false)
{
SetGraphImpl(
MediaStreamGraph::GetInstance(
MediaStreamGraph::SYSTEM_THREAD_DRIVER, AudioChannel::Normal));
mFakeMediaStreamGraph = new FakeMediaStreamGraph();
}
void
CameraPreviewMediaStream::AddAudioOutput(void* aKey)
{
}
void
CameraPreviewMediaStream::SetAudioOutputVolume(void* aKey, float aVolume)
{
}
void
CameraPreviewMediaStream::RemoveAudioOutput(void* aKey)
{
}
void
CameraPreviewMediaStream::AddVideoOutput(MediaStreamVideoSink* aSink, TrackID aID)
{
MutexAutoLock lock(mMutex);
RefPtr<MediaStreamVideoSink> sink = aSink;
AddVideoOutputImpl(sink.forget(), aID);
}
void
CameraPreviewMediaStream::RemoveVideoOutput(MediaStreamVideoSink* aSink, TrackID aID)
{
MutexAutoLock lock(mMutex);
RemoveVideoOutputImpl(aSink, aID);
}
void
CameraPreviewMediaStream::AddListener(MediaStreamListener* aListener)
{
MutexAutoLock lock(mMutex);
MediaStreamListener* listener = *mListeners.AppendElement() = aListener;
listener->NotifyBlockingChanged(mFakeMediaStreamGraph, MediaStreamListener::UNBLOCKED);
listener->NotifyHasCurrentData(mFakeMediaStreamGraph);
}
void
CameraPreviewMediaStream::RemoveListener(MediaStreamListener* aListener)
{
MutexAutoLock lock(mMutex);
RefPtr<MediaStreamListener> listener(aListener);
mListeners.RemoveElement(aListener);
listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamGraphEvent::EVENT_REMOVED);
}
void
CameraPreviewMediaStream::OnPreviewStateChange(bool aActive)
{
if (aActive) {
MutexAutoLock lock(mMutex);
if (!mTrackCreated) {
mTrackCreated = true;
VideoSegment tmpSegment;
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
l->NotifyQueuedTrackChanges(mFakeMediaStreamGraph, TRACK_VIDEO, 0,
TrackEventCommand::TRACK_EVENT_CREATED,
tmpSegment);
l->NotifyFinishedTrackCreation(mFakeMediaStreamGraph);
}
}
}
}
void
CameraPreviewMediaStream::Destroy()
{
MutexAutoLock lock(mMutex);
mMainThreadDestroyed = true;
DestroyImpl();
}
void
CameraPreviewMediaStream::Invalidate()
{
MutexAutoLock lock(mMutex);
--mInvalidatePending;
for (const TrackBound<MediaStreamVideoSink>& sink : mVideoOutputs) {
VideoFrameContainer* output = sink.mListener->AsVideoFrameContainer();
if (!output) {
continue;
}
output->Invalidate();
}
}
void
CameraPreviewMediaStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
uint32_t aFlags)
{
return;
}
void
CameraPreviewMediaStream::RateLimit(bool aLimit)
{
mRateLimit = aLimit;
}
void
CameraPreviewMediaStream::SetCurrentFrame(const gfx::IntSize& aIntrinsicSize, Image* aImage)
{
{
MutexAutoLock lock(mMutex);
if (mInvalidatePending > 0) {
if (mRateLimit || mInvalidatePending > MAX_INVALIDATE_PENDING) {
++mDiscardedFrames;
DOM_CAMERA_LOGW("Discard preview frame %d, %d invalidation(s) pending",
mDiscardedFrames, mInvalidatePending);
return;
}
DOM_CAMERA_LOGI("Update preview frame, %d invalidation(s) pending",
mInvalidatePending);
}
mDiscardedFrames = 0;
TimeStamp now = TimeStamp::Now();
for (const TrackBound<MediaStreamVideoSink>& sink : mVideoOutputs) {
VideoFrameContainer* output = sink.mListener->AsVideoFrameContainer();
if (!output) {
continue;
}
output->SetCurrentFrame(aIntrinsicSize, aImage, now);
}
++mInvalidatePending;
}
NS_DispatchToMainThread(NewRunnableMethod(this, &CameraPreviewMediaStream::Invalidate));
}
void
CameraPreviewMediaStream::ClearCurrentFrame()
{
MutexAutoLock lock(mMutex);
for (const TrackBound<MediaStreamVideoSink>& sink : mVideoOutputs) {
VideoFrameContainer* output = sink.mListener->AsVideoFrameContainer();
if (!output) {
continue;
}
output->ClearCurrentFrame();
NS_DispatchToMainThread(NewRunnableMethod(output, &VideoFrameContainer::Invalidate));
}
}
} // namespace mozilla

Просмотреть файл

@ -1,81 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H
#define DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H
#include "MediaStreamGraph.h"
#include "mozilla/Mutex.h"
namespace mozilla {
class MediaStreamVideoSink;
class FakeMediaStreamGraph : public MediaStreamGraph
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FakeMediaStreamGraph)
public:
FakeMediaStreamGraph()
: MediaStreamGraph(16000)
{
}
virtual void
DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable) override;
protected:
~FakeMediaStreamGraph()
{}
};
/**
* This is a stream for camera preview.
*
* XXX It is a temporary fix of SourceMediaStream.
* A camera preview requests no delay and no buffering stream,
* but the SourceMediaStream does not support it.
*/
class CameraPreviewMediaStream : public ProcessedMediaStream
{
typedef mozilla::layers::Image Image;
public:
CameraPreviewMediaStream();
void AddAudioOutput(void* aKey) override;
void SetAudioOutputVolume(void* aKey, float aVolume) override;
void RemoveAudioOutput(void* aKey) override;
void AddVideoOutput(MediaStreamVideoSink* aSink, TrackID aID) override;
void RemoveVideoOutput(MediaStreamVideoSink* aSink, TrackID aID) override;
void Suspend() override {}
void Resume() override {}
void AddListener(MediaStreamListener* aListener) override;
void RemoveListener(MediaStreamListener* aListener) override;
void Destroy() override;
void OnPreviewStateChange(bool aActive);
void Invalidate();
void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
// Call these on any thread.
void SetCurrentFrame(const gfx::IntSize& aIntrinsicSize, Image* aImage);
void ClearCurrentFrame();
void RateLimit(bool aLimit);
protected:
// mMutex protects all the class' fields.
// This class is not registered to MediaStreamGraph.
// It needs to protect all the fields.
Mutex mMutex;
int32_t mInvalidatePending;
uint32_t mDiscardedFrames;
bool mRateLimit;
bool mTrackCreated;
RefPtr<FakeMediaStreamGraph> mFakeMediaStreamGraph;
};
} // namespace mozilla
#endif // DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H

Просмотреть файл

@ -1,220 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
const MOZ_CAMERATESTHW_CONTRACTID = "@mozilla.org/cameratesthardware;1";
const MOZ_CAMERATESTHW_CID = Components.ID("{fcb7b4cd-689e-453c-8a2c-611a45fa09ac}");
const DEBUG = false;
function debug(msg) {
if (DEBUG) {
dump('-*- MozCameraTestHardware: ' + msg + '\n');
}
}
function MozCameraTestHardware() {
this._params = {};
}
MozCameraTestHardware.prototype = {
classID: MOZ_CAMERATESTHW_CID,
contractID: MOZ_CAMERATESTHW_CONTRACTID,
classInfo: XPCOMUtils.generateCI({classID: MOZ_CAMERATESTHW_CID,
contractID: MOZ_CAMERATESTHW_CONTRACTID,
flags: Ci.nsIClassInfo.SINGLETON,
interfaces: [Ci.nsICameraTestHardware]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICameraTestHardware]),
_params: null,
_window: null,
_mock: null,
_handler: null,
attach: function(mock) {
/* Waive xrays permits us to call functions provided to us
in the mock */
this._mock = Components.utils.waiveXrays(mock);
},
detach: function() {
this._mock = null;
},
/* Trigger a delegate handler attached to the test hardware
if given via attach. If there is no delegate attached, or
it does not provide a handler for this specific operation,
or the handler returns true, it will execute the default
behaviour. The handler may throw an exception in order to
return an error code from the driver call. */
_delegate: function(prop) {
return (this._mock && this._mock[prop] && !this._mock[prop]());
},
get params() {
return this._params;
},
set params(aParams) {
this._params = aParams;
},
setHandler: function(handler) {
this._handler = handler;
},
dispatchEvent: function(evt) {
var self = this;
/* We should not dispatch the event in the current thread
context because it may be directly from a driver call
and we could hit a deadlock situation. */
this._window.setTimeout(function() {
if (self._handler) {
self._handler.handleEvent(evt);
}
}, 0);
},
reset: function(aWindow) {
this._window = aWindow;
this._mock = null;
this._params = {};
},
initCamera: function() {
this._delegate('init');
},
pushParameters: function(params) {
let oldParams = this._params;
this._params = {};
let s = params.split(';');
for(let i = 0; i < s.length; ++i) {
let parts = s[i].split('=');
if (parts.length == 2) {
this._params[parts[0]] = parts[1];
}
}
try {
this._delegate('pushParameters');
} catch(e) {
this._params = oldParams;
throw e;
}
},
pullParameters: function() {
this._delegate('pullParameters');
let ret = "";
for(let p in this._params) {
ret += p + "=" + this._params[p] + ";";
}
return ret;
},
autoFocus: function() {
if (!this._delegate('autoFocus')) {
this.fireAutoFocusComplete(true);
}
},
fireAutoFocusMoving: function(moving) {
let evt = new this._window.CameraStateChangeEvent('focus', { 'newState': moving ? 'focusing' : 'not_focusing' } );
this.dispatchEvent(evt);
},
fireAutoFocusComplete: function(state) {
let evt = new this._window.CameraStateChangeEvent('focus', { 'newState': state ? 'focused' : 'unfocused' } );
this.dispatchEvent(evt);
},
cancelAutoFocus: function() {
this._delegate('cancelAutoFocus');
},
fireShutter: function() {
let evt = new this._window.Event('shutter');
this.dispatchEvent(evt);
},
takePicture: function() {
if (!this._delegate('takePicture')) {
this.fireTakePictureComplete(new this._window.Blob(['foobar'], {'type': 'jpeg'}));
}
},
fireTakePictureComplete: function(blob) {
let evt = new this._window.BlobEvent('picture', {'data': blob});
this.dispatchEvent(evt);
},
fireTakePictureError: function() {
let evt = new this._window.ErrorEvent('error', {'message': 'picture'});
this.dispatchEvent(evt);
},
cancelTakePicture: function() {
this._delegate('cancelTakePicture');
},
startPreview: function() {
this._delegate('startPreview');
},
stopPreview: function() {
this._delegate('stopPreview');
},
startFaceDetection: function() {
this._delegate('startFaceDetection');
},
stopFaceDetection: function() {
this._delegate('stopFaceDetection');
},
fireFacesDetected: function(faces) {
/* This works around the fact that we can't have references to
dictionaries in a dictionary in WebIDL; we provide a boolean
to indicate whether or not the values for those features are
actually valid. */
let facesIf = [];
if (typeof(faces) === 'object' && typeof(faces.faces) === 'object') {
let self = this;
faces.faces.forEach(function(face) {
face.hasLeftEye = face.hasOwnProperty('leftEye') && face.leftEye != null;
face.hasRightEye = face.hasOwnProperty('rightEye') && face.rightEye != null;
face.hasMouth = face.hasOwnProperty('mouth') && face.mouth != null;
facesIf.push(new self._window.CameraDetectedFace(face));
});
}
let evt = new this._window.CameraFacesDetectedEvent('facesdetected', {'faces': facesIf});
this.dispatchEvent(evt);
},
startRecording: function() {
this._delegate('startRecording');
},
stopRecording: function() {
this._delegate('stopRecording');
},
fireSystemError: function() {
let evt = new this._window.ErrorEvent('error', {'message': 'system'});
this.dispatchEvent(evt);
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozCameraTestHardware]);

Просмотреть файл

@ -1,2 +0,0 @@
component {fcb7b4cd-689e-453c-8a2c-611a45fa09ac} CameraTestHardware.js
contract @mozilla.org/cameratesthardware;1 {fcb7b4cd-689e-453c-8a2c-611a45fa09ac}

Просмотреть файл

@ -1,604 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DOMCameraCapabilities.h"
#include "nsPIDOMWindow.h"
#include "nsContentUtils.h"
#include "nsProxyRelease.h"
#include "mozilla/dom/CameraManagerBinding.h"
#include "mozilla/dom/CameraCapabilitiesBinding.h"
#include "Navigator.h"
#include "CameraCommon.h"
#include "ICameraControl.h"
#include "CameraControlListener.h"
namespace mozilla {
namespace dom {
/**
* CameraClosedListenerProxy and CameraClosedMessage
*/
template<class T>
class CameraClosedMessage : public Runnable
{
public:
explicit CameraClosedMessage(nsMainThreadPtrHandle<T> aListener)
: mListener(aListener)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<T> listener = mListener.get();
if (listener) {
listener->OnHardwareClosed();
}
return NS_OK;
}
protected:
virtual ~CameraClosedMessage()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
nsMainThreadPtrHandle<T> mListener;
};
template<class T>
class CameraClosedListenerProxy : public CameraControlListener
{
public:
explicit CameraClosedListenerProxy(T* aListener)
: mListener(new nsMainThreadPtrHolder<T>(aListener))
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
virtual void
OnHardwareStateChange(HardwareState aState, nsresult aReason) override
{
if (aState != kHardwareClosed) {
return;
}
NS_DispatchToMainThread(new CameraClosedMessage<T>(mListener));
}
protected:
virtual ~CameraClosedListenerProxy()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
nsMainThreadPtrHandle<T> mListener;
};
/**
* CameraRecorderVideoProfile
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderVideoProfile, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderVideoProfile)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderVideoProfile)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraRecorderVideoProfile)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
CameraRecorderVideoProfile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CameraRecorderVideoProfileBinding::Wrap(aCx, this, aGivenProto);
}
CameraRecorderVideoProfile::CameraRecorderVideoProfile(nsISupports* aParent,
const ICameraControl::RecorderProfile::Video& aProfile)
: mParent(aParent)
, mCodec(aProfile.GetCodec())
, mBitrate(aProfile.GetBitsPerSecond())
, mFramerate(aProfile.GetFramesPerSecond())
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
mSize.mWidth = aProfile.GetSize().width;
mSize.mHeight = aProfile.GetSize().height;
DOM_CAMERA_LOGI(" video: '%s' %ux%u bps=%u fps=%u\n",
NS_ConvertUTF16toUTF8(mCodec).get(), mSize.mWidth, mSize.mHeight, mBitrate, mFramerate);
}
CameraRecorderVideoProfile::~CameraRecorderVideoProfile()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
/**
* CameraRecorderAudioProfile
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderAudioProfile, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderAudioProfile)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderAudioProfile)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraRecorderAudioProfile)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
CameraRecorderAudioProfile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CameraRecorderAudioProfileBinding::Wrap(aCx, this, aGivenProto);
}
CameraRecorderAudioProfile::CameraRecorderAudioProfile(nsISupports* aParent,
const ICameraControl::RecorderProfile::Audio& aProfile)
: mParent(aParent)
, mCodec(aProfile.GetCodec())
, mBitrate(aProfile.GetBitsPerSecond())
, mSamplerate(aProfile.GetSamplesPerSecond())
, mChannels(aProfile.GetChannels())
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
DOM_CAMERA_LOGI(" audio: '%s' bps=%u samples/s=%u channels=%u\n",
NS_ConvertUTF16toUTF8(mCodec).get(), mBitrate, mSamplerate, mChannels);
}
CameraRecorderAudioProfile::~CameraRecorderAudioProfile()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
/**
* CameraRecorderProfile
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfile,
mParent,
mVideo,
mAudio)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderProfile)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderProfile)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraRecorderProfile)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
CameraRecorderProfile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CameraRecorderProfileBinding::Wrap(aCx, this, aGivenProto);
}
CameraRecorderProfile::CameraRecorderProfile(nsISupports* aParent,
const ICameraControl::RecorderProfile& aProfile)
: mParent(aParent)
, mName(aProfile.GetName())
, mContainerFormat(aProfile.GetContainer())
, mMimeType(aProfile.GetMimeType())
, mVideo(new CameraRecorderVideoProfile(this, aProfile.GetVideo()))
, mAudio(new CameraRecorderAudioProfile(this, aProfile.GetAudio()))
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
DOM_CAMERA_LOGI("profile: '%s' container=%s mime-type=%s\n",
NS_ConvertUTF16toUTF8(mName).get(),
NS_ConvertUTF16toUTF8(mContainerFormat).get(),
NS_ConvertUTF16toUTF8(mMimeType).get());
}
CameraRecorderProfile::~CameraRecorderProfile()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
/**
* CameraRecorderProfiles
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfiles,
mParent,
mProfiles)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderProfiles)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderProfiles)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraRecorderProfiles)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
CameraRecorderProfiles::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CameraRecorderProfilesBinding::Wrap(aCx, this, aGivenProto);
}
CameraRecorderProfiles::CameraRecorderProfiles(nsISupports* aParent,
ICameraControl* aCameraControl)
: mParent(aParent)
, mCameraControl(aCameraControl)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (mCameraControl) {
mListener = new CameraClosedListenerProxy<CameraRecorderProfiles>(this);
mCameraControl->AddListener(mListener);
}
}
CameraRecorderProfiles::~CameraRecorderProfiles()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
void
CameraRecorderProfiles::GetSupportedNames(nsTArray<nsString>& aNames)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n",
__func__, __LINE__, this);
if (!mCameraControl) {
aNames.Clear();
return;
}
nsresult rv = mCameraControl->GetRecorderProfiles(aNames);
if (NS_WARN_IF(NS_FAILED(rv))) {
aNames.Clear();
}
}
CameraRecorderProfile*
CameraRecorderProfiles::NamedGetter(const nsAString& aName, bool& aFound)
{
DOM_CAMERA_LOGT("%s:%d : this=%p, name='%s'\n", __func__, __LINE__, this,
NS_ConvertUTF16toUTF8(aName).get());
if (!mCameraControl) {
return nullptr;
}
CameraRecorderProfile* profile = mProfiles.GetWeak(aName, &aFound);
if (!aFound || !profile) {
RefPtr<ICameraControl::RecorderProfile> p = mCameraControl->GetProfileInfo(aName);
if (p) {
profile = new CameraRecorderProfile(this, *p);
mProfiles.Put(aName, profile);
aFound = true;
}
}
return profile;
}
void
CameraRecorderProfiles::OnHardwareClosed()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
if (mCameraControl) {
mCameraControl->RemoveListener(mListener);
mCameraControl = nullptr;
}
mListener = nullptr;
}
/**
* CameraCapabilities
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraCapabilities, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraCapabilities)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraCapabilities)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraCapabilities)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
/* static */
bool
CameraCapabilities::HasSupport(JSContext* aCx, JSObject* aGlobal)
{
return Navigator::HasCameraSupport(aCx, aGlobal);
}
CameraCapabilities::CameraCapabilities(nsPIDOMWindowInner* aWindow,
ICameraControl* aCameraControl)
: mWindow(aWindow)
, mCameraControl(aCameraControl)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_COUNT_CTOR(CameraCapabilities);
if (mCameraControl) {
mListener = new CameraClosedListenerProxy<CameraCapabilities>(this);
mCameraControl->AddListener(mListener);
}
}
CameraCapabilities::~CameraCapabilities()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_COUNT_DTOR(CameraCapabilities);
}
void
CameraCapabilities::OnHardwareClosed()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
if (mCameraControl) {
mCameraControl->RemoveListener(mListener);
mCameraControl = nullptr;
}
mListener = nullptr;
}
JSObject*
CameraCapabilities::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CameraCapabilitiesBinding::Wrap(aCx, this, aGivenProto);
}
#define LOG_IF_ERROR(rv, param) \
do { \
if (NS_FAILED(rv)) { \
DOM_CAMERA_LOGW("Error %x trying to get " #param "\n", \
(rv)); \
} \
} while(0)
nsresult
CameraCapabilities::TranslateToDictionary(uint32_t aKey, nsTArray<CameraSize>& aSizes)
{
if (NS_WARN_IF(!mCameraControl)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv;
nsTArray<ICameraControl::Size> sizes;
rv = mCameraControl->Get(aKey, sizes);
if (NS_FAILED(rv)) {
return rv;
}
aSizes.Clear();
aSizes.SetCapacity(sizes.Length());
for (uint32_t i = 0; i < sizes.Length(); ++i) {
CameraSize* s = aSizes.AppendElement();
s->mWidth = sizes[i].width;
s->mHeight = sizes[i].height;
}
return NS_OK;
}
// The following attributes are tagged [Cached, Constant] in the WebIDL, so
// the framework will handle caching them for us.
void
CameraCapabilities::GetPreviewSizes(nsTArray<dom::CameraSize>& aRetVal)
{
nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
}
void
CameraCapabilities::GetPictureSizes(nsTArray<dom::CameraSize>& aRetVal)
{
nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_PICTURESIZES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTURESIZES);
}
void
CameraCapabilities::GetThumbnailSizes(nsTArray<dom::CameraSize>& aRetVal)
{
nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES);
}
void
CameraCapabilities::GetVideoSizes(nsTArray<dom::CameraSize>& aRetVal)
{
nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_VIDEOSIZES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_VIDEOSIZES);
}
void
CameraCapabilities::GetFileFormats(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_PICTUREFORMATS, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
}
void
CameraCapabilities::GetWhiteBalanceModes(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_WHITEBALANCES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
}
void
CameraCapabilities::GetSceneModes(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_SCENEMODES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_SCENEMODES);
}
void
CameraCapabilities::GetEffects(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EFFECTS, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EFFECTS);
}
void
CameraCapabilities::GetFlashModes(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FLASHMODES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FLASHMODES);
}
void
CameraCapabilities::GetFocusModes(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FOCUSMODES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FOCUSMODES);
}
void
CameraCapabilities::GetZoomRatios(nsTArray<double>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_ZOOMRATIOS);
}
uint32_t
CameraCapabilities::MaxFocusAreas()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0;
}
int32_t areas = 0;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS, areas);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
return areas < 0 ? 0 : areas;
}
uint32_t
CameraCapabilities::MaxMeteringAreas()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0;
}
int32_t areas = 0;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS, areas);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
return areas < 0 ? 0 : areas;
}
uint32_t
CameraCapabilities::MaxDetectedFaces()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0;
}
int32_t faces = 0;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES, faces);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES);
return faces < 0 ? 0 : faces;
}
double
CameraCapabilities::MinExposureCompensation()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0.0;
}
double minEv = 0.0;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, minEv);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
return minEv;
}
double
CameraCapabilities::MaxExposureCompensation()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0.0;
}
double maxEv = 0.0;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION, maxEv);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
return maxEv;
}
double
CameraCapabilities::ExposureCompensationStep()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0.0;
}
double evStep = 0.0;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, evStep);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
return evStep;
}
CameraRecorderProfiles*
CameraCapabilities::RecorderProfiles()
{
if (NS_WARN_IF(!mCameraControl)) {
return nullptr;
}
RefPtr<CameraRecorderProfiles> profiles =
new CameraRecorderProfiles(this, mCameraControl);
return profiles;
}
void
CameraCapabilities::GetIsoModes(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ISOMODES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_ISOMODES);
}
void
CameraCapabilities::GetMeteringModes(nsTArray<nsString>& aRetVal)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_METERINGMODES, aRetVal);
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_METERINGMODES);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -1,243 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_CameraCapabilities_h__
#define mozilla_dom_CameraCapabilities_h__
#include "nsString.h"
#include "base/basictypes.h"
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/CameraManagerBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "nsPIDOMWindow.h"
#include "nsHashKeys.h"
#include "nsRefPtrHashtable.h"
#include "nsDataHashtable.h"
#include "ICameraControl.h"
struct JSContext;
namespace mozilla {
namespace dom {
/**
* CameraRecorderVideoProfile
*/
class CameraRecorderVideoProfile final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CameraRecorderVideoProfile)
explicit CameraRecorderVideoProfile(nsISupports* aParent,
const ICameraControl::RecorderProfile::Video& aProfile);
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
uint32_t BitsPerSecond() const { return mBitrate; }
uint32_t FramesPerSecond() const { return mFramerate; }
void GetCodec(nsAString& aCodec) const { aCodec = mCodec; }
void GetSize(dom::CameraSize& aSize) const { aSize = mSize; }
// XXXmikeh - legacy, remove these when the Camera app is updated
uint32_t Width() const { return mSize.mWidth; }
uint32_t Height() const { return mSize.mHeight; }
protected:
virtual ~CameraRecorderVideoProfile();
nsCOMPtr<nsISupports> mParent;
const nsString mCodec;
uint32_t mBitrate;
uint32_t mFramerate;
dom::CameraSize mSize;
private:
DISALLOW_EVIL_CONSTRUCTORS(CameraRecorderVideoProfile);
};
/**
* CameraRecorderAudioProfile
*/
class CameraRecorderAudioProfile final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CameraRecorderAudioProfile)
explicit CameraRecorderAudioProfile(nsISupports* aParent,
const ICameraControl::RecorderProfile::Audio& aProfile);
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
uint32_t BitsPerSecond() const { return mBitrate; }
uint32_t SamplesPerSecond() const { return mSamplerate; }
uint32_t Channels() const { return mChannels; }
void GetCodec(nsAString& aCodec) const { aCodec = mCodec; }
protected:
virtual ~CameraRecorderAudioProfile();
nsCOMPtr<nsISupports> mParent;
const nsString mCodec;
uint32_t mBitrate;
uint32_t mSamplerate;
uint32_t mChannels;
private:
DISALLOW_EVIL_CONSTRUCTORS(CameraRecorderAudioProfile);
};
/**
* CameraRecorderProfile
*/
class CameraRecorderProfile final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CameraRecorderProfile)
explicit CameraRecorderProfile(nsISupports* aParent,
const ICameraControl::RecorderProfile& aProfile);
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void GetMimeType(nsAString& aMimeType) const { aMimeType = mMimeType; }
CameraRecorderVideoProfile* Video() { return mVideo; }
CameraRecorderAudioProfile* Audio() { return mAudio; }
void GetName(nsAString& aName) const { aName = mName; }
void
GetContainerFormat(nsAString& aContainerFormat) const
{
aContainerFormat = mContainerFormat;
}
protected:
virtual ~CameraRecorderProfile();
nsCOMPtr<nsISupports> mParent;
const nsString mName;
const nsString mContainerFormat;
const nsString mMimeType;
RefPtr<CameraRecorderVideoProfile> mVideo;
RefPtr<CameraRecorderAudioProfile> mAudio;
private:
DISALLOW_EVIL_CONSTRUCTORS(CameraRecorderProfile);
};
/**
* CameraRecorderProfiles
*/
template<class T> class CameraClosedListenerProxy;
class CameraRecorderProfiles final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CameraRecorderProfiles)
explicit CameraRecorderProfiles(nsISupports* aParent,
ICameraControl* aCameraControl);
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
CameraRecorderProfile* NamedGetter(const nsAString& aName, bool& aFound);
void GetSupportedNames(nsTArray<nsString>& aNames);
virtual void OnHardwareClosed();
protected:
virtual ~CameraRecorderProfiles();
nsCOMPtr<nsISupports> mParent;
RefPtr<ICameraControl> mCameraControl;
nsRefPtrHashtable<nsStringHashKey, CameraRecorderProfile> mProfiles;
RefPtr<CameraClosedListenerProxy<CameraRecorderProfiles>> mListener;
private:
DISALLOW_EVIL_CONSTRUCTORS(CameraRecorderProfiles);
};
/**
* CameraCapabilities
*/
class CameraCapabilities final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CameraCapabilities)
// Because this header's filename doesn't match its C++ or DOM-facing
// classname, we can't rely on the [Func="..."] WebIDL tag to implicitly
// include the right header for us; instead we must explicitly include a
// HasSupport() method in each header. We can get rid of these with the
// Great Renaming proposed in bug 983177.
static bool HasSupport(JSContext* aCx, JSObject* aGlobal);
explicit CameraCapabilities(nsPIDOMWindowInner* aWindow,
ICameraControl* aCameraControl);
nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void GetPreviewSizes(nsTArray<CameraSize>& aRetVal);
void GetPictureSizes(nsTArray<CameraSize>& aRetVal);
void GetThumbnailSizes(nsTArray<CameraSize>& aRetVal);
void GetVideoSizes(nsTArray<CameraSize>& aRetVal);
void GetFileFormats(nsTArray<nsString>& aRetVal);
void GetWhiteBalanceModes(nsTArray<nsString>& aRetVal);
void GetSceneModes(nsTArray<nsString>& aRetVal);
void GetEffects(nsTArray<nsString>& aRetVal);
void GetFlashModes(nsTArray<nsString>& aRetVal);
void GetFocusModes(nsTArray<nsString>& aRetVal);
void GetZoomRatios(nsTArray<double>& aRetVal);
uint32_t MaxFocusAreas();
uint32_t MaxMeteringAreas();
uint32_t MaxDetectedFaces();
double MinExposureCompensation();
double MaxExposureCompensation();
double ExposureCompensationStep();
void GetIsoModes(nsTArray<nsString>& aRetVal);
void GetMeteringModes(nsTArray<nsString>& aRetVal);
CameraRecorderProfiles* RecorderProfiles();
virtual void OnHardwareClosed();
protected:
~CameraCapabilities();
nsresult TranslateToDictionary(uint32_t aKey, nsTArray<CameraSize>& aSizes);
RefPtr<nsPIDOMWindowInner> mWindow;
RefPtr<ICameraControl> mCameraControl;
RefPtr<CameraClosedListenerProxy<CameraCapabilities>> mListener;
private:
DISALLOW_EVIL_CONSTRUCTORS(CameraCapabilities);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_CameraCapabilities_h__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,262 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_DOMCAMERACONTROL_H
#define DOM_CAMERA_DOMCAMERACONTROL_H
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/dom/CameraControlBinding.h"
#include "mozilla/dom/Promise.h"
#include "ICameraControl.h"
#include "CameraCommon.h"
#include "DOMMediaStream.h"
#include "AudioChannelAgent.h"
#include "nsProxyRelease.h"
#include "nsHashPropertyBag.h"
#include "DeviceStorage.h"
#include "DOMCameraControlListener.h"
#include "nsWeakReference.h"
#ifdef MOZ_WIDGET_GONK
#include "nsITimer.h"
#endif
class nsDOMDeviceStorage;
class nsPIDOMWindowInner;
class nsIDOMBlob;
namespace mozilla {
namespace dom {
class CameraCapabilities;
struct CameraPictureOptions;
struct CameraStartRecordingOptions;
struct CameraRegion;
struct CameraSize;
template<typename T> class Optional;
} // namespace dom
class ErrorResult;
class StartRecordingHelper;
class RecorderPosterHelper;
class TrackCreatedListener;
#define NS_DOM_CAMERA_CONTROL_CID \
{ 0x3700c096, 0xf920, 0x438d, \
{ 0x8b, 0x3f, 0x15, 0xb3, 0xc9, 0x96, 0x23, 0x62 } }
// Main camera control.
class nsDOMCameraControl final : public DOMMediaStream
, public nsSupportsWeakReference
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_CAMERA_CONTROL_CID)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMCameraControl, DOMMediaStream)
NS_DECL_ISUPPORTS_INHERITED
// Because this header's filename doesn't match its C++ or DOM-facing
// classname, we can't rely on the [Func="..."] WebIDL tag to implicitly
// include the right header for us; instead we must explicitly include a
// HasSupport() method in each header. We can get rid of these with the
// Great Renaming proposed in bug 983177.
static bool HasSupport(JSContext* aCx, JSObject* aGlobal);
nsDOMCameraControl(uint32_t aCameraId,
const dom::CameraConfiguration& aInitialConfig,
dom::Promise* aPromise,
nsPIDOMWindowInner* aWindow);
void Shutdown();
nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
MediaStream* GetCameraStream() const override;
// Called by TrackCreatedListener when the underlying track has been created.
// XXX Bug 1124630. This can be removed with CameraPreviewMediaStream.
void TrackCreated(TrackID aTrackID);
// Attributes.
void GetEffect(nsString& aEffect, ErrorResult& aRv);
void SetEffect(const nsAString& aEffect, ErrorResult& aRv);
void GetWhiteBalanceMode(nsString& aMode, ErrorResult& aRv);
void SetWhiteBalanceMode(const nsAString& aMode, ErrorResult& aRv);
void GetSceneMode(nsString& aMode, ErrorResult& aRv);
void SetSceneMode(const nsAString& aMode, ErrorResult& aRv);
void GetFlashMode(nsString& aMode, ErrorResult& aRv);
void SetFlashMode(const nsAString& aMode, ErrorResult& aRv);
void GetFocusMode(nsString& aMode, ErrorResult& aRv);
void SetFocusMode(const nsAString& aMode, ErrorResult& aRv);
double GetZoom(ErrorResult& aRv);
void SetZoom(double aZoom, ErrorResult& aRv);
double GetFocalLength(ErrorResult& aRv);
double GetFocusDistanceNear(ErrorResult& aRv);
double GetFocusDistanceOptimum(ErrorResult& aRv);
double GetFocusDistanceFar(ErrorResult& aRv);
void SetExposureCompensation(double aCompensation, ErrorResult& aRv);
double GetExposureCompensation(ErrorResult& aRv);
int32_t SensorAngle();
already_AddRefed<dom::CameraCapabilities> Capabilities();
void GetIsoMode(nsString& aMode, ErrorResult& aRv);
void SetIsoMode(const nsAString& aMode, ErrorResult& aRv);
double GetPictureQuality(ErrorResult& aRv);
void SetPictureQuality(double aQuality, ErrorResult& aRv);
void GetMeteringMode(nsString& aMode, ErrorResult& aRv);
void SetMeteringMode(const nsAString& aMode, ErrorResult& aRv);
// Methods.
already_AddRefed<dom::Promise> SetConfiguration(const dom::CameraConfiguration& aConfiguration,
ErrorResult& aRv);
void GetMeteringAreas(nsTArray<dom::CameraRegion>& aAreas, ErrorResult& aRv);
void SetMeteringAreas(const dom::Optional<dom::Sequence<dom::CameraRegion> >& aAreas, ErrorResult& aRv);
void GetFocusAreas(nsTArray<dom::CameraRegion>& aAreas, ErrorResult& aRv);
void SetFocusAreas(const dom::Optional<dom::Sequence<dom::CameraRegion> >& aAreas, ErrorResult& aRv);
void GetPictureSize(dom::CameraSize& aSize, ErrorResult& aRv);
void SetPictureSize(const dom::CameraSize& aSize, ErrorResult& aRv);
void GetThumbnailSize(dom::CameraSize& aSize, ErrorResult& aRv);
void SetThumbnailSize(const dom::CameraSize& aSize, ErrorResult& aRv);
already_AddRefed<dom::Promise> AutoFocus(ErrorResult& aRv);
void StartFaceDetection(ErrorResult& aRv);
void StopFaceDetection(ErrorResult& aRv);
already_AddRefed<dom::Promise> TakePicture(const dom::CameraPictureOptions& aOptions,
ErrorResult& aRv);
already_AddRefed<dom::Promise> StartRecording(const dom::CameraStartRecordingOptions& aOptions,
nsDOMDeviceStorage& storageArea,
const nsAString& filename,
ErrorResult& aRv);
void StopRecording(ErrorResult& aRv);
void PauseRecording(ErrorResult& aRv);
void ResumeRecording(ErrorResult& aRv);
void ResumePreview(ErrorResult& aRv);
already_AddRefed<dom::Promise> ReleaseHardware(ErrorResult& aRv);
void ResumeContinuousFocus(ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
operator nsISupports*() { return static_cast<DOMMediaStream*>(this); }
#ifdef MOZ_WIDGET_GONK
static void PreinitCameraHardware();
static void DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure);
#endif
IMPL_EVENT_HANDLER(facesdetected)
IMPL_EVENT_HANDLER(shutter)
IMPL_EVENT_HANDLER(close)
IMPL_EVENT_HANDLER(recorderstatechange)
IMPL_EVENT_HANDLER(previewstatechange)
IMPL_EVENT_HANDLER(focus)
IMPL_EVENT_HANDLER(picture)
IMPL_EVENT_HANDLER(configurationchange)
IMPL_EVENT_HANDLER(poster)
protected:
virtual ~nsDOMCameraControl();
class DOMCameraConfiguration final : public dom::CameraConfiguration
{
public:
NS_INLINE_DECL_REFCOUNTING(DOMCameraConfiguration)
DOMCameraConfiguration();
explicit DOMCameraConfiguration(const dom::CameraConfiguration& aConfiguration);
// Additional configuration options that aren't exposed to the DOM
uint32_t mMaxFocusAreas;
uint32_t mMaxMeteringAreas;
private:
// Private destructor, to discourage deletion outside of Release():
~DOMCameraConfiguration();
};
friend class DOMCameraControlListener;
friend class mozilla::StartRecordingHelper;
friend class mozilla::RecorderPosterHelper;
void OnCreatedFileDescriptor(bool aSucceeded);
void OnAutoFocusComplete(bool aAutoFocusSucceeded);
void OnAutoFocusMoving(bool aIsMoving);
void OnTakePictureComplete(nsIDOMBlob* aPicture);
void OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces);
void OnPoster(dom::BlobImpl* aPoster);
void OnGetCameraComplete();
void OnHardwareStateChange(DOMCameraControlListener::HardwareState aState, nsresult aReason);
void OnPreviewStateChange(DOMCameraControlListener::PreviewState aState);
void OnRecorderStateChange(CameraControlListener::RecorderState aState, int32_t aStatus, int32_t aTrackNum);
void OnConfigurationChange(DOMCameraConfiguration* aConfiguration);
void OnShutter();
void OnUserError(CameraControlListener::UserContext aContext, nsresult aError);
bool IsWindowStillActive();
nsresult SelectPreviewSize(const dom::CameraSize& aRequestedPreviewSize, ICameraControl::Size& aSelectedPreviewSize);
void ReleaseAudioChannelAgent();
nsresult NotifyRecordingStatusChange(const nsString& aMsg);
already_AddRefed<dom::Promise> CreatePromise(ErrorResult& aRv);
void AbortPromise(RefPtr<dom::Promise>& aPromise);
virtual void EventListenerAdded(nsIAtom* aType) override;
void DispatchPreviewStateEvent(DOMCameraControlListener::PreviewState aState);
void DispatchStateEvent(const nsString& aType, const nsString& aState);
RefPtr<ICameraControl> mCameraControl; // non-DOM camera control
// An agent used to join audio channel service.
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
nsresult Set(uint32_t aKey, const dom::Optional<dom::Sequence<dom::CameraRegion> >& aValue, uint32_t aLimit);
nsresult Get(uint32_t aKey, nsTArray<dom::CameraRegion>& aValue);
RefPtr<DOMCameraConfiguration> mCurrentConfiguration;
RefPtr<dom::CameraCapabilities> mCapabilities;
// camera control pending promises
RefPtr<dom::Promise> mGetCameraPromise;
RefPtr<dom::Promise> mAutoFocusPromise;
RefPtr<dom::Promise> mTakePicturePromise;
RefPtr<dom::Promise> mStartRecordingPromise;
RefPtr<dom::Promise> mReleasePromise;
RefPtr<dom::Promise> mSetConfigurationPromise;
// Camera event listener; we only need this weak reference so that
// we can remove the listener from the camera when we're done
// with it.
DOMCameraControlListener* mListener;
// our viewfinder stream
RefPtr<CameraPreviewMediaStream> mInput;
// A listener on mInput for adding tracks to the DOM side.
RefPtr<TrackCreatedListener> mTrackCreatedListener;
// set once when this object is created
nsCOMPtr<nsPIDOMWindowInner> mWindow;
dom::CameraStartRecordingOptions mOptions;
RefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
DOMCameraControlListener::PreviewState mPreviewState;
bool mRecording;
bool mRecordingStoppedDeferred;
bool mSetInitialConfig;
#ifdef MOZ_WIDGET_GONK
// cached camera control, to improve start-up time
static StaticRefPtr<ICameraControl> sCachedCameraControl;
static nsresult sCachedCameraControlStartResult;
static nsCOMPtr<nsITimer> sDiscardCachedCameraControlTimer;
#endif
private:
nsDOMCameraControl(const nsDOMCameraControl&) = delete;
nsDOMCameraControl& operator=(const nsDOMCameraControl&) = delete;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMCameraControl, NS_DOM_CAMERA_CONTROL_CID)
} // namespace mozilla
#endif // DOM_CAMERA_DOMCAMERACONTROL_H

Просмотреть файл

@ -1,436 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DOMCameraControlListener.h"
#include "nsThreadUtils.h"
#include "CameraCommon.h"
#include "DOMCameraControl.h"
#include "CameraPreviewMediaStream.h"
#include "mozilla/dom/CameraManagerBinding.h"
#include "mozilla/dom/File.h"
#include "nsQueryObject.h"
using namespace mozilla;
using namespace mozilla::dom;
DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl,
CameraPreviewMediaStream* aStream)
: mDOMCameraControl(
new nsMainThreadPtrHolder<nsISupports>(static_cast<DOMMediaStream*>(aDOMCameraControl)))
, mStream(aStream)
{
DOM_CAMERA_LOGT("%s:%d : this=%p, camera=%p, stream=%p\n",
__func__, __LINE__, this, aDOMCameraControl, aStream);
}
DOMCameraControlListener::~DOMCameraControlListener()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
// Boilerplate callback runnable
class DOMCameraControlListener::DOMCallback : public Runnable
{
public:
explicit DOMCallback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
: mDOMCameraControl(aDOMCameraControl)
{
MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback);
}
protected:
virtual ~DOMCallback()
{
MOZ_COUNT_DTOR(DOMCameraControlListener::DOMCallback);
}
public:
virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0;
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<nsDOMCameraControl> camera = do_QueryObject(mDOMCameraControl.get());
if (!camera) {
DOM_CAMERA_LOGE("do_QueryObject failed to get an nsDOMCameraControl\n");
return NS_ERROR_INVALID_ARG;
}
RunCallback(camera);
return NS_OK;
}
protected:
nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
};
// Specific callback handlers
void
DOMCameraControlListener::OnHardwareStateChange(HardwareState aState,
nsresult aReason)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
HardwareState aState, nsresult aReason)
: DOMCallback(aDOMCameraControl)
, mState(aState)
, mReason(aReason)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnHardwareStateChange(mState, mReason);
}
protected:
HardwareState mState;
nsresult mReason;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState, aReason));
}
void
DOMCameraControlListener::OnPreviewStateChange(PreviewState aState)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
PreviewState aState)
: DOMCallback(aDOMCameraControl)
, mState(aState)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnPreviewStateChange(mState);
}
protected:
PreviewState mState;
};
switch (aState) {
case kPreviewStopped:
// Clear the current frame right away, without dispatching a
// runnable. This is an ugly coupling between the camera's
// SurfaceTextureClient and the MediaStream/ImageContainer,
// but without it, the preview can fail to start.
DOM_CAMERA_LOGI("Preview stopped, clearing current frame\n");
mStream->ClearCurrentFrame();
break;
case kPreviewPaused:
// In the paused state, we still want to reflect the change
// in preview state, but we don't want to clear the current
// frame as above, since doing so seems to cause genlock
// problems when we restart the preview. See bug 957749.
DOM_CAMERA_LOGI("Preview paused\n");
break;
case kPreviewStarted:
DOM_CAMERA_LOGI("Preview started\n");
break;
default:
DOM_CAMERA_LOGE("Unknown preview state %d\n", aState);
MOZ_ASSERT_UNREACHABLE("Invalid preview state");
return;
}
mStream->OnPreviewStateChange(aState == kPreviewStarted);
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState));
}
void
DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
int32_t aStatus, int32_t aTrackNum)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
RecorderState aState,
int32_t aStatus,
int32_t aTrackNum)
: DOMCallback(aDOMCameraControl)
, mState(aState)
, mStatus(aStatus)
, mTrackNum(aTrackNum)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnRecorderStateChange(mState, mStatus, mTrackNum);
}
protected:
RecorderState mState;
int32_t mStatus;
int32_t mTrackNum;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState, aStatus, aTrackNum));
}
void
DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
const CameraListenerConfiguration& aConfiguration)
: DOMCallback(aDOMCameraControl)
, mConfiguration(aConfiguration)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
RefPtr<nsDOMCameraControl::DOMCameraConfiguration> config =
new nsDOMCameraControl::DOMCameraConfiguration();
switch (mConfiguration.mMode) {
case ICameraControl::kVideoMode:
config->mMode = CameraMode::Video;
break;
case ICameraControl::kPictureMode:
config->mMode = CameraMode::Picture;
break;
default:
DOM_CAMERA_LOGI("Camera mode still unspecified, nothing to do\n");
return;
}
// Map CameraControl parameters to their DOM-facing equivalents
config->mRecorderProfile = mConfiguration.mRecorderProfile;
config->mPreviewSize.mWidth = mConfiguration.mPreviewSize.width;
config->mPreviewSize.mHeight = mConfiguration.mPreviewSize.height;
config->mPictureSize.mWidth = mConfiguration.mPictureSize.width;
config->mPictureSize.mHeight = mConfiguration.mPictureSize.height;
config->mMaxMeteringAreas = mConfiguration.mMaxMeteringAreas;
config->mMaxFocusAreas = mConfiguration.mMaxFocusAreas;
aDOMCameraControl->OnConfigurationChange(config);
}
protected:
const CameraListenerConfiguration mConfiguration;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aConfiguration));
}
void
DOMCameraControlListener::OnAutoFocusMoving(bool aIsMoving)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl, bool aIsMoving)
: DOMCallback(aDOMCameraControl)
, mIsMoving(aIsMoving)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnAutoFocusMoving(mIsMoving);
}
protected:
bool mIsMoving;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aIsMoving));
}
void
DOMCameraControlListener::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
const nsTArray<ICameraControl::Face>& aFaces)
: DOMCallback(aDOMCameraControl)
, mFaces(aFaces)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnFacesDetected(mFaces);
}
protected:
const nsTArray<ICameraControl::Face> mFaces;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aFaces));
}
void
DOMCameraControlListener::OnShutter()
{
class Callback : public DOMCallback
{
public:
explicit Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
: DOMCallback(aDOMCameraControl)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnShutter();
}
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl));
}
void
DOMCameraControlListener::OnRateLimitPreview(bool aLimit)
{
mStream->RateLimit(aLimit);
}
bool
DOMCameraControlListener::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
{
DOM_CAMERA_LOGI("OnNewPreviewFrame: got %d x %d frame\n", aWidth, aHeight);
mStream->SetCurrentFrame(gfx::IntSize(aWidth, aHeight), aImage);
return true;
}
void
DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
bool aAutoFocusSucceeded)
: DOMCallback(aDOMCameraControl)
, mAutoFocusSucceeded(aAutoFocusSucceeded)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnAutoFocusComplete(mAutoFocusSucceeded);
}
protected:
bool mAutoFocusSucceeded;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aAutoFocusSucceeded));
}
void
DOMCameraControlListener::OnTakePictureComplete(const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
: DOMCallback(aDOMCameraControl)
, mLength(aLength)
, mMimeType(aMimeType)
{
mData = (uint8_t*) malloc(aLength);
memcpy(mData, aData, aLength);
}
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
nsCOMPtr<nsIDOMBlob> picture =
Blob::CreateMemoryBlob(mDOMCameraControl.get(),
static_cast<void*>(mData),
static_cast<uint64_t>(mLength),
mMimeType);
aDOMCameraControl->OnTakePictureComplete(picture);
mData = NULL;
}
protected:
virtual
~Callback()
{
free(mData);
}
uint8_t* mData;
uint32_t mLength;
nsString mMimeType;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aData, aLength, aMimeType));
}
void
DOMCameraControlListener::OnUserError(UserContext aContext, nsresult aError)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
UserContext aContext,
nsresult aError)
: DOMCallback(aDOMCameraControl)
, mContext(aContext)
, mError(aError)
{ }
virtual void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnUserError(mContext, mError);
}
protected:
UserContext mContext;
nsresult mError;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aContext, aError));
}
void
DOMCameraControlListener::OnPoster(BlobImpl* aBlobImpl)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl, BlobImpl* aBlobImpl)
: DOMCallback(aDOMCameraControl)
, mBlobImpl(aBlobImpl)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnPoster(mBlobImpl);
}
protected:
RefPtr<BlobImpl> mBlobImpl;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aBlobImpl));
}

Просмотреть файл

@ -1,51 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_DOMCAMERACONTROLLISTENER_H
#define DOM_CAMERA_DOMCAMERACONTROLLISTENER_H
#include "nsProxyRelease.h"
#include "CameraControlListener.h"
namespace mozilla {
class nsDOMCameraControl;
class CameraPreviewMediaStream;
class DOMCameraControlListener : public CameraControlListener
{
public:
DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl, CameraPreviewMediaStream* aStream);
virtual void OnAutoFocusComplete(bool aAutoFocusSucceeded) override;
virtual void OnAutoFocusMoving(bool aIsMoving) override;
virtual void OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces) override;
virtual void OnTakePictureComplete(const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) override;
virtual void OnHardwareStateChange(HardwareState aState, nsresult aReason) override;
virtual void OnPreviewStateChange(PreviewState aState) override;
virtual void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum) override;
virtual void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration) override;
virtual void OnShutter() override;
virtual void OnRateLimitPreview(bool aLimit) override;
virtual bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) override;
virtual void OnUserError(UserContext aContext, nsresult aError) override;
virtual void OnPoster(dom::BlobImpl* aBlobImpl) override;
protected:
virtual ~DOMCameraControlListener();
nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
CameraPreviewMediaStream* mStream;
class DOMCallback;
private:
DOMCameraControlListener(const DOMCameraControlListener&) = delete;
DOMCameraControlListener& operator=(const DOMCameraControlListener&) = delete;
};
} // namespace mozilla
#endif // DOM_CAMERA_DOMCAMERACONTROLLISTENER_H

Просмотреть файл

@ -1,89 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DOMCameraDetectedFace.h"
#include "Navigator.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMCameraDetectedFace, mParent,
mBounds, mLeftEye, mRightEye, mMouth)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCameraDetectedFace)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCameraDetectedFace)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCameraDetectedFace)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
/* static */
bool
DOMCameraDetectedFace::HasSupport(JSContext* aCx, JSObject* aGlobal)
{
return Navigator::HasCameraSupport(aCx, aGlobal);
}
JSObject*
DOMCameraDetectedFace::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CameraDetectedFaceBinding::Wrap(aCx, this, aGivenProto);
}
/* static */
already_AddRefed<DOMCameraDetectedFace>
DOMCameraDetectedFace::Constructor(const GlobalObject& aGlobal,
const dom::CameraDetectedFaceInit& aFace,
ErrorResult& aRv)
{
RefPtr<DOMCameraDetectedFace> face =
new DOMCameraDetectedFace(aGlobal.GetAsSupports(), aFace);
return face.forget();
}
DOMCameraDetectedFace::DOMCameraDetectedFace(nsISupports* aParent,
const dom::CameraDetectedFaceInit& aFace)
: mParent(aParent)
, mId(aFace.mId)
, mScore(aFace.mScore)
, mBounds(new DOMRect(this))
{
mBounds->SetRect(aFace.mBounds.mLeft,
aFace.mBounds.mTop,
aFace.mBounds.mRight - aFace.mBounds.mLeft,
aFace.mBounds.mBottom - aFace.mBounds.mTop);
if (aFace.mHasLeftEye) {
mLeftEye = new DOMPoint(this, aFace.mLeftEye.mX, aFace.mLeftEye.mY);
}
if (aFace.mHasRightEye) {
mRightEye = new DOMPoint(this, aFace.mRightEye.mX, aFace.mRightEye.mY);
}
if (aFace.mHasMouth) {
mMouth = new DOMPoint(this, aFace.mMouth.mX, aFace.mMouth.mY);
}
}
DOMCameraDetectedFace::DOMCameraDetectedFace(nsISupports* aParent,
const ICameraControl::Face& aFace)
: mParent(aParent)
, mId(aFace.id)
, mScore(aFace.score)
, mBounds(new DOMRect(this))
{
mBounds->SetRect(aFace.bound.left,
aFace.bound.top,
aFace.bound.right - aFace.bound.left,
aFace.bound.bottom - aFace.bound.top);
if (aFace.hasLeftEye) {
mLeftEye = new DOMPoint(this, aFace.leftEye.x, aFace.leftEye.y);
}
if (aFace.hasRightEye) {
mRightEye = new DOMPoint(this, aFace.rightEye.x, aFace.rightEye.y);
}
if (aFace.hasMouth) {
mMouth = new DOMPoint(this, aFace.mouth.x, aFace.mouth.y);
}
}

Просмотреть файл

@ -1,80 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_DOMCAMERADETECTEDFACE_H
#define DOM_CAMERA_DOMCAMERADETECTEDFACE_H
#include "mozilla/dom/CameraControlBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/DOMPoint.h"
#include "ICameraControl.h"
namespace mozilla {
namespace dom {
class DOMCameraDetectedFace final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMCameraDetectedFace)
// Because this header's filename doesn't match its C++ or DOM-facing
// classname, we can't rely on the [Func="..."] WebIDL tag to implicitly
// include the right header for us; instead we must explicitly include a
// HasSupport() method in each header. We can get rid of these with the
// Great Renaming proposed in bug 983177.
static bool HasSupport(JSContext* aCx, JSObject* aGlobal);
static already_AddRefed<DOMCameraDetectedFace> Constructor(const GlobalObject& aGlobal,
const dom::CameraDetectedFaceInit& aFace,
ErrorResult& aRv);
DOMCameraDetectedFace(nsISupports* aParent, const ICameraControl::Face& aFace);
uint32_t Id() { return mId; }
uint32_t Score() { return mScore; }
bool HasLeftEye() { return mLeftEye; }
bool HasRightEye() { return mRightEye; }
bool HasMouth() { return mMouth; }
dom::DOMRect* Bounds() { return mBounds; }
dom::DOMPoint* GetLeftEye() { return mLeftEye; }
dom::DOMPoint* GetRightEye() { return mRightEye; }
dom::DOMPoint* GetMouth() { return mMouth; }
nsISupports*
GetParentObject() const
{
MOZ_ASSERT(mParent);
return mParent;
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
protected:
DOMCameraDetectedFace(nsISupports* aParent, const dom::CameraDetectedFaceInit& aFace);
virtual ~DOMCameraDetectedFace() { }
nsCOMPtr<nsISupports> mParent;
uint32_t mId;
uint32_t mScore;
RefPtr<dom::DOMRect> mBounds;
RefPtr<dom::DOMPoint> mLeftEye;
RefPtr<dom::DOMPoint> mRightEye;
RefPtr<dom::DOMPoint> mMouth;
};
} // namespace dom
} // namespace mozilla
#endif // DOM_CAMERA_DOMCAMERADETECTEDFACE_H

Просмотреть файл

@ -1,451 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DOMCameraManager.h"
#include "nsDebug.h"
#include "jsapi.h"
#include "Navigator.h"
#include "nsPIDOMWindow.h"
#include "mozilla/Services.h"
#include "nsContentPermissionHelper.h"
#include "nsIContentPermissionPrompt.h"
#include "nsIObserverService.h"
#include "nsIPermissionManager.h"
#include "nsIScriptObjectPrincipal.h"
#include "DOMCameraControl.h"
#include "nsDOMClassInfo.h"
#include "CameraCommon.h"
#include "CameraPreferences.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "nsQueryObject.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCameraManager, mWindow)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCameraManager)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCameraManager)
/**
* Global camera logging object
*
* Set the MOZ_LOG environment variable to enable logging
* in a debug build, e.g. MOZ_LOG=Camera:5
*/
LogModule*
GetCameraLog()
{
static LazyLogModule sLog("Camera");
return sLog;
}
::WindowTable* nsDOMCameraManager::sActiveWindows = nullptr;
nsDOMCameraManager::nsDOMCameraManager(nsPIDOMWindowInner* aWindow)
: mWindowId(aWindow->WindowID())
, mPermission(nsIPermissionManager::DENY_ACTION)
, mWindow(aWindow)
{
/* member initializers and constructor code */
DOM_CAMERA_LOGT("%s:%d : this=%p, windowId=%" PRIx64 "\n", __func__, __LINE__, this, mWindowId);
MOZ_COUNT_CTOR(nsDOMCameraManager);
}
nsDOMCameraManager::~nsDOMCameraManager()
{
/* destructor code */
MOZ_COUNT_DTOR(nsDOMCameraManager);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
/* static */
void
nsDOMCameraManager::GetListOfCameras(nsTArray<nsString>& aList, ErrorResult& aRv)
{
aRv = ICameraControl::GetListOfCameras(aList);
}
/* static */
bool
nsDOMCameraManager::HasSupport(JSContext* aCx, JSObject* aGlobal)
{
return Navigator::HasCameraSupport(aCx, aGlobal);
}
/* static */
bool
nsDOMCameraManager::CheckPermission(nsPIDOMWindowInner* aWindow)
{
nsCOMPtr<nsIPermissionManager> permMgr =
services::GetPermissionManager();
NS_ENSURE_TRUE(permMgr, false);
uint32_t permission = nsIPermissionManager::DENY_ACTION;
permMgr->TestPermissionFromWindow(aWindow, "camera", &permission);
if (permission != nsIPermissionManager::ALLOW_ACTION &&
permission != nsIPermissionManager::PROMPT_ACTION) {
return false;
}
return true;
}
/* static */
already_AddRefed<nsDOMCameraManager>
nsDOMCameraManager::CreateInstance(nsPIDOMWindowInner* aWindow)
{
// Initialize the shared active window tracker
if (!sActiveWindows) {
sActiveWindows = new ::WindowTable();
}
RefPtr<nsDOMCameraManager> cameraManager =
new nsDOMCameraManager(aWindow);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs) {
DOM_CAMERA_LOGE("Camera manager failed to get observer service\n");
return nullptr;
}
nsresult rv = obs->AddObserver(cameraManager, "xpcom-shutdown", true);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGE("Camera manager failed to add 'xpcom-shutdown' observer (0x%x)\n", rv);
return nullptr;
}
return cameraManager.forget();
}
class CameraPermissionRequest : public nsIContentPermissionRequest
, public nsIRunnable
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
NS_DECL_NSIRUNNABLE
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CameraPermissionRequest,
nsIContentPermissionRequest)
CameraPermissionRequest(nsIPrincipal* aPrincipal,
nsPIDOMWindowInner* aWindow,
RefPtr<nsDOMCameraManager> aManager,
uint32_t aCameraId,
const CameraConfiguration& aInitialConfig,
RefPtr<Promise> aPromise)
: mPrincipal(aPrincipal)
, mWindow(aWindow)
, mCameraManager(aManager)
, mCameraId(aCameraId)
, mInitialConfig(aInitialConfig)
, mPromise(aPromise)
, mRequester(new nsContentPermissionRequester(mWindow))
{ }
protected:
virtual ~CameraPermissionRequest() { }
nsresult DispatchCallback(uint32_t aPermission);
void CallAllow();
void CallCancel();
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
RefPtr<nsDOMCameraManager> mCameraManager;
uint32_t mCameraId;
CameraConfiguration mInitialConfig;
RefPtr<Promise> mPromise;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
};
NS_IMPL_CYCLE_COLLECTION(CameraPermissionRequest, mWindow, mPromise)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraPermissionRequest)
NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraPermissionRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraPermissionRequest)
NS_IMETHODIMP
CameraPermissionRequest::Run()
{
return nsContentPermissionUtils::AskPermission(this, mWindow);
}
NS_IMETHODIMP
CameraPermissionRequest::GetPrincipal(nsIPrincipal** aRequestingPrincipal)
{
NS_ADDREF(*aRequestingPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHODIMP
CameraPermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
{
NS_ADDREF(*aRequestingWindow = mWindow);
return NS_OK;
}
NS_IMETHODIMP
CameraPermissionRequest::GetElement(nsIDOMElement** aElement)
{
*aElement = nullptr;
return NS_OK;
}
NS_IMETHODIMP
CameraPermissionRequest::Cancel()
{
return DispatchCallback(nsIPermissionManager::DENY_ACTION);
}
NS_IMETHODIMP
CameraPermissionRequest::Allow(JS::HandleValue aChoices)
{
MOZ_ASSERT(aChoices.isUndefined());
return DispatchCallback(nsIPermissionManager::ALLOW_ACTION);
}
NS_IMETHODIMP
CameraPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
{
NS_ENSURE_ARG_POINTER(aRequester);
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
requester.forget(aRequester);
return NS_OK;
}
nsresult
CameraPermissionRequest::DispatchCallback(uint32_t aPermission)
{
nsCOMPtr<nsIRunnable> callbackRunnable;
if (aPermission == nsIPermissionManager::ALLOW_ACTION) {
callbackRunnable = NewRunnableMethod(this, &CameraPermissionRequest::CallAllow);
} else {
callbackRunnable = NewRunnableMethod(this, &CameraPermissionRequest::CallCancel);
}
return NS_DispatchToMainThread(callbackRunnable.forget());
}
void
CameraPermissionRequest::CallAllow()
{
mCameraManager->PermissionAllowed(mCameraId, mInitialConfig, mPromise);
}
void
CameraPermissionRequest::CallCancel()
{
mCameraManager->PermissionCancelled(mCameraId, mInitialConfig, mPromise);
}
NS_IMETHODIMP
CameraPermissionRequest::GetTypes(nsIArray** aTypes)
{
nsTArray<nsString> emptyOptions;
return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("camera"),
NS_LITERAL_CSTRING("unused"),
emptyOptions,
aTypes);
}
#ifdef MOZ_WIDGET_GONK
/* static */ void
nsDOMCameraManager::PreinitCameraHardware()
{
nsDOMCameraControl::PreinitCameraHardware();
}
#endif
already_AddRefed<Promise>
nsDOMCameraManager::GetCamera(const nsAString& aCamera,
const CameraConfiguration& aInitialConfig,
ErrorResult& aRv)
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
uint32_t cameraId = 0; // back (or forward-facing) camera by default
if (aCamera.EqualsLiteral("front")) {
cameraId = 1;
}
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
if (!global) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
if (mPermission == nsIPermissionManager::ALLOW_ACTION) {
PermissionAllowed(cameraId, aInitialConfig, promise);
return promise.forget();
}
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
if (!sop) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
// If we are a CERTIFIED app, we can short-circuit the permission check,
// which gets us a performance win.
// Unprivileged mochitests always fail the dispatched permission check,
// even if permission to the camera has been granted.
bool immediateCheck = false;
CameraPreferences::GetPref("camera.control.test.permission", immediateCheck);
if ((principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED || immediateCheck) &&
CheckPermission(mWindow)) {
PermissionAllowed(cameraId, aInitialConfig, promise);
return promise.forget();
}
nsCOMPtr<nsIRunnable> permissionRequest =
new CameraPermissionRequest(principal, mWindow, this, cameraId,
aInitialConfig, promise);
NS_DispatchToMainThread(permissionRequest);
return promise.forget();
}
void
nsDOMCameraManager::PermissionAllowed(uint32_t aCameraId,
const CameraConfiguration& aInitialConfig,
Promise* aPromise)
{
mPermission = nsIPermissionManager::ALLOW_ACTION;
// Creating this object will trigger the aOnSuccess callback
// (or the aOnError one, if it fails).
RefPtr<nsDOMCameraControl> cameraControl =
new nsDOMCameraControl(aCameraId, aInitialConfig, aPromise, mWindow);
Register(cameraControl);
}
void
nsDOMCameraManager::PermissionCancelled(uint32_t aCameraId,
const CameraConfiguration& aInitialConfig,
Promise* aPromise)
{
mPermission = nsIPermissionManager::DENY_ACTION;
aPromise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
}
void
nsDOMCameraManager::Register(nsDOMCameraControl* aDOMCameraControl)
{
DOM_CAMERA_LOGI(">>> Register( aDOMCameraControl = %p ) mWindowId = 0x%" PRIx64 "\n", aDOMCameraControl, mWindowId);
MOZ_ASSERT(NS_IsMainThread());
CameraControls* controls = sActiveWindows->Get(mWindowId);
if (!controls) {
controls = new CameraControls();
sActiveWindows->Put(mWindowId, controls);
}
// Remove any stale CameraControl objects to limit our memory usage
uint32_t i = controls->Length();
while (i > 0) {
--i;
RefPtr<nsDOMCameraControl> cameraControl =
do_QueryObject(controls->ElementAt(i));
if (!cameraControl) {
controls->RemoveElementAt(i);
}
}
// Put the camera control into the hash table
nsWeakPtr cameraControl =
do_GetWeakReference(static_cast<DOMMediaStream*>(aDOMCameraControl));
controls->AppendElement(cameraControl);
}
void
nsDOMCameraManager::Shutdown(uint64_t aWindowId)
{
DOM_CAMERA_LOGI(">>> Shutdown( aWindowId = 0x%" PRIx64 " )\n", aWindowId);
MOZ_ASSERT(NS_IsMainThread());
CameraControls* controls = sActiveWindows->Get(aWindowId);
if (!controls) {
return;
}
uint32_t i = controls->Length();
while (i > 0) {
--i;
RefPtr<nsDOMCameraControl> cameraControl =
do_QueryObject(controls->ElementAt(i));
if (cameraControl) {
cameraControl->Shutdown();
}
}
controls->Clear();
sActiveWindows->Remove(aWindowId);
}
void
nsDOMCameraManager::XpComShutdown()
{
DOM_CAMERA_LOGI(">>> XPCOM Shutdown\n");
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->RemoveObserver(this, "xpcom-shutdown");
delete sActiveWindows;
sActiveWindows = nullptr;
}
nsresult
nsDOMCameraManager::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
{
if (strcmp(aTopic, "xpcom-shutdown") == 0) {
XpComShutdown();
}
return NS_OK;
}
void
nsDOMCameraManager::OnNavigation(uint64_t aWindowId)
{
DOM_CAMERA_LOGI(">>> OnNavigation event\n");
Shutdown(aWindowId);
}
bool
nsDOMCameraManager::IsWindowStillActive(uint64_t aWindowId)
{
MOZ_ASSERT(NS_IsMainThread());
if (!sActiveWindows) {
return false;
}
return !!sActiveWindows->Get(aWindowId);
}
JSObject*
nsDOMCameraManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CameraManagerBinding::Wrap(aCx, this, aGivenProto);
}

Просмотреть файл

@ -1,104 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_DOMCAMERAMANAGER_H
#define DOM_CAMERA_DOMCAMERAMANAGER_H
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Promise.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsHashKeys.h"
#include "nsWrapperCache.h"
#include "nsWeakReference.h"
#include "nsClassHashtable.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
class nsPIDOMWindowInner;
namespace mozilla {
class ErrorResult;
class nsDOMCameraControl;
namespace dom {
struct CameraConfiguration;
} // namespace dom
} // namespace mozilla
typedef nsTArray<nsWeakPtr> CameraControls;
typedef nsClassHashtable<nsUint64HashKey, CameraControls> WindowTable;
class nsDOMCameraManager final
: public nsIObserver
, public nsSupportsWeakReference
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDOMCameraManager,
nsIObserver)
NS_DECL_NSIOBSERVER
// Because this header's filename doesn't match its C++ or DOM-facing
// classname, we can't rely on the [Func="..."] WebIDL tag to implicitly
// include the right header for us; instead we must explicitly include a
// HasSupport() method in each header. We can get rid of these with the
// Great Renaming proposed in bug 983177.
static bool HasSupport(JSContext* aCx, JSObject* aGlobal);
static bool CheckPermission(nsPIDOMWindowInner* aWindow);
static already_AddRefed<nsDOMCameraManager>
CreateInstance(nsPIDOMWindowInner* aWindow);
static bool IsWindowStillActive(uint64_t aWindowId);
void Register(mozilla::nsDOMCameraControl* aDOMCameraControl);
void OnNavigation(uint64_t aWindowId);
void PermissionAllowed(uint32_t aCameraId,
const mozilla::dom::CameraConfiguration& aOptions,
mozilla::dom::Promise* aPromise);
void PermissionCancelled(uint32_t aCameraId,
const mozilla::dom::CameraConfiguration& aOptions,
mozilla::dom::Promise* aPromise);
// WebIDL
already_AddRefed<mozilla::dom::Promise>
GetCamera(const nsAString& aCamera,
const mozilla::dom::CameraConfiguration& aOptions,
mozilla::ErrorResult& aRv);
void GetListOfCameras(nsTArray<nsString>& aList, mozilla::ErrorResult& aRv);
nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
#ifdef MOZ_WIDGET_GONK
static void PreinitCameraHardware();
#endif
protected:
void XpComShutdown();
void Shutdown(uint64_t aWindowId);
~nsDOMCameraManager();
private:
nsDOMCameraManager() = delete;
explicit nsDOMCameraManager(nsPIDOMWindowInner* aWindow);
nsDOMCameraManager(const nsDOMCameraManager&) = delete;
nsDOMCameraManager& operator=(const nsDOMCameraManager&) = delete;
protected:
uint64_t mWindowId;
uint32_t mPermission;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
/**
* 'sActiveWindows' is only ever accessed while in the Main Thread,
* so it is not otherwise protected.
*/
static ::WindowTable* sActiveWindows;
};
#endif // DOM_CAMERA_DOMCAMERAMANAGER_H

Просмотреть файл

@ -1,73 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CameraControlImpl.h"
using namespace mozilla;
using namespace mozilla::dom;
namespace mozilla {
class RecorderProfileManager;
namespace layers {
class GraphicBufferLocked;
} // namespace layers
} // namespace mozilla
/**
* Fallback camera control subclass. Can be used as a template for the
* definition of new camera support classes.
*/
class FallbackCameraControl : public CameraControlImpl
{
public:
explicit FallbackCameraControl() : CameraControlImpl() { }
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, nsAString& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, double aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, double& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, int32_t aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, int32_t& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, int64_t aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, int64_t& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, bool aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, bool& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, const Size& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, Size& aValue) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, nsTArray<Region>& aRegions) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult SetLocation(const Position& aLocation) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult GetRecorderProfiles(nsTArray<nsString>& aProfiles) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual RecorderProfile* GetProfileInfo(const nsAString& aProfile) override { return nullptr; }
nsresult PushParameters() { return NS_ERROR_NOT_INITIALIZED; }
nsresult PullParameters() { return NS_ERROR_NOT_INITIALIZED; }
protected:
~FallbackCameraControl();
virtual nsresult StartPreviewImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult StopPreviewImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult AutoFocusImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult StartFaceDetectionImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult StopFaceDetectionImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult TakePictureImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions = nullptr) override
{ return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult StopRecordingImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult PushParametersImpl() override { return NS_ERROR_NOT_INITIALIZED; }
virtual nsresult PullParametersImpl() override { return NS_ERROR_NOT_INITIALIZED; }
private:
FallbackCameraControl(const FallbackCameraControl&) = delete;
FallbackCameraControl& operator=(const FallbackCameraControl&) = delete;
};

Просмотреть файл

@ -1,32 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ICameraControl.h"
using namespace mozilla;
// From ICameraControl.
nsresult
ICameraControl::GetNumberOfCameras(int32_t& aDeviceCount)
{
return NS_ERROR_NOT_IMPLEMENTED;
};
nsresult
ICameraControl::GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
already_AddRefed<ICameraControl>
ICameraControl::Create(uint32_t aCameraId)
{
return nullptr;
}

Просмотреть файл

@ -1,91 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2015 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "FallbackCameraPlatform.h"
using namespace android;
MediaProfiles* MediaProfiles::sMediaProfiles = nullptr;
const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
const char CameraParameters::KEY_ROTATION[] = "rotation";
const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
const char CameraParameters::KEY_GPS_PROCESSING_METHOD[] = "gps-processing-method";
const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
const char CameraParameters::KEY_EFFECT[] = "effect";
const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas";
const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas";
const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported";
const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
const char CameraParameters::KEY_ZOOM[] = "zoom";
const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported";
const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
const char CameraParameters::KEY_LIGHTFX[] = "light-fx";

Просмотреть файл

@ -1,304 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2015 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.
*/
#ifndef DOM_CAMERA_FALLBACKCAMERAPLATFORM_H
#define DOM_CAMERA_FALLBACKCAMERAPLATFORM_H
#include <inttypes.h>
#include <string.h>
typedef struct {
int32_t id;
int32_t score;
int32_t rect[4];
int32_t left_eye[2];
int32_t right_eye[2];
int32_t mouth[2];
} camera_face_t;
typedef struct {
uint32_t number_of_faces;
camera_face_t* faces;
} camera_frame_metadata_t;
namespace android {
enum camcorder_quality {
CAMCORDER_QUALITY_LOW,
CAMCORDER_QUALITY_HIGH,
CAMCORDER_QUALITY_QCIF,
CAMCORDER_QUALITY_CIF,
CAMCORDER_QUALITY_480P,
CAMCORDER_QUALITY_720P,
CAMCORDER_QUALITY_1080P,
CAMCORDER_QUALITY_QVGA,
CAMCORDER_QUALITY_VGA,
CAMCORDER_QUALITY_LIST_START = CAMCORDER_QUALITY_LOW,
CAMCORDER_QUALITY_LIST_END = CAMCORDER_QUALITY_VGA
};
enum output_format {
OUTPUT_FORMAT_THREE_GPP,
OUTPUT_FORMAT_MPEG_4
};
enum video_encoder {
VIDEO_ENCODER_H263,
VIDEO_ENCODER_H264,
VIDEO_ENCODER_MPEG_4_SP
};
enum audio_encoder {
AUDIO_ENCODER_AMR_WB,
AUDIO_ENCODER_AMR_NB,
AUDIO_ENCODER_AAC
};
template <class T>
class sp final
{
public:
sp()
: mPtr(nullptr)
{ }
sp(T *aPtr)
: mPtr(aPtr)
{ }
virtual ~sp() { }
T* get() const { return mPtr; }
void clear() { mPtr = nullptr; }
T* operator->() const { return get(); }
private:
RefPtr<T> mPtr;
};
typedef uint64_t nsecs_t;
enum error_t {
OK = 0,
UNKNOWN_ERROR,
INVALID_OPERATION
};
enum camera_msg_t {
CAMERA_MSG_SHUTTER,
CAMERA_MSG_COMPRESSED_IMAGE
};
class String8 final
{
public:
String8() { }
String8(const char* aData) { mData.AssignASCII(aData); }
virtual ~String8() { }
const char* string() const { return mData.Data(); }
private:
nsCString mData;
};
enum camera_facing_t {
CAMERA_FACING_BACK,
CAMERA_FACING_FRONT
};
struct CameraInfo {
camera_facing_t facing;
};
class Camera final : public nsISupports
{
public:
NS_DECL_ISUPPORTS;
void disconnect() { }
String8 getParameters() { return String8(); }
int setParameters(const String8& aParams) { return UNKNOWN_ERROR; }
int storeMetaDataInBuffers(bool aEnabled) { return UNKNOWN_ERROR; }
int autoFocus() { return UNKNOWN_ERROR; }
int cancelAutoFocus() { return UNKNOWN_ERROR; }
int takePicture(uint32_t flags) { return UNKNOWN_ERROR; }
int startPreview() { return UNKNOWN_ERROR; }
int stopPreview() { return UNKNOWN_ERROR; }
int startRecording() { return UNKNOWN_ERROR; }
int stopRecording() { return UNKNOWN_ERROR; }
int startFaceDetection() { return UNKNOWN_ERROR; }
int stopFaceDetection() { return UNKNOWN_ERROR; }
static int32_t getNumberOfCameras() { return 2; }
static int getCameraInfo(int32_t aDevice, CameraInfo* aInfo)
{
switch (aDevice) {
case 0:
aInfo->facing = CAMERA_FACING_BACK;
break;
case 1:
aInfo->facing = CAMERA_FACING_FRONT;
break;
default:
return UNKNOWN_ERROR;
}
return OK;
}
protected:
Camera() { }
virtual ~Camera() { }
private:
Camera(const Camera&) = delete;
Camera& operator=(const Camera&) = delete;
};
class CameraParameters final
{
public:
static const char KEY_PREVIEW_SIZE[];
static const char KEY_SUPPORTED_PREVIEW_SIZES[];
static const char KEY_PREVIEW_FPS_RANGE[];
static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
static const char KEY_PREVIEW_FORMAT[];
static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
static const char KEY_PREVIEW_FRAME_RATE[];
static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
static const char KEY_PICTURE_SIZE[];
static const char KEY_SUPPORTED_PICTURE_SIZES[];
static const char KEY_PICTURE_FORMAT[];
static const char KEY_SUPPORTED_PICTURE_FORMATS[];
static const char KEY_JPEG_THUMBNAIL_WIDTH[];
static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
static const char KEY_JPEG_THUMBNAIL_QUALITY[];
static const char KEY_JPEG_QUALITY[];
static const char KEY_ROTATION[];
static const char KEY_GPS_LATITUDE[];
static const char KEY_GPS_LONGITUDE[];
static const char KEY_GPS_ALTITUDE[];
static const char KEY_GPS_TIMESTAMP[];
static const char KEY_GPS_PROCESSING_METHOD[];
static const char KEY_WHITE_BALANCE[];
static const char KEY_SUPPORTED_WHITE_BALANCE[];
static const char KEY_EFFECT[];
static const char KEY_SUPPORTED_EFFECTS[];
static const char KEY_ANTIBANDING[];
static const char KEY_SUPPORTED_ANTIBANDING[];
static const char KEY_SCENE_MODE[];
static const char KEY_SUPPORTED_SCENE_MODES[];
static const char KEY_FLASH_MODE[];
static const char KEY_SUPPORTED_FLASH_MODES[];
static const char KEY_FOCUS_MODE[];
static const char KEY_SUPPORTED_FOCUS_MODES[];
static const char KEY_MAX_NUM_FOCUS_AREAS[];
static const char KEY_FOCUS_AREAS[];
static const char KEY_FOCAL_LENGTH[];
static const char KEY_HORIZONTAL_VIEW_ANGLE[];
static const char KEY_VERTICAL_VIEW_ANGLE[];
static const char KEY_EXPOSURE_COMPENSATION[];
static const char KEY_MAX_EXPOSURE_COMPENSATION[];
static const char KEY_MIN_EXPOSURE_COMPENSATION[];
static const char KEY_EXPOSURE_COMPENSATION_STEP[];
static const char KEY_AUTO_EXPOSURE_LOCK[];
static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
static const char KEY_AUTO_WHITEBALANCE_LOCK[];
static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
static const char KEY_MAX_NUM_METERING_AREAS[];
static const char KEY_METERING_AREAS[];
static const char KEY_ZOOM[];
static const char KEY_MAX_ZOOM[];
static const char KEY_ZOOM_RATIOS[];
static const char KEY_ZOOM_SUPPORTED[];
static const char KEY_SMOOTH_ZOOM_SUPPORTED[];
static const char KEY_FOCUS_DISTANCES[];
static const char KEY_VIDEO_SIZE[];
static const char KEY_SUPPORTED_VIDEO_SIZES[];
static const char KEY_MAX_NUM_DETECTED_FACES_HW[];
static const char KEY_MAX_NUM_DETECTED_FACES_SW[];
static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
static const char KEY_VIDEO_FRAME_FORMAT[];
static const char KEY_RECORDING_HINT[];
static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
static const char KEY_VIDEO_STABILIZATION[];
static const char KEY_VIDEO_STABILIZATION_SUPPORTED[];
static const char KEY_LIGHTFX[];
};
class MediaProfiles final
{
public:
static MediaProfiles* getInstance() {
if (!sMediaProfiles) {
sMediaProfiles = new MediaProfiles();
}
return sMediaProfiles;
}
bool hasCamcorderProfile(int aCameraId, camcorder_quality aQuality) const {
switch (aQuality) {
case CAMCORDER_QUALITY_LOW:
case CAMCORDER_QUALITY_HIGH:
case CAMCORDER_QUALITY_QVGA:
case CAMCORDER_QUALITY_VGA:
return true;
default:
break;
}
return false;
}
int getCamcorderProfileParamByName(const char* aParameter, int aCameraId, camcorder_quality aQuality) const {
switch (aQuality) {
case CAMCORDER_QUALITY_LOW:
case CAMCORDER_QUALITY_QVGA:
if (strcmp(aParameter, "vid.width") == 0) {
return 320;
} else if (strcmp(aParameter, "vid.height") == 0) {
return 240;
} else if (strcmp(aParameter, "vid.fps") == 0) {
return 30;
}
return 0;
case CAMCORDER_QUALITY_HIGH:
case CAMCORDER_QUALITY_VGA:
if (strcmp(aParameter, "vid.width") == 0) {
return 640;
} else if (strcmp(aParameter, "vid.height") == 0) {
return 480;
} else if (strcmp(aParameter, "vid.fps") == 0) {
return 30;
}
return 0;
default:
break;
}
return -1;
}
protected:
MediaProfiles() { }
virtual ~MediaProfiles() { }
private:
MediaProfiles(const MediaProfiles&) = delete;
MediaProfiles& operator=(const MediaProfiles&) = delete;
static MediaProfiles* sMediaProfiles;
};
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,237 +0,0 @@
/*
* Copyright (C) 2012-2014 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.
*/
#ifndef DOM_CAMERA_GONKCAMERACONTROL_H
#define DOM_CAMERA_GONKCAMERACONTROL_H
#include "base/basictypes.h"
#include "nsRefPtrHashtable.h"
#include "mozilla/ReentrantMonitor.h"
#include "DeviceStorage.h"
#include "CameraControlImpl.h"
#include "CameraCommon.h"
#include "GonkCameraHwMgr.h"
#include "GonkCameraParameters.h"
#ifdef MOZ_WIDGET_GONK
#include <media/MediaProfiles.h>
#include <camera/Camera.h>
#include "GonkRecorder.h"
#else
#include "FallbackCameraPlatform.h"
#endif
class nsITimer;
namespace android {
class GonkCameraHardware;
class GonkRecorder;
class GonkCameraSource;
}
namespace mozilla {
namespace layers {
class TextureClient;
class ImageContainer;
class Image;
}
class nsGonkCameraControl : public CameraControlImpl
{
public:
nsGonkCameraControl(uint32_t aCameraId);
void OnAutoFocusMoving(bool aIsMoving);
void OnAutoFocusComplete(bool aSuccess, bool aExpired);
void OnFacesDetected(camera_frame_metadata_t* aMetaData);
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength);
void OnTakePictureError();
void OnRateLimitPreview(bool aLimit);
void OnPoster(void* aData, uint32_t aLength);
void OnNewPreviewFrame(layers::TextureClient* aBuffer);
#ifdef MOZ_WIDGET_GONK
void OnRecorderEvent(int msg, int ext1, int ext2);
#endif
void OnSystemError(CameraControlListener::SystemContext aWhere, nsresult aError);
// See ICameraControl.h for getter/setter return values.
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) override;
virtual nsresult Get(uint32_t aKey, nsAString& aValue) override;
virtual nsresult Set(uint32_t aKey, double aValue) override;
virtual nsresult Get(uint32_t aKey, double& aValue) override;
virtual nsresult Set(uint32_t aKey, int32_t aValue) override;
virtual nsresult Get(uint32_t aKey, int32_t& aValue) override;
virtual nsresult Set(uint32_t aKey, int64_t aValue) override;
virtual nsresult Get(uint32_t aKey, int64_t& aValue) override;
virtual nsresult Set(uint32_t aKey, bool aValue) override;
virtual nsresult Get(uint32_t aKey, bool& aValue) override;
virtual nsresult Set(uint32_t aKey, const Size& aValue) override;
virtual nsresult Get(uint32_t aKey, Size& aValue) override;
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) override;
virtual nsresult Get(uint32_t aKey, nsTArray<Region>& aRegions) override;
virtual nsresult SetLocation(const Position& aLocation) override;
virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) override;
virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) override;
virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) override;
virtual nsresult GetRecorderProfiles(nsTArray<nsString>& aProfiles) override;
virtual ICameraControl::RecorderProfile*
GetProfileInfo(const nsAString& aProfile) override;
nsresult PushParameters();
nsresult PullParameters();
protected:
~nsGonkCameraControl();
using CameraControlImpl::OnRateLimitPreview;
using CameraControlImpl::OnNewPreviewFrame;
using CameraControlImpl::OnAutoFocusComplete;
using CameraControlImpl::OnFacesDetected;
using CameraControlImpl::OnTakePictureComplete;
using CameraControlImpl::OnConfigurationChange;
using CameraControlImpl::OnUserError;
typedef nsTArray<Size>::index_type SizeIndex;
virtual void BeginBatchParameterSet() override;
virtual void EndBatchParameterSet() override;
nsresult Initialize();
nsresult ValidateConfiguration(const Configuration& aConfig, Configuration& aValidatedConfig);
nsresult SetConfigurationInternal(const Configuration& aConfig);
nsresult SetPictureConfiguration(const Configuration& aConfig);
nsresult SetVideoConfiguration(const Configuration& aConfig);
nsresult StartInternal(const Configuration* aInitialConfig);
nsresult StartPreviewInternal();
nsresult StopInternal();
template<class T> nsresult SetAndPush(uint32_t aKey, const T& aValue);
// See CameraControlImpl.h for these methods' return values.
virtual nsresult StartImpl(const Configuration* aInitialConfig = nullptr) override;
virtual nsresult SetConfigurationImpl(const Configuration& aConfig) override;
virtual nsresult StopImpl() override;
virtual nsresult StartPreviewImpl() override;
virtual nsresult StopPreviewImpl() override;
virtual nsresult AutoFocusImpl() override;
virtual nsresult StartFaceDetectionImpl() override;
virtual nsresult StopFaceDetectionImpl() override;
virtual nsresult TakePictureImpl() override;
virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions = nullptr) override;
virtual nsresult StopRecordingImpl() override;
virtual nsresult PauseRecordingImpl() override;
virtual nsresult ResumeRecordingImpl() override;
virtual nsresult ResumeContinuousFocusImpl() override;
virtual nsresult PushParametersImpl() override;
virtual nsresult PullParametersImpl() override;
nsresult SetupRecording(int aFd, int aRotation, uint64_t aMaxFileSizeBytes,
uint64_t aMaxVideoLengthMs);
nsresult SetupRecordingFlash(bool aAutoEnableLowLightTorch);
nsresult SelectCaptureAndPreviewSize(const Size& aPreviewSize, const Size& aCaptureSize,
const Size& aMaxSize, uint32_t aCaptureSizeKey);
nsresult MaybeAdjustVideoSize();
nsresult PausePreview();
nsresult GetSupportedSize(const Size& aSize, const nsTArray<Size>& supportedSizes, Size& best);
void CreatePoster(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight, int32_t aRotation);
nsresult LoadRecorderProfiles();
friend class SetPictureSize;
friend class SetThumbnailSize;
nsresult SetPictureSize(const Size& aSize);
nsresult SetPictureSizeImpl(const Size& aSize);
nsresult SetThumbnailSize(const Size& aSize);
nsresult UpdateThumbnailSize();
nsresult SetThumbnailSizeImpl(const Size& aSize);
friend class android::GonkCameraSource;
android::sp<android::GonkCameraHardware> GetCameraHw();
int32_t RationalizeRotation(int32_t aRotation);
uint32_t mCameraId;
android::sp<android::GonkCameraHardware> mCameraHw;
Size mLastThumbnailSize;
Size mLastRecorderSize;
Size mRequestedPreviewSize;
uint32_t mPreviewFps;
bool mResumePreviewAfterTakingPicture;
bool mFlashSupported;
bool mLuminanceSupported;
bool mAutoFlashModeOverridden;
bool mSeparateVideoAndPreviewSizesSupported;
Atomic<uint32_t> mDeferConfigUpdate;
GonkCameraParameters mParams;
RefPtr<mozilla::layers::ImageContainer> mImageContainer;
#ifdef MOZ_WIDGET_GONK
RefPtr<android::GonkRecorder> mRecorder;
#endif
// Touching mRecorder happens inside this monitor because the destructor
// can run on any thread, and we need to be able to clean up properly if
// GonkCameraControl goes away.
ReentrantMonitor mRecorderMonitor;
// Supported recorder profiles
nsRefPtrHashtable<nsStringHashKey, RecorderProfile> mRecorderProfiles;
RefPtr<DeviceStorageFile> mVideoFile;
nsString mFileFormat;
Atomic<bool> mCapturePoster;
int32_t mVideoRotation;
bool mAutoFocusPending;
nsCOMPtr<nsITimer> mAutoFocusCompleteTimer;
int32_t mAutoFocusCompleteExpired;
uint32_t mPrevFacesDetected;
// Guards against calling StartPreviewImpl() while in OnTakePictureComplete().
ReentrantMonitor mReentrantMonitor;
private:
nsGonkCameraControl(const nsGonkCameraControl&) = delete;
nsGonkCameraControl& operator=(const nsGonkCameraControl&) = delete;
};
// camera driver callbacks
void OnRateLimitPreview(nsGonkCameraControl* gc, bool aLimit);
void OnTakePictureComplete(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
void OnTakePictureError(nsGonkCameraControl* gc);
void OnAutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
void OnAutoFocusMoving(nsGonkCameraControl* gc, bool aIsMoving);
void OnFacesDetected(nsGonkCameraControl* gc, camera_frame_metadata_t* aMetaData);
void OnNewPreviewFrame(nsGonkCameraControl* gc, layers::TextureClient* aBuffer);
void OnShutter(nsGonkCameraControl* gc);
void OnSystemError(nsGonkCameraControl* gc,
CameraControlListener::SystemContext aWhere,
int32_t aArg1, int32_t aArg2);
} // namespace mozilla
#endif // DOM_CAMERA_GONKCAMERACONTROL_H

Просмотреть файл

@ -1,520 +0,0 @@
/*
* Copyright (C) 2012-2015 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "GonkCameraHwMgr.h"
#include "TestGonkCameraHardware.h"
#ifdef MOZ_WIDGET_GONK
#include <binder/IPCThreadState.h>
#include <sys/system_properties.h>
#include "GonkNativeWindow.h"
#endif
#include "base/basictypes.h"
#include "nsDebug.h"
#include "mozilla/layers/TextureClient.h"
#include "CameraPreferences.h"
#include "mozilla/RefPtr.h"
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
#include "GonkBufferQueueProducer.h"
#endif
#include "GonkCameraControl.h"
#include "CameraCommon.h"
using namespace mozilla;
using namespace mozilla::layers;
using namespace android;
#ifndef MOZ_WIDGET_GONK
NS_IMPL_ISUPPORTS0(GonkCameraHardware);
NS_IMPL_ISUPPORTS0(android::Camera);
#endif
GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera)
: mCameraId(aCameraId)
, mClosing(false)
, mNumFrames(0)
#ifdef MOZ_WIDGET_GONK
, mCamera(aCamera)
#endif
, mTarget(aTarget)
, mRawSensorOrientation(0)
, mSensorOrientation(0)
, mEmulated(false)
{
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget);
}
void
GonkCameraHardware::OnRateLimitPreview(bool aLimit)
{
::OnRateLimitPreview(mTarget, aLimit);
}
#ifdef MOZ_WIDGET_GONK
void
GonkCameraHardware::OnNewFrame()
{
if (mClosing) {
return;
}
RefPtr<TextureClient> buffer = mNativeWindow->getCurrentBuffer();
if (!buffer) {
DOM_CAMERA_LOGE("received null frame");
return;
}
OnNewPreviewFrame(mTarget, buffer);
}
// Android data callback
void
GonkCameraHardware::postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, camera_frame_metadata_t* metadata)
{
if (mClosing) {
return;
}
switch (aMsgType) {
case CAMERA_MSG_PREVIEW_FRAME:
// Do nothing
break;
case CAMERA_MSG_COMPRESSED_IMAGE:
if (aDataPtr != nullptr) {
OnTakePictureComplete(mTarget, static_cast<uint8_t*>(aDataPtr->pointer()), aDataPtr->size());
} else {
OnTakePictureError(mTarget);
}
break;
case CAMERA_MSG_PREVIEW_METADATA:
OnFacesDetected(mTarget, metadata);
break;
default:
DOM_CAMERA_LOGE("Unhandled data callback event %d\n", aMsgType);
break;
}
}
// Android notify callback
void
GonkCameraHardware::notify(int32_t aMsgType, int32_t ext1, int32_t ext2)
{
if (mClosing) {
return;
}
switch (aMsgType) {
case CAMERA_MSG_FOCUS:
OnAutoFocusComplete(mTarget, !!ext1);
break;
#if ANDROID_VERSION >= 16
case CAMERA_MSG_FOCUS_MOVE:
OnAutoFocusMoving(mTarget, !!ext1);
break;
#endif
case CAMERA_MSG_SHUTTER:
OnShutter(mTarget);
break;
case CAMERA_MSG_ERROR:
OnSystemError(mTarget, CameraControlListener::kSystemService, ext1, ext2);
break;
default:
DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType);
break;
}
}
void
GonkCameraHardware::postDataTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory>& aDataPtr)
{
DOM_CAMERA_LOGI("%s",__func__);
if (mClosing) {
return;
}
if (mListener.get()) {
DOM_CAMERA_LOGI("Listener registered, posting recording frame!");
if (!mListener->postDataTimestamp(aTimestamp, aMsgType, aDataPtr)) {
DOM_CAMERA_LOGW("Listener unable to process. Drop a recording frame.");
mCamera->releaseRecordingFrame(aDataPtr);
}
} else {
DOM_CAMERA_LOGW("No listener was set. Drop a recording frame.");
mCamera->releaseRecordingFrame(aDataPtr);
}
}
#endif
nsresult
GonkCameraHardware::Init()
{
DOM_CAMERA_LOGT("%s: this=%p\n", __func__, (void* )this);
#ifdef MOZ_WIDGET_GONK
CameraInfo info;
int rv = Camera::getCameraInfo(mCameraId, &info);
if (rv != 0) {
DOM_CAMERA_LOGE("%s: failed to get CameraInfo mCameraId %d\n", __func__, mCameraId);
return NS_ERROR_NOT_INITIALIZED;
}
mRawSensorOrientation = info.orientation;
mSensorOrientation = mRawSensorOrientation;
/**
* Non-V4L2-based camera driver adds extra offset onto picture orientation
* set by gecko, so we have to adjust it back.
*/
char propname[PROP_NAME_MAX];
char prop[PROP_VALUE_MAX];
int offset = 0;
snprintf(propname, sizeof(propname), "ro.moz.cam.%d.sensor_offset", mCameraId);
if (__system_property_get(propname, prop) > 0) {
offset = clamped(atoi(prop), 0, 270);
mSensorOrientation += offset;
mSensorOrientation %= 360;
}
DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation);
if (__system_property_get("ro.kernel.qemu", prop) > 0 && atoi(prop)) {
DOM_CAMERA_LOGI("Using emulated camera\n");
mEmulated = true;
}
// Disable shutter sound in android CameraService because gaia camera app will play it
mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);
#if ANDROID_VERSION >= 21
sp<IGraphicBufferProducer> producer;
sp<IGonkGraphicBufferConsumer> consumer;
GonkBufferQueue::createBufferQueue(&producer, &consumer);
static_cast<GonkBufferQueueProducer*>(producer.get())->setSynchronousMode(false);
mNativeWindow = new GonkNativeWindow(consumer, GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
mCamera->setPreviewTarget(producer);
#elif ANDROID_VERSION >= 19
mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
bq->setSynchronousMode(false);
mCamera->setPreviewTarget(mNativeWindow->getBufferQueue());
#elif ANDROID_VERSION >= 17
mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
bq->setSynchronousMode(false);
mCamera->setPreviewTexture(mNativeWindow->getBufferQueue());
#else
mNativeWindow = new GonkNativeWindow();
mCamera->setPreviewTexture(mNativeWindow);
#endif
mNativeWindow->setNewFrameCallback(this);
mCamera->setListener(this);
#if ANDROID_VERSION >= 16
rv = mCamera->sendCommand(CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG, 1, 0);
if (rv != OK) {
NS_WARNING("Failed to send command CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG");
}
#endif
#endif
return NS_OK;
}
sp<GonkCameraHardware>
GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId)
{
sp<Camera> camera;
nsCString test;
CameraPreferences::GetPref("camera.control.test.enabled", test);
if (!test.EqualsASCII("hardware")) {
#ifdef MOZ_WIDGET_GONK
#if ANDROID_VERSION >= 18
camera = Camera::connect(aCameraId, /* clientPackageName */String16("gonk.camera"), Camera::USE_CALLING_UID);
#else
camera = Camera::connect(aCameraId);
#endif
#endif
if (camera.get() == nullptr) {
return nullptr;
}
}
sp<GonkCameraHardware> cameraHardware;
if (test.EqualsASCII("hardware")) {
NS_WARNING("Using test Gonk hardware layer");
cameraHardware = new TestGonkCameraHardware(aTarget, aCameraId, camera);
} else {
cameraHardware = new GonkCameraHardware(aTarget, aCameraId, camera);
}
nsresult rv = cameraHardware->Init();
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGE("Failed to initialize camera hardware (0x%X)\n", rv);
cameraHardware->Close();
return nullptr;
}
return cameraHardware;
}
void
GonkCameraHardware::Close()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this);
mClosing = true;
if (mCamera.get()) {
mCamera->stopPreview();
mCamera->disconnect();
}
mCamera.clear();
#ifdef MOZ_WIDGET_GONK
if (mNativeWindow.get()) {
mNativeWindow->abandon();
}
mNativeWindow.clear();
// Ensure that ICamera's destructor is actually executed
IPCThreadState::self()->flushCommands();
#endif
}
GonkCameraHardware::~GonkCameraHardware()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this);
mCamera.clear();
#ifdef MOZ_WIDGET_GONK
mNativeWindow.clear();
#endif
}
int
GonkCameraHardware::GetSensorOrientation(uint32_t aType)
{
DOM_CAMERA_LOGI("%s\n", __func__);
switch (aType) {
case OFFSET_SENSOR_ORIENTATION:
return mSensorOrientation;
case RAW_SENSOR_ORIENTATION:
return mRawSensorOrientation;
default:
DOM_CAMERA_LOGE("%s:%d : unknown aType=%d\n", __func__, __LINE__, aType);
return 0;
}
}
bool
GonkCameraHardware::IsEmulated()
{
return mEmulated;
}
int
GonkCameraHardware::AutoFocus()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->autoFocus();
}
int
GonkCameraHardware::CancelAutoFocus()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->cancelAutoFocus();
}
int
GonkCameraHardware::StartFaceDetection()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
int rv = INVALID_OPERATION;
#if ANDROID_VERSION >= 15
rv = mCamera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0);
#endif
if (rv != OK) {
DOM_CAMERA_LOGE("Start face detection failed with status %d", rv);
}
return rv;
}
int
GonkCameraHardware::StopFaceDetection()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (mClosing) {
return DEAD_OBJECT;
}
int rv = INVALID_OPERATION;
#if ANDROID_VERSION >= 15
rv = mCamera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0);
#endif
if (rv != OK) {
DOM_CAMERA_LOGE("Stop face detection failed with status %d", rv);
}
return rv;
}
int
GonkCameraHardware::TakePicture()
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->takePicture(CAMERA_MSG_SHUTTER | CAMERA_MSG_COMPRESSED_IMAGE);
}
void
GonkCameraHardware::CancelTakePicture()
{
DOM_CAMERA_LOGW("%s: android::Camera do not provide this capability\n", __func__);
}
int
GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
const String8 s = aParams.Flatten();
return mCamera->setParameters(s);
}
nsresult
GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return NS_ERROR_NOT_AVAILABLE;
}
const String8 s = mCamera->getParameters();
return aParams.Unflatten(s);
}
#ifdef MOZ_WIDGET_GONK
int
GonkCameraHardware::PushParameters(const CameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
String8 s = aParams.flatten();
return mCamera->setParameters(s);
}
void
GonkCameraHardware::PullParameters(CameraParameters& aParams)
{
if (!NS_WARN_IF(mClosing)) {
const String8 s = mCamera->getParameters();
aParams.unflatten(s);
}
}
#endif
int
GonkCameraHardware::StartPreview()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->startPreview();
}
void
GonkCameraHardware::StopPreview()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (!mClosing) {
mCamera->stopPreview();
}
}
int
GonkCameraHardware::StartRecording()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
int rv = mCamera->startRecording();
if (rv != OK) {
DOM_CAMERA_LOGE("mHardware->startRecording() failed with status %d", rv);
}
return rv;
}
int
GonkCameraHardware::StopRecording()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (mClosing) {
return DEAD_OBJECT;
}
mCamera->stopRecording();
return OK;
}
#ifdef MOZ_WIDGET_GONK
int
GonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener)
{
mListener = aListener;
return OK;
}
void
GonkCameraHardware::ReleaseRecordingFrame(const sp<IMemory>& aFrame)
{
if (!NS_WARN_IF(mClosing)) {
mCamera->releaseRecordingFrame(aFrame);
}
}
#endif
int
GonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->storeMetaDataInBuffers(aEnabled);
}

Просмотреть файл

@ -1,154 +0,0 @@
/*
* Copyright (C) 2012-2014 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.
*/
#ifndef DOM_CAMERA_GONKCAMERAHWMGR_H
#define DOM_CAMERA_GONKCAMERAHWMGR_H
#include "GonkCameraControl.h"
#include "CameraCommon.h"
#include "GonkCameraParameters.h"
#include "mozilla/ReentrantMonitor.h"
#ifdef MOZ_WIDGET_GONK
#include <binder/IMemory.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
#include <utils/threads.h>
#include "GonkCameraListener.h"
#include "GonkNativeWindow.h"
#else
#include "FallbackCameraPlatform.h"
#endif
namespace mozilla {
class nsGonkCameraControl;
class GonkCameraParameters;
}
namespace android {
class GonkCameraHardware
#ifdef MOZ_WIDGET_GONK
: public GonkNativeWindowNewFrameCallback
, public CameraListener
#else
: public nsISupports
#endif
{
#ifndef MOZ_WIDGET_GONK
NS_DECL_ISUPPORTS
#endif
protected:
GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera);
virtual ~GonkCameraHardware();
// Initialize the AOSP camera interface.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_NOT_INITIALIZED if the interface could not be initialized.
virtual nsresult Init();
public:
static sp<GonkCameraHardware> Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId);
virtual void Close();
virtual void OnRateLimitPreview(bool aLimit);
#ifdef MOZ_WIDGET_GONK
// derived from GonkNativeWindowNewFrameCallback
virtual void OnNewFrame() override;
// derived from CameraListener
virtual void notify(int32_t aMsgType, int32_t ext1, int32_t ext2);
virtual void postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, camera_frame_metadata_t* metadata);
virtual void postDataTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory>& aDataPtr);
#endif
/**
* The physical orientation of the camera sensor: 0, 90, 180, or 270.
*
* For example, suppose a device has a naturally tall screen. The
* back-facing camera sensor is mounted in landscape. You are looking at
* the screen. If the top side of the camera sensor is aligned with the
* right edge of the screen in natural orientation, the value should be
* 90. If the top side of a front-facing camera sensor is aligned with the
* right of the screen, the value should be 270.
*
* RAW_SENSOR_ORIENTATION is the uncorrected orientation returned directly
* by get_camera_info(); OFFSET_SENSOR_ORIENTATION is the offset adjusted
* orientation.
*/
enum {
RAW_SENSOR_ORIENTATION,
OFFSET_SENSOR_ORIENTATION
};
virtual int GetSensorOrientation(uint32_t aType = RAW_SENSOR_ORIENTATION);
virtual bool IsEmulated();
/**
* MIN_UNDEQUEUED_BUFFERS has increased to 4 since Android JB. For FFOS, more
* than 3 gralloc buffers are necessary between ImageHost and GonkBufferQueue
* for consuming preview stream. To keep the stability for older platform, we
* set MIN_UNDEQUEUED_BUFFERS to 4 only in Android KK base.
* See also bug 988704.
*/
enum { MIN_UNDEQUEUED_BUFFERS = 4};
virtual int AutoFocus();
virtual int CancelAutoFocus();
virtual int StartFaceDetection();
virtual int StopFaceDetection();
virtual int TakePicture();
virtual void CancelTakePicture();
virtual int StartPreview();
virtual void StopPreview();
virtual int PushParameters(const mozilla::GonkCameraParameters& aParams);
virtual nsresult PullParameters(mozilla::GonkCameraParameters& aParams);
#ifdef MOZ_WIDGET_GONK
virtual int PushParameters(const CameraParameters& aParams);
virtual void PullParameters(CameraParameters& aParams);
virtual int SetListener(const sp<GonkCameraListener>& aListener);
virtual void ReleaseRecordingFrame(const sp<IMemory>& aFrame);
#endif
virtual int StartRecording();
virtual int StopRecording();
virtual int StoreMetaDataInBuffers(bool aEnabled);
protected:
uint32_t mCameraId;
bool mClosing;
uint32_t mNumFrames;
sp<Camera> mCamera;
mozilla::nsGonkCameraControl* mTarget;
#ifdef MOZ_WIDGET_GONK
sp<GonkNativeWindow> mNativeWindow;
sp<GonkCameraListener> mListener;
#endif
int mRawSensorOrientation;
int mSensorOrientation;
bool mEmulated;
private:
GonkCameraHardware(const GonkCameraHardware&) = delete;
GonkCameraHardware& operator=(const GonkCameraHardware&) = delete;
};
} // namespace android
#endif // GONK_IMPL_HW_MGR_H

Просмотреть файл

@ -1,37 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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.
*/
#ifndef GONK_CAMERA_LISTENER_H
#define GONK_CAMERA_LISTENER_H
#include <utils/Timers.h>
#include <camera/Camera.h>
namespace android {
// ref-counted object for callbacks
class GonkCameraListener: virtual public RefBase
{
public:
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
virtual bool postData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata) = 0;
virtual bool postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
};
}; // namespace android
#endif

Просмотреть файл

@ -1,137 +0,0 @@
/*
* Copyright (C) 2012-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ICameraControl.h"
#include "CameraCommon.h"
#include "GonkCameraControl.h"
#include "CameraPreferences.h"
#include "TestGonkCameraControl.h"
#ifdef MOZ_WIDGET_GONK
#include <camera/Camera.h>
#else
#include "FallbackCameraPlatform.h"
#endif
using namespace mozilla;
// From ICameraControl, gonk-specific management functions
nsresult
ICameraControl::GetNumberOfCameras(int32_t& aDeviceCount)
{
aDeviceCount = android::Camera::getNumberOfCameras();
return NS_OK;
}
nsresult
ICameraControl::GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName)
{
int32_t count = android::Camera::getNumberOfCameras();
int32_t deviceNum = static_cast<int32_t>(aDeviceNum);
DOM_CAMERA_LOGI("GetCameraName : getNumberOfCameras() returned %d\n", count);
if (deviceNum < 0 || deviceNum > count) {
DOM_CAMERA_LOGE("GetCameraName : invalid device number (%u)\n", aDeviceNum);
return NS_ERROR_INVALID_ARG;
}
android::CameraInfo info;
int rv = android::Camera::getCameraInfo(deviceNum, &info);
if (rv != 0) {
DOM_CAMERA_LOGE("GetCameraName : get_camera_info(%d) failed: %d\n", deviceNum, rv);
return NS_ERROR_NOT_AVAILABLE;
}
switch (info.facing) {
case CAMERA_FACING_BACK:
aDeviceName.AssignLiteral("back");
break;
case CAMERA_FACING_FRONT:
aDeviceName.AssignLiteral("front");
break;
default:
aDeviceName.AssignLiteral("extra-camera-");
aDeviceName.AppendInt(deviceNum);
break;
}
return NS_OK;
}
nsresult
ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
{
int32_t count = android::Camera::getNumberOfCameras();
DOM_CAMERA_LOGI("getListOfCameras : getNumberOfCameras() returned %d\n", count);
if (count <= 0) {
aList.Clear();
return NS_OK;
}
// Allocate 2 extra slots to reserve space for 'front' and 'back' cameras
// at the front of the array--we will collapse any empty slots below.
aList.SetLength(2);
uint32_t extraIdx = 2;
bool gotFront = false;
bool gotBack = false;
while (count--) {
nsCString cameraName;
nsresult result = GetCameraName(count, cameraName);
if (result != NS_OK) {
continue;
}
// The first camera we find named 'back' gets slot 0; and the first
// we find named 'front' gets slot 1. All others appear after these.
if (cameraName.EqualsLiteral("back")) {
CopyUTF8toUTF16(cameraName, aList[0]);
gotBack = true;
} else if (cameraName.EqualsLiteral("front")) {
CopyUTF8toUTF16(cameraName, aList[1]);
gotFront = true;
} else {
CopyUTF8toUTF16(cameraName, *aList.InsertElementAt(extraIdx));
extraIdx++;
}
}
if (!gotFront) {
aList.RemoveElementAt(1);
}
if (!gotBack) {
aList.RemoveElementAt(0);
}
return NS_OK;
}
// implementation-specific camera factory
already_AddRefed<ICameraControl>
ICameraControl::Create(uint32_t aCameraId)
{
nsCString test;
CameraPreferences::GetPref("camera.control.test.enabled", test);
RefPtr<nsGonkCameraControl> control;
if (test.EqualsASCII("control")) {
NS_WARNING("Using test CameraControl layer");
control = new TestGonkCameraControl(aCameraId);
} else {
control = new nsGonkCameraControl(aCameraId);
}
return control.forget();
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,301 +0,0 @@
/*
* Copyright (C) 2013-2015 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.
*/
#ifndef DOM_CAMERA_GONKCAMERAPARAMETERS_H
#define DOM_CAMERA_GONKCAMERAPARAMETERS_H
#include <math.h>
#include "nsTArray.h"
#include "nsString.h"
#include "mozilla/Mutex.h"
#include "nsClassHashtable.h"
#include "ICameraControl.h"
#ifdef MOZ_WIDGET_GONK
#include <camera/CameraParameters.h>
#else
#include "FallbackCameraPlatform.h"
#endif
namespace mozilla {
class GonkCameraParameters
{
public:
GonkCameraParameters();
virtual ~GonkCameraParameters();
// IMPORTANT: This class is read and written by multiple threads --
// ALL public methods must hold mLock, for either reading or writing,
// for the life of their operation. Not doing so was the cause of
// bug 928856, which was -painful- to track down.
//
// Return values:
// - see return values for GetTranslated() and SetTranslated() below.
template<class T> nsresult
Set(uint32_t aKey, const T& aValue)
{
MutexAutoLock lock(mLock);
nsresult rv = SetTranslated(aKey, aValue);
mDirty = mDirty || NS_SUCCEEDED(rv);
return rv;
}
template<class T> nsresult
Get(uint32_t aKey, T& aValue)
{
MutexAutoLock lock(mLock);
return GetTranslated(aKey, aValue);
}
bool
TestAndClearDirtyFlag()
{
bool dirty;
MutexAutoLock lock(mLock);
dirty = mDirty;
mDirty = false;
return dirty;
}
android::String8 Flatten() const;
nsresult Unflatten(const android::String8& aFlatParameters);
protected:
mutable Mutex mLock;
bool mDirty;
bool mInitialized;
// Required internal properties
double mExposureCompensationStep;
int32_t mExposureCompensationMinIndex;
int32_t mExposureCompensationMaxIndex;
const char* mVendorSpecificKeyIsoMode;
const char* mVendorSpecificKeySupportedIsoModes;
nsTArray<int> mZoomRatios;
nsTArray<nsString> mIsoModes;
nsTArray<nsString> mSceneModes;
nsTArray<nsString> mMeteringModes;
nsClassHashtable<nsStringHashKey, nsCString> mIsoModeMap;
nsClassHashtable<nsCStringHashKey, nsCString> mParams;
nsresult SetImpl(const char* aKey, const char* aValue)
{
if (!aValue || strchr(aValue, ';') || strchr(aValue, '=')) {
return NS_ERROR_ILLEGAL_VALUE;
}
nsDependentCString key(aKey);
mParams.Put(key, new nsCString(aValue));
return NS_OK;
}
nsresult SetImpl(const char* aKey, int aValue)
{
nsDependentCString key(aKey);
nsCString* value = new nsCString();
value->AppendInt(aValue);
mParams.Put(key, value);
return NS_OK;
}
nsresult SetImpl(const char* aKey, double aValue)
{
nsDependentCString key(aKey);
nsCString* value = new nsCString();
value->AppendFloat(aValue);
mParams.Put(key, value);
return NS_OK;
}
nsresult SetImpl(const char* aKey, float aValue)
{
nsDependentCString key(aKey);
nsCString* value = new nsCString();
value->AppendFloat(aValue);
mParams.Put(key, value);
return NS_OK;
}
nsresult SetImpl(const char* aKey, bool aValue)
{
nsDependentCString key(aKey);
mParams.Put(key, new nsCString(aValue ? "true" : "false"));
return NS_OK;
}
nsresult GetImpl(const char* aKey, const char*& aRet)
{
nsDependentCString key(aKey);
nsCString* value;
if (!mParams.Get(key, &value)) {
aRet = nullptr;
return NS_ERROR_FAILURE;
}
aRet = value->Data();
return NS_OK;
}
nsresult GetImpl(const char* aKey, float& aRet)
{
nsDependentCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
aRet = value->ToFloat(&rv);
} else {
aRet = 0.0;
}
return rv;
}
nsresult GetImpl(const char* aKey, double& aRet)
{
nsDependentCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
aRet = value->ToFloat(&rv);
} else {
aRet = 0.0;
}
return rv;
}
nsresult GetImpl(const char* aKey, int& aRet)
{
nsDependentCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
aRet = value->ToInteger(&rv);
} else {
aRet = 0.0;
}
return rv;
}
nsresult GetImpl(const char* aKey, bool& aRet)
{
nsDependentCString key(aKey);
nsCString* value;
if (!mParams.Get(key, &value)) {
aRet = false;
return NS_ERROR_FAILURE;
}
aRet = value->EqualsLiteral("true");
return NS_OK;
}
const char* GetTextKey(uint32_t aKey);
const char* FindVendorSpecificKey(const char* aPotentialKeys[], size_t aPotentialKeyCount);
// The *Impl() templates handle converting the parameter keys from
// their enum values to string types, if necessary. These are the
// bottom layer accessors to mParams.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_NOT_IMPLEMENTED if the numeric 'aKey' value is invalid.
template<typename T> nsresult
SetImpl(uint32_t aKey, const T& aValue)
{
const char* key = GetTextKey(aKey);
NS_ENSURE_TRUE(key, NS_ERROR_NOT_IMPLEMENTED);
return SetImpl(key, aValue);
}
template<typename T> nsresult
GetImpl(uint32_t aKey, T& aValue)
{
const char* key = GetTextKey(aKey);
NS_ENSURE_TRUE(key, NS_ERROR_NOT_IMPLEMENTED);
return GetImpl(key, aValue);
}
nsresult
ClearImpl(const char* aKey)
{
nsDependentCString key(aKey);
mParams.Remove(key);
return NS_OK;
}
// The *Translated() functions allow us to handle special cases;
// for example, where the thumbnail size setting is exposed as an
// ICameraControl::Size object, but is handled by the AOSP layer
// as two separate parameters.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_INVALID_ARG if 'aValue' contains an invalid value;
// - NS_ERROR_NOT_IMPLEMENTED if 'aKey' is invalid;
// - NS_ERROR_NOT_AVAILABLE if the getter fails to retrieve a valid value,
// or if a setter fails because it requires one or more values that
// could not be retrieved;
// - NS_ERROR_FAILURE on unexpected internal failures.
nsresult SetTranslated(uint32_t aKey, const nsAString& aValue);
nsresult GetTranslated(uint32_t aKey, nsAString& aValue);
nsresult SetTranslated(uint32_t aKey, const ICameraControl::Size& aSize);
nsresult GetTranslated(uint32_t aKey, ICameraControl::Size& aSize);
nsresult GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Size>& aSizes);
nsresult SetTranslated(uint32_t aKey, const nsTArray<ICameraControl::Region>& aRegions);
nsresult GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Region>& aRegions);
nsresult SetTranslated(uint32_t aKey, const ICameraControl::Position& aPosition);
nsresult SetTranslated(uint32_t aKey, const int64_t& aValue);
nsresult GetTranslated(uint32_t aKey, int64_t& aValue);
nsresult SetTranslated(uint32_t aKey, const double& aValue);
nsresult GetTranslated(uint32_t aKey, double& aValue);
nsresult SetTranslated(uint32_t aKey, const int& aValue);
nsresult GetTranslated(uint32_t aKey, int& aValue);
nsresult SetTranslated(uint32_t aKey, const uint32_t& aValue);
nsresult GetTranslated(uint32_t aKey, uint32_t& aValue);
nsresult SetTranslated(uint32_t aKey, const bool& aValue);
nsresult GetTranslated(uint32_t aKey, bool& aValue);
nsresult GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues);
nsresult GetTranslated(uint32_t aKey, nsTArray<double>& aValues);
// Converts a string of multiple, comma-separated values into an array
// of the appropriate type.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_NOT_IMPLEMENTED if 'aKey' is invalid;
// - NS_ERROR_NOT_AVAILABLE if a valid value could not be returned.
template<class T> nsresult GetListAsArray(uint32_t aKey, nsTArray<T>& aArray);
// Converts ISO values (e.g., "auto", "hjr", "100", "200", etc.) to and from
// values understood by Gonk (e.g., "auto", "ISO_HJR", "ISO100", "ISO200",
// respectively).
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_INVALID_ARG if the 'aIso' argument is not a valid form.
nsresult MapIsoToGonk(const nsAString& aIso, nsACString& aIsoOut);
nsresult MapIsoFromGonk(const char* aIso, nsAString& aIsoOut);
// Call once to initialize local cached values used in translating other
// arguments between Gecko and Gonk. Always returns NS_OK.
nsresult Initialize();
// Returns true if we're a memory-constrained platform that requires
// certain features to be disabled; returns false otherwise.
static bool IsLowMemoryPlatform();
};
} // namespace mozilla
#endif // DOM_CAMERA_GONKCAMERAPARAMETERS_H

Просмотреть файл

@ -1,803 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
* Copyright (C) 2013 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <base/basictypes.h>
#include "nsDebug.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
/*
#define CS_LOGD(...) DOM_CAMERA_LOGA(__VA_ARGS__)
#define CS_LOGV(...) DOM_CAMERA_LOGI(__VA_ARGS__)
#define CS_LOGI(...) DOM_CAMERA_LOGI(__VA_ARGS__)
#define CS_LOGW(...) DOM_CAMERA_LOGW(__VA_ARGS__)
#define CS_LOGE(...) DOM_CAMERA_LOGE(__VA_ARGS__)
*/
#define CS_LOGD(fmt, ...) DOM_CAMERA_LOGA("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGV(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGI(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGW(fmt, ...) DOM_CAMERA_LOGW("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGE(fmt, ...) DOM_CAMERA_LOGE("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#include <OMX_Component.h>
#include <binder/IPCThreadState.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <camera/CameraParameters.h>
#include <utils/String8.h>
#include <cutils/properties.h>
#include "GonkCameraSource.h"
#include "GonkCameraListener.h"
#include "GonkCameraHwMgr.h"
#include "ICameraControl.h"
using namespace mozilla;
namespace android {
static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
struct GonkCameraSourceListener : public GonkCameraListener {
GonkCameraSourceListener(const sp<GonkCameraSource> &source);
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
virtual bool postData(int32_t msgType, const sp<IMemory> &dataPtr,
camera_frame_metadata_t *metadata);
virtual bool postDataTimestamp(
nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
protected:
virtual ~GonkCameraSourceListener();
private:
wp<GonkCameraSource> mSource;
GonkCameraSourceListener(const GonkCameraSourceListener &);
GonkCameraSourceListener &operator=(const GonkCameraSourceListener &);
};
GonkCameraSourceListener::GonkCameraSourceListener(const sp<GonkCameraSource> &source)
: mSource(source) {
}
GonkCameraSourceListener::~GonkCameraSourceListener() {
}
void GonkCameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
CS_LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
}
bool GonkCameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
camera_frame_metadata_t *metadata) {
CS_LOGV("postData(%d, ptr:%p, size:%d)",
msgType, dataPtr->pointer(), dataPtr->size());
sp<GonkCameraSource> source = mSource.promote();
if (source.get() != NULL) {
source->dataCallback(msgType, dataPtr);
return true;
}
return false;
}
bool GonkCameraSourceListener::postDataTimestamp(
nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
sp<GonkCameraSource> source = mSource.promote();
if (source.get() != NULL) {
source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
return true;
}
return false;
}
static int32_t getColorFormat(const char* colorFormat) {
return OMX_COLOR_FormatYUV420SemiPlanar; //XXX nsGonkCameraControl uses only YUV420SemiPlanar
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
return OMX_COLOR_FormatYUV420Planar;
}
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) {
return OMX_COLOR_FormatYUV422SemiPlanar;
}
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
return OMX_COLOR_FormatYUV420SemiPlanar;
}
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
return OMX_COLOR_FormatYCbYCr;
}
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
return OMX_COLOR_Format16bitRGB565;
}
if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE)) {
return OMX_COLOR_FormatAndroidOpaque;
}
#endif
CS_LOGE("Uknown color format (%s), please add it to "
"GonkCameraSource::getColorFormat", colorFormat);
CHECK(!"Unknown color format");
}
GonkCameraSource *GonkCameraSource::Create(
const sp<GonkCameraHardware>& aCameraHw,
Size videoSize,
int32_t frameRate,
bool storeMetaDataInVideoBuffers) {
GonkCameraSource *source = new GonkCameraSource(aCameraHw,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
return source;
}
GonkCameraSource *GonkCameraSource::Create(
ICameraControl* aControl,
Size videoSize,
int32_t frameRate)
{
mozilla::nsGonkCameraControl* control =
static_cast<mozilla::nsGonkCameraControl*>(aControl);
return Create(control->GetCameraHw(), videoSize, frameRate, false);
}
GonkCameraSource::GonkCameraSource(
const sp<GonkCameraHardware>& aCameraHw,
Size videoSize,
int32_t frameRate,
bool storeMetaDataInVideoBuffers)
: mCameraFlags(0),
mNumInputBuffers(0),
mVideoFrameRate(-1),
mNumFramesReceived(0),
mLastFrameTimestampUs(0),
mStarted(false),
mNumFramesEncoded(0),
mTimeBetweenFrameCaptureUs(0),
mRateLimit(false),
mFirstFrameTimeUs(0),
mNumFramesDropped(0),
mNumGlitches(0),
mGlitchDurationThresholdUs(200000),
mCollectStats(false),
mCameraHw(aCameraHw) {
mVideoSize.width = -1;
mVideoSize.height = -1;
mInitCheck = init(
videoSize, frameRate,
storeMetaDataInVideoBuffers);
if (mInitCheck != OK) releaseCamera();
}
status_t GonkCameraSource::initCheck() const {
return mInitCheck;
}
//TODO: Do we need to reimplement isCameraAvailable?
/*
* Check to see whether the requested video width and height is one
* of the supported sizes.
* @param width the video frame width in pixels
* @param height the video frame height in pixels
* @param suppportedSizes the vector of sizes that we check against
* @return true if the dimension (width and height) is supported.
*/
static bool isVideoSizeSupported(
int32_t width, int32_t height,
const Vector<Size>& supportedSizes) {
CS_LOGV("isVideoSizeSupported");
for (size_t i = 0; i < supportedSizes.size(); ++i) {
if (width == supportedSizes[i].width &&
height == supportedSizes[i].height) {
return true;
}
}
return false;
}
/*
* If the preview and video output is separate, we only set the
* the video size, and applications should set the preview size
* to some proper value, and the recording framework will not
* change the preview size; otherwise, if the video and preview
* output is the same, we need to set the preview to be the same
* as the requested video size.
*
*/
/*
* Query the camera to retrieve the supported video frame sizes
* and also to see whether CameraParameters::setVideoSize()
* is supported or not.
* @param params CameraParameters to retrieve the information
* @@param isSetVideoSizeSupported retunrs whether method
* CameraParameters::setVideoSize() is supported or not.
* @param sizes returns the vector of Size objects for the
* supported video frame sizes advertised by the camera.
*/
static void getSupportedVideoSizes(
const CameraParameters& params,
bool *isSetVideoSizeSupported,
Vector<Size>& sizes) {
*isSetVideoSizeSupported = true;
params.getSupportedVideoSizes(sizes);
if (sizes.size() == 0) {
CS_LOGD("Camera does not support setVideoSize()");
params.getSupportedPreviewSizes(sizes);
*isSetVideoSizeSupported = false;
}
}
/*
* Check whether the camera has the supported color format
* @param params CameraParameters to retrieve the information
* @return OK if no error.
*/
status_t GonkCameraSource::isCameraColorFormatSupported(
const CameraParameters& params) {
mColorFormat = getColorFormat(params.get(
CameraParameters::KEY_VIDEO_FRAME_FORMAT));
if (mColorFormat == -1) {
return BAD_VALUE;
}
return OK;
}
/*
* Configure the camera to use the requested video size
* (width and height) and/or frame rate. If both width and
* height are -1, configuration on the video size is skipped.
* if frameRate is -1, configuration on the frame rate
* is skipped. Skipping the configuration allows one to
* use the current camera setting without the need to
* actually know the specific values (see Create() method).
*
* @param params the CameraParameters to be configured
* @param width the target video frame width in pixels
* @param height the target video frame height in pixels
* @param frameRate the target frame rate in frames per second.
* @return OK if no error.
*/
status_t GonkCameraSource::configureCamera(
CameraParameters* params,
int32_t width, int32_t height,
int32_t frameRate) {
CS_LOGV("configureCamera");
Vector<Size> sizes;
bool isSetVideoSizeSupportedByCamera = true;
getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
bool isCameraParamChanged = false;
if (width != -1 && height != -1) {
if (!isVideoSizeSupported(width, height, sizes)) {
CS_LOGE("Video dimension (%dx%d) is unsupported", width, height);
return BAD_VALUE;
}
if (isSetVideoSizeSupportedByCamera) {
params->setVideoSize(width, height);
} else {
params->setPreviewSize(width, height);
}
isCameraParamChanged = true;
} else if ((width == -1 && height != -1) ||
(width != -1 && height == -1)) {
// If one and only one of the width and height is -1
// we reject such a request.
CS_LOGE("Requested video size (%dx%d) is not supported", width, height);
return BAD_VALUE;
} else { // width == -1 && height == -1
// Do not configure the camera.
// Use the current width and height value setting from the camera.
}
if (frameRate != -1) {
CHECK(frameRate > 0 && frameRate <= 120);
const char* supportedFrameRates =
params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
CHECK(supportedFrameRates != NULL);
CS_LOGV("Supported frame rates: %s", supportedFrameRates);
char buf[4];
snprintf(buf, 4, "%d", frameRate);
if (strstr(supportedFrameRates, buf) == NULL) {
CS_LOGE("Requested frame rate (%d) is not supported: %s",
frameRate, supportedFrameRates);
return BAD_VALUE;
}
// The frame rate is supported, set the camera to the requested value.
params->setPreviewFrameRate(frameRate);
isCameraParamChanged = true;
} else { // frameRate == -1
// Do not configure the camera.
// Use the current frame rate value setting from the camera
}
if (isCameraParamChanged) {
// Either frame rate or frame size needs to be changed.
if (OK != mCameraHw->PushParameters(*params)) {
CS_LOGE("Could not change settings."
" Someone else is using camera?");
return -EBUSY;
}
}
return OK;
}
/*
* Check whether the requested video frame size
* has been successfully configured or not. If both width and height
* are -1, check on the current width and height value setting
* is performed.
*
* @param params CameraParameters to retrieve the information
* @param the target video frame width in pixels to check against
* @param the target video frame height in pixels to check against
* @return OK if no error
*/
status_t GonkCameraSource::checkVideoSize(
const CameraParameters& params,
int32_t width, int32_t height) {
CS_LOGV("checkVideoSize");
// The actual video size is the same as the preview size
// if the camera hal does not support separate video and
// preview output. In this case, we retrieve the video
// size from preview.
int32_t frameWidthActual = -1;
int32_t frameHeightActual = -1;
Vector<Size> sizes;
params.getSupportedVideoSizes(sizes);
if (sizes.size() == 0) {
// video size is the same as preview size
params.getPreviewSize(&frameWidthActual, &frameHeightActual);
} else {
// video size may not be the same as preview
params.getVideoSize(&frameWidthActual, &frameHeightActual);
}
if (frameWidthActual < 0 || frameHeightActual < 0) {
CS_LOGE("Failed to retrieve video frame size (%dx%d)",
frameWidthActual, frameHeightActual);
return UNKNOWN_ERROR;
}
// Check the actual video frame size against the target/requested
// video frame size.
if (width != -1 && height != -1) {
if (frameWidthActual != width || frameHeightActual != height) {
CS_LOGE("Failed to set video frame size to %dx%d. "
"The actual video size is %dx%d ", width, height,
frameWidthActual, frameHeightActual);
return UNKNOWN_ERROR;
}
}
// Good now.
mVideoSize.width = frameWidthActual;
mVideoSize.height = frameHeightActual;
return OK;
}
/*
* Check the requested frame rate has been successfully configured or not.
* If the target frameRate is -1, check on the current frame rate value
* setting is performed.
*
* @param params CameraParameters to retrieve the information
* @param the target video frame rate to check against
* @return OK if no error.
*/
status_t GonkCameraSource::checkFrameRate(
const CameraParameters& params,
int32_t frameRate) {
CS_LOGV("checkFrameRate");
int32_t frameRateActual = params.getPreviewFrameRate();
if (frameRateActual < 0) {
CS_LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
return UNKNOWN_ERROR;
}
// Check the actual video frame rate against the target/requested
// video frame rate.
if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
CS_LOGE("Failed to set preview frame rate to %d fps. The actual "
"frame rate is %d", frameRate, frameRateActual);
return UNKNOWN_ERROR;
}
// Good now.
mVideoFrameRate = frameRateActual;
return OK;
}
/*
* Initialize the GonkCameraSource so that it becomes
* ready for providing the video input streams as requested.
* @param camera the camera object used for the video source
* @param cameraId if camera == 0, use camera with this id
* as the video source
* @param videoSize the target video frame size. If both
* width and height in videoSize is -1, use the current
* width and heigth settings by the camera
* @param frameRate the target frame rate in frames per second.
* if it is -1, use the current camera frame rate setting.
* @param storeMetaDataInVideoBuffers request to store meta
* data or real YUV data in video buffers. Request to
* store meta data in video buffers may not be honored
* if the source does not support this feature.
*
* @return OK if no error.
*/
status_t GonkCameraSource::init(
Size videoSize,
int32_t frameRate,
bool storeMetaDataInVideoBuffers) {
CS_LOGV("init");
status_t err = OK;
//TODO: need to do something here to check the sanity of camera
CameraParameters params;
mCameraHw->PullParameters(params);
if ((err = isCameraColorFormatSupported(params)) != OK) {
return err;
}
// Set the camera to use the requested video frame size
// and/or frame rate.
if ((err = configureCamera(&params,
videoSize.width, videoSize.height,
frameRate))) {
return err;
}
// Check on video frame size and frame rate.
CameraParameters newCameraParams;
mCameraHw->PullParameters(newCameraParams);
if ((err = checkVideoSize(newCameraParams,
videoSize.width, videoSize.height)) != OK) {
return err;
}
if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) {
return err;
}
// By default, do not store metadata in video buffers
mIsMetaDataStoredInVideoBuffers = false;
mCameraHw->StoreMetaDataInBuffers(false);
if (storeMetaDataInVideoBuffers) {
if (OK == mCameraHw->StoreMetaDataInBuffers(true)) {
mIsMetaDataStoredInVideoBuffers = true;
}
}
int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
if (glitchDurationUs > mGlitchDurationThresholdUs) {
mGlitchDurationThresholdUs = glitchDurationUs;
}
// XXX: query camera for the stride and slice height
// when the capability becomes available.
mMeta = new MetaData;
mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
mMeta->setInt32(kKeyColorFormat, mColorFormat);
mMeta->setInt32(kKeyWidth, mVideoSize.width);
mMeta->setInt32(kKeyHeight, mVideoSize.height);
mMeta->setInt32(kKeyStride, mVideoSize.width);
mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
return OK;
}
GonkCameraSource::~GonkCameraSource() {
if (mStarted) {
reset();
} else if (mInitCheck == OK) {
// Camera is initialized but because start() is never called,
// the lock on Camera is never released(). This makes sure
// Camera's lock is released in this case.
// TODO: Don't think I need to do this
releaseCamera();
}
}
int GonkCameraSource::startCameraRecording() {
CS_LOGV("startCameraRecording");
return mCameraHw->StartRecording();
}
status_t GonkCameraSource::start(MetaData *meta) {
int rv;
CS_LOGV("start");
CHECK(!mStarted);
if (mInitCheck != OK) {
CS_LOGE("GonkCameraSource is not initialized yet");
return mInitCheck;
}
char value[PROPERTY_VALUE_MAX];
if (property_get("media.stagefright.record-stats", value, NULL)
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
mCollectStats = true;
}
mStartTimeUs = 0;
mNumInputBuffers = 0;
if (meta) {
int64_t startTimeUs;
if (meta->findInt64(kKeyTime, &startTimeUs)) {
mStartTimeUs = startTimeUs;
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
int32_t nBuffers;
if (meta->findInt32(kKeyNumBuffers, &nBuffers)) {
CHECK_GT(nBuffers, 0);
mNumInputBuffers = nBuffers;
}
#endif
}
// Register a listener with GonkCameraHardware so that we can get callbacks
mCameraHw->SetListener(new GonkCameraSourceListener(this));
rv = startCameraRecording();
mStarted = (rv == OK);
return rv;
}
void GonkCameraSource::stopCameraRecording() {
CS_LOGV("stopCameraRecording");
mCameraHw->StopRecording();
}
void GonkCameraSource::releaseCamera() {
CS_LOGV("releaseCamera");
}
status_t GonkCameraSource::reset() {
CS_LOGD("reset: E");
Mutex::Autolock autoLock(mLock);
mStarted = false;
mFrameAvailableCondition.signal();
releaseQueuedFrames();
while (!mFramesBeingEncoded.empty()) {
if (NO_ERROR !=
mFrameCompleteCondition.waitRelative(mLock,
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
CS_LOGW("Timed out waiting for outstanding frames being encoded: %d",
mFramesBeingEncoded.size());
}
}
stopCameraRecording();
if (mRateLimit) {
mRateLimit = false;
mCameraHw->OnRateLimitPreview(false);
}
releaseCamera();
if (mDirectBufferListener.get()) {
mDirectBufferListener = nullptr;
}
if (mCollectStats) {
CS_LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
mLastFrameTimestampUs - mFirstFrameTimeUs);
}
if (mNumGlitches > 0) {
CS_LOGW("%d long delays between neighboring video frames", mNumGlitches);
}
CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
CS_LOGD("reset: X");
return OK;
}
void GonkCameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
CS_LOGV("releaseRecordingFrame");
mCameraHw->ReleaseRecordingFrame(frame);
}
void GonkCameraSource::releaseQueuedFrames() {
List<sp<IMemory> >::iterator it;
while (!mFramesReceived.empty()) {
it = mFramesReceived.begin();
releaseRecordingFrame(*it);
mFramesReceived.erase(it);
++mNumFramesDropped;
}
}
sp<MetaData> GonkCameraSource::getFormat() {
return mMeta;
}
void GonkCameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
releaseRecordingFrame(frame);
}
void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) {
CS_LOGV("signalBufferReturned: %p", buffer->data());
Mutex::Autolock autoLock(mLock);
for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
it != mFramesBeingEncoded.end(); ++it) {
if ((*it)->pointer() == buffer->data()) {
releaseOneRecordingFrame((*it));
mFramesBeingEncoded.erase(it);
++mNumFramesEncoded;
buffer->setObserver(0);
buffer->release();
mFrameCompleteCondition.signal();
return;
}
}
CHECK(!"signalBufferReturned: bogus buffer");
}
status_t GonkCameraSource::AddDirectBufferListener(DirectBufferListener* aListener) {
if (mDirectBufferListener.get()) {
return UNKNOWN_ERROR;
}
mDirectBufferListener = aListener;
return OK;
}
status_t GonkCameraSource::read(
MediaBuffer **buffer, const ReadOptions *options) {
CS_LOGV("read");
*buffer = NULL;
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
return ERROR_UNSUPPORTED;
}
sp<IMemory> frame;
int64_t frameTime;
{
Mutex::Autolock autoLock(mLock);
while (mStarted && mFramesReceived.empty()) {
if (NO_ERROR !=
mFrameAvailableCondition.waitRelative(mLock,
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
//TODO: check sanity of camera?
CS_LOGW("Timed out waiting for incoming camera video frames: %lld us",
mLastFrameTimestampUs);
}
}
if (!mStarted) {
return OK;
}
frame = *mFramesReceived.begin();
mFramesReceived.erase(mFramesReceived.begin());
frameTime = *mFrameTimes.begin();
mFrameTimes.erase(mFrameTimes.begin());
mFramesBeingEncoded.push_back(frame);
*buffer = new MediaBuffer(frame->pointer(), frame->size());
(*buffer)->setObserver(this);
(*buffer)->add_ref();
(*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
}
return OK;
}
void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
int32_t msgType, const sp<IMemory> &data) {
bool rateLimit;
bool prevRateLimit;
CS_LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
{
Mutex::Autolock autoLock(mLock);
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
CS_LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
releaseOneRecordingFrame(data);
return;
}
if (mNumFramesReceived > 0) {
if (timestampUs <= mLastFrameTimestampUs) {
CS_LOGE("Drop frame at %lld us, before last at %lld us",
timestampUs, mLastFrameTimestampUs);
releaseOneRecordingFrame(data);
return;
}
if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
++mNumGlitches;
}
}
// May need to skip frame or modify timestamp. Currently implemented
// by the subclass CameraSourceTimeLapse.
if (skipCurrentFrame(timestampUs)) {
releaseOneRecordingFrame(data);
return;
}
mLastFrameTimestampUs = timestampUs;
if (mNumFramesReceived == 0) {
mFirstFrameTimeUs = timestampUs;
// Initial delay
if (mStartTimeUs > 0) {
if (timestampUs < mStartTimeUs) {
// Frame was captured before recording was started
// Drop it without updating the statistical data.
releaseOneRecordingFrame(data);
return;
}
mStartTimeUs = timestampUs - mStartTimeUs;
}
}
++mNumFramesReceived;
// If a backlog is building up in the receive queue, we are likely
// resource constrained and we need to throttle
prevRateLimit = mRateLimit;
rateLimit = mFramesReceived.empty();
mRateLimit = rateLimit;
CHECK(data != NULL && data->size() > 0);
mFramesReceived.push_back(data);
int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
mFrameTimes.push_back(timeUs);
CS_LOGV("initial delay: %lld, current time stamp: %lld",
mStartTimeUs, timeUs);
mFrameAvailableCondition.signal();
}
if(prevRateLimit != rateLimit) {
mCameraHw->OnRateLimitPreview(rateLimit);
}
if (mDirectBufferListener.get()) {
MediaBuffer* mediaBuffer;
if (read(&mediaBuffer) == OK) {
mDirectBufferListener->BufferAvailable(mediaBuffer);
// read() calls MediaBuffer->add_ref() so it needs to be released here.
mediaBuffer->release();
}
}
}
bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {
CS_LOGV("isMetaDataStoredInVideoBuffers");
return mIsMetaDataStoredInVideoBuffers;
}
} // namespace android

Просмотреть файл

@ -1,192 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* 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.
*/
#ifndef GONK_CAMERA_SOURCE_H_
#define GONK_CAMERA_SOURCE_H_
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaSource.h>
#include <camera/CameraParameters.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
#include "GonkCameraHwMgr.h"
namespace mozilla {
class ICameraControl;
}
namespace android {
class IMemory;
class GonkCameraSource : public MediaSource, public MediaBufferObserver {
public:
static GonkCameraSource *Create(const sp<GonkCameraHardware>& aCameraHw,
Size videoSize,
int32_t frameRate,
bool storeMetaDataInVideoBuffers = false);
static GonkCameraSource *Create(mozilla::ICameraControl* aControl,
Size videoSize,
int32_t frameRate);
virtual ~GonkCameraSource();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop() { return reset(); }
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL);
/**
* Check whether a GonkCameraSource object is properly initialized.
* Must call this method before stop().
* @return OK if initialization has successfully completed.
*/
virtual status_t initCheck() const;
/**
* Returns the MetaData associated with the GonkCameraSource,
* including:
* kKeyColorFormat: YUV color format of the video frames
* kKeyWidth, kKeyHeight: dimension (in pixels) of the video frames
* kKeySampleRate: frame rate in frames per second
* kKeyMIMEType: always fixed to be MEDIA_MIMETYPE_VIDEO_RAW
*/
virtual sp<MetaData> getFormat();
/**
* Tell whether this camera source stores meta data or real YUV
* frame data in video buffers.
*
* @return true if meta data is stored in the video
* buffers; false if real YUV data is stored in
* the video buffers.
*/
bool isMetaDataStoredInVideoBuffers() const;
virtual void signalBufferReturned(MediaBuffer* buffer);
/**
* It sends recording frames to listener directly in the same thread.
* Because recording frame is critical resource and it should not be
* propagated to other thread as much as possible or there could be frame
* rate jitter due to camera HAL waiting for resource.
*/
class DirectBufferListener : public RefBase {
public:
DirectBufferListener() {};
virtual status_t BufferAvailable(MediaBuffer* aBuffer) = 0;
protected:
virtual ~DirectBufferListener() {}
};
status_t AddDirectBufferListener(DirectBufferListener* aListener);
protected:
enum CameraFlags {
FLAGS_SET_CAMERA = 1L << 0,
FLAGS_HOT_CAMERA = 1L << 1,
};
int32_t mCameraFlags;
Size mVideoSize;
int32_t mNumInputBuffers;
int32_t mVideoFrameRate;
int32_t mColorFormat;
status_t mInitCheck;
sp<MetaData> mMeta;
int64_t mStartTimeUs;
int32_t mNumFramesReceived;
int64_t mLastFrameTimestampUs;
bool mStarted;
int32_t mNumFramesEncoded;
// Time between capture of two frames.
int64_t mTimeBetweenFrameCaptureUs;
GonkCameraSource(const sp<GonkCameraHardware>& aCameraHw,
Size videoSize, int32_t frameRate,
bool storeMetaDataInVideoBuffers = false);
virtual int startCameraRecording();
virtual void stopCameraRecording();
virtual void releaseRecordingFrame(const sp<IMemory>& frame);
// Returns true if need to skip the current frame.
// Called from dataCallbackTimestamp.
virtual bool skipCurrentFrame(int64_t timestampUs) {return false;}
friend class GonkCameraSourceListener;
// Callback called when still camera raw data is available.
virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {}
virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
const sp<IMemory> &data);
private:
Mutex mLock;
Condition mFrameAvailableCondition;
Condition mFrameCompleteCondition;
List<sp<IMemory> > mFramesReceived;
List<sp<IMemory> > mFramesBeingEncoded;
List<int64_t> mFrameTimes;
bool mRateLimit;
int64_t mFirstFrameTimeUs;
int32_t mNumFramesDropped;
int32_t mNumGlitches;
int64_t mGlitchDurationThresholdUs;
bool mCollectStats;
bool mIsMetaDataStoredInVideoBuffers;
sp<GonkCameraHardware> mCameraHw;
sp<DirectBufferListener> mDirectBufferListener;
void releaseQueuedFrames();
void releaseOneRecordingFrame(const sp<IMemory>& frame);
status_t init(Size videoSize, int32_t frameRate,
bool storeMetaDataInVideoBuffers);
status_t isCameraColorFormatSupported(const CameraParameters& params);
status_t configureCamera(CameraParameters* params,
int32_t width, int32_t height,
int32_t frameRate);
status_t checkVideoSize(const CameraParameters& params,
int32_t width, int32_t height);
status_t checkFrameRate(const CameraParameters& params,
int32_t frameRate);
void releaseCamera();
status_t reset();
GonkCameraSource(const GonkCameraSource &);
GonkCameraSource &operator=(const GonkCameraSource &);
};
} // namespace android
#endif // GONK_CAMERA_SOURCE_H_

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,198 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* 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.
*/
#ifndef GONK_RECORDER_H_
#define GONK_RECORDER_H_
#include "nsISupportsImpl.h"
#include "GonkCameraHwMgr.h"
#include <media/MediaRecorderBase.h>
#include <camera/CameraParameters.h>
#include <utils/String8.h>
#include <system/audio.h>
#if ANDROID_VERSION >= 21
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#endif
#include "mozilla/RefPtr.h"
#include "GonkCameraHwMgr.h"
namespace android {
class GonkCameraSource;
struct MOZ_EXPORT MediaSource;
struct MediaWriter;
class MOZ_EXPORT MetaData;
struct MOZ_EXPORT AudioSource;
class GonkCameraHardware;
struct GonkRecorder {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GonkRecorder)
GonkRecorder();
virtual status_t init();
virtual status_t setAudioSource(audio_source_t as);
virtual status_t setVideoSource(video_source vs);
virtual status_t setOutputFormat(output_format of);
virtual status_t setAudioEncoder(audio_encoder ae);
virtual status_t setVideoEncoder(video_encoder ve);
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setParameters(const String8& params);
virtual status_t setCamera(const sp<GonkCameraHardware>& aCameraHw);
virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
virtual status_t setClientName(const String16& clientName);
virtual status_t prepare();
virtual status_t start();
virtual status_t pause();
virtual status_t resume();
virtual status_t stop();
virtual status_t close();
virtual status_t reset();
virtual status_t getMaxAmplitude(int *max);
virtual status_t dump(int fd, const Vector<String16>& args) const;
// Querying a SurfaceMediaSourcer
protected:
virtual ~GonkRecorder();
private:
struct WrappedMediaSource;
sp<IMediaRecorderClient> mListener;
String16 mClientName;
uid_t mClientUid;
sp<MediaWriter> mWriter;
sp<WrappedMediaSource> mWriterSource;
int mOutputFd;
sp<AudioSource> mAudioSourceNode;
audio_source_t mAudioSource;
video_source mVideoSource;
output_format mOutputFormat;
audio_encoder mAudioEncoder;
video_encoder mVideoEncoder;
bool mUse64BitFileOffset;
int32_t mVideoWidth, mVideoHeight;
int32_t mFrameRate;
int32_t mVideoBitRate;
int32_t mAudioBitRate;
int32_t mAudioChannels;
int32_t mSampleRate;
int32_t mInterleaveDurationUs;
int32_t mIFramesIntervalSec;
int32_t mCameraId;
int32_t mVideoEncoderProfile;
int32_t mVideoEncoderLevel;
int32_t mMovieTimeScale;
int32_t mVideoTimeScale;
int32_t mAudioTimeScale;
int64_t mMaxFileSizeBytes;
int64_t mMaxFileDurationUs;
int64_t mTrackEveryTimeDurationUs;
int32_t mRotationDegrees; // Clockwise
int32_t mLatitudex10000;
int32_t mLongitudex10000;
int32_t mStartTimeOffsetMs;
String8 mParams;
bool mIsMetaDataStoredInVideoBuffers;
MediaProfiles *mEncoderProfiles;
bool mStarted;
#if ANDROID_VERSION >= 21
sp<ALooper> mLooper;
#endif
sp<GonkCameraHardware> mCameraHw;
status_t setupMPEG4Recording(
int outputFd,
int32_t videoWidth, int32_t videoHeight,
int32_t videoBitRate,
int32_t *totalBitRate,
sp<MediaWriter> *mediaWriter,
sp<WrappedMediaSource> *mediaSource);
void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
sp<MetaData> *meta);
status_t startMPEG4Recording();
status_t startAMRRecording();
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
status_t startAACRecording();
#endif
status_t startRawAudioRecording();
status_t startRTPRecording();
status_t startMPEG2TSRecording();
sp<MediaSource> createAudioSource();
status_t checkVideoEncoderCapabilities();
status_t checkAudioEncoderCapabilities();
// Generic MediaSource set-up. Returns the appropriate
// source (CameraSource or SurfaceMediaSource)
// depending on the videosource type
status_t setupMediaSource(sp<MediaSource> *mediaSource);
status_t setupCameraSource(sp<GonkCameraSource> *cameraSource);
// setup the surfacemediasource for the encoder
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
status_t setupVideoEncoder(
sp<MediaSource> cameraSource,
int32_t videoBitRate,
sp<MediaSource> *source);
// Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);
status_t setParamAudioEncodingBitRate(int32_t bitRate);
status_t setParamAudioNumberOfChannels(int32_t channles);
status_t setParamAudioSamplingRate(int32_t sampleRate);
status_t setParamAudioTimeScale(int32_t timeScale);
status_t setParamVideoEncodingBitRate(int32_t bitRate);
status_t setParamVideoIFramesInterval(int32_t seconds);
status_t setParamVideoEncoderProfile(int32_t profile);
status_t setParamVideoEncoderLevel(int32_t level);
status_t setParamVideoCameraId(int32_t cameraId);
status_t setParamVideoTimeScale(int32_t timeScale);
status_t setParamVideoRotation(int32_t degrees);
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
status_t setParamInterleaveDuration(int32_t durationUs);
status_t setParam64BitFileOffset(bool use64BitFileOffset);
status_t setParamMaxFileDurationUs(int64_t timeUs);
status_t setParamMaxFileSizeBytes(int64_t bytes);
status_t setParamMovieTimeScale(int32_t timeScale);
status_t setParamGeoDataLongitude(int64_t longitudex10000);
status_t setParamGeoDataLatitude(int64_t latitudex10000);
void clipVideoBitRate();
void clipVideoFrameRate();
void clipVideoFrameWidth();
void clipVideoFrameHeight();
void clipAudioBitRate();
void clipAudioSampleRate();
void clipNumberOfAudioChannels();
void setDefaultProfileIfNecessary();
GonkRecorder(const GonkRecorder &);
GonkRecorder &operator=(const GonkRecorder &);
};
} // namespace android
#endif // GONK_RECORDER_H_

Просмотреть файл

@ -1,425 +0,0 @@
/*
* Copyright (C) 2012-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "GonkRecorderProfiles.h"
#include "nsMimeTypes.h"
#include "CameraControlImpl.h"
#include "CameraCommon.h"
#ifdef MOZ_WIDGET_GONK
#include "GonkRecorder.h"
#endif
using namespace mozilla;
using namespace android;
namespace mozilla {
struct ProfileConfig {
const char* name;
int quality;
uint32_t priority;
};
#define DEF_GONK_RECORDER_PROFILE(e, n, p) { n, e, p },
static const ProfileConfig ProfileList[] = {
#include "GonkRecorderProfiles.def"
};
static const size_t ProfileListSize = MOZ_ARRAY_LENGTH(ProfileList);
struct ProfileConfigDetect {
const char* name;
uint32_t width;
uint32_t height;
uint32_t priority;
};
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h, p) { n, w, h, p },
static const ProfileConfigDetect ProfileListDetect[] = {
#include "GonkRecorderProfiles.def"
};
static const size_t ProfileListDetectSize = MOZ_ARRAY_LENGTH(ProfileListDetect);
};
/* static */ nsClassHashtable<nsUint32HashKey, ProfileHashtable> GonkRecorderProfile::sProfiles;
/* static */ android::MediaProfiles* sMediaProfiles = nullptr;
static MediaProfiles*
GetMediaProfiles()
{
if (!sMediaProfiles) {
sMediaProfiles = MediaProfiles::getInstance();
}
MOZ_ASSERT(sMediaProfiles);
return sMediaProfiles;
}
static bool
IsProfileSupported(uint32_t aCameraId, int aQuality)
{
MediaProfiles* profiles = GetMediaProfiles();
return profiles->hasCamcorderProfile(static_cast<int>(aCameraId),
static_cast<camcorder_quality>(aQuality));
}
static int
GetProfileParameter(uint32_t aCameraId, int aQuality, const char* aParameter)
{
MediaProfiles* profiles = GetMediaProfiles();
return profiles->getCamcorderProfileParamByName(aParameter, static_cast<int>(aCameraId),
static_cast<camcorder_quality>(aQuality));
}
/* static */ bool
GonkRecorderVideo::Translate(video_encoder aCodec, nsAString& aCodecName)
{
switch (aCodec) {
case VIDEO_ENCODER_H263:
aCodecName.AssignASCII("h263");
break;
case VIDEO_ENCODER_H264:
aCodecName.AssignASCII("h264");
break;
case VIDEO_ENCODER_MPEG_4_SP:
aCodecName.AssignASCII("mpeg4sp");
break;
default:
return false;
}
return true;
}
int
GonkRecorderVideo::GetProfileParameter(const char* aParameter)
{
return ::GetProfileParameter(mCameraId, mQuality, aParameter);
}
GonkRecorderVideo::GonkRecorderVideo(uint32_t aCameraId, int aQuality)
: mCameraId(aCameraId)
, mQuality(aQuality)
, mIsValid(false)
{
mPlatformEncoder = static_cast<video_encoder>(GetProfileParameter("vid.codec"));
bool isValid = Translate(mPlatformEncoder, mCodec);
int v = GetProfileParameter("vid.width");
if (v >= 0) {
mSize.width = v;
} else {
isValid = false;
}
v = GetProfileParameter("vid.height");
if (v >= 0) {
mSize.height = v;
} else {
isValid = false;
}
v = GetProfileParameter("vid.bps");
if (v >= 0) {
mBitsPerSecond = v;
} else {
isValid = false;
}
v = GetProfileParameter("vid.fps");
if (v >= 0) {
mFramesPerSecond = v;
} else {
isValid = false;
}
mIsValid = isValid;
}
/* static */ bool
GonkRecorderAudio::Translate(audio_encoder aCodec, nsAString& aCodecName)
{
switch (aCodec) {
case AUDIO_ENCODER_AMR_NB:
aCodecName.AssignASCII("amrnb");
break;
case AUDIO_ENCODER_AMR_WB:
aCodecName.AssignASCII("amrwb");
break;
case AUDIO_ENCODER_AAC:
aCodecName.AssignASCII("aac");
break;
default:
return false;
}
return true;
}
int
GonkRecorderAudio::GetProfileParameter(const char* aParameter)
{
return ::GetProfileParameter(mCameraId, mQuality, aParameter);
}
GonkRecorderAudio::GonkRecorderAudio(uint32_t aCameraId, int aQuality)
: mCameraId(aCameraId)
, mQuality(aQuality)
, mIsValid(false)
{
mPlatformEncoder = static_cast<audio_encoder>(GetProfileParameter("aud.codec"));
bool isValid = Translate(mPlatformEncoder, mCodec);
int v = GetProfileParameter("aud.ch");
if (v >= 0) {
mChannels = v;
} else {
isValid = false;
}
v = GetProfileParameter("aud.bps");
if (v >= 0) {
mBitsPerSecond = v;
} else {
isValid = false;
}
v = GetProfileParameter("aud.hz");
if (v >= 0) {
mSamplesPerSecond = v;
} else {
isValid = false;
}
mIsValid = isValid;
}
/* static */ bool
GonkRecorderProfile::Translate(output_format aContainer, nsAString& aContainerName)
{
switch (aContainer) {
case OUTPUT_FORMAT_THREE_GPP:
aContainerName.AssignASCII("3gp");
break;
case OUTPUT_FORMAT_MPEG_4:
aContainerName.AssignASCII("mp4");
break;
default:
return false;
}
return true;
}
/* static */ bool
GonkRecorderProfile::GetMimeType(output_format aContainer, nsAString& aMimeType)
{
switch (aContainer) {
case OUTPUT_FORMAT_THREE_GPP:
aMimeType.AssignASCII(VIDEO_3GPP);
break;
case OUTPUT_FORMAT_MPEG_4:
aMimeType.AssignASCII(VIDEO_MP4);
break;
default:
return false;
}
return true;
}
int
GonkRecorderProfile::GetProfileParameter(const char* aParameter)
{
return ::GetProfileParameter(mCameraId, mQuality, aParameter);
}
GonkRecorderProfile::GonkRecorderProfile(uint32_t aCameraId,
int aQuality)
: GonkRecorderProfileBase<GonkRecorderAudio, GonkRecorderVideo>(aCameraId,
aQuality)
, mCameraId(aCameraId)
, mQuality(aQuality)
, mIsValid(false)
{
mOutputFormat = static_cast<output_format>(GetProfileParameter("file.format"));
bool isValid = Translate(mOutputFormat, mContainer);
isValid = GetMimeType(mOutputFormat, mMimeType) ? isValid : false;
mIsValid = isValid && mAudio.IsValid() && mVideo.IsValid();
}
/* static */
already_AddRefed<GonkRecorderProfile>
GonkRecorderProfile::CreateProfile(uint32_t aCameraId, int aQuality)
{
if (!IsProfileSupported(aCameraId, aQuality)) {
DOM_CAMERA_LOGI("Profile %d not supported by platform\n", aQuality);
return nullptr;
}
RefPtr<GonkRecorderProfile> profile = new GonkRecorderProfile(aCameraId, aQuality);
if (!profile->IsValid()) {
DOM_CAMERA_LOGE("Profile %d is not valid\n", aQuality);
return nullptr;
}
return profile.forget();
}
/* static */
ProfileHashtable*
GonkRecorderProfile::GetProfileHashtable(uint32_t aCameraId)
{
ProfileHashtable* profiles = sProfiles.Get(aCameraId);
if (!profiles) {
profiles = new ProfileHashtable();
sProfiles.Put(aCameraId, profiles);
/* First handle the profiles with a known enum. We can process those
efficently because MediaProfiles indexes their profiles that way. */
int highestKnownQuality = CAMCORDER_QUALITY_LIST_START - 1;
for (size_t i = 0; i < ProfileListSize; ++i) {
const ProfileConfig& p = ProfileList[i];
if (p.quality > highestKnownQuality) {
highestKnownQuality = p.quality;
}
RefPtr<GonkRecorderProfile> profile = CreateProfile(aCameraId, p.quality);
if (!profile) {
continue;
}
DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", p.quality, p.name);
profile->mName.AssignASCII(p.name);
profile->mPriority = p.priority;
profiles->Put(profile->GetName(), profile);
}
/* However not all of the potentially supported profiles have a known
enum on all of our supported platforms because some entries may
be missing from MediaProfiles.h. As such, we can't rely upon
having the CAMCORDER_QUALITY_* enums for those profiles. We need
to map the profiles to a name by matching the width and height of
the video resolution to our configured values.
In theory there may be collisions given that there can be multiple
resolutions sharing the same name (e.g. 800x480 and 768x480 are both
wvga). In practice this should not happen because there should be
only one WVGA profile given there is only one enum for it. In the
situation there is a collision, it will merely select the last
detected profile. */
for (int q = highestKnownQuality + 1; q <= CAMCORDER_QUALITY_LIST_END; ++q) {
RefPtr<GonkRecorderProfile> profile = CreateProfile(aCameraId, q);
if (!profile) {
continue;
}
const ICameraControl::Size& s = profile->GetVideo().GetSize();
size_t match;
for (match = 0; match < ProfileListDetectSize; ++match) {
const ProfileConfigDetect& p = ProfileListDetect[match];
if (s.width == p.width && s.height == p.height) {
DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", q, p.name);
profile->mName.AssignASCII(p.name);
profile->mPriority = p.priority;
profiles->Put(profile->GetName(), profile);
break;
}
}
if (match == ProfileListDetectSize) {
DOM_CAMERA_LOGW("Profile %d size %u x %u is not recognized\n",
q, s.width, s.height);
}
}
}
return profiles;
}
/* static */ nsresult
GonkRecorderProfile::GetAll(uint32_t aCameraId,
nsTArray<RefPtr<ICameraControl::RecorderProfile>>& aProfiles)
{
ProfileHashtable* profiles = GetProfileHashtable(aCameraId);
if (!profiles) {
return NS_ERROR_FAILURE;
}
aProfiles.Clear();
for (auto iter = profiles->Iter(); !iter.Done(); iter.Next()) {
aProfiles.AppendElement(iter.UserData());
}
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
nsresult
GonkRecorderProfile::ConfigureRecorder(GonkRecorder& aRecorder)
{
static const size_t SIZE = 256;
char buffer[SIZE];
// set all the params
CHECK_SETARG(aRecorder.setAudioSource(AUDIO_SOURCE_CAMCORDER));
CHECK_SETARG(aRecorder.setVideoSource(VIDEO_SOURCE_CAMERA));
CHECK_SETARG(aRecorder.setOutputFormat(mOutputFormat));
CHECK_SETARG(aRecorder.setVideoFrameRate(mVideo.GetFramesPerSecond()));
CHECK_SETARG(aRecorder.setVideoSize(mVideo.GetSize().width, mVideo.GetSize().height));
CHECK_SETARG(aRecorder.setVideoEncoder(mVideo.GetPlatformEncoder()));
CHECK_SETARG(aRecorder.setAudioEncoder(mAudio.GetPlatformEncoder()));
snprintf(buffer, SIZE, "video-param-encoding-bitrate=%d", mVideo.GetBitsPerSecond());
CHECK_SETARG(aRecorder.setParameters(String8(buffer)));
snprintf(buffer, SIZE, "audio-param-encoding-bitrate=%d", mAudio.GetBitsPerSecond());
CHECK_SETARG(aRecorder.setParameters(String8(buffer)));
snprintf(buffer, SIZE, "audio-param-number-of-channels=%d", mAudio.GetChannels());
CHECK_SETARG(aRecorder.setParameters(String8(buffer)));
snprintf(buffer, SIZE, "audio-param-sampling-rate=%d", mAudio.GetSamplesPerSecond());
CHECK_SETARG(aRecorder.setParameters(String8(buffer)));
return NS_OK;
}
/* static */ nsresult
GonkRecorderProfile::ConfigureRecorder(android::GonkRecorder& aRecorder,
uint32_t aCameraId,
const nsAString& aProfileName)
{
ProfileHashtable* profiles = GetProfileHashtable(aCameraId);
if (!profiles) {
return NS_ERROR_FAILURE;
}
GonkRecorderProfile* profile;
if (!profiles->Get(aProfileName, &profile)) {
return NS_ERROR_INVALID_ARG;
}
return profile->ConfigureRecorder(aRecorder);
}
#endif

Просмотреть файл

@ -1,58 +0,0 @@
/*
* Copyright (C) 2012-2015 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.
*/
/**
* DO NOT PUT RE-INCLUSION GUARD MACROS AROUND THIS HEADER!!!
*/
#ifndef DEF_GONK_RECORDER_PROFILE
#define DEF_GONK_RECORDER_PROFILE(e, n, p)
#endif
#ifndef DEF_GONK_RECORDER_PROFILE_DETECT
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h, p)
#endif
/* Enum value, name, and priority. The supported profile with the
* lowest priority and then largest area is selected as the default.
*/
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_LOW, "low", 900)
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_HIGH, "high", 900)
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_QCIF, "qcif", 300)
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_CIF, "cif", 300)
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_480P, "480p", 200)
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_720P, "720p", 100)
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_1080P, "1080p", 0)
/**
* The following profiles do not appear in all versions of the
* MediaProfiles.h and must be detected at runtime. Additionally some
* profiles may have more than one resolution, depending on the camera.
*/
DEF_GONK_RECORDER_PROFILE_DETECT("4kuhd", 3840, 2160, 800)
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 864, 480, 200)
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 854, 480, 200)
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 800, 480, 200)
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 768, 480, 200)
DEF_GONK_RECORDER_PROFILE_DETECT("vga", 640, 480, 200)
DEF_GONK_RECORDER_PROFILE_DETECT("hvga", 480, 320, 300)
DEF_GONK_RECORDER_PROFILE_DETECT("wqvga", 400, 240, 300)
DEF_GONK_RECORDER_PROFILE_DETECT("qvga", 320, 240, 300)
#undef DEF_GONK_RECORDER_PROFILE
#undef DEF_GONK_RECORDER_PROFILE_DETECT

Просмотреть файл

@ -1,159 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_GONK_RECORDER_PROFILES_H
#define DOM_CAMERA_GONK_RECORDER_PROFILES_H
#ifdef MOZ_WIDGET_GONK
#include <media/MediaProfiles.h>
#else
#include "FallbackCameraPlatform.h"
#endif
#include "ICameraControl.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
#ifndef CHECK_SETARG_RETURN
#define CHECK_SETARG_RETURN(x, rv) \
do { \
if (x) { \
DOM_CAMERA_LOGE(#x " failed\n"); \
return rv; \
} \
} while(0)
#endif
#ifndef CHECK_SETARG
#define CHECK_SETARG(x) CHECK_SETARG_RETURN(x, NS_ERROR_NOT_AVAILABLE)
#endif
namespace android {
class GonkRecorder;
};
namespace mozilla {
/**
* class GonkRecorderProfileBase
*/
template<class A, class V>
class GonkRecorderProfileBase : public ICameraControl::RecorderProfile
{
public:
GonkRecorderProfileBase(uint32_t aCameraId, int aQuality)
: RecorderProfile()
, mAudio(aCameraId, aQuality)
, mVideo(aCameraId, aQuality)
{ }
virtual const Audio& GetAudio() const override { return mAudio; }
virtual const Video& GetVideo() const override { return mVideo; }
protected:
virtual ~GonkRecorderProfileBase() { }
A mAudio;
V mVideo;
};
/**
* class GonkRecorderVideo
*/
class GonkRecorderVideo : public ICameraControl::RecorderProfile::Video
{
public:
GonkRecorderVideo(uint32_t aCameraId, int aQuality);
virtual ~GonkRecorderVideo() { }
android::video_encoder GetPlatformEncoder() const { return mPlatformEncoder; }
bool IsValid() const { return mIsValid; }
protected:
int GetProfileParameter(const char* aParameter);
static bool Translate(android::video_encoder aCodec, nsAString& aCodecName);
uint32_t mCameraId;
int mQuality;
bool mIsValid;
android::video_encoder mPlatformEncoder;
};
/**
* class GonkRecorderAudio
*/
class GonkRecorderAudio : public ICameraControl::RecorderProfile::Audio
{
public:
GonkRecorderAudio(uint32_t aCameraId, int aQuality);
virtual ~GonkRecorderAudio() { }
android::audio_encoder GetPlatformEncoder() const { return mPlatformEncoder; }
bool IsValid() const { return mIsValid; }
protected:
int GetProfileParameter(const char* aParameter);
static bool Translate(android::audio_encoder aCodec, nsAString& aCodecName);
uint32_t mCameraId;
int mQuality;
bool mIsValid;
android::audio_encoder mPlatformEncoder;
};
/**
* class GonkRecorderProfile
*/
class GonkRecorderProfile;
typedef nsRefPtrHashtable<nsStringHashKey, GonkRecorderProfile> ProfileHashtable;
class GonkRecorderProfile
: public GonkRecorderProfileBase<GonkRecorderAudio, GonkRecorderVideo>
{
public:
static nsresult GetAll(uint32_t aCameraId,
nsTArray<RefPtr<ICameraControl::RecorderProfile>>& aProfiles);
#ifdef MOZ_WIDGET_GONK
// Configures the specified recorder using the specified profile.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_INVALID_ARG if the profile isn't supported;
// - NS_ERROR_NOT_AVAILABLE if the recorder rejected the profile.
static nsresult ConfigureRecorder(android::GonkRecorder& aRecorder,
uint32_t aCameraId,
const nsAString& aProfileName);
#endif
protected:
GonkRecorderProfile(uint32_t aCameraId,
int aQuality);
int GetProfileParameter(const char* aParameter);
bool Translate(android::output_format aContainer, nsAString& aContainerName);
bool GetMimeType(android::output_format aContainer, nsAString& aMimeType);
bool IsValid() const { return mIsValid; };
#ifdef MOZ_WIDGET_GONK
nsresult ConfigureRecorder(android::GonkRecorder& aRecorder);
#endif
static already_AddRefed<GonkRecorderProfile> CreateProfile(uint32_t aCameraId,
int aQuality);
static ProfileHashtable* GetProfileHashtable(uint32_t aCameraId);
uint32_t mCameraId;
int mQuality;
bool mIsValid;
android::output_format mOutputFormat;
static nsClassHashtable<nsUint32HashKey, ProfileHashtable> sProfiles;
private:
DISALLOW_EVIL_CONSTRUCTORS(GonkRecorderProfile);
};
}; // namespace mozilla
#endif // DOM_CAMERA_GONK_RECORDER_PROFILES_H

Просмотреть файл

@ -1,337 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_ICAMERACONTROL_H
#define DOM_CAMERA_ICAMERACONTROL_H
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsISupportsImpl.h"
#include "base/basictypes.h"
struct DeviceStorageFileDescriptor;
namespace mozilla {
class CameraControlListener;
// XXXmikeh - In some future patch this should move into the ICameraControl
// class as well, and the names updated to the 'k'-style;
// e.g. kParamPreviewSize, etc.
enum {
// current settings
CAMERA_PARAM_PREVIEWSIZE,
CAMERA_PARAM_PREVIEWFORMAT,
CAMERA_PARAM_PREVIEWFRAMERATE,
CAMERA_PARAM_VIDEOSIZE,
CAMERA_PARAM_PICTURE_SIZE,
CAMERA_PARAM_PICTURE_FILEFORMAT,
CAMERA_PARAM_PICTURE_ROTATION,
CAMERA_PARAM_PICTURE_LOCATION,
CAMERA_PARAM_PICTURE_DATETIME,
CAMERA_PARAM_PICTURE_QUALITY,
CAMERA_PARAM_EFFECT,
CAMERA_PARAM_WHITEBALANCE,
CAMERA_PARAM_SCENEMODE,
CAMERA_PARAM_FLASHMODE,
CAMERA_PARAM_FOCUSMODE,
CAMERA_PARAM_ZOOM,
CAMERA_PARAM_METERINGAREAS,
CAMERA_PARAM_FOCUSAREAS,
CAMERA_PARAM_FOCALLENGTH,
CAMERA_PARAM_FOCUSDISTANCENEAR,
CAMERA_PARAM_FOCUSDISTANCEOPTIMUM,
CAMERA_PARAM_FOCUSDISTANCEFAR,
CAMERA_PARAM_EXPOSURECOMPENSATION,
CAMERA_PARAM_THUMBNAILSIZE,
CAMERA_PARAM_THUMBNAILQUALITY,
CAMERA_PARAM_SENSORANGLE,
CAMERA_PARAM_ISOMODE,
CAMERA_PARAM_LUMINANCE,
CAMERA_PARAM_SCENEMODE_HDR_RETURNNORMALPICTURE,
CAMERA_PARAM_RECORDINGHINT,
CAMERA_PARAM_PREFERRED_PREVIEWSIZE_FOR_VIDEO,
CAMERA_PARAM_METERINGMODE,
// supported features
CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
CAMERA_PARAM_SUPPORTED_PICTURESIZES,
CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
CAMERA_PARAM_SUPPORTED_SCENEMODES,
CAMERA_PARAM_SUPPORTED_EFFECTS,
CAMERA_PARAM_SUPPORTED_FLASHMODES,
CAMERA_PARAM_SUPPORTED_FOCUSMODES,
CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
CAMERA_PARAM_SUPPORTED_ZOOM,
CAMERA_PARAM_SUPPORTED_ZOOMRATIOS,
CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES,
CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES,
CAMERA_PARAM_SUPPORTED_ISOMODES,
CAMERA_PARAM_SUPPORTED_METERINGMODES
};
class ICameraControl
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ICameraControl)
// Returns the number of cameras supported by the system.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_FAILURE if the camera count cannot be retrieved.
static nsresult GetNumberOfCameras(int32_t& aDeviceCount);
// Gets the (possibly-meaningful) name of a particular camera.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_INVALID_ARG if 'aDeviceNum' is not a valid camera number;
// - NS_ERROR_NOT_AVAILABLE if 'aDeviceNum' is valid but the camera name
// could still not be retrieved.
static nsresult GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName);
// Returns a list of names of all cameras supported by the system.
//
// Return values:
// - NS_OK on success, even if no camera names are returned (in which
// case 'aList' will be empty);
// - NS_ERROR_NOT_AVAILABLE if the list of cameras cannot be retrieved.
static nsresult GetListOfCameras(nsTArray<nsString>& aList);
enum Mode {
kUnspecifiedMode,
kPictureMode,
kVideoMode,
};
struct Size {
uint32_t width;
uint32_t height;
bool Equals(const Size& aSize) const
{
return width == aSize.width && height == aSize.height;
}
};
struct Region {
int32_t top;
int32_t left;
int32_t bottom;
int32_t right;
uint32_t weight;
};
struct Position {
double latitude;
double longitude;
double altitude;
double timestamp;
};
struct StartRecordingOptions {
uint32_t rotation;
uint64_t maxFileSizeBytes;
uint64_t maxVideoLengthMs;
bool autoEnableLowLightTorch;
bool createPoster;
};
struct Configuration {
Mode mMode;
Size mPreviewSize;
Size mPictureSize;
nsString mRecorderProfile;
};
struct Point {
int32_t x;
int32_t y;
};
struct Face {
uint32_t id;
uint32_t score;
Region bound;
bool hasLeftEye;
Point leftEye;
bool hasRightEye;
Point rightEye;
bool hasMouth;
Point mouth;
};
class RecorderProfile
{
public:
class Video
{
public:
Video() { }
virtual ~Video() { }
const nsString& GetCodec() const { return mCodec; }
const Size& GetSize() const { return mSize; }
uint32_t GetBitsPerSecond() const { return mBitsPerSecond; }
uint32_t GetFramesPerSecond() const { return mFramesPerSecond; }
protected:
nsString mCodec;
Size mSize;
uint32_t mBitsPerSecond;
uint32_t mFramesPerSecond;
private:
DISALLOW_EVIL_CONSTRUCTORS(Video);
};
class Audio
{
public:
Audio() { }
virtual ~Audio() { }
const nsString& GetCodec() const { return mCodec; }
uint32_t GetChannels() const { return mChannels; }
uint32_t GetBitsPerSecond() const { return mBitsPerSecond; }
uint32_t GetSamplesPerSecond() const { return mSamplesPerSecond; }
protected:
nsString mCodec;
uint32_t mChannels;
uint32_t mBitsPerSecond;
uint32_t mSamplesPerSecond;
private:
DISALLOW_EVIL_CONSTRUCTORS(Audio);
};
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecorderProfile)
RecorderProfile()
{ }
const nsString& GetName() const { return mName; }
const nsString& GetContainer() const { return mContainer; }
const nsString& GetMimeType() const { return mMimeType; }
uint32_t GetPriority() const { return mPriority; }
virtual const Video& GetVideo() const = 0;
virtual const Audio& GetAudio() const = 0;
protected:
virtual ~RecorderProfile() { }
nsString mName;
nsString mContainer;
nsString mMimeType;
uint32_t mPriority;
private:
DISALLOW_EVIL_CONSTRUCTORS(RecorderProfile);
};
static already_AddRefed<ICameraControl> Create(uint32_t aCameraId);
virtual void AddListener(CameraControlListener* aListener) = 0;
virtual void RemoveListener(CameraControlListener* aListener) = 0;
// Camera control methods.
//
// Return values:
// - NS_OK on success (if the method requires an asynchronous process,
// this value indicates that the process has begun successfully);
// - NS_ERROR_INVALID_ARG if one or more arguments is invalid;
// - NS_ERROR_FAILURE if an asynchronous method could not be dispatched.
virtual nsresult Start(const Configuration* aInitialConfig = nullptr) = 0;
virtual nsresult Stop() = 0;
virtual nsresult SetConfiguration(const Configuration& aConfig) = 0;
virtual nsresult StartPreview() = 0;
virtual nsresult StopPreview() = 0;
virtual nsresult AutoFocus() = 0;
virtual nsresult TakePicture() = 0;
virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions = nullptr) = 0;
virtual nsresult StopRecording() = 0;
virtual nsresult PauseRecording() = 0;
virtual nsresult ResumeRecording() = 0;
virtual nsresult StartFaceDetection() = 0;
virtual nsresult StopFaceDetection() = 0;
virtual nsresult ResumeContinuousFocus() = 0;
// Camera parameter getters and setters. 'aKey' must be one of the
// CAMERA_PARAM_* values enumerated above.
//
// Return values:
// - NS_OK on success;
// - NS_ERROR_INVALID_ARG if 'aValue' contains an invalid value;
// - NS_ERROR_NOT_IMPLEMENTED if 'aKey' is invalid;
// - NS_ERROR_NOT_AVAILABLE if the getter fails to retrieve a valid value,
// or if a setter fails because it requires one or more values that
// could not be retrieved;
// - NS_ERROR_FAILURE on unexpected internal failures.
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0;
virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0;
virtual nsresult Set(uint32_t aKey, double aValue) = 0;
virtual nsresult Get(uint32_t aKey, double& aValue) = 0;
virtual nsresult Set(uint32_t aKey, int32_t aValue) = 0;
virtual nsresult Get(uint32_t aKey, int32_t& aValue) = 0;
virtual nsresult Set(uint32_t aKey, int64_t aValue) = 0;
virtual nsresult Get(uint32_t aKey, int64_t& aValue) = 0;
virtual nsresult Set(uint32_t aKey, bool aValue) = 0;
virtual nsresult Get(uint32_t aKey, bool& aValue) = 0;
virtual nsresult Set(uint32_t aKey, const Size& aValue) = 0;
virtual nsresult Get(uint32_t aKey, Size& aValue) = 0;
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) = 0;
virtual nsresult Get(uint32_t aKey, nsTArray<Region>& aRegions) = 0;
virtual nsresult SetLocation(const Position& aLocation) = 0;
virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) = 0;
virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) = 0;
virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) = 0;
virtual nsresult GetRecorderProfiles(nsTArray<nsString>& aProfiles) = 0;
virtual RecorderProfile* GetProfileInfo(const nsAString& aProfile) = 0;
protected:
virtual ~ICameraControl() { }
friend class ICameraControlParameterSetAutoEnter;
virtual void BeginBatchParameterSet() = 0;
virtual void EndBatchParameterSet() = 0;
};
// Helper class to make it easy to update a batch of camera parameters;
// the parameters are applied atomically when this object goes out of
// scope.
class ICameraControlParameterSetAutoEnter
{
public:
explicit ICameraControlParameterSetAutoEnter(ICameraControl* aCameraControl)
: mCameraControl(aCameraControl)
{
mCameraControl->BeginBatchParameterSet();
}
virtual ~ICameraControlParameterSetAutoEnter()
{
mCameraControl->EndBatchParameterSet();
}
protected:
RefPtr<ICameraControl> mCameraControl;
};
} // namespace mozilla
#endif // DOM_CAMERA_ICAMERACONTROL_H

Просмотреть файл

@ -1,28 +0,0 @@
This README file details from where some of the camcorder source files were derived from and how to apply the provided patch file to get the updated files for B2G.
---------------------------------
Following is the list of B2G files which were derived from an android ics_chocolate build. It also shows the corresponding locations where the original source files can be found:
GonkRecoder.cpp:
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmediaplayerservice/StagefrightRecorder.cpp;hb=ef1672482a9c2b88d8017927df68144fee42626c
GonkRecorder.h:
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmediaplayerservice/StagefrightRecorder.h;hb=e3682213bcd3fe43b059e00f0fe4dbebc3f3c35d
GonkCameraSource.cpp:
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libstagefright/CameraSource.cpp;hb=7fa677babfee9c241a131b22c9c1c5ab512ef2d2
GonkCameraSource.h:
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=include/media/stagefright/CameraSource.h;hb=96af14d9b013496accf40a85a66fefcba3ac0111
AudioParameter.cpp:
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmedia/AudioParameter.cpp;hb=4dc22e77cfd2a1c3671e5646ee87c5e4c15596a0
GonkCameraListener.h:
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=include/camera/Camera.h;hb=796f35e408d9dca386f90d8fbde80471ac011fa6
There were quite a few changes done to the above listed sources to support camcorder on B2G platform.
update.patch lists the changes on top of the original files.
update.sh shell script copies the files from an android tree and applies the patch to get updated files for B2G.

Просмотреть файл

@ -1,278 +0,0 @@
/*
* Copyright (C) 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "TestGonkCameraControl.h"
#include "CameraPreferences.h"
using namespace mozilla;
TestGonkCameraControl::TestGonkCameraControl(uint32_t aCameraId)
: nsGonkCameraControl(aCameraId)
{
DOM_CAMERA_LOGA("v===== Created TestGonkCameraControl =====v\n");
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
TestGonkCameraControl::~TestGonkCameraControl()
{
DOM_CAMERA_LOGA("^===== Destroyed TestGonkCameraControl =====^\n");
}
nsresult
TestGonkCameraControl::ForceMethodFailWithCodeInternal(const char* aFile, int aLine)
{
nsresult rv = NS_OK;
CameraPreferences::GetPref("camera.control.test.method.error", rv);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGI("[%s:%d] CameraControl method error override: 0x%x\n",
aFile, aLine, rv);
}
return rv;
}
nsresult
TestGonkCameraControl::ForceAsyncFailWithCodeInternal(const char* aFile, int aLine)
{
nsresult rv = NS_OK;
CameraPreferences::GetPref("camera.control.test.async.error", rv);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGI("[%s:%d] CameraControl async error override: 0x%x\n",
aFile, aLine, rv);
}
return rv;
}
nsresult
TestGonkCameraControl::Start(const Configuration* aConfig)
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::Start(aConfig);
}
nsresult
TestGonkCameraControl::StartImpl(const Configuration* aInitialConfig)
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartImpl(aInitialConfig);
}
nsresult
TestGonkCameraControl::Stop()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::Stop();
}
nsresult
TestGonkCameraControl::StopImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StopImpl();
}
nsresult
TestGonkCameraControl::SetConfiguration(const Configuration& aConfig)
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::SetConfiguration(aConfig);
}
nsresult
TestGonkCameraControl::SetConfigurationImpl(const Configuration& aConfig)
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::SetConfigurationImpl(aConfig);
}
nsresult
TestGonkCameraControl::StartPreview()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartPreview();
}
nsresult
TestGonkCameraControl::StartPreviewImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartImpl();
}
nsresult
TestGonkCameraControl::StopPreview()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StopPreview();
}
nsresult
TestGonkCameraControl::StopPreviewImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartImpl();
}
nsresult
TestGonkCameraControl::AutoFocus()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::AutoFocus();
}
nsresult
TestGonkCameraControl::AutoFocusImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::AutoFocusImpl();
}
nsresult
TestGonkCameraControl::StartFaceDetection()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartFaceDetection();
}
nsresult
TestGonkCameraControl::StartFaceDetectionImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartFaceDetectionImpl();
}
nsresult
TestGonkCameraControl::StopFaceDetection()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StopFaceDetection();
}
nsresult
TestGonkCameraControl::StopFaceDetectionImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StopFaceDetectionImpl();
}
nsresult
TestGonkCameraControl::TakePicture()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::TakePicture();
}
nsresult
TestGonkCameraControl::TakePictureImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::TakePictureImpl();
}
nsresult
TestGonkCameraControl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions)
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartRecording(aFileDescriptor, aOptions);
}
nsresult
TestGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions)
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StartRecordingImpl(aFileDescriptor, aOptions);
}
nsresult
TestGonkCameraControl::StopRecording()
{
nsresult rv = ForceMethodFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StopRecording();
}
nsresult
TestGonkCameraControl::StopRecordingImpl()
{
nsresult rv = ForceAsyncFailWithCode();
if (NS_FAILED(rv)) {
return rv;
}
return nsGonkCameraControl::StopRecordingImpl();
}

Просмотреть файл

@ -1,71 +0,0 @@
/*
* Copyright (C) 2014 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.
*/
#ifndef DOM_CAMERA_TESTGONKCAMERACONTROL_H
#define DOM_CAMERA_TESTGONKCAMERACONTROL_H
#include "GonkCameraControl.h"
namespace mozilla {
class TestGonkCameraControl : public nsGonkCameraControl
{
public:
TestGonkCameraControl(uint32_t aCameraId);
virtual nsresult Start(const Configuration* aConfig = nullptr) override;
virtual nsresult Stop() override;
virtual nsresult SetConfiguration(const Configuration& aConfig) override;
virtual nsresult StartPreview() override;
virtual nsresult StopPreview() override;
virtual nsresult AutoFocus() override;
virtual nsresult StartFaceDetection() override;
virtual nsresult StopFaceDetection() override;
virtual nsresult TakePicture() override;
virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions) override;
virtual nsresult StopRecording() override;
protected:
virtual ~TestGonkCameraControl();
virtual nsresult StartImpl(const Configuration* aInitialConfig = nullptr) override;
virtual nsresult StopImpl() override;
virtual nsresult SetConfigurationImpl(const Configuration& aConfig) override;
virtual nsresult StartPreviewImpl() override;
virtual nsresult StopPreviewImpl() override;
virtual nsresult AutoFocusImpl() override;
virtual nsresult StartFaceDetectionImpl() override;
virtual nsresult StopFaceDetectionImpl() override;
virtual nsresult TakePictureImpl() override;
virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions = nullptr) override;
virtual nsresult StopRecordingImpl() override;
nsresult ForceMethodFailWithCodeInternal(const char* aFile, int aLine);
nsresult ForceAsyncFailWithCodeInternal(const char* aFile, int aLine);
private:
TestGonkCameraControl(const TestGonkCameraControl&) = delete;
TestGonkCameraControl& operator=(const TestGonkCameraControl&) = delete;
};
#define ForceMethodFailWithCode() ForceMethodFailWithCodeInternal(__FILE__, __LINE__)
#define ForceAsyncFailWithCode() ForceAsyncFailWithCodeInternal(__FILE__, __LINE__)
} // namespace mozilla
#endif // DOM_CAMERA_TESTGONKCAMERACONTROL_H

Просмотреть файл

@ -1,757 +0,0 @@
/*
* Copyright (C) 2013-2015 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "TestGonkCameraHardware.h"
#include "CameraPreferences.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/EventListenerBinding.h"
#include "mozilla/dom/BlobEvent.h"
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/CameraFacesDetectedEvent.h"
#include "mozilla/dom/CameraStateChangeEvent.h"
#include "mozilla/DebugOnly.h"
#include "nsNetUtil.h"
#include "DOMCameraDetectedFace.h"
#include "nsServiceManagerUtils.h"
#include "nsICameraTestHardware.h"
using namespace android;
using namespace mozilla;
using namespace mozilla::dom;
#ifndef MOZ_WIDGET_GONK
NS_IMPL_ISUPPORTS_INHERITED0(TestGonkCameraHardware, GonkCameraHardware);
#endif
static void
CopyFaceFeature(int32_t (&aDst)[2], bool aExists, const DOMPoint* aSrc)
{
if (aExists && aSrc) {
aDst[0] = static_cast<int32_t>(aSrc->X());
aDst[1] = static_cast<int32_t>(aSrc->Y());
} else {
aDst[0] = -2000;
aDst[1] = -2000;
}
}
class TestGonkCameraHardwareListener : public nsIDOMEventListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
TestGonkCameraHardwareListener(nsGonkCameraControl* aTarget, nsIThread* aCameraThread)
: mTarget(aTarget)
, mCameraThread(aCameraThread)
{
MOZ_COUNT_CTOR(TestGonkCameraHardwareListener);
}
protected:
virtual ~TestGonkCameraHardwareListener()
{
MOZ_COUNT_DTOR(TestGonkCameraHardwareListener);
}
RefPtr<nsGonkCameraControl> mTarget;
nsCOMPtr<nsIThread> mCameraThread;
};
NS_IMETHODIMP
TestGonkCameraHardwareListener::HandleEvent(nsIDOMEvent* aEvent)
{
nsString eventType;
aEvent->GetType(eventType);
DOM_CAMERA_LOGI("Inject '%s' event",
NS_ConvertUTF16toUTF8(eventType).get());
if (eventType.EqualsLiteral("focus")) {
CameraStateChangeEvent* event = aEvent->InternalDOMEvent()->AsCameraStateChangeEvent();
if (!NS_WARN_IF(!event)) {
nsString state;
event->GetNewState(state);
if (state.EqualsLiteral("focused")) {
OnAutoFocusComplete(mTarget, true);
} else if (state.EqualsLiteral("unfocused")) {
OnAutoFocusComplete(mTarget, false);
} else if (state.EqualsLiteral("focusing")) {
OnAutoFocusMoving(mTarget, true);
} else if (state.EqualsLiteral("not_focusing")) {
OnAutoFocusMoving(mTarget, false);
} else {
DOM_CAMERA_LOGE("Unhandled focus state '%s'\n",
NS_ConvertUTF16toUTF8(state).get());
}
}
} else if (eventType.EqualsLiteral("shutter")) {
DOM_CAMERA_LOGI("Inject shutter event");
OnShutter(mTarget);
} else if (eventType.EqualsLiteral("picture")) {
BlobEvent* event = aEvent->InternalDOMEvent()->AsBlobEvent();
if (!NS_WARN_IF(!event)) {
Blob* blob = event->GetData();
if (blob) {
static const uint64_t MAX_FILE_SIZE = 2147483647;
ErrorResult rv;
uint64_t dataLength = blob->GetSize(rv);
if (NS_WARN_IF(rv.Failed()) || NS_WARN_IF(dataLength > MAX_FILE_SIZE)) {
rv.SuppressException();
return NS_OK;
}
nsCOMPtr<nsIInputStream> inputStream;
blob->GetInternalStream(getter_AddRefs(inputStream), rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return NS_OK;
}
uint8_t* data = new uint8_t[dataLength];
rv = NS_ReadInputStreamToBuffer(inputStream,
reinterpret_cast<void**>(&data),
static_cast<uint32_t>(dataLength));
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
delete [] data;
return NS_OK;
}
OnTakePictureComplete(mTarget, data, dataLength);
delete [] data;
} else {
OnTakePictureComplete(mTarget, nullptr, 0);
}
}
} else if(eventType.EqualsLiteral("error")) {
ErrorEvent* event = aEvent->InternalDOMEvent()->AsErrorEvent();
if (!NS_WARN_IF(!event)) {
nsString errorType;
event->GetMessage(errorType);
if (errorType.EqualsLiteral("picture")) {
OnTakePictureError(mTarget);
} else if (errorType.EqualsLiteral("system")) {
if (!NS_WARN_IF(!mCameraThread)) {
class DeferredSystemFailure : public Runnable
{
public:
DeferredSystemFailure(nsGonkCameraControl* aTarget)
: mTarget(aTarget)
{ }
NS_IMETHOD
Run() override
{
OnSystemError(mTarget, CameraControlListener::kSystemService, 100, 0);
return NS_OK;
}
protected:
RefPtr<nsGonkCameraControl> mTarget;
};
mCameraThread->Dispatch(new DeferredSystemFailure(mTarget), NS_DISPATCH_NORMAL);
}
} else {
DOM_CAMERA_LOGE("Unhandled error event type '%s'\n",
NS_ConvertUTF16toUTF8(errorType).get());
}
}
} else if(eventType.EqualsLiteral("facesdetected")) {
CameraFacesDetectedEvent* event = aEvent->InternalDOMEvent()->AsCameraFacesDetectedEvent();
if (!NS_WARN_IF(!event)) {
Nullable<nsTArray<RefPtr<DOMCameraDetectedFace>>> faces;
event->GetFaces(faces);
camera_frame_metadata_t metadata;
memset(&metadata, 0, sizeof(metadata));
if (faces.IsNull()) {
OnFacesDetected(mTarget, &metadata);
} else {
const nsTArray<RefPtr<DOMCameraDetectedFace>>& facesData = faces.Value();
uint32_t i = facesData.Length();
metadata.number_of_faces = i;
metadata.faces = new camera_face_t[i];
memset(metadata.faces, 0, sizeof(camera_face_t) * i);
while (i > 0) {
--i;
const RefPtr<DOMCameraDetectedFace>& face = facesData[i];
camera_face_t& f = metadata.faces[i];
const DOMRect& bounds = *face->Bounds();
f.rect[0] = static_cast<int32_t>(bounds.Left());
f.rect[1] = static_cast<int32_t>(bounds.Top());
f.rect[2] = static_cast<int32_t>(bounds.Right());
f.rect[3] = static_cast<int32_t>(bounds.Bottom());
CopyFaceFeature(f.left_eye, face->HasLeftEye(), face->GetLeftEye());
CopyFaceFeature(f.right_eye, face->HasRightEye(), face->GetRightEye());
CopyFaceFeature(f.mouth, face->HasMouth(), face->GetMouth());
f.id = face->Id();
f.score = face->Score();
}
OnFacesDetected(mTarget, &metadata);
delete [] metadata.faces;
}
}
} else {
DOM_CAMERA_LOGE("Unhandled injected event '%s'",
NS_ConvertUTF16toUTF8(eventType).get());
}
return NS_OK;
}
NS_IMPL_ISUPPORTS(TestGonkCameraHardwareListener, nsIDOMEventListener)
class TestGonkCameraHardware::ControlMessage : public Runnable
{
public:
ControlMessage(TestGonkCameraHardware* aTestHw)
: mTestHw(aTestHw)
{ }
NS_IMETHOD
Run() override
{
if (NS_WARN_IF(!mTestHw)) {
return NS_ERROR_INVALID_ARG;
}
MutexAutoLock lock(mTestHw->mMutex);
mTestHw->mStatus = RunInline();
DebugOnly<nsresult> rv = mTestHw->mCondVar.Notify();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Notify failed");
return NS_OK;
}
nsresult
RunInline()
{
if (NS_WARN_IF(!mTestHw)) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
mJSTestWrapper = do_GetService("@mozilla.org/cameratesthardware;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
DOM_CAMERA_LOGE("Cannot get camera test service\n");
return rv;
}
rv = RunImpl();
mJSTestWrapper = nullptr;
return rv;
}
protected:
NS_IMETHOD RunImpl() = 0;
virtual ~ControlMessage() { }
nsCOMPtr<nsICameraTestHardware> mJSTestWrapper;
/* Since we block the control thread until we have finished
processing the request on the main thread, we know that this
pointer will not go out of scope because the control thread
and calling class is the owner. */
TestGonkCameraHardware* mTestHw;
};
TestGonkCameraHardware::TestGonkCameraHardware(nsGonkCameraControl* aTarget,
uint32_t aCameraId,
const sp<Camera>& aCamera)
: GonkCameraHardware(aTarget, aCameraId, aCamera)
, mMutex("TestGonkCameraHardware::mMutex")
, mCondVar(mMutex, "TestGonkCameraHardware::mCondVar")
{
DOM_CAMERA_LOGA("v===== Created TestGonkCameraHardware =====v\n");
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n",
__func__, __LINE__, this, aTarget);
MOZ_COUNT_CTOR(TestGonkCameraHardware);
mCameraThread = NS_GetCurrentThread();
}
TestGonkCameraHardware::~TestGonkCameraHardware()
{
MOZ_COUNT_DTOR(TestGonkCameraHardware);
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
if (mTestHw->mDomListener) {
mTestHw->mDomListener = nullptr;
DebugOnly<nsresult> rv = mJSTestWrapper->SetHandler(nullptr);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetHandler failed");
}
return NS_OK;
}
};
DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
DOM_CAMERA_LOGA("^===== Destroyed TestGonkCameraHardware =====^\n");
}
nsresult
TestGonkCameraHardware::WaitWhileRunningOnMainThread(RefPtr<ControlMessage> aRunnable)
{
MutexAutoLock lock(mMutex);
if (NS_WARN_IF(!aRunnable)) {
mStatus = NS_ERROR_INVALID_ARG;
} else if (!NS_IsMainThread()) {
nsresult rv = NS_DispatchToMainThread(aRunnable);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = mCondVar.Wait();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
/* Cannot dispatch to main thread since we would block on
the condvar, so we need to run inline. */
mStatus = aRunnable->RunInline();
}
return mStatus;
}
nsresult
TestGonkCameraHardware::Init()
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
nsresult rv = mJSTestWrapper->InitCamera();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mTestHw->mDomListener = new TestGonkCameraHardwareListener(mTestHw->mTarget, mTestHw->mCameraThread);
if (NS_WARN_IF(!mTestHw->mDomListener)) {
return NS_ERROR_FAILURE;
}
rv = mJSTestWrapper->SetHandler(mTestHw->mDomListener);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
};
DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
return NS_OK;
}
int
TestGonkCameraHardware::AutoFocus()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->AutoFocus();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
int
TestGonkCameraHardware::CancelAutoFocus()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->CancelAutoFocus();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
int
TestGonkCameraHardware::StartFaceDetection()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->StartFaceDetection();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
int
TestGonkCameraHardware::StopFaceDetection()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->StopFaceDetection();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
int
TestGonkCameraHardware::TakePicture()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->TakePicture();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
void
TestGonkCameraHardware::CancelTakePicture()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->CancelTakePicture();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
}
int
TestGonkCameraHardware::StartPreview()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->StartPreview();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
void
TestGonkCameraHardware::StopPreview()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->StopPreview();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
}
class TestGonkCameraHardware::PushParametersDelegate : public ControlMessage
{
public:
PushParametersDelegate(TestGonkCameraHardware* aTestHw, String8* aParams)
: ControlMessage(aTestHw)
, mParams(aParams)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
if (NS_WARN_IF(!mParams)) {
return NS_ERROR_INVALID_ARG;
}
DOM_CAMERA_LOGI("Push test parameters: %s\n", mParams->string());
return mJSTestWrapper->PushParameters(NS_ConvertASCIItoUTF16(mParams->string()));
}
String8* mParams;
};
class TestGonkCameraHardware::PullParametersDelegate : public ControlMessage
{
public:
PullParametersDelegate(TestGonkCameraHardware* aTestHw, nsString* aParams)
: ControlMessage(aTestHw)
, mParams(aParams)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
if (NS_WARN_IF(!mParams)) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv = mJSTestWrapper->PullParameters(*mParams);
DOM_CAMERA_LOGI("Pull test parameters: %s\n",
NS_LossyConvertUTF16toASCII(*mParams).get());
return rv;
}
nsString* mParams;
};
int
TestGonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
String8 s = aParams.Flatten();
nsresult rv = WaitWhileRunningOnMainThread(new PushParametersDelegate(this, &s));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
nsresult
TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsString as;
nsresult rv = WaitWhileRunningOnMainThread(new PullParametersDelegate(this, &as));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
String8 s(NS_LossyConvertUTF16toASCII(as).get());
aParams.Unflatten(s);
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
int
TestGonkCameraHardware::PushParameters(const CameraParameters& aParams)
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
String8 s = aParams.flatten();
nsresult rv = WaitWhileRunningOnMainThread(new PushParametersDelegate(this, &s));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
void
TestGonkCameraHardware::PullParameters(CameraParameters& aParams)
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsString as;
nsresult rv = WaitWhileRunningOnMainThread(new PullParametersDelegate(this, &as));
if (NS_WARN_IF(NS_FAILED(rv))) {
as.Truncate();
}
String8 s(NS_LossyConvertUTF16toASCII(as).get());
aParams.unflatten(s);
}
#endif
int
TestGonkCameraHardware::StartRecording()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->StartRecording();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
int
TestGonkCameraHardware::StopRecording()
{
class Delegate : public ControlMessage
{
public:
Delegate(TestGonkCameraHardware* aTestHw)
: ControlMessage(aTestHw)
{ }
protected:
NS_IMETHOD
RunImpl() override
{
return mJSTestWrapper->StopRecording();
}
};
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
if (NS_WARN_IF(NS_FAILED(rv))) {
return UNKNOWN_ERROR;
}
return OK;
}
int
TestGonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
return OK;
}

Просмотреть файл

@ -1,78 +0,0 @@
/*
* Copyright (C) 2013-2015 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.
*/
#ifndef DOM_CAMERA_TESTGONKCAMERAHARDWARE_H
#define DOM_CAMERA_TESTGONKCAMERAHARDWARE_H
#include "GonkCameraHwMgr.h"
#include "nsIDOMEventListener.h"
#include "mozilla/CondVar.h"
namespace mozilla {
class TestGonkCameraHardware : public android::GonkCameraHardware
{
#ifndef MOZ_WIDGET_GONK
NS_DECL_ISUPPORTS_INHERITED
#endif
public:
virtual nsresult Init() override;
virtual int AutoFocus() override;
virtual int CancelAutoFocus() override;
virtual int StartFaceDetection() override;
virtual int StopFaceDetection() override;
virtual int TakePicture() override;
virtual void CancelTakePicture() override;
virtual int StartPreview() override;
virtual void StopPreview() override;
virtual int PushParameters(const mozilla::GonkCameraParameters& aParams) override;
virtual nsresult PullParameters(mozilla::GonkCameraParameters& aParams) override;
virtual int StartRecording() override;
virtual int StopRecording() override;
virtual int StoreMetaDataInBuffers(bool aEnabled) override;
#ifdef MOZ_WIDGET_GONK
virtual int PushParameters(const android::CameraParameters& aParams) override;
virtual void PullParameters(android::CameraParameters& aParams) override;
#endif
TestGonkCameraHardware(mozilla::nsGonkCameraControl* aTarget,
uint32_t aCameraId,
const android::sp<android::Camera>& aCamera);
protected:
virtual ~TestGonkCameraHardware();
class ControlMessage;
class PushParametersDelegate;
class PullParametersDelegate;
nsresult WaitWhileRunningOnMainThread(RefPtr<ControlMessage> aRunnable);
nsCOMPtr<nsIDOMEventListener> mDomListener;
nsCOMPtr<nsIThread> mCameraThread;
mozilla::Mutex mMutex;
mozilla::CondVar mCondVar;
nsresult mStatus;
private:
TestGonkCameraHardware(const TestGonkCameraHardware&) = delete;
TestGonkCameraHardware& operator=(const TestGonkCameraHardware&) = delete;
};
} // namespace mozilla
#endif // DOM_CAMERA_TESTGONKCAMERAHARDWARE_H

Просмотреть файл

@ -1,80 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
if CONFIG['MOZ_B2G_CAMERA']:
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
EXPORTS += [
'CameraCommon.h',
'CameraPreferences.h',
'DOMCameraManager.h',
]
UNIFIED_SOURCES += [
'CameraControlImpl.cpp',
'CameraPreferences.cpp',
'CameraPreviewMediaStream.cpp',
'DOMCameraCapabilities.cpp',
'DOMCameraControl.cpp',
'DOMCameraControlListener.cpp',
'DOMCameraDetectedFace.cpp',
'DOMCameraManager.cpp',
]
if CONFIG['MOZ_B2G_CAMERA']:
XPIDL_SOURCES += [
'nsICameraTestHardware.idl',
]
XPIDL_MODULE = 'dom_camera'
UNIFIED_SOURCES += [
'GonkCameraControl.cpp',
'GonkCameraHwMgr.cpp',
'GonkCameraManager.cpp',
'GonkCameraParameters.cpp',
'GonkRecorderProfiles.cpp',
'TestGonkCameraControl.cpp',
'TestGonkCameraHardware.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
UNIFIED_SOURCES += [
'GonkCameraSource.cpp',
'GonkRecorder.cpp',
]
else:
UNIFIED_SOURCES += [
'FallbackCameraPlatform.cpp',
]
EXTRA_COMPONENTS += [
'CameraTestHardware.js',
'CameraTestHardware.manifest',
]
else:
UNIFIED_SOURCES += [
'FallbackCameraControl.cpp',
'FallbackCameraManager.cpp',
]
LOCAL_INCLUDES += [
'../base',
'/media/libyuv/include',
]
include('/ipc/chromium/chromium-config.mozbuild')
# Suppress some GCC warnings being treated as errors:
# - about attributes on forward declarations for types that are already
# defined, which complains about an important MOZ_EXPORT for android::AString
if CONFIG['GNU_CC']:
CXXFLAGS += [
'-Wno-error=attributes',
'-Wno-error=shadow',
]
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -1,191 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIDOMBlob;
interface nsIDOMEventListener;
[scriptable, uuid(2e567730-f164-49d7-b975-862caa4425a5)]
interface nsICameraTestHardware : nsISupports
{
/* The following methods are intended to be used by the test cases
written in JavaScript to define the behaviour of the hardware: */
/* Attach a delegate handler object such that the test hardware
will call the given handlers for the given operations to decide
what to do. This allows a test case to define specific behaviours
on a fine grained basis.
The following handlers may be supplied as properties of the
given delagate handler object:
autoFocus
cancelAutoFocus
cancelTakePicture
init
pushParameters
pullParameters
startFaceDetection
startPreview
startRecording
stopFaceDetection
stopPreview
stopRecording
takePicture
Implementation notes for handlers:
- If the handler throws an error, we will the return code
of the driver operation.
- If the handler returns true, we will perform the default
action (if any) for the operation. */
void attach(in jsval mock);
/* Detach a delegate handler object such that the test hardware
will revert to default behaviour when a function is called. */
void detach();
/* Reset the state of the test hardware back to the initial state.
This is useful when one test case has been completed and we need
a clean slate for the next. */
void reset(in jsval window);
/* Trigger an OnAutoFocusMoving callback at the Gonk layer.
state is a boolean indicating where or not the camera focus
is moving. */
void fireAutoFocusComplete(in boolean state);
/* Trigger an OnAutoFocusComplete callback at the Gonk layer.
state is a boolean indicating where or not the camera is focused. */
void fireAutoFocusMoving(in boolean moving);
/* Trigger an OnTakePictureComplete callback at the Gonk layer.
blob should be a Blob object. The actual content of the blob
is unimportant since nothing processes it as an image internally. */
void fireTakePictureComplete(in nsIDOMBlob picture);
/* Trigger an OnTakePictureError callback at the Gonk layer. */
void fireTakePictureError();
/* Trigger an OnSystemError callback at the Gonk layer. */
void fireSystemError();
/* Trigger an OnShutter callback at the Gonk layer. */
void fireShutter();
/* Trigger an OnFacesDetected callback at the Gonk layer.
faces is an array of CameraDetectedFaceInit dictionaries although
hasLeftEye, hasRightEye and hasMouth may be omitted and will be
implied by the presence/absence of leftEye, rightEye and mouth. */
void fireFacesDetected(in jsval faces);
/* Object which stores the camera parameters read/written by the
camera control layer from the hardware. The test case may set
its own values to control the behaviour of the camera middleware.
E.g. params['preview-sizes'] = '320x240,640x480'; */
attribute jsval params;
/* The following methods are intended to be used by the Gonk layer
in order to call back into JavaScript to get test case defined
behaviour: */
/* Set a handler to capture asynchronous events triggered by the
test case via the fireXXX methods. E.g.:
nsCOMPtr<nsICameraHardware> wrapper =
do_GetService("@mozilla.org/cameratesthardware;1");
nsCOMPtr<nsIDOMEventListener> listener = new HwListener();
wrapper->setHander(listener);
where
class HwListener : public nsIDOMEventListener {
NS_IMETHODIMP HandleEvent(nsIDOMEvent *aEvent) {
nsString type;
aEvent->GetType(&type);
if (aEvent.EqualsLiteral("focus")) {
...
} else {
...
}
}
};
The following event types may be generated:
focus: CameraStateChangeEvent where newState should map
to the OnAutoFocusComplete and OnAutoFocusMoving callbacks:
-- focused: OnAutoFocusComplete(false)
-- unfocused: OnAutoFocusComplete(true)
-- focusing: OnAutoFocusMoving(true)
-- not_focusing: OnAutoFocusMoving(false)
picture: BlobEvent which contains the picture type and
data corresponding to the OnTakePictureComplete callback.
error: ErrorEvent corresponding to the various error callbacks,
where the message is:
-- picture: OnTakePictureError()
-- system: OnSystemError(100, 0)
facesdetected: CameraFacesDetectedEvent which contains the
faces data corresponding to OnFacesDetected callback.
shutter: Event which corresponds to the OnShutter callback. */
void setHandler(in nsIDOMEventListener handler);
/* Execute an intercepted Init() driver call. */
void initCamera();
/* Execute an intercepted AutoFocus() driver call. Default behaviour is
to trigger OnAutoFocusComplete where the camera is focused. */
void autoFocus();
/* Execute an intercepted CancelAutoFocus() driver call. */
void cancelAutoFocus();
/* Execute an intercepted StartFaceDetection() driver call. */
void startFaceDetection();
/* Execute an intercepted StopFaceDetection() driver call. */
void stopFaceDetection();
/* Execute an intercepted TakePicture() driver call. Default behaviour is
to trigger OnTakePictureComplete with a fake jpeg blob. */
void takePicture();
/* Execute an intercepted CancelTakePicture() driver call. */
void cancelTakePicture();
/* Execute an intercepted StartPreview() driver call. */
void startPreview();
/* Execute an intercepted StopPreview() driver call. */
void stopPreview();
/* Execute an intercepted StartRecording() driver call. */
void startRecording();
/* Execute an intercepted StopRecording() driver call. */
void stopRecording();
/* Execute an intercepted PushParameters() driver call. If the delegate
handler throws an error, it will restore the old parameters.
When the delegate is called, the new proposed parameters are
placed in this.params. */
void pushParameters(in DOMString params);
/* Execute an intercepted PullParameters() driver call. Unless the delegate
handler throws an error, it will return an assembled parameter
list derived from the this.params hash table. */
DOMString pullParameters();
};

Просмотреть файл

@ -1,467 +0,0 @@
function isDefinedObj(obj) {
return typeof(obj) !== 'undefined' && obj != null;
}
function isDefined(obj) {
return typeof(obj) !== 'undefined';
}
/* This is a simple test suite class removing the need to
write a lot of boilerplate for camera tests. It can
manage the platform configurations for testing, any
cleanup required, and common actions such as fetching
the camera or waiting for the preview to be completed.
To create the suite:
var suite = new CameraTestSuite();
To add a test case to the suite:
suite.test('test-name', function() {
function startAutoFocus(p) {
return suite.camera.autoFocus();
}
return suite.getCamera()
.then(startAutoFocus, suite.rejectGetCamera);
});
Finally, to execute the test cases:
suite.setup()
.then(suite.run);
Behind the scenes, suite configured the native camera
to use the JS hardware, setup that hardware such that
the getCamera would succeed, got a camera control
reference and saved it to suite.camera, and after the
tests were finished, it reset any modified state,
released the camera object, and concluded the mochitest
appropriately.
*/
function CameraTestSuite() {
SimpleTest.waitForExplicitFinish();
this._window = window;
this._document = document;
this.viewfinder = document.getElementById('viewfinder');
this._tests = [];
this.hwType = '';
/* Ensure that the this pointer is bound to all functions so that
they may be used as promise resolve/reject handlers without any
special effort, permitting code like this:
getCamera().catch(suite.rejectGetCamera);
instead of:
getCamera().catch(suite.rejectGetCamera.bind(suite));
*/
this.setup = this._setup.bind(this);
this.teardown = this._teardown.bind(this);
this.test = this._test.bind(this);
this.run = this._run.bind(this);
this.waitPreviewStarted = this._waitPreviewStarted.bind(this);
this.waitParameterPush = this._waitParameterPush.bind(this);
this.initJsHw = this._initJsHw.bind(this);
this.getCamera = this._getCamera.bind(this);
this.setLowMemoryPlatform = this._setLowMemoryPlatform.bind(this);
this.logError = this._logError.bind(this);
this.expectedError = this._expectedError.bind(this);
this.expectedRejectGetCamera = this._expectedRejectGetCamera.bind(this);
this.expectedRejectConfigure = this._expectedRejectConfigure.bind(this);
this.expectedRejectAutoFocus = this._expectedRejectAutoFocus.bind(this);
this.expectedRejectTakePicture = this._expectedRejectTakePicture.bind(this);
this.expectedRejectStartRecording = this._expectedRejectStartRecording.bind(this);
this.expectedRejectStopRecording = this._expectedRejectStopRecording.bind(this);
this.rejectGetCamera = this._rejectGetCamera.bind(this);
this.rejectConfigure = this._rejectConfigure.bind(this);
this.rejectRelease = this._rejectRelease.bind(this);
this.rejectAutoFocus = this._rejectAutoFocus.bind(this);
this.rejectTakePicture = this._rejectTakePicture.bind(this);
this.rejectStartRecording = this._rejectStartRecording.bind(this);
this.rejectStopRecording = this._rejectStopRecording.bind(this);
this.rejectPauseRecording = this._rejectPauseRecording.bind(this);
this.rejectResumeRecording = this._rejectResumeRecording.bind(this);
this.rejectPreviewStarted = this._rejectPreviewStarted.bind(this);
var self = this;
this._window.addEventListener('beforeunload', function() {
if (isDefinedObj(self.viewfinder)) {
self.viewfinder.srcObject = null;
}
self.hw = null;
if (isDefinedObj(self.camera)) {
ok(false, 'window unload triggered camera release instead of test completion');
self.camera.release();
self.camera = null;
}
});
}
CameraTestSuite.prototype = {
camera: null,
hw: null,
_lowMemSet: false,
_reloading: false,
_setupPermission: function(permission) {
if (!SpecialPowers.hasPermission(permission, document)) {
info("requesting " + permission + " permission");
SpecialPowers.addPermission(permission, true, document);
this._reloading = true;
}
},
/* Returns a promise which is resolved when the test suite is ready
to be executing individual test cases. One may provide the expected
hardware type here if desired; the default is to use the JS test
hardware. Use '' for the native emulated camera hardware. */
_setup: function(hwType) {
/* Depending on how we run the mochitest, we may not have the necessary
permissions yet. If we do need to request them, then we have to reload
the window to ensure the reconfiguration propogated properly. */
this._setupPermission("camera");
this._setupPermission("device-storage:videos");
this._setupPermission("device-storage:videos-create");
this._setupPermission("device-storage:videos-write");
if (this._reloading) {
window.location.reload();
return Promise.reject();
}
info("has necessary permissions");
if (!isDefined(hwType)) {
hwType = 'hardware';
}
this._hwType = hwType;
return new Promise(function(resolve, reject) {
SpecialPowers.pushPrefEnv({'set': [['device.storage.prompt.testing', true]]}, function() {
SpecialPowers.pushPrefEnv({'set': [['camera.control.test.permission', true]]}, function() {
SpecialPowers.pushPrefEnv({'set': [['camera.control.test.enabled', hwType]]}, function() {
resolve();
});
});
});
});
},
/* Returns a promise which is resolved when all of the SpecialPowers
parameters that were set while testing are flushed. This includes
camera.control.test.enabled and camera.control.test.is_low_memory. */
_teardown: function() {
return new Promise(function(resolve, reject) {
SpecialPowers.flushPrefEnv(function() {
resolve();
});
});
},
/* Returns a promise which is resolved when the set low memory
parameter is set. If no value is given, it defaults to true.
This is intended to be used inside a test case at the beginning
of its promise chain to configure the platform as desired. */
_setLowMemoryPlatform: function(val) {
if (typeof(val) === 'undefined') {
val = true;
}
if (this._lowMemSet === val) {
return Promise.resolve();
}
var self = this;
return new Promise(function(resolve, reject) {
SpecialPowers.pushPrefEnv({'set': [['camera.control.test.is_low_memory', val]]}, function() {
self._lowMemSet = val;
resolve();
});
}).catch(function(e) {
return self.logError('set low memory ' + val + ' failed', e);
});
},
/* Add a test case to the test suite to be executed later. */
_test: function(aName, aCb) {
this._tests.push({
name: aName,
cb: aCb
});
},
/* Execute all test cases (after setup is called). */
_run: function() {
if (this._reloading) {
return;
}
var test = this._tests.shift();
var self = this;
if (test) {
info(test.name + ' started');
function runNextTest() {
self.run();
}
function resetLowMem() {
return self.setLowMemoryPlatform(false);
}
function postTest(pass) {
ok(pass, test.name + ' finished');
var camera = self.camera;
self.viewfinder.srcObject = null;
self.camera = null;
if (!isDefinedObj(camera)) {
return Promise.resolve();
}
function handler(e) {
ok(typeof(e) === 'undefined', 'camera released');
return Promise.resolve();
}
return camera.release().then(handler).catch(handler);
}
this.initJsHw();
var testPromise;
try {
testPromise = test.cb();
if (!isDefinedObj(testPromise)) {
testPromise = Promise.resolve();
}
} catch(e) {
ok(false, 'caught exception while running test: ' + e);
testPromise = Promise.reject(e);
}
testPromise
.then(function(p) {
return postTest(true);
}, function(e) {
self.logError('unhandled error', e);
return postTest(false);
})
.then(resetLowMem, resetLowMem)
.then(runNextTest, runNextTest);
} else {
ok(true, 'all tests completed');
var finish = SimpleTest.finish.bind(SimpleTest);
this.teardown().then(finish, finish);
}
},
/* If the JS hardware is in use, get (and possibly initialize)
the service XPCOM object. The native Gonk layers are able
to get it via the same mechanism. Save a reference to it
so that the test case may manipulate it as it sees fit in
this.hw. Minimal setup is done for the test hardware such
that the camera is able to be brought up without issue.
This function has no effect if the JS hardware is not used. */
_initJsHw: function() {
if (this._hwType === 'hardware') {
this.hw = SpecialPowers.Cc['@mozilla.org/cameratesthardware;1']
.getService(SpecialPowers.Ci.nsICameraTestHardware);
this.hw.reset(this._window);
/* Minimum parameters required to get camera started */
this.hw.params['preview-size'] = '320x240';
this.hw.params['preview-size-values'] = '320x240';
this.hw.params['picture-size-values'] = '320x240';
} else {
this.hw = null;
}
},
/* Returns a promise which resolves when the camera has
been successfully opened with the given name and
configuration. If no name is given, it uses the first
camera in the list from the camera manager. */
_getCamera: function(name, config) {
var cameraManager = navigator.mozCameras;
if (!isDefined(name)) {
name = cameraManager.getListOfCameras()[0];
}
var self = this;
return cameraManager.getCamera(name, config).then(
function(p) {
ok(isDefinedObj(p) && isDefinedObj(p.camera), 'got camera');
self.camera = p.camera;
/* Ensure a followup promise can verify config by
returning the same parameter again. */
return Promise.resolve(p);
}
);
},
/* Returns a promise which resolves when the camera has
successfully started the preview and is bound to the
given viewfinder object. Note that this requires that
a video element be present with the ID 'viewfinder'. */
_waitPreviewStarted: function() {
var self = this;
return new Promise(function(resolve, reject) {
function onPreviewStateChange(e) {
try {
if (e.newState === 'started') {
ok(true, 'viewfinder is ready and playing');
self.camera.removeEventListener('previewstatechange', onPreviewStateChange);
resolve();
}
} catch(e) {
reject(e);
}
}
if (!isDefinedObj(self.viewfinder)) {
reject(new Error('no viewfinder object'));
return;
}
self.viewfinder.srcObject = self.camera;
self.viewfinder.play();
self.camera.addEventListener('previewstatechange', onPreviewStateChange);
});
},
/* Returns a promise which resolves when the camera hardware
has received a push parameters request. This is useful
when setting camera parameters from the application and
you want confirmation when the operation is complete if
there is no asynchronous notification provided. */
_waitParameterPush: function() {
var self = this;
return new Promise(function(resolve, reject) {
self.hw.attach({
'pushParameters': function() {
self._window.setTimeout(resolve);
}
});
});
},
/* When an error occurs in the promise chain, all of the relevant rejection
functions will be triggered. Most of the time however we only want the
first rejection to be handled and then let the failure trickle down the
chain to terminate the test. There is no way to exit a promise chain
early so the convention is to handle the error in the first reject and
then give an empty error for subsequent reject handlers so they know
it is not for them.
For example:
function rejectSomething(e) {
return suite.logError('something call failed');
}
getCamera()
.then(, suite.rejectGetCamera)
.then(something)
.then(, rejectSomething)
If the getCamera promise is rejected, suite.rejectGetCamera reports an
error, but rejectSomething remains silent. */
_logError: function(msg, e) {
if (isDefined(e)) {
ok(false, msg + ': ' + e);
}
// Make sure the error is undefined for later handlers
return Promise.reject();
},
/* The reject handlers below are intended to be used
when a test case does not expect a particular call
to fail but otherwise does not require any special
handling of that situation beyond failing the test
case and logging why.*/
_rejectGetCamera: function(e) {
return this.logError('get camera failed', e);
},
_rejectConfigure: function(e) {
return this.logError('set configuration failed', e);
},
_rejectRelease: function(e) {
return this.logError('release camera failed', e);
},
_rejectAutoFocus: function(e) {
return this.logError('auto focus failed', e);
},
_rejectTakePicture: function(e) {
return this.logError('take picture failed', e);
},
_rejectStartRecording: function(e) {
return this.logError('start recording failed', e);
},
_rejectStopRecording: function(e) {
return this.logError('stop recording failed', e);
},
_rejectPauseRecording: function(e) {
return this.logError('pause recording failed', e);
},
_rejectResumeRecording: function(e) {
return this.logError('resume recording failed', e);
},
_rejectPreviewStarted: function(e) {
return this.logError('preview start failed', e);
},
/* The success handlers below are intended to be used
when a test case does not expect a particular call
to succed but otherwise does not require any special
handling of that situation beyond failing the test
case and logging why.*/
_expectedError: function(msg) {
ok(false, msg);
/* Since the original promise was technically resolved
we actually want to pass up a rejection to try and
end the test case sooner */
return Promise.reject();
},
_expectedRejectGetCamera: function(p) {
/* Copy handle to ensure it gets released at the end
of the test case */
self.camera = p.camera;
return this.expectedError('expected get camera to fail');
},
_expectedRejectConfigure: function(p) {
return this.expectedError('expected set configuration to fail');
},
_expectedRejectAutoFocus: function(p) {
return this.expectedError('expected auto focus to fail');
},
_expectedRejectTakePicture: function(p) {
return this.expectedError('expected take picture to fail');
},
_expectedRejectStartRecording: function(p) {
return this.expectedError('expected start recording to fail');
},
_expectedRejectStopRecording: function(p) {
return this.expectedError('expected stop recording to fail');
},
};
is(SpecialPowers.sanityCheck(), "foo", "SpecialPowers passed sanity check");

Просмотреть файл

@ -1,20 +0,0 @@
[DEFAULT]
support-files = camera_common.js
[test_camera_configuration.html]
[test_camera_release.html]
[test_camera_auto_focus.html]
[test_camera_take_picture.html]
[test_camera_record.html]
skip-if = toolkit == 'gonk'
[test_camera_face_detection.html]
[test_camera_fake_parameters.html]
[test_camera_hardware_init_failure.html]
[test_camera.html]
skip-if = toolkit != 'gonk'
[test_camera_2.html]
skip-if = toolkit != 'gonk'
[test_camera_3.html]
skip-if = toolkit != 'gonk'
[test_bug1104913.html]
skip-if = toolkit != 'gonk'

Просмотреть файл

@ -1,81 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 1104913</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
recorderProfile: 'qvga',
pictureSize: {
width: 640,
height: 480
},
previewSize: {
width: 320,
height: 240
}
};
function onError(e) {
ok(false, "Error: " + JSON.stringify(e));
}
var Camera = {
cameraObj: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
start: function test_start() {
function getCamera_onSuccess(d) {
var camera = d.camera;
var cfg = d.configuration;
Camera.cameraObj = camera;
Camera.viewfinder.srcObject = camera;
Camera.viewfinder.play();
// Check the default configuration
ok(cfg.mode === config.mode, "Initial mode = " + cfg.mode);
ok(cfg.previewSize.width === config.previewSize.width &&
cfg.previewSize.height === config.previewSize.height,
"Initial preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
ok(cfg.pictureSize.width === config.pictureSize.width &&
cfg.pictureSize.height === config.pictureSize.height,
"Initial picture size = " + cfg.pictureSize.width + "x" + cfg.pictureSize.height);
ok(cfg.recorderProfile === config.recorderProfile,
"Initial recorder profile = '" + cfg.recorderProfile + "'");
SimpleTest.finish();
}
navigator.mozCameras.getCamera(whichCamera, {}).then(getCamera_onSuccess, onError);
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.srcObject = null;
if (Camera.cameraObj) {
Camera.cameraObj.release();
Camera.cameraObj = null;
}
});
Camera.start();
</script>
</body>
</html>

Просмотреть файл

@ -1,258 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for mozCameras.getCamera() with separate .setConfiguration() call</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var options = {
mode: 'picture',
recorderProfile: 'high',
previewSize: {
width: 320,
height: 240
}
};
var config = {
dateTime: Date.now() / 1000,
pictureSize: null,
fileFormat: 'jpeg',
rotation: 90
};
function onError(e) {
ok(false, "Error " + e);
}
var capabilities = [ 'previewSizes', 'pictureSizes', 'fileFormats', 'maxFocusAreas', 'minExposureCompensation',
'maxExposureCompensation', 'stepExposureCompensation', 'maxMeteringAreas', 'videoSizes',
'recorderProfiles', 'zoomRatios', 'isoModes'];
var Camera = {
cameraObj: null,
_recording: false,
_currentTest: null,
_autoFocusSupported: 0,
_manuallyFocused: false,
_flashmodes: null,
_pictureSizes: null,
_previewSizes: null,
_whiteBalanceModes: null,
_zoomRatios: null,
_sceneModes: null,
_focusModes: null,
_zoomRatios: null,
_testsCompleted: 0,
_shutter: 0,
_config: {
dateTime: Date.now() / 1000,
pictureSize: null,
fileFormat: 'jpeg',
rotation: 90
},
_tests: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
setFlashMode: function camera_setFlash(mode) {
this.cameraObj.flashMode = mode;
},
setFocus: function camera_setfocus(mode) {
this.cameraObj.focus = mode;
},
setZoom: function camera_setZoom(zoom) {
this.cameraObj.zoom = zoom;
},
getZoom: function camera_getZoom() {
return this.cameraObj.zoom;
},
getFileFormats: function camera_formats() {
this._fileFormats = this.cameraObj.capabilities.fileFormats;
},
getFlashModes: function camera_getFlash() {
this._flashmodes = this.cameraObj.capabilities.flashModes;
},
getFocusModes: function camera_getFocus() {
this._focusModes = this.cameraObj.capabilities.focusModes;
},
getSceneModes: function camera_getScene() {
this._sceneModes = this.cameraObj.capabilities.sceneModes;
},
getZoomRatios: function camera_getZoom() {
this._zoomRatios = this.cameraObj.capabilities.zoomRatios;
},
getWhiteBalance: function camera_white() {
this._whitebalanceModes = this.cameraObj.capabilities.whiteBalanceModes;
},
getPictureSizes: function camera_sizes() {
this._pictureSizes = this.cameraObj.capabilities.pictureSizes;
},
getPreviewSizes: function camera_preview() {
this._previewSizes = this.cameraObj.capabilities.previewSizes;
},
getZoomRatios: function camera_preview() {
this._zoomRatios = this.cameraObj.capabilities.zoomRatios;
},
takePictureSuccess: function taken_foto(blob) {
ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
ok("image/" + this._currentTest.fileFormat === blob.type, "Blob Type = " + blob.type);
},
takePictureEvent: function taken_foto_evt(e) {
var blob = e.data;
var img = new Image();
var test = this._currentTest;
var onPreviewStateChange = function(e) {
if (e.newState === 'started') {
ok(true, "viewfinder is ready and playing after resume");
Camera.cameraObj.removeEventListener('previewstatechange', onPreviewStateChange);
Camera._testsCompleted++;
if(Camera._testsCompleted == Camera._tests.length) {
ok(true, "test finishing");
SimpleTest.finish();
} else {
Camera.runTests();
}
}
}
Camera.cameraObj.addEventListener('previewstatechange', onPreviewStateChange);
img.onload = function Imgsize() {
ok(this.width == test.pictureSize.width, "The image taken has the width " +
this.width + " pictureSize width = " + test.pictureSize.width);
ok(this.height == test.pictureSize.height, "The image taken has the height " +
this.height + " picturesize height = " + test.pictureSize.height);
Camera.cameraObj.resumePreview();
}
ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
ok("image/" + test.fileFormat == blob.type, "Blob Type = " + blob.type);
img.src = window.URL.createObjectURL(blob);
},
shutter: function onShutter () {
Camera._shutter++;
ok(Camera._shutter == (Camera._testsCompleted + 1), "on Shutter has been called " +
Camera._shutter + " times");
},
onReady: function onReady() {
var camcap = Camera.cameraObj.capabilities;
var tests = {};
for (var prop in capabilities) {
prop = capabilities[prop];
ok(camcap[prop] || isFinite(camcap[prop]) || camcap[prop] == null, "Camera Capability: " +
prop + " is exposed, value = " + JSON.stringify(camcap[prop]));
}
ok(camcap.maxMeteringAreas >= 0, "maxMeteringAreas = " + camcap.maxMeteringAreas);
ok(camcap.maxFocusAreas >= 0, "maxFocusAreas = " + camcap.maxFocusAreas);
for (var prop in camcap) {
if(camcap[prop] && camcap[prop].length > 1) {
tests[prop] = camcap[prop];
}
}
Camera.getPictureSizes();
Camera.getPreviewSizes();
Camera.getFileFormats();
Camera.getFocusModes();
Camera.getZoomRatios();
ok(Camera._previewSizes.length > 0, "previewSizes length = " + Camera._previewSizes.length);
ok(Camera._pictureSizes.length > 0, "picturesizes length = " + Camera._pictureSizes.length);
ok(Camera._fileFormats.length > 0, "file formats length = " + Camera._fileFormats.length);
ok(camcap.isoModes.length == 0, "ISO modes length = " + camcap.isoModes.length);
// The emulator doesn't support zoom, so these parameters will be very constrained
// For more ambitious tests, see test_camera_fake_parameters.html
ok(Camera._zoomRatios.length == 1, "zoom ratios length = " + Camera._zoomRatios.length);
ok(Camera.cameraObj.zoom == 1.0, "zoom = " + Camera.cameraObj.zoom);
// Test snapping to supported values
Camera.cameraObj.zoom = 0.9;
ok(Camera.cameraObj.zoom == 1.0, "zoom (lower limit) = " + Camera.cameraObj.zoom);
Camera.cameraObj.zoom = 1.1;
ok(Camera.cameraObj.zoom == 1.0, "zoom (upper limit) = " + Camera.cameraObj.zoom);
// Check image quality handling
Camera.cameraObj.pictureQuality = 0.0;
ok(Camera.cameraObj.pictureQuality == 0.0, "picture quality = " + Camera.cameraObj.pictureQuality);
Camera.cameraObj.pictureQuality = -0.1;
ok(Camera.cameraObj.pictureQuality == 0.0, "picture quality (minimum limit) = " + Camera.cameraObj.pictureQuality);
Camera.cameraObj.pictureQuality = -Math.pow(2, 80);
ok(Camera.cameraObj.pictureQuality == 0.0, "picture quality (BIG negative) = " + Camera.cameraObj.pictureQuality);
Camera.cameraObj.pictureQuality = 1.0;
ok(Camera.cameraObj.pictureQuality == 1.0, "picture quality = " + Camera.cameraObj.pictureQuality);
Camera.cameraObj.pictureQuality = 1.1;
ok(Camera.cameraObj.pictureQuality == 1.0, "picture quality (maximum limit) = " + Camera.cameraObj.pictureQuality);
Camera.cameraObj.pictureQuality = Math.pow(2, 80);
ok(Camera.cameraObj.pictureQuality == 1.0, "picture quality (BIG positive) = " + Camera.cameraObj.pictureQuality);
Camera._tests = new Array();
for (var i in Camera._pictureSizes) {
for (var l in Camera._fileFormats) {
var config = {
pictureSize: Camera._pictureSizes[i],
fileFormat: Camera._fileFormats[l]
};
Camera._tests.push(config);
}
}
Camera.runTests();
},
runTests: function run_tests() {
var test = this._tests[this._testsCompleted];
this._currentTest = test;
Camera.setFlashMode(test.flashMode);
config.fileFormat = test.fileFormat;
config.pictureSize = test.pictureSize;
ok(true, "testing picture size " + JSON.stringify(config.pictureSize));
Camera.cameraObj.takePicture(config).then(this.takePictureSuccess.bind(this), onError);
},
onConfigChange: function onConfigChange(config) {
ok(config.mode === options.mode, "configuration mode = " + config.mode);
ok(config.recorderProfile === options.recorderProfile, "recorder profile = " + config.recorderProfile);
ok(config.previewSize.width === options.previewSize.width &&
config.previewSize.height === options.previewSize.height,
"preview size (w x h) = " + config.previewSize.width + " x " + config.previewSize.height);
},
onPreviewStateChange: function onPreviewStateChange(e) {
if (e.newState === 'started') {
ok(true, "viewfinder is ready and playing");
Camera.cameraObj.removeEventListener('previewstatechange', Camera.onPreviewStateChange);
Camera.onReady();
}
},
setUp: function setup_tests() {
function onSuccess(d) {
Camera.cameraObj = d.camera;
Camera.cameraObj.addEventListener('previewstatechange', Camera.onPreviewStateChange);
Camera.cameraObj.addEventListener('configurationchanged', Camera.onConfigChange);
Camera.cameraObj.addEventListener('shutter', Camera.shutter);
Camera.cameraObj.addEventListener('picture', Camera.takePictureEvent.bind(Camera));
Camera.viewfinder.srcObject = d.camera;
Camera.viewfinder.play();
SimpleTest.expectAssertions(0);
ok(true, "Camera Control object has been successfully initialized");
Camera.cameraObj.setConfiguration(options).then(Camera.onConfigChange, onError);
};
navigator.mozCameras.getCamera(whichCamera, null).then(onSuccess, onError);
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.srcObject = null;
Camera.cameraObj.release();
Camera.cameraObj = null;
});
Camera.setUp();
</script>
</body>
</html>

Просмотреть файл

@ -1,203 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for mozCameras.getCamera() using an initial configuration</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var options = {
mode: 'picture',
recorderProfile: 'high',
previewSize: {
width: 320,
height: 240
}
};
var config = {
dateTime: Date.now() / 1000,
pictureSize: null,
fileFormat: 'jpeg',
rotation: 90
};
function onError(e) {
ok(false, "Error " + e);
}
var capabilities = [ 'previewSizes', 'pictureSizes', 'fileFormats', 'maxFocusAreas', 'minExposureCompensation',
'maxExposureCompensation', 'stepExposureCompensation', 'maxMeteringAreas', 'videoSizes',
'recorderProfiles'];
var Camera = {
cameraObj: null,
_recording: false,
_currentTest: null,
_autoFocusSupported: 0,
_manuallyFocused: false,
_flashmodes: null,
_pictureSizes: null,
_previewSizes: null,
_whiteBalanceModes: null,
_zoomRatios: null,
_sceneModes: null,
_focusModes: null,
_testsCompleted: 0,
_shutter: 0,
_config: {
dateTime: Date.now() / 1000,
pictureSize: null,
fileFormat: 'jpeg',
rotation: 90
},
_tests: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
setFlashMode: function camera_setFlash(mode) {
this.cameraObj.flashMode = mode;
},
setFocus: function camera_setfocus(mode) {
this.cameraObj.focus = mode;
},
getFileFormats: function camera_formats() {
this._fileFormats = this.cameraObj.capabilities.fileFormats;
},
getFlashModes: function camera_getFlash() {
this._flashmodes = this.cameraObj.capabilities.flashModes;
},
getFocusModes: function camera_getFocus() {
this._focusModes = this.cameraObj.capabilities.focusModes;
},
getSceneModes: function camera_getScene() {
this._sceneModes = this.cameraObj.capabilities.sceneModes;
},
getZoomRatios: function camera_getZoom() {
this._zoomRatios = this.cameraObj.capabilities.zoomRatios;
},
getWhiteBalance: function camera_white() {
this._whitebalanceModes = this.cameraObj.capabilities.whiteBalanceModes;
},
getPictureSizes: function camera_sizes() {
this._pictureSizes = this.cameraObj.capabilities.pictureSizes;
},
getPreviewSizes: function camera_preview() {
this._previewSizes = this.cameraObj.capabilities.previewSizes;
},
takePictureSuccess: function taken_foto(blob) {
var img = new Image();
var test = this._currentTest;
img.onload = function Imgsize() {
ok(this.width == test.pictureSize.width, "The image taken has the width " +
this.width + " pictureSize width = " + test.pictureSize.width);
ok(this.height == test.pictureSize.height, "The image taken has the height " +
this.height + " picturesize height = " + test.pictureSize.height);
Camera._testsCompleted++;
if(Camera._testsCompleted == Camera._tests.length) {
ok(true, "test finishing");
SimpleTest.finish();
} else {
Camera.runTests();
}
}
ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
ok("image/" + test.fileFormat == blob.type, "Blob Type = " + blob.type);
img.src = window.URL.createObjectURL(blob);
},
shutter: function onShutter () {
Camera._shutter++;
ok(Camera._shutter == (Camera._testsCompleted + 1), "on Shutter has been called " +
Camera._shutter + " times");
},
onPreviewStateChange: function onPreviewStateChange(e) {
ok(true, "viewfinder state change " + e);
if (e.newState === 'started') {
ok(true, "viewfinder is ready and playing");
Camera.cameraObj.removeEventListener('previewstatechange', Camera.onPreviewStateChange);
Camera.onReady();
}
},
onReady: function onReady() {
var camcap = Camera.cameraObj.capabilities;
var tests = {};
for (var prop in capabilities) {
prop = capabilities[prop];
ok(camcap[prop] || isFinite(camcap[prop]) || camcap[prop] == null, "Camera Capability: " +
prop + " is exposed, value = " + JSON.stringify(camcap[prop]));
}
for (var prop in camcap) {
if(camcap[prop] && camcap[prop].length > 1) {
tests[prop] = camcap[prop];
}
}
Camera.getPictureSizes();
Camera.getPreviewSizes();
Camera.getFileFormats();
Camera.getFocusModes();
ok(Camera._previewSizes.length > 0, "previewSizes length = " + Camera._previewSizes.length);
ok(Camera._pictureSizes.length > 0, "picturesizes length = " + Camera._pictureSizes.length);
ok(Camera._fileFormats.length > 0, "file formats length = " + Camera._fileFormats.length);
Camera._tests = new Array();
for (var i in Camera._pictureSizes) {
for (var l in Camera._fileFormats) {
var config = {
pictureSize: Camera._pictureSizes[i],
fileFormat: Camera._fileFormats[l]
};
Camera._tests.push(config);
}
}
Camera.runTests();
},
runTests: function run_tests() {
var test = this._tests[this._testsCompleted];
this._currentTest = test;
Camera.setFlashMode(test.flashMode);
config.fileFormat = test.fileFormat;
config.pictureSize = test.pictureSize;
ok(true, "testing picture size " + JSON.stringify(config.pictureSize));
Camera.cameraObj.takePicture(config).then(this.takePictureSuccess.bind(this), onError);
},
setUp: function setup_tests() {
function onSuccess(d) {
var config = d.configuration;
ok(true, "Camera Control object has been successfully initialized");
ok(config.mode === options.mode, "configuration mode = " + config.mode);
ok(config.recorderProfile === options.recorderProfile, "recorder profile = " + config.recorderProfile);
ok(config.previewSize.width === options.previewSize.width &&
config.previewSize.height === options.previewSize.height,
"preview size (w x h) = " + config.previewSize.width + " x " + config.previewSize.height);
Camera.cameraObj = d.camera;
Camera.cameraObj.addEventListener('previewstatechange', Camera.onPreviewStateChange);
Camera.cameraObj.addEventListener('shutter', Camera.shutter);
Camera.viewfinder.srcObject = d.camera;
Camera.viewfinder.play();
SimpleTest.expectAssertions(0);
};
navigator.mozCameras.getCamera(whichCamera, options).then(onSuccess, onError);
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.srcObject = null;
Camera.cameraObj.release();
Camera.cameraObj = null;
});
Camera.setUp();
</script>
</body>
</html>

Просмотреть файл

@ -1,77 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for multiple calls to mozCameras.getCamera()</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var options = {
mode: 'picture',
recorderProfile: 'high',
previewSize: {
width: 352,
height: 288
}
};
function onError(e) {
ok(false, "Error " + e);
}
var Camera = {
cameraObj: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
onReady: function take_two() {
function onSuccess(d) {
ok(false, "Unexpectedly got second camera instance: " + d.config.toSource);
}
function onFailure(error) {
ok(true, "Correctly failed to get camera again");
SimpleTest.finish();
}
navigator.mozCameras.getCamera(whichCamera, options).then(onSuccess, onFailure);
},
onPreviewStateChange: function onPreviewStateChange(e) {
if (e.newState === 'started') {
ok(true, "viewfinder is ready and playing");
Camera.cameraObj.removeEventListener('previewstatechange', Camera.onPreviewStateChange);
Camera.onReady();
}
},
release: function release() {
cameraObj = null;
},
start: function run_test() {
function onSuccess(d) {
Camera.cameraObj = d.camera;
Camera.cameraObj.addEventListener('previewstatechange', Camera.onPreviewStateChange);
Camera.viewfinder.srcObject = d.camera;
Camera.viewfinder.play();
};
navigator.mozCameras.getCamera(whichCamera, options).then(onSuccess, onError);
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.srcObject = null;
Camera.cameraObj.release();
Camera.cameraObj = null;
});
Camera.start();
</script>
</body>
</html>

Просмотреть файл

@ -1,238 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for auto focus</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var suite = new CameraTestSuite();
/* Each discrete test case can be added to the test queue here.
They won't be run until you call suite setup and run. */
suite.test('auto-focus-failures', function() {
function startAutoFocusFail(p) {
suite.hw.attach({
autoFocus: function() {
suite.hw.fireAutoFocusComplete(false);
}
});
return suite.camera.autoFocus();
}
function resolveAutoFocusFail(focused) {
ok(!focused, 'autoFocus() should be unfocused: ' + focused);
}
function startAutoFocusError(p) {
suite.hw.attach({
autoFocus: function() {
throw SpecialPowers.Cr.NS_ERROR_FAILURE;
}
});
return suite.camera.autoFocus();
}
function rejectAutoFocusError(e) {
ok(e.name === 'NS_ERROR_FAILURE', 'autoFocus() should fail: ' + e);
}
/* This is the promise chain which drives the test execution.
suite.getCamera
This returns a promise which is resolved when the suite
acquires the camera object (i.e. returns as if one
called cameraManager.getCamera() directly). It saves
the CameraControl reference in suite.camera and will
automatically release it for you when the test is
completed.
.then(startAutoFocusFail, suite.rejectGetCamera)
If the getCamera promise is resolved, startAutoFocusFail
will be called. That function attaches a handler to
the camera test hardware to intercept the auto focus
driver call so that we can change the behaviour to
trigger an OnAutoFocusComplete(false) event. It then
calls camera.autoFocus() and returns the promise for
that camera call so that the next promise in the chain
can block waiting for that promise to be fulfilled.
If the getCamera promise is rejected,
suite.rejectGetCamera will be called. This is a helper
handler provided by the test suite; it will log
a get camera failure and fail the test via ok, and
return a new promise rejecting *without* an error
object (i.e. promise parameter is undefined). This is
important because all reject handlers further down
the promise chain will still be called due to the
failure. However since we replaced the promise with
an error object, with a promise without one, we can
use this to identify errors that have already been
handled.
.then(resolveAutoFocusFail, suite.rejectAutoFocus)
If the suite.camera.autoFocus() promise is resolved,
resolveAutoFocusFail will be called. That function
simply verifies the result from the autoFocus() call.
It should be false, given the modified behaviour we
gave the driver. Since it doesn't return a new promise
explicitly, it will generate a new promise which is
already resolved (without the focused state parameter,
will now be undefined to the next .then handler).
If the suite.camera.autoFocus() promise is rejected,
we want to fail the test case again, just like when
suite.getCamera() failed.
.then(startAutoFocusError)
Assuming the first suite.camera.autoFocus() promise
was resolved, startAutoFocusError will be called.
That function is similar to startAutoFocusFail but
now it throws an error in the intercepted auto focus
driver call in order to trigger an OnUserError(kAutoFocus)
event. It then calls and returns the promise from
suite.camera.autoFocus().
.then(suite.expectedRejectAutoFocus, rejectAutoFocusError)
Now we are expecting the previous suite.camera.autoFocus()
promise to be rejected, which would call
rejectAutoFocusError. This simply verifies that we
got the error we expected.
If, on the other hand, it somehow succeeded, we
let suite.expectedRejectAutoFocus handle it, which
similar to the suite.rejectAutoFocus method, will
fail and return an empty rejected promise.
Note that this method itself returns the promise chain.
This allows the test suite to 1) capture any unhandled
errors in the promise chain and ensure the test case
fails as a result, and 2) perform any cleanup operations
such as resetting low memory state, releasing the camera,
etc, before starting the next test.
*/
return suite.getCamera()
.then(startAutoFocusFail, suite.rejectGetCamera)
.then(resolveAutoFocusFail, suite.rejectAutoFocus)
.then(startAutoFocusError)
.then(suite.expectedRejectAutoFocus, rejectAutoFocusError)
});
suite.test('auto-focus-moving', function() {
function triggerAutoFocusMoving(p) {
var sync = new Promise(function(resolve, reject) {
function onEvent(e) {
suite.camera.removeEventListener('focus', onEvent);
ok(e.newState === 'focusing', 'autofocus event state focusing == ' + e.newState);
resolve();
}
suite.camera.addEventListener('focus', onEvent);
});
suite.hw.fireAutoFocusMoving(true);
return sync;
}
function waitAutoFocusComplete(p) {
var sync = new Promise(function(resolve, reject) {
function onEvent(e) {
suite.camera.removeEventListener('focus', onEvent);
ok(e.newState === 'focused', 'autofocus event state focused == ' + e.newState);
resolve();
}
suite.camera.addEventListener('focus', onEvent);
});
// Missing the fireAutoFocusComplete but it should timeout on its own
suite.hw.fireAutoFocusMoving(false);
return sync;
}
function runAutoFocusCycle(p) {
return triggerAutoFocusMoving(p)
.then(waitAutoFocusComplete);
}
/* If the driver doesn't supply an onAutoFocusComplete notification,
gecko will timeout and provide it. After three times, it will no
longer rely upon a timeout and fire it immediately. */
return suite.getCamera()
.then(runAutoFocusCycle)
.then(runAutoFocusCycle)
.then(runAutoFocusCycle)
.then(runAutoFocusCycle);
});
suite.test('auto-focus-interrupted', function() {
// bug 1022766
function triggerAutoFocus(p) {
return new Promise(function(resolve, reject) {
var firstCall = false;
var secondCall = false;
function end() {
if (firstCall && secondCall) {
resolve();
}
}
// It doesn't matter if the emulator supports focus or not;
// this is just testing the sequencing.
suite.camera.autoFocus().then(function(p) {
ok(false, "First call to autoFocus() succeeded unexpectedly");
firstCall = true;
end();
}, function(e) {
ok(e.name === 'NS_ERROR_IN_PROGRESS', 'First call to autoFocus() failed with: ' + e);
firstCall = true;
end();
});
suite.camera.autoFocus().then(function(p) {
ok(true, "Second call to autoFocus() succeeded");
secondCall = true;
end();
}, function(e) {
ok(false, "Second call to autoFocus() failed unexpectedly with: " + e);
secondCall = true;
end();
});
});
}
return suite.getCamera()
.then(triggerAutoFocus, suite.rejectGetCamera)
});
suite.test('cancel-auto-focus', function() {
function cancelAutoFocus(p) {
var promise = new Promise(function(resolve, reject) {
suite.hw.attach({
cancelAutoFocus: function() {
ok(true, 'got cancel auto focus');
resolve();
}
});
});
suite.camera.resumeContinuousFocus();
return promise;
}
return suite.getCamera()
.then(cancelAutoFocus, suite.rejectGetCamera);
});
suite.setup()
.then(suite.run);
</script>
</body>
</html>

Просмотреть файл

@ -1,598 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for camera configuration</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var suite = new CameraTestSuite();
function verifyConfig(cfg, expConfig)
{
ok(cfg.mode === expConfig.mode, "Configured mode = " + cfg.mode +
", expected = " + expConfig.mode);
ok(cfg.previewSize.width === expConfig.previewSize.width &&
cfg.previewSize.height === expConfig.previewSize.height,
"Configured preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height +
", expected = " + expConfig.previewSize.width + "x" + expConfig.previewSize.height);
ok(cfg.pictureSize.width === expConfig.pictureSize.width &&
cfg.pictureSize.height === expConfig.pictureSize.height,
"Configured picture size = " + cfg.pictureSize.width + "x" + cfg.pictureSize.height +
", expected = " + expConfig.pictureSize.width + "x" + expConfig.pictureSize.height);
ok(cfg.recorderProfile === expConfig.recorderProfile,
"Configured recorder profile = '" + cfg.recorderProfile + "'" +
", expected = '" + expConfig.recorderProfile + "'");
}
function setAndVerifyConfig(setConfig, expConfig)
{
return suite.getCamera(undefined, setConfig)
.catch(suite.rejectGetCamera)
.then(function(p) {
verifyConfig(p.configuration, expConfig);
});
}
suite.test('bad-initial-config', function() {
function getCamera() {
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
recorderProfile: 'foobar',
};
return navigator.mozCameras.getCamera(whichCamera, config);
}
function rejectGetCamera(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"getCamera() failed with: " + error.name);
return Promise.resolve();
}
return getCamera()
.then(suite.expectedRejectGetCamera, rejectGetCamera);
});
suite.test('start-unspecified', function() {
// bug 1037322
var cameraManager = navigator.mozCameras;
var whichCamera = cameraManager.getListOfCameras()[0];
var postConfig = {
mode: 'picture',
recorderProfile: 'low',
previewSize: {
width: 320,
height: 240
},
pictureSize: {
width: 320,
height: 240
}
};
function resolveGetCamera(p) {
suite.camera = p.camera;
// Check the default configuration
var cfg = p.configuration;
ok(cfg.mode === "unspecified", "Initial mode = " + cfg.mode);
ok(cfg.previewSize.width === 0 && cfg.previewSize.height === 0,
"Initial preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
ok(cfg.recorderProfile === "default",
"Initial recorder profile = '" + cfg.recorderProfile + "'");
}
function configure(p) {
// Apply our specific configuration
return suite.camera.setConfiguration(postConfig);
}
function resolveConfigure(cfg) {
// Check our specific configuration
verifyConfig(cfg, postConfig);
}
return cameraManager.getCamera(whichCamera, {mode: 'unspecified'})
.then(resolveGetCamera, suite.rejectGetCamera)
.then(configure)
.then(resolveConfigure, suite.rejectConfigure);
});
suite.test('picture-mode', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['preview-size-values'] = '640x480,320x240,1x1';
suite.hw.params['picture-size-values'] = '1280x960,640x480,320x240,1x1';
suite.hw.params['video-size-values'] = '320x240';
var setConfig = {
mode: 'picture',
previewSize: {
width: 640,
height: 480
}
};
var expConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 1280,
height: 960
}
};
var postConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 640,
height: 480
}
};
function syncPreview() {
return new Promise(function(resolve, reject) {
function onEvent(e) {
if (e.newState === 'started') {
resolve();
}
}
suite.camera.addEventListener('previewstatechange', onEvent);
});
}
function reconfigure(p) {
// The preview restarting confirms the configuration actually happened
var sync = new Promise(function(resolve, reject) {
var i = 0;
var expState = ['started', 'stopped', 'started'];
function onEvent(e) {
ok(e.newState === expState[i], 'preview event state ' + expState[i] +
' === ' + e.newState);
++i;
if (i === expState.length) { return; }
suite.camera.removeEventListener('previewstatechange', onEvent);
resolve();
}
suite.camera.addEventListener('previewstatechange', onEvent);
});
var configure = suite.camera.setConfiguration(postConfig)
.then(resolveReconfigure);
return Promise.all([sync, configure]);
}
function resolveReconfigure(cfg) {
verifyConfig(cfg, postConfig);
}
return setAndVerifyConfig(setConfig, expConfig)
.then(syncPreview)
.then(reconfigure);
});
suite.test('picture-mode-larger-picture-size', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['preview-size-values'] = '640x480,320x240,1x1';
suite.hw.params['picture-size-values'] = '1280x960,640x480,320x240,1x1';
suite.hw.params['video-size-values'] = '320x240';
var setConfig = {
mode: 'picture',
previewSize: {
width: 640,
height: 480
}
};
var expConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 1280,
height: 960
}
};
return setAndVerifyConfig(setConfig, expConfig);
});
suite.test('picture-mode-size-unsupported-big', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['preview-size-values'] = '640x480,320x240,1x1';
suite.hw.params['picture-size-values'] = '1280x960,640x480,320x240,1x1';
suite.hw.params['video-size-values'] = '320x240';
var setConfig = {
mode: 'picture',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 2000,
height: 2000
},
};
var expConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 1280,
height: 960
},
};
return setAndVerifyConfig(setConfig, expConfig);
});
suite.test('picture-mode-size-unsupported', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['preview-size-values'] = '640x480,320x240,1x1';
suite.hw.params['picture-size-values'] = '1280x960,640x480,320x240,100x100,1x1';
suite.hw.params['video-size-values'] = '320x240';
var setConfig = {
mode: 'picture',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 641,
height: 481,
},
};
var expConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 640,
height: 480
},
};
return setAndVerifyConfig(setConfig, expConfig);
});
suite.test('picture-mode-asr-mismatch', function() {
suite.hw.params['preview-size'] = '320x240';
suite.hw.params['picture-size'] = '640x480';
suite.hw.params['preview-size-values'] = '640x480,320x240,50x50';
suite.hw.params['picture-size-values'] = '1280x960,640x480,320x240,100x100';
suite.hw.params['video-size-values'] = '320x240';
var setConfig = {
mode: 'picture',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 100,
height: 100,
},
};
var expConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 50,
height: 50
},
pictureSize: {
width: 100,
height: 100,
},
};
return setAndVerifyConfig(setConfig, expConfig);
});
suite.test('picture-mode-update-video-size', function() {
suite.hw.params['preview-size'] = '320x240';
suite.hw.params['picture-size'] = '640x480';
suite.hw.params['video-size'] = '50x50';
suite.hw.params['preview-size-values'] = '640x480,320x240,50x50';
suite.hw.params['video-size-values'] = '1280x960,640x480,320x240,50x50';
suite.hw.params['picture-size-values'] = '1280x960,640x480,320x240,100x100';
var setConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 320,
height: 240
},
pictureSize: {
width: 320,
height: 240,
},
};
var expConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 320,
height: 240
},
pictureSize: {
width: 320,
height: 240,
},
};
function checkVideoSize(p) {
ok(suite.hw.params['video-size'] === '320x240', 'video size reset with picture mode switch');
}
return setAndVerifyConfig(setConfig, expConfig)
.then(checkVideoSize);
});
suite.test('picture-mode-no-update-video-size', function() {
suite.hw.params['preview-size'] = '320x240';
suite.hw.params['picture-size'] = '640x480';
suite.hw.params['video-size'] = '1280x960';
suite.hw.params['preview-size-values'] = '640x480,320x240,50x50';
suite.hw.params['video-size-values'] = '1280x960,640x480,320x240,50x50';
suite.hw.params['picture-size-values'] = '1280x960,640x480,320x240,100x100';
var setConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 640,
height: 480,
},
};
var expConfig = {
mode: 'picture',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
},
pictureSize: {
width: 640,
height: 480,
},
};
function checkVideoSize(p) {
ok(suite.hw.params['video-size'] === '1280x960', 'video size retained with picture mode switch');
}
return setAndVerifyConfig(setConfig, expConfig)
.then(checkVideoSize);
});
suite.test('video-mode-preview-size', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['recording-hint'] = 'false';
suite.hw.params['preview-size-values'] = '640x480,320x240,1x1';
suite.hw.params['picture-size-values'] = '700x700,640x480,320x240,1x1';
var setConfig = {
mode: 'video',
recorderProfile: 'qvga'
};
var expConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 320,
height: 240
},
pictureSize: {
width: 700,
height: 700
}
};
function checkRecordingHint(p) {
ok(suite.hw.params['recording-hint'] === 'true', 'recording hint enabled');
}
return setAndVerifyConfig(setConfig, expConfig)
.then(checkRecordingHint);
});
suite.test('video-mode', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['video-size'] = '1x1';
suite.hw.params['recording-hint'] = 'false';
suite.hw.params['preferred-preview-size-for-video'] = '640x480';
suite.hw.params['preview-size-values'] = '640x480,320x240,1x1';
suite.hw.params['picture-size-values'] = '700x700,640x480,320x240,1x1';
suite.hw.params['video-size-values'] = '700x700,640x480,320x240,1x1';
var setConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 320,
height: 240
}
};
var expConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 320,
height: 240
},
pictureSize: {
width: 700,
height: 700
}
};
function checkRecordingHint(p) {
ok(suite.hw.params['recording-hint'] === 'true', 'recording hint enabled');
}
return setAndVerifyConfig(setConfig, expConfig)
.then(checkRecordingHint);
});
suite.test('video-mode-larger-preview-size', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['video-size'] = '1x1';
suite.hw.params['recording-hint'] = 'false';
suite.hw.params['preferred-preview-size-for-video'] = '640x480';
suite.hw.params['preview-size-values'] = '640x480,320x240,1x1';
suite.hw.params['picture-size-values'] = '700x700,640x480,320x240,1x1';
suite.hw.params['video-size-values'] = '700x700,640x480,320x240,1x1';
var setConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 640,
height: 480
}
};
var expConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 320,
height: 240
},
pictureSize: {
width: 700,
height: 700
}
};
return setAndVerifyConfig(setConfig, expConfig);
});
suite.test('video-mode-smaller-preview-size', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['video-size'] = '1x1';
suite.hw.params['recording-hint'] = 'false';
suite.hw.params['preferred-preview-size-for-video'] = '640x480';
suite.hw.params['preview-size-values'] = '640x480,320x240,160x120,1x1';
suite.hw.params['picture-size-values'] = '700x700,640x480,320x240,1x1';
suite.hw.params['video-size-values'] = '700x700,640x480,320x240,1x1';
var setConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 160,
height: 120
}
};
var expConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 160,
height: 120
},
pictureSize: {
width: 700,
height: 700
}
};
return setAndVerifyConfig(setConfig, expConfig);
});
suite.test('video-mode-larger-preview-size-than-preferred', function() {
suite.hw.params['preview-size'] = '1x1';
suite.hw.params['picture-size'] = '1x1';
suite.hw.params['video-size'] = '1x1';
suite.hw.params['recording-hint'] = 'false';
suite.hw.params['preferred-preview-size-for-video'] = '200x200';
suite.hw.params['preview-size-values'] = '640x480,320x240,160x120,1x1';
suite.hw.params['picture-size-values'] = '700x700,640x480,320x240,1x1';
suite.hw.params['video-size-values'] = '700x700,640x480,400x400,320x240,1x1';
var setConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 320,
height: 240
}
};
var expConfig = {
mode: 'video',
recorderProfile: 'qvga',
previewSize: {
width: 160,
height: 120
},
pictureSize: {
width: 700,
height: 700
}
};
return setAndVerifyConfig(setConfig, expConfig);
});
suite.setup()
.then(suite.run);
</script>
</body>
</html>

Просмотреть файл

@ -1,357 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=965420
-->
<head>
<title>Bug 965420 - Test camera hardware API for face detection</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=965420">Mozilla Bug 965420</a>
<video id="viewfinder" width = "200" height = "200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
function compareFaces(aFaces, expected)
{
ok(aFaces, "have detected faces object");
ok(aFaces.length == expected.faces.length,
"expected=" + expected.faces.length + ", got=" + aFaces.length);
aFaces.forEach(function (face, index) {
let result = compareFace(face, expected.faces[index]);
ok(result === "ok", "face check: " + result);
if (result !== "ok") {
return false;
}
});
return true;
}
function compareFace(aFace, expected)
{
if (aFace.id != expected.id) {
return "expected face.id=" + expected.id + ", got=" + aFace.id;
}
if (aFace.score != expected.score) {
return "expected face.score=" + expected.score + ", got=" + aFace.score;
}
if (!aFace.bounds) {
return "face.bounds is missing";
}
if (aFace.bounds.left != expected.bounds.left ||
aFace.bounds.top != expected.bounds.top ||
aFace.bounds.right != expected.bounds.right ||
aFace.bounds.bottom != expected.bounds.bottom) {
return "expected face.bounds=" + expected.bounds.toSource() +
", got=({left:" + aFace.bounds.left + ", top:" + aFace.bounds.top + ", right:" + aFace.bounds.right + ", bottom:" + aFace.bounds.bottom + "})";
}
if (aFace.leftEye && !expected.leftEye) {
return "expected null face.leftEye, got=({x:" + aFace.leftEye.x + ", y:" + aFace.leftEye.y + "})";
}
if (!aFace.leftEye && expected.leftEye) {
return "expected face.leftEye=" + expected.leftEye.toSource() + ", got null leftEye";
}
if (aFace.leftEye && expected.leftEye &&
(aFace.leftEye.x != expected.leftEye.x || aFace.leftEye.y != expected.leftEye.y)) {
return "expected face.leftEye=" + expected.leftEye.toSource() +
", got=({x:" + aFace.leftEye.x + ", y:" + aFace.leftEye.y + "})";
}
if (aFace.rightEye && !expected.rightEye) {
return "expected null face.rightEye, got=({x:" + aFace.rightEye.x + ", y:" + aFace.rightEye.y + "})";
}
if (!aFace.rightEye && expected.rightEye) {
return "expected face.rightEye=" + expected.rightEye.toSource() + ", got null rightEye";
}
if (aFace.rightEye && expected.rightEye &&
(aFace.rightEye.x != expected.rightEye.x || aFace.rightEye.y != expected.rightEye.y)) {
return "expected face.rightEye=" + expected.rightEye.toSource() +
", got=({x:" + aFace.rightEye.x + ", y:" + aFace.rightEye.y + "})";
}
if (aFace.mouth && !expected.mouth) {
return "expected null face.mouth, got=({x:" + aFace.mouth.x + ", y:" + aFace.mouth.y + "})";
}
if (!aFace.mouth && expected.mouth) {
return "expected face.mouth=" + expected.mouth.toSource() + ", got null mouth";
}
if (aFace.mouth && expected.mouth &&
(aFace.mouth.x != expected.mouth.x || aFace.mouth.y != expected.mouth.y)) {
return "expected face.mouth=" + expected.mouth.toSource() +
", got=({x:" + aFace.mouth.x + ", y:" + aFace.mouth.y + "})";
}
return "ok";
}
var suite = new CameraTestSuite();
suite.test('face-detection-op', function() {
function start(p) {
return new Promise(function(resolve, reject) {
suite.hw.attach({
startFaceDetection: function() {
ok(true, "startFaceDetection() requested");
resolve();
}
});
try {
suite.camera.startFaceDetection();
ok(true, "startFaceDetection() succeeded");
} catch(e) {
ok(false, "startFaceDetection() failed with: " + e.name);
resolve();
}
});
}
function stop(p) {
return new Promise(function(resolve, reject) {
suite.hw.attach({
stopFaceDetection: function() {
ok(true, "stopFaceDetection() requested");
resolve();
}
});
try {
suite.camera.stopFaceDetection();
ok(true, "stopFaceDetection() succeeded");
} catch(e) {
ok(false, "stopFaceDetection() failed with: " + e.name);
resolve();
}
});
}
function startFailure(p) {
return new Promise(function(resolve, reject) {
suite.hw.attach({
startFaceDetection: function() {
ok(true, "startFaceDetection() requested and failed");
resolve();
throw SpecialPowers.Cr.NS_ERROR_FAILURE;
}
});
try {
suite.camera.startFaceDetection();
ok(true, "startFaceDetection() succeeded and error swallowed");
} catch(e) {
ok(false, "startFaceDetection() failed with: " + e.name);
resolve();
}
});
}
function stopFailure(p) {
return new Promise(function(resolve, reject) {
suite.hw.attach({
stopFaceDetection: function() {
ok(true, "stopFaceDetection() requested and failed");
resolve();
throw SpecialPowers.Cr.NS_ERROR_FAILURE;
}
});
try {
suite.camera.stopFaceDetection();
ok(true, "stopFaceDetection() succeeded and error swallowed");
} catch(e) {
ok(false, "stopFaceDetection() failed with: " + e.name);
resolve();
}
});
}
return suite.getCamera()
.then(start, suite.rejectGetCamera)
.then(stop)
.then(startFailure)
.then(stopFailure);
});
suite.test('face-detection', function() {
function detectFace(msg, given, expected) {
if (expected === undefined) {
expected = given;
}
var sync = new Promise(function(resolve, reject) {
function onEvent(evt) {
try {
suite.camera.removeEventListener('facesdetected', onEvent);
ok(compareFaces(evt.faces, expected),
"facedetected event received " + msg + " correctly");
resolve();
} catch(e) {
reject(e);
}
}
suite.camera.addEventListener('facesdetected', onEvent);
});
suite.hw.fireFacesDetected(given);
return sync;
}
function detectOneFace(p) {
return detectFace('one-face',
{
faces: [ {
id: 1,
score: 2,
bounds: {
left: 3,
top: 4,
right: 5,
bottom: 6
},
leftEye: {
x: 7,
y: 8
},
rightEye: {
x: 9,
y: 10
},
mouth: {
x: 11,
y: 12
}
} ]
}
);
}
function detectTwoFaces(p) {
return detectFace('two-faces',
{
faces: [ {
id: 1,
score: 2,
bounds: {
left: 3,
top: 4,
right: 5,
bottom: 6
},
leftEye: {
x: 7,
y: 8
},
rightEye: {
x: 9,
y: 10
},
mouth: {
x: 11,
y: 12
}
},
{
id: 13,
score: 14,
bounds: {
left: 15,
top: 16,
right: 17,
bottom: 18
},
leftEye: {
x: 19,
y: 20
},
rightEye: {
x: 21,
y: 22
},
mouth: {
x: 23,
y: 24
}
} ]
}
);
}
function detectOneFaceNoFeatures() {
return detectFace('one-face-no-features',
{
faces: [ {
id: 1,
score: 100,
bounds: {
left: 3,
top: 4,
right: 5,
bottom: 6
},
leftEye: null,
rightEye: null,
mouth: null
} ]
}
);
}
function detectNoFaces() {
return detectFace('no-faces',
{
faces: []
}
);
}
function detectOneFaceExcessScore() {
return detectFace('one-face-excess-score',
{
faces: [ {
id: 1,
score: 120,
bounds: {
left: 3,
top: 4,
right: 5,
bottom: 6
},
leftEye: null,
rightEye: null,
mouth: null
} ]
},
{
faces: [ {
id: 1,
score: 100,
bounds: {
left: 3,
top: 4,
right: 5,
bottom: 6
},
leftEye: null,
rightEye: null,
mouth: null
} ]
}
);
}
return suite.getCamera()
.then(detectOneFace, suite.rejectGetCamera)
.then(detectTwoFaces)
.then(detectOneFaceNoFeatures)
.then(detectNoFaces)
.then(detectOneFaceExcessScore);
});
suite.setup()
.then(suite.run);
</script>
</body>
</html>

Просмотреть файл

@ -1,559 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for CameraParameters we need to fake</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=976802">Mozilla Bug 976802</a>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var suite = new CameraTestSuite();
suite.test('fake-zoom', function() {
suite.hw.params['zoom-ratios'] = '100,150,200,300,400';
suite.hw.params['max-zoom'] = '4';
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.zoomRatios.length == 5, "zoom ratios length = " + cap.zoomRatios.length);
// test individual zoom ratios
cap.zoomRatios.forEach(function(zoom, index) {
cam.zoom = zoom;
ok(cam.zoom === zoom,
"zoom[" + index + "] = " + zoom + "x, cam.zoom = " + cam.zoom + "x");
});
// test below-lower-bound zoom ratio
var zoom = cap.zoomRatios[0] - 0.1;
cam.zoom = zoom;
ok(cam.zoom === cap.zoomRatios[0],
zoom + "x zoom clamps to minimum: " +
cap.zoomRatios[0] + "x, cam.zoom = " + cam.zoom + "x");
// test above-upper-bound zoom ratio
zoom = cap.zoomRatios.slice(-1)[0] + 1.0;
cam.zoom = zoom;
ok(cam.zoom === cap.zoomRatios.slice(-1)[0],
zoom + "x zoom clamps to maximum: " + cap.zoomRatios.slice(-1)[0] +
"x, cam.zoom = " + cam.zoom + "x");
// test snapping to supported zoom ratio
if (cap.zoomRatios.length > 1) {
zoom = (cap.zoomRatios[0] + cap.zoomRatios[1]) / 2;
cam.zoom = zoom;
ok(cam.zoom === cap.zoomRatios[0],
zoom + "x zoom rounded down to: " + cap.zoomRatios[0] +
"x, cam.zoom = " + cam.zoom + "x");
}
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-zoom-out-of-order', function() {
// We expect the camera library to give us zoom ratios in order; if
// it doesn't we ignore the list and just return 1x support.
suite.hw.params['zoom-ratios'] = '100,150,200,400,300';
suite.hw.params['max-zoom'] = '4';
function resolve(p) {
var cap = suite.camera.capabilities;
ok(cap.zoomRatios.length == 1, "zoom ratios length = " + cap.zoomRatios.length);
ok(cap.zoomRatios[0] == 1.0, "only supported zoom = " + cap.zoomRatios[0] + "x");
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-high-memory-platform', function() {
suite.hw.params['scene-mode-values'] = 'none,snow,beach,hdr,nothdr';
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.sceneModes.length == 5, "scene modes length = " + cap.zoomRatios.length);
// make sure expected values are present and can be set
[ "none", "snow", "beach", "hdr", "nothdr" ].forEach(function(mode) {
ok(cap.sceneModes.indexOf(mode) != -1, "Scene mode '" + mode + "' is present");
cam.sceneMode = mode;
ok(cam.sceneMode == mode, "Scene mode '" + cam.sceneMode + "' is set");
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-low-memory-platform', function() {
suite.hw.params['scene-mode-values'] = 'none,hdr,snow,beach,hdr,nothdr';
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.sceneModes.length == 4, "scene modes length = " + cap.zoomRatios.length);
// make sure expected values are present and can be set
[ "none", "snow", "beach", "nothdr" ].forEach(function(mode) {
ok(cap.sceneModes.indexOf(mode) != -1, "Scene mode '" + mode + "' is present");
cam.sceneMode = mode;
ok(cam.sceneMode == mode, "Scene mode '" + cam.sceneMode + "' is set");
});
// make sure unsupported values have been removed, and can't be set
var sceneMode = cam.sceneMode;
[ "hdr" ].forEach(function(mode) {
ok(cap.sceneModes.indexOf(mode) == -1, "Scene mode '" + mode + "' is not present");
try {
cam.sceneMode = mode;
} catch(e) {
}
ok(cam.sceneMode != mode, "Scene mode '" + cam.sceneMode + "' is still set, '"
+ mode + "' rejected");
});
ok(cam.sceneMode == sceneMode, "Scene mode '" + cam.sceneMode + "' is still set");
}
return suite.setLowMemoryPlatform()
.then(suite.getCamera)
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-effects', function() {
var supportedValues = ['none', 'mono', 'negative', 'solarize', 'sepia', 'posterize', 'whiteboard', 'blackboard', 'aqua'];
suite.hw.params['effect'] = 'none';
suite.hw.params['effect-values'] = supportedValues.join(',');
function resolve(p) {
var cap = suite.camera.capabilities;
ok(cap.effects.length == supportedValues.length, "Effects length = " + cap.effects.length);
// make sure expected values are present
supportedValues.forEach(function(val) {
ok(cap.effects.indexOf(val) != -1, "Effect '" + val + "' is present");
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-flash-modes', function() {
var supportedValues = ['off', 'auto', 'on', 'red-eye', 'torch'];
suite.hw.params['flash-mode'] = 'auto';
suite.hw.params['flash-mode-values'] = supportedValues.join(',');
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.flashModes.length == supportedValues.length, "Flash modes length = " + cap.flashModes.length);
// make sure expected values are present
supportedValues.forEach(function(val) {
ok(cap.flashModes.indexOf(val) != -1, "Flash mode '" + val + "' is present");
});
// test setters/getters
cap.flashModes.forEach(function(val, index) {
cam.flashMode = val;
ok(cam.flashMode === val,
"Flash Mode [" + index + "] = " + val + ", cam.flashMode = " + cam.flashMode);
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-focus-modes', function() {
var supportedValues = ['auto', 'infinity', 'macro', 'fixed', 'edof', 'continuous-video'];
suite.hw.params['focus-mode'] = 'auto';
suite.hw.params['focus-mode-values'] = supportedValues.join(',');
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.focusModes.length == supportedValues.length, "Focus modes length = " + cap.focusModes.length);
// make sure expected values are present
supportedValues.forEach(function(val) {
ok(cap.focusModes.indexOf(val) != -1, "Focus mode '" + val + "' is present");
});
// test setters/getters
cap.focusModes.forEach(function(val, index) {
cam.focusMode = val;
ok(cam.focusMode === val,
"Focus Mode [" + index + "] = " + val + ", cam.focusMode = " + cam.focusMode);
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-white-balance-modes', function() {
var supportedValues = ['auto', 'incandescent', 'fluorescent', 'warm-fluorescent', 'daylight', 'cloudy-daylight', 'twilight', 'shade'];
suite.hw.params['whitebalance'] = 'auto';
suite.hw.params['whitebalance-values'] = supportedValues.join(',');
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.whiteBalanceModes.length == supportedValues.length, "White balance modes length = " + cap.whiteBalanceModes.length);
// make sure expected values are present
supportedValues.forEach(function(val) {
ok(cap.whiteBalanceModes.indexOf(val) != -1, "White balance mode '" + val + "' is present");
});
// test setters/getters
cap.whiteBalanceModes.forEach(function(val, index) {
cam.whiteBalanceMode = val;
ok(cam.whiteBalanceMode === val,
"White balance mode [" + index + "] = " + val + ", cam.whiteBalanceMode = " + cam.whiteBalanceMode);
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-video-sizes', function() {
var supportedValues = ['auto', 'incandescent', 'fluorescent', 'warm-fluorescent', 'daylight', 'cloudy-daylight', 'twilight', 'shade'];
suite.hw.params['whitebalance'] = 'auto';
suite.hw.params['whitebalance-values'] = supportedValues.join(',');
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.whiteBalanceModes.length == supportedValues.length, "White balance modes length = " + cap.whiteBalanceModes.length);
// make sure expected values are present
supportedValues.forEach(function(val) {
ok(cap.whiteBalanceModes.indexOf(val) != -1, "White balance mode '" + val + "' is present");
});
// test setters/getters
cap.whiteBalanceModes.forEach(function(val, index) {
cam.whiteBalanceMode = val;
ok(cam.whiteBalanceMode === val,
"White balance mode [" + index + "] = " + val + ", cam.whiteBalanceMode = " + cam.whiteBalanceMode);
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-iso', function() {
suite.hw.params['iso'] = 'auto';
suite.hw.params['iso-values'] = 'auto,ISO_HJR,ISO100,foo,ISObar,ISO150moz,ISO200,400,ISO800,1600';
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.isoModes.length == 7, "ISO modes length = " + cap.isoModes.length);
// make sure we're not leaking any unexpected values formats
[ "ISO_HJR", "_HJR", "HJR", "ISO100", "ISO200", "ISO800" ].forEach(function(iso) {
ok(cap.isoModes.indexOf(iso) == -1, "ISO mode '" + iso + "' does not appear");
});
// make sure any weird values are dropped entirely
[ "foo", "ISObar", "bar", "ISO150moz", "150moz", "150" ].forEach(function(iso) {
ok(cap.isoModes.indexOf(iso) == -1, "Unknown ISO mode '" + iso + "' is ignored");
});
// make sure expected values are present
[ "auto", "hjr", "100", "200", "400", "800", "1600" ].forEach(function(iso) {
ok(cap.isoModes.indexOf(iso) != -1, "ISO mode '" + iso + "' is present");
});
// test setters/getters for individual ISO modes
cap.isoModes.forEach(function(iso, index) {
cam.isoMode = iso;
ok(cam.isoMode === iso,
"ISO[" + index + "] = " + iso + ", cam.iso = " + cam.isoMode);
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-faces-detected', function() {
suite.hw.params['max-num-detected-faces-hw'] = '5';
function resolve(p) {
var cap = suite.camera.capabilities;
ok(cap.maxDetectedFaces == 5, "maxDetectedFaces = " + cap.maxDetectedFaces);
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-metering-areas', function() {
suite.hw.params['max-num-metering-areas'] = '1';
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.maxMeteringAreas == 1, "maxMeteringAreas = " + cap.maxMeteringAreas);
cam.setMeteringAreas([
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getMeteringAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -500, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 500, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -500, "area[0] left = " + areas[0].left);
ok(areas[0].right == 500, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 100, "area[0] weight = " + areas[0].weight);
cam.setMeteringAreas([
{top: -501, bottom: 502, left: -503, right: 504, weight: 105},
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getMeteringAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -501, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 502, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -503, "area[0] left = " + areas[0].left);
ok(areas[0].right == 504, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 105, "area[0] weight = " + areas[0].weight);
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-focus-areas', function() {
suite.hw.params['max-num-focus-areas'] = '1';
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.maxFocusAreas == 1, "maxFocusAreas = " + cap.maxFocusAreas);
cam.setFocusAreas([
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getFocusAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -500, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 500, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -500, "area[0] left = " + areas[0].left);
ok(areas[0].right == 500, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 100, "area[0] weight = " + areas[0].weight);
cam.setFocusAreas([
{top: -501, bottom: 502, left: -503, right: 504, weight: 105},
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getFocusAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -501, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 502, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -503, "area[0] left = " + areas[0].left);
ok(areas[0].right == 504, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 105, "area[0] weight = " + areas[0].weight);
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('fake-exposure-compensation', function() {
suite.hw.params['max-num-focus-areas'] = '1';
suite.hw.params['exposure-compensation'] = '-1';
suite.hw.params['max-exposure-compensation'] = '6';
suite.hw.params['min-exposure-compensation'] = '-6';
suite.hw.params['exposure-compensation-step'] = '0.5'
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.exposureCompensationStep == 0.5,
"exposureCompensationStep = " + cap.exposureCompensationStep);
ok(cap.minExposureCompensation == -3.0,
"minExposureCompensation = " + cap.minExposureCompensation);
ok(cap.maxExposureCompensation == 3.0,
"maxExposureCompensation = " + cap.maxExposureCompensation);
ok(cam.exposureCompensation == -0.5,
"exposureCompensation = " + cam.exposureCompensation);
// Check normal values
cam.exposureCompensation = 0.0;
ok(cam.exposureCompensation == 0.0,
"exposureCompensation = " + cam.exposureCompensation);
cam.exposureCompensation = cap.minExposureCompensation;
ok(cam.exposureCompensation == cap.minExposureCompensation,
"exposureCompensation(min) = " + cam.exposureCompensation);
cam.exposureCompensation = cap.maxExposureCompensation;
ok(cam.exposureCompensation == cap.maxExposureCompensation,
"exposureCompensation(max) = " + cam.exposureCompensation);
// Rounding
cam.exposureCompensation = 1.24;
ok(cam.exposureCompensation == 1.0,
"exposureCompensation(1.24) = " + cam.exposureCompensation);
cam.exposureCompensation = 1.25;
ok(cam.exposureCompensation == 1.5,
"exposureCompensation(1.25) = " + cam.exposureCompensation);
cam.exposureCompensation = -1.24;
ok(cam.exposureCompensation == -1.0,
"exposureCompensation(-1.24) = " + cam.exposureCompensation);
cam.exposureCompensation = -1.25;
ok(cam.exposureCompensation == -1.5,
"exposureCompensation(-1.25) = " + cam.exposureCompensation);
// Check out-of-bounds values
cam.exposureCompensation = cap.minExposureCompensation - 1.0;
ok(cam.exposureCompensation == cap.minExposureCompensation,
"exposureCompensation(min - 1.0) = " + cam.exposureCompensation);
cam.exposureCompensation = cap.maxExposureCompensation + 1.0;
ok(cam.exposureCompensation == cap.maxExposureCompensation,
"exposureCompensation(max + 1.0) = " + cam.exposureCompensation);
// Check extreme values
cam.exposureCompensation = -1 * Math.pow(2, 32);
ok(cam.exposureCompensation == cap.minExposureCompensation,
"exposureCompensation(-2^32) = " + cam.exposureCompensation);
cam.exposureCompensation = Math.pow(2, 32);
ok(cam.exposureCompensation == cap.maxExposureCompensation,
"exposureCompensation(2^32) = " + cam.exposureCompensation);
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('bug-1054803', function() {
// The important part of this test is that 3264 * 1836 = 5,992,704 = 2448 * 2448,
// so we need to make sure that the size-matching algorithm picks the right size.
suite.hw.params['picture-size-values'] = '3264x1836,2448x2448,1836x3264';
function verify(p) {
var cam = suite.camera;
var cap = cam.capabilities;
var expSizes = [ { height: 3264, width: 1836 },
{ height: 1836, width: 3264 },
{ height: 2448, width: 2448 } ];
// validate the capability attribute
ok(cap.pictureSizes.length == expSizes.length, "pictureSizes.length = " + cap.pictureSizes.length);
var found = 0;
expSizes.forEach(function(size) {
found = 0;
cap.pictureSizes.forEach(function(capSize) {
if (capSize.height == size.height && capSize.width == size.width) {
++found;
}
});
ok(found == 1, "found size " + size.toSource() + " in pictureSizes");
});
var sizeIterator = expSizes.values();
return new Promise(function(resolve, reject) {
function nextSize() {
var {value:size, done} = sizeIterator.next();
if (done) {
resolve();
return;
}
var sync = suite.waitParameterPush();
cam.setPictureSize(size);
sync.then(function() {
var got = cam.getPictureSize();
ok(got.width == size.width && got.height == size.height,
"Set size " + size.toSource() + ", got size " + got.toSource());
nextSize();
}, reject);
}
nextSize();
});
}
return suite.getCamera()
.then(verify, suite.rejectGetCamera);
});
suite.test('bug-1052851', function() {
// We should reject duplicate values.
suite.hw.params['auto-exposure'] = 'frame-average';
suite.hw.params['auto-exposure-values'] = 'spot,frame-average,center-weighted,spot,center-weighted';
function resolve(p) {
var cam = suite.camera;
var cap = cam.capabilities;
ok(cap.meteringModes.length == 3, "Metering modes length = " + cap.meteringModes.length);
// make sure expected values are present
[ "spot", "frame-average", "center-weighted" ].forEach(function(mode) {
ok(cap.meteringModes.indexOf(mode) != -1, "Metering mode '" + mode + "' is present");
});
// test setters/getters for individual metering modes
cap.meteringModes.forEach(function(mode, index) {
cam.meteringMode = mode;
ok(cam.meteringMode === mode,
"Metering Mode[" + index + "] = " + mode + ", cam.meteringMode = " + cam.meteringMode);
});
}
return suite.getCamera()
.then(resolve, suite.rejectGetCamera);
});
suite.test('bug-1124338', function() {
function triggerAutoFocus(p) {
var sync = new Promise(function(resolve, reject) {
function onEvent(e) {
suite.camera.removeEventListener('focus', onEvent);
var thumbnailSize = suite.camera.getThumbnailSize();
ok(thumbnailSize.width == 640 && thumbnailSize.height == 480, 'thumbnail size reset with auto focus');
resolve();
}
suite.camera.addEventListener('focus', onEvent);
});
var initThumbnailSize = suite.camera.getThumbnailSize();
ok(initThumbnailSize.width == 320 && initThumbnailSize.height == 240, 'initial thumbnail size incorrect');
suite.hw.params['jpeg-thumbnail-width'] = '640';
suite.hw.params['jpeg-thumbnail-height'] = '480';
suite.hw.fireAutoFocusComplete(false);
return sync;
}
suite.hw.params['jpeg-thumbnail-size-values'] = '320x240,640x480';
suite.hw.params['jpeg-thumbnail-width'] = '320';
suite.hw.params['jpeg-thumbnail-height'] = '240';
return suite.getCamera()
.then(triggerAutoFocus)
});
suite.setup()
.then(suite.run);
</script>
</body>
</html>

Просмотреть файл

@ -1,88 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=940424
-->
<head>
<title>Bug 940424 - Test camera hardware init failure handling</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=940424">Mozilla Bug 940424</a>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var suite = new CameraTestSuite();
suite.test('init-failure', function() {
var cameraManager = navigator.mozCameras;
var whichCamera = cameraManager.getListOfCameras()[0];
suite.hw.attach({
init: function() {
throw SpecialPowers.Cr.NS_ERROR_NOT_INITIALIZED;
}
});
function rejectGetCamera(e) {
ok(e.name === 'NS_ERROR_NOT_AVAILABLE', 'onError called correctly on getCamera init failure: ' + e);
// Let the next getCamera attempt succeed
suite.initJsHw();
return Promise.resolve();
}
function resolveGetCamera(p) {
ok(true, 'onSuccess called correctly for second getCamera request');
}
return cameraManager.getCamera(whichCamera)
.then(suite.expectedRejectGetCamera, rejectGetCamera)
.then(suite.getCamera)
.then(resolveGetCamera, suite.rejectGetCamera)
});
/* Test for bug 1099390 to make sure events related to the underlying
platform failing are generated and handled properly. */
suite.test('post-init-system-failure', function() {
function triggerSystemFailure(p) {
var sync = new Promise(function(resolve, reject) {
function onClosedEvent(e) {
suite.camera.removeEventListener('close', onClosedEvent);
ok(e.reason === 'SystemFailure', 'reason is: ' + e.reason);
resolve();
}
suite.camera.addEventListener('close', onClosedEvent);
});
suite.hw.fireSystemError();
return sync;
}
function releaseCamera(p) {
var camera = suite.camera;
suite.camera = null;
return camera.release();
}
function releasedCamera(p) {
ok(true, 'camera released after system failure');
}
return suite.getCamera()
.then(triggerSystemFailure, suite.rejectGetCamera)
.then(releaseCamera)
.then(releasedCamera, suite.rejectRelease);
});
suite.setup()
.then(suite.run);
</script>
</body>
</html>

Просмотреть файл

@ -1,208 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test Camera Recording</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width = "200" height = "200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var suite = new CameraTestSuite();
var baseConfig = {
mode: 'video',
};
var testFilePath = 'test.3gp';
var storage = navigator.getDeviceStorage("videos");
function cleanup()
{
return storage.delete(testFilePath).then(function(p) {
}, function(e) {
Promise.resolve();
});
}
suite.test('recording', function() {
function startRecording(p) {
var eventPromise = new Promise(function(resolve, reject) {
function onEvent(evt) {
ok(evt.newState === 'Started', 'recorder state change event = ' + evt.newState);
suite.camera.removeEventListener('recorderstatechange', onEvent);
resolve();
}
suite.camera.addEventListener('recorderstatechange', onEvent);
});
var domPromise = suite.camera.startRecording({}, storage, testFilePath);
return Promise.all([domPromise, eventPromise]);
}
function pauseRecording(p) {
var eventPromise = new Promise(function(resolve, reject) {
function onEvent(evt) {
ok(evt.newState === 'Paused', 'recorder state change event = ' + evt.newState);
suite.camera.removeEventListener('recorderstatechange', onEvent);
resolve();
}
suite.camera.addEventListener('recorderstatechange', onEvent);
});
var domPromise = new Promise(function(resolve, reject) {
try {
suite.camera.pauseRecording();
resolve();
} catch(e) {
reject(e);
}
});
return Promise.all([domPromise, eventPromise]);
}
function resumeRecording(p) {
var eventPromise = new Promise(function(resolve, reject) {
function onEvent(evt) {
ok(evt.newState === 'Resumed', 'recorder state change event = ' + evt.newState);
suite.camera.removeEventListener('recorderstatechange', onEvent);
resolve();
}
suite.camera.addEventListener('recorderstatechange', onEvent);
});
var domPromise = new Promise(function(resolve, reject) {
try {
suite.camera.resumeRecording();
resolve();
} catch(e) {
reject(e);
}
});
return Promise.all([domPromise, eventPromise]);
}
function stopRecording(p) {
var eventPromise = new Promise(function(resolve, reject) {
function onEvent(evt) {
ok(evt.newState === 'Stopped', 'recorder state change event = ' + evt.newState);
suite.camera.removeEventListener('recorderstatechange', onEvent);
resolve();
}
suite.camera.addEventListener('recorderstatechange', onEvent);
});
var domPromise = new Promise(function(resolve, reject) {
try {
suite.camera.stopRecording();
resolve();
} catch(e) {
reject(e);
}
});
return Promise.all([domPromise, eventPromise]);
}
return suite.getCamera(undefined, baseConfig)
.then(cleanup, suite.rejectGetCamera)
.then(startRecording)
.then(pauseRecording, suite.rejectStartRecording)
.then(resumeRecording, suite.rejectPauseRecording)
.then(stopRecording, suite.rejectResumeRecording)
.catch(suite.rejectStopRecording);
});
// bug 1152500
suite.test('interrupt-record', function() {
function startRecording(p) {
var startPromise = suite.camera.startRecording({}, storage, testFilePath);
suite.camera.stopRecording();
return startPromise;
}
function rejectStartRecording(e) {
ok(e.name === 'NS_ERROR_ABORT', 'onError called correctly on startRecording interrupted: ' + e);
}
return suite.getCamera(undefined, baseConfig)
.then(cleanup, suite.rejectGetCamera)
.then(startRecording)
.then(suite.expectedRejectStartRecording, rejectStartRecording);
});
// bug 1152500
suite.test('already-initiated-recording', function() {
function startRecording(p) {
return new Promise(function(resolve, reject) {
var firstCall = false;
var secondCall = false;
function end() {
if (firstCall && secondCall) {
resolve();
}
}
suite.camera.startRecording({}, storage, testFilePath).then(function(p) {
ok(true, "First call to startRecording() succeeded");
firstCall = true;
end();
}, function(e) {
ok(false, "First call to startRecording() failed unexpectedly with: " + e);
firstCall = true;
end();
});
suite.camera.startRecording({}, storage, testFilePath).then(function(p) {
ok(false, "Second call to startRecording() succeeded unexpectedly");
secondCall = true;
end();
}, function(e) {
ok(e.name === 'NS_ERROR_IN_PROGRESS', "Second call to startRecording() failed expectedly with: " + e);
secondCall = true;
end();
});
});
}
return suite.getCamera(undefined, baseConfig)
.then(cleanup, suite.rejectGetCamera)
.then(startRecording);
});
// bug 1152500
suite.test('already-started-recording', function() {
function startRecording(p) {
return suite.camera.startRecording({}, storage, testFilePath);
}
function startRecordingAgain(p) {
return suite.camera.startRecording({}, storage, testFilePath);
}
function rejectStartRecordingAgain(e) {
ok(e.name === 'NS_ERROR_IN_PROGRESS', "Second call to startRecording() failed expectedly with: " + e);
}
return suite.getCamera(undefined, baseConfig)
.then(cleanup, suite.rejectGetCamera)
.then(startRecording)
.then(startRecordingAgain, suite.rejectStartRecording)
.then(suite.expectedRejectStartRecording, rejectStartRecordingAgain)
});
suite.setup()
.then(suite.run);
</script>
</body>
</html>

Просмотреть файл

@ -1,243 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 975472</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var suite = new CameraTestSuite();
function cameraRelease(p) {
return suite.camera.release();
}
suite.test('release-close-event', function() {
// bug 1099390
function release(p) {
return new Promise(function(resolve, reject) {
var gotCloseEvent = false;
var gotReleasePromise = false;
var onClosed = function(e) {
suite.camera.removeEventListener('close', onClosed);
ok(!gotCloseEvent, "gotCloseEvent was " + gotCloseEvent);
ok(e.reason === "HardwareReleased", "'close' event reason is: " + e.reason);
gotCloseEvent = true;
if (gotReleasePromise) {
resolve();
}
};
suite.camera.addEventListener('close', onClosed);
suite.camera.release().then(function(p) {
ok(true, "released camera");
gotReleasePromise = true;
if (gotCloseEvent) {
resolve();
}
}).catch(reject);
});
}
return suite.getCamera()
.then(release, suite.rejectGetCamera);
});
suite.test('release-after-release', function() {
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(cameraRelease, suite.rejectRelease)
.catch(suite.rejectRelease);
});
suite.test('set-picture-size-after-release', function() {
function setPictureSize(p) {
try {
suite.camera.setPictureSize({ width: 0, height: 0 });
ok(false, "SetPictureSize() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setPictureSize() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(setPictureSize, suite.rejectRelease);
});
suite.test('set-thumbnail-size-after-release', function() {
function setThumbnailSize(p) {
try {
suite.camera.setThumbnailSize({ width: 0, height: 0 });
ok(false, "SetThumbnailSize() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setThumbnailSize() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(setThumbnailSize, suite.rejectRelease);
});
suite.test('get-sensor-angle-after-release', function() {
function getSensorAngle(p) {
ok(suite.camera.sensorAngle == 0, "camera.sensorAngle = " + suite.camera.sensorAngle);
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(getSensorAngle, suite.rejectRelease);
});
suite.test('resume-preview-after-release', function() {
function resumePreview(p) {
try {
suite.camera.resumePreview();
ok(false, "resumePreview() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"resumePreview() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(resumePreview, suite.rejectRelease);
});
suite.test('auto-focus-after-release', function() {
function autoFocus(p) {
return suite.camera.autoFocus();
}
function rejectAutoFocus(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"autoFocus() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(autoFocus, suite.rejectRelease)
.then(suite.expectedRejectAutoFocus, rejectAutoFocus);
});
suite.test('take-picture-after-release', function() {
function takePicture(p) {
return suite.camera.takePicture(null);
}
function rejectTakePicture(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(takePicture, suite.rejectRelease)
.then(suite.expectedRejectTakePicture, rejectTakePicture);
});
suite.test('start-recording-after-release', function() {
function startRecording(p) {
return suite.camera.startRecording(
{
profile: 'high',
rotation: 0
},
navigator.getDeviceStorage('videos'),
'bug975472.mp4'
);
}
function rejectStartRecording(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(startRecording, suite.rejectRelease)
.then(suite.expectedRejectStartRecording, rejectStartRecording);
});
suite.test('stop-recording-after-release', function() {
function stopRecording(p) {
try {
suite.camera.stopRecording();
ok(false, "stopRecording() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"stopRecording() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(stopRecording, suite.rejectRelease);
});
suite.test('face-detection-after-release', function() {
function startFaceDetection(p) {
try {
suite.camera.startFaceDetection();
ok(false, "startFaceDetection() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"startFaceDetection() failed with: " + e.name);
}
}
function stopFaceDetection(p) {
try {
suite.camera.stopFaceDetection();
ok(false, "stopFaceDetection() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"stopFaceDetection() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(startFaceDetection, suite.rejectRelease)
.then(stopFaceDetection);
});
suite.test('set-configuration-after-release', function() {
function configure(p) {
return suite.camera.setConfiguration(null);
}
function rejectConfigure(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(configure, suite.rejectRelease)
.then(suite.expectedRejectConfigure, rejectConfigure);
});
suite.setup()
.then(suite.run);
</script>
</body>
</html>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше