mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
58c90485f3
@ -19,13 +19,13 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="bf9aaf39dd5a6491925a022db167c460f8207d34"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="bf9aaf39dd5a6491925a022db167c460f8207d34"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "ccd8b59df6230fc0eb5d47e9c617e58ddb4673dd",
|
||||
"revision": "f705a3f96020c7d7aa5ec63bf3417db29e1ab2a2",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,12 +17,12 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -17,12 +17,12 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2580a49ddeb99f4bdaaae6716ea99c9547cb6d9f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="40cac290f0a3253d31242d7f50b1d2ddd2f47cda"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,13 +9,19 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MozLoopService"];
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource://gre/modules/devtools/Console.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI",
|
||||
"resource:///modules/loop/MozLoopAPI.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "convertToRTCStatsReport",
|
||||
"resource://gre/modules/media/RTCStatsReport.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Chat", "resource:///modules/Chat.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
|
||||
@ -33,6 +39,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "deriveHawkCredentials",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
|
||||
"resource:///modules/loop/MozLoopPushHandler.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
/**
|
||||
* Internal helper methods and state
|
||||
*
|
||||
@ -303,6 +313,72 @@ let MozLoopServiceInternal = {
|
||||
return this._localizedStrings = map;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves loop logs to the saved-telemetry-pings folder.
|
||||
*
|
||||
* @param {Object} pc The peerConnection in question.
|
||||
*/
|
||||
stageForTelemetryUpload: function(window, pc) {
|
||||
window.WebrtcGlobalInformation.getAllStats(allStats => {
|
||||
let internalFormat = allStats.reports[0]; // filtered on pc.id
|
||||
window.WebrtcGlobalInformation.getLogging('', logs => {
|
||||
let report = convertToRTCStatsReport(internalFormat);
|
||||
let logStr = "";
|
||||
logs.forEach(s => { logStr += s + "\n"; });
|
||||
|
||||
// We have stats and logs.
|
||||
|
||||
// Create worker job. ping = saved telemetry ping file header + payload
|
||||
//
|
||||
// Prepare payload according to https://wiki.mozilla.org/Loop/Telemetry
|
||||
|
||||
let ai = Services.appinfo;
|
||||
let uuid = uuidgen.generateUUID().toString();
|
||||
uuid = uuid.substr(1,uuid.length-2); // remove uuid curly braces
|
||||
|
||||
let directory = OS.Path.join(OS.Constants.Path.profileDir,
|
||||
"saved-telemetry-pings");
|
||||
let job = {
|
||||
directory: directory,
|
||||
filename: uuid + ".json",
|
||||
ping: {
|
||||
reason: "loop",
|
||||
slug: uuid,
|
||||
payload: {
|
||||
ver: 1,
|
||||
info: {
|
||||
appUpdateChannel: ai.defaultUpdateChannel,
|
||||
appBuildID: ai.appBuildID,
|
||||
appName: ai.name,
|
||||
appVersion: ai.version,
|
||||
reason: "loop",
|
||||
OS: ai.OS,
|
||||
version: Services.sysinfo.getProperty("version")
|
||||
},
|
||||
report: "ice failure",
|
||||
connectionstate: pc.iceConnectionState,
|
||||
stats: report,
|
||||
localSdp: internalFormat.localSdp,
|
||||
remoteSdp: internalFormat.remoteSdp,
|
||||
log: logStr
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Send job to worker to do log sanitation, transcoding and saving to
|
||||
// disk for pickup by telemetry on next startup, which then uploads it.
|
||||
|
||||
let worker = new ChromeWorker("MozLoopWorker.js");
|
||||
worker.onmessage = function(e) {
|
||||
console.log(e.data.ok ?
|
||||
"Successfully staged loop report for telemetry upload." :
|
||||
("Failed to stage loop report. Error: " + e.data.fail));
|
||||
}
|
||||
worker.postMessage(job);
|
||||
});
|
||||
}, pc.id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens the chat window
|
||||
*
|
||||
@ -310,9 +386,8 @@ let MozLoopServiceInternal = {
|
||||
* be null.
|
||||
* @param {String} title The title of the chat window.
|
||||
* @param {String} url The page to load in the chat window.
|
||||
* @param {String} mode May be "minimized" or undefined.
|
||||
*/
|
||||
openChatWindow: function(contentWindow, title, url, mode) {
|
||||
openChatWindow: function(contentWindow, title, url) {
|
||||
// So I guess the origin is the loop server!?
|
||||
let origin = this.loopServerUri;
|
||||
url = url.spec || url;
|
||||
@ -332,8 +407,33 @@ let MozLoopServiceInternal = {
|
||||
return;
|
||||
}
|
||||
chatbox.removeEventListener("DOMContentLoaded", loaded, true);
|
||||
injectLoopAPI(chatbox.contentWindow);
|
||||
}, true);
|
||||
|
||||
let window = chatbox.contentWindow;
|
||||
injectLoopAPI(window);
|
||||
|
||||
let ourID = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
|
||||
|
||||
let onPCLifecycleChange = (pc, winID, type) => {
|
||||
if (winID != ourID) {
|
||||
return;
|
||||
}
|
||||
if (type == "iceconnectionstatechange") {
|
||||
switch(pc.iceConnectionState) {
|
||||
case "failed":
|
||||
case "disconnected":
|
||||
if (Services.telemetry.canSend ||
|
||||
Services.prefs.getBoolPref("toolkit.telemetry.test")) {
|
||||
this.stageForTelemetryUpload(window, pc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let pc_static = new window.mozRTCPeerConnectionStatic();
|
||||
pc_static.registerPeerConnectionLifecycleCallback(onPCLifecycleChange);
|
||||
}.bind(this), true);
|
||||
};
|
||||
|
||||
Chat.open(contentWindow, origin, title, url, undefined, undefined, callback);
|
||||
|
161
browser/components/loop/MozLoopWorker.js
Normal file
161
browser/components/loop/MozLoopWorker.js
Normal file
@ -0,0 +1,161 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* A worker dedicated to loop-report sanitation and writing for MozLoopService.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
|
||||
let File = OS.File;
|
||||
let Encoder = new TextEncoder();
|
||||
let Counter = 0;
|
||||
|
||||
const MAX_LOOP_LOGS = 5;
|
||||
/**
|
||||
* Communications with the controller.
|
||||
*
|
||||
* Accepts messages:
|
||||
* { path: filepath, ping: data }
|
||||
*
|
||||
* Sends messages:
|
||||
* { ok: true }
|
||||
* { fail: serialized_form_of_OS.File.Error }
|
||||
*/
|
||||
|
||||
onmessage = function(e) {
|
||||
if (++Counter > MAX_LOOP_LOGS) {
|
||||
postMessage({
|
||||
fail: "Maximum " + MAX_LOOP_LOGS + "loop reports reached for this session"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let directory = e.data.directory;
|
||||
let filename = e.data.filename;
|
||||
let ping = e.data.ping;
|
||||
|
||||
// Anonymize data
|
||||
resetIpMask();
|
||||
ping.payload.localSdp = redactSdp(ping.payload.localSdp);
|
||||
ping.payload.remoteSdp = redactSdp(ping.payload.remoteSdp);
|
||||
ping.payload.log = sanitizeLogs(ping.payload.log);
|
||||
|
||||
let pingStr = anonymizeIPv4(sanitizeUrls(JSON.stringify(ping)));
|
||||
|
||||
// Save to disk
|
||||
let array = Encoder.encode(pingStr);
|
||||
try {
|
||||
File.makeDir(directory,
|
||||
{ unixMode: OS.Constants.S_IRWXU, ignoreExisting: true });
|
||||
File.writeAtomic(OS.Path.join(directory, filename), array);
|
||||
postMessage({ ok: true });
|
||||
} catch (ex if ex instanceof File.Error) {
|
||||
// Instances of OS.File.Error know how to serialize themselves
|
||||
postMessage({fail: File.Error.toMsg(ex)});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mask upper 24-bits of ip address with fake numbers. Call resetIpMask() first.
|
||||
*/
|
||||
|
||||
let IpMap = {};
|
||||
let IpCount = 0;
|
||||
|
||||
function resetIpMask() {
|
||||
IpMap = {};
|
||||
IpCount = Math.floor(Math.random() * 16777215) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Masks upper 24-bits of ip address with fake numbers. Grunt function.
|
||||
*
|
||||
* @param {DOMString} ip address
|
||||
*/
|
||||
function maskIp(ip) {
|
||||
let isInvalidOrRfc1918or3927 = function(p1, p2, p3, p4) {
|
||||
let invalid = octet => octet < 0 || octet > 255;
|
||||
return invalid(p1) || invalid(p2) || invalid(p3) || invalid(p4) ||
|
||||
(p1 == 10) ||
|
||||
(p1 == 172 && p2 >= 16 && p2 <= 31) ||
|
||||
(p1 == 192 && p2 == 168) ||
|
||||
(p1 == 169 && p2 == 254);
|
||||
};
|
||||
|
||||
let [p1, p2, p3, p4] = ip.split(".");
|
||||
|
||||
if (isInvalidOrRfc1918or3927(p1, p2, p3, p4)) {
|
||||
return ip;
|
||||
}
|
||||
let key = [p1, p2, p3].join();
|
||||
if (!IpMap[key]) {
|
||||
do {
|
||||
IpCount = (IpCount + 1049039) % 16777216; // + prime % 2^24
|
||||
p1 = (IpCount >> 16) % 256;
|
||||
p2 = (IpCount >> 8) % 256;
|
||||
p3 = IpCount % 256;
|
||||
} while (isInvalidOrRfc1918or3927(p1, p2, p3, p4));
|
||||
IpMap[key] = p1 + "." + p2 + "." + p3;
|
||||
}
|
||||
return IpMap[key] + "." + p4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Partially masks ip numbers in input text.
|
||||
*
|
||||
* @param {DOMString} text Input text containing IP numbers as words.
|
||||
*/
|
||||
function anonymizeIPv4(text) {
|
||||
return text.replace(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g,
|
||||
maskIp.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes any urls of session information, like
|
||||
*
|
||||
* - (id=31 url=https://call.services.mozilla.com/#call/ongoing/AQHYjqH_...)
|
||||
* + (id=31 url=https://call.services.mozilla.com/#call/xxxx)
|
||||
*
|
||||
* - (id=35 url=about:loopconversation#incoming/1403134352854)
|
||||
* + (id=35 url=about:loopconversation#incoming/xxxx)
|
||||
*
|
||||
* @param {DOMString} text The text.
|
||||
*/
|
||||
function sanitizeUrls(text) {
|
||||
let trimUrl = url => url.replace(/(#call|#incoming).*/g,
|
||||
(match, type) => type + "/xxxx");
|
||||
return text.replace(/\(id=(\d+) url=([^\)]+)\)/g,
|
||||
(match, id, url) =>
|
||||
"(id=" + id + " url=" + trimUrl(url) + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes privacy sensitive information from SDP input text outright, like
|
||||
*
|
||||
* a=fingerprint:sha-256 E9:DE:6A:FE:2A:2F:05: etc.
|
||||
* a=identity ...
|
||||
*
|
||||
* Redacts lines from match to EOL. Assumes \r\n\ linebreaks.
|
||||
*
|
||||
* @param {DOMString} sdp The sdp text.
|
||||
*/
|
||||
let redactSdp = sdp => sdp.replace(/\r\na=(fingerprint|identity):.*?\r\n/g,
|
||||
"\r\n");
|
||||
|
||||
/**
|
||||
* Sanitizes log text of sensitive information, like
|
||||
*
|
||||
* - srflx(IP4:192.168.1.3:60348/UDP|turn402-oak.tokbox.com:3478)
|
||||
* + srflx(IP4:192.168.1.3:60348/UDP|xxxx.xxx)
|
||||
*
|
||||
* @param {DOMString} log The log text.
|
||||
*/
|
||||
function sanitizeLogs(log) {
|
||||
let rex = /(srflx|relay)\(IP4:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}\/(UDP|TCP)\|[^\)]+\)/g;
|
||||
|
||||
return log.replace(rex, match => match.replace(/\|[^\)]+\)/, "|xxxx.xxx)"));
|
||||
}
|
@ -14,4 +14,5 @@ EXTRA_JS_MODULES += [
|
||||
'MozLoopAPI.jsm',
|
||||
'MozLoopPushHandler.jsm',
|
||||
'MozLoopService.jsm',
|
||||
'MozLoopWorker.js',
|
||||
]
|
||||
|
@ -134,45 +134,39 @@ this.WebappManager = {
|
||||
|
||||
let manifestURL = aData.app.manifestURL;
|
||||
|
||||
let cleanup = () => {
|
||||
let nativeApp = new NativeApp(aData.app, jsonManifest,
|
||||
aData.app.categories);
|
||||
|
||||
this.installations[manifestURL] = Promise.defer();
|
||||
this.installations[manifestURL].promise.then(() => {
|
||||
notifyInstallSuccess(aData.app, nativeApp, bundle);
|
||||
}, (error) => {
|
||||
Cu.reportError("Error installing webapp: " + error);
|
||||
}).then(() => {
|
||||
popupProgressContent.removeChild(progressMeter);
|
||||
delete this.installations[manifestURL];
|
||||
if (Object.getOwnPropertyNames(this.installations).length == 0) {
|
||||
notification.remove();
|
||||
}
|
||||
};
|
||||
|
||||
this.installations[manifestURL] = Promise.defer();
|
||||
this.installations[manifestURL].promise.then(null, (error) => {
|
||||
Cu.reportError("Error installing webapp: " + error);
|
||||
cleanup();
|
||||
});
|
||||
|
||||
let nativeApp = new NativeApp(aData.app, jsonManifest,
|
||||
aData.app.categories);
|
||||
let localDir;
|
||||
try {
|
||||
localDir = nativeApp.createProfile();
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error installing webapp: " + ex);
|
||||
DOMApplicationRegistry.denyInstall(aData);
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(aData, localDir,
|
||||
(aApp, aManifest, aZipPath) => Task.spawn((function*() {
|
||||
Task.async(function*(aApp, aManifest, aZipPath) {
|
||||
try {
|
||||
yield nativeApp.install(aApp, aManifest, aZipPath);
|
||||
yield this.installations[manifestURL].promise;
|
||||
notifyInstallSuccess(aApp, nativeApp, bundle);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error installing webapp: " + ex);
|
||||
// TODO: Notify user that the installation has failed
|
||||
} finally {
|
||||
cleanup();
|
||||
throw ex;
|
||||
}
|
||||
}).bind(this))
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -88,13 +88,9 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
|
||||
|
||||
# Use a separate cache file for libffi, since it does things differently
|
||||
# from our configure.
|
||||
mkdir -p $_objdir/js/src/ctypes/libffi
|
||||
old_cache_file=$cache_file
|
||||
cache_file=$_objdir/js/src/ctypes/libffi/config.cache
|
||||
old_config_files=$CONFIG_FILES
|
||||
unset CONFIG_FILES
|
||||
AC_OUTPUT_SUBDIRS(js/src/ctypes/libffi)
|
||||
cache_file=$old_cache_file
|
||||
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
|
||||
CONFIG_FILES=$old_config_files
|
||||
fi
|
||||
|
@ -18,33 +18,45 @@ MOZ_CONFIG_LOG_TRAP
|
||||
])
|
||||
|
||||
dnl Disable the trap when running sub-configures.
|
||||
define([_MOZ_AC_OUTPUT_SUBDIRS], defn([AC_OUTPUT_SUBDIRS]))
|
||||
define([MOZ_SUBCONFIGURE_WRAP],
|
||||
[ _CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
case "$host" in
|
||||
*-mingw*)
|
||||
define(GEN_MOZ_AC_OUTPUT_SUBDIRS, [
|
||||
define([_MOZ_AC_OUTPUT_SUBDIRS], [
|
||||
patsubst($@, [$srcdir/$ac_config_dir], [$srcdir/$moz_config_srcdir])
|
||||
])
|
||||
])
|
||||
GEN_MOZ_AC_OUTPUT_SUBDIRS(defn([AC_OUTPUT_SUBDIRS]))
|
||||
|
||||
define([AC_OUTPUT_SUBDIRS],
|
||||
[trap '' EXIT
|
||||
for moz_config_dir in $1; do
|
||||
case "$moz_config_dir" in
|
||||
*:*)
|
||||
moz_config_srcdir=$(echo $moz_config_dir | awk -F: '{print [$]1}')
|
||||
moz_config_dir=$(echo $moz_config_dir | awk -F: '{print [$]2}')
|
||||
;;
|
||||
*)
|
||||
moz_config_srcdir=$moz_config_dir
|
||||
;;
|
||||
esac
|
||||
_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
case "$host" in
|
||||
*-mingw*)
|
||||
_CONFIG_SHELL=$(cd $(dirname $_CONFIG_SHELL); pwd -W)/$(basename $_CONFIG_SHELL)
|
||||
if test ! -e "$_CONFIG_SHELL" -a -e "${_CONFIG_SHELL}.exe"; then
|
||||
_CONFIG_SHELL="${_CONFIG_SHELL}.exe"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
|
||||
if test -d "$1"; then
|
||||
(cd "$1"; $PYTHON $_topsrcdir/build/subconfigure.py dump "$_CONFIG_SHELL")
|
||||
else
|
||||
mkdir -p "$1"
|
||||
fi
|
||||
$2
|
||||
(cd "$1"; $PYTHON $_topsrcdir/build/subconfigure.py adjust $ac_sub_configure)
|
||||
])
|
||||
|
||||
define([AC_OUTPUT_SUBDIRS],
|
||||
[trap '' EXIT
|
||||
for moz_config_dir in $1; do
|
||||
MOZ_SUBCONFIGURE_WRAP([$moz_config_dir],[
|
||||
_MOZ_AC_OUTPUT_SUBDIRS($moz_config_dir)
|
||||
])
|
||||
if test -d "$moz_config_dir"; then
|
||||
(cd "$moz_config_dir"; eval $PYTHON $_topsrcdir/build/subconfigure.py dump "$_CONFIG_SHELL" $ac_configure_args)
|
||||
else
|
||||
mkdir -p "$moz_config_dir"
|
||||
fi
|
||||
_save_cache_file="$cache_file"
|
||||
ifelse($2,,cache_file="$moz_config_dir/config.cache",cache_file="$2")
|
||||
_MOZ_AC_OUTPUT_SUBDIRS($moz_config_dir)
|
||||
cache_file="$_save_cache_file"
|
||||
(cd "$moz_config_dir"; $PYTHON $_topsrcdir/build/subconfigure.py adjust $ac_sub_configure)
|
||||
done
|
||||
|
||||
MOZ_CONFIG_LOG_TRAP
|
||||
|
@ -154,27 +154,8 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
|
||||
ICU_CPPFLAGS="$ICU_CPPFLAGS -I$icudir/common -I$icudir/i18n"
|
||||
|
||||
ICU_CROSS_BUILD_OPT=""
|
||||
ICU_SRCDIR=""
|
||||
if test "$HOST_OS_ARCH" = "WINNT"; then
|
||||
ICU_SRCDIR="--srcdir=$(cd $srcdir/intl/icu/source; pwd -W)"
|
||||
fi
|
||||
|
||||
if test "$CROSS_COMPILE"; then
|
||||
# Building host tools. It is necessary to build target binary.
|
||||
case "$HOST_OS_ARCH" in
|
||||
Darwin)
|
||||
ICU_TARGET=MacOSX
|
||||
;;
|
||||
Linux)
|
||||
ICU_TARGET=Linux
|
||||
;;
|
||||
WINNT)
|
||||
ICU_TARGET=MSYS/MSVC
|
||||
;;
|
||||
DragonFly|FreeBSD|NetBSD|OpenBSD|GNU_kFreeBSD)
|
||||
ICU_TARGET=BSD
|
||||
;;
|
||||
esac
|
||||
# Remove _DEPEND_CFLAGS from HOST_FLAGS to avoid configure error
|
||||
HOST_ICU_CFLAGS="$HOST_CFLAGS"
|
||||
HOST_ICU_CXXFLAGS="$HOST_CXXFLAGS"
|
||||
@ -196,24 +177,20 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
|
||||
|
||||
abs_srcdir=`(cd $srcdir; pwd)`
|
||||
mkdir -p $_objdir/intl/icu/host
|
||||
(cd $_objdir/intl/icu/host
|
||||
MOZ_SUBCONFIGURE_WRAP([.],[
|
||||
AR="$HOST_AR" RANLIB="$HOST_RANLIB" \
|
||||
CC="$HOST_CC" CXX="$HOST_CXX" LD="$HOST_LD" \
|
||||
CFLAGS="$HOST_ICU_CFLAGS $HOST_OPTIMIZE_FLAGS" \
|
||||
CPPFLAGS="$ICU_CPPFLAGS" \
|
||||
CXXFLAGS="$HOST_ICU_CXXFLAGS $HOST_OPTIMIZE_FLAGS" \
|
||||
LDFLAGS="$HOST_LDFLAGS" \
|
||||
$SHELL $abs_srcdir/intl/icu/source/runConfigureICU \
|
||||
$HOST_ICU_BUILD_OPTS \
|
||||
$ICU_TARGET \
|
||||
dnl Shell quoting is fun.
|
||||
${ICU_SRCDIR+"$ICU_SRCDIR"} \
|
||||
--enable-static --disable-shared \
|
||||
--enable-extras=no --enable-icuio=no --enable-layout=no \
|
||||
--enable-tests=no --enable-samples=no || exit 1
|
||||
])
|
||||
) || exit 1
|
||||
(export AR="$HOST_AR"
|
||||
export RANLIB="$HOST_RANLIB"
|
||||
export CC="$HOST_CC"
|
||||
export CXX="$HOST_CXX"
|
||||
export CPP="$HOST_CPP"
|
||||
export LD="$HOST_LD"
|
||||
export CFLAGS="$HOST_ICU_CFLAGS $HOST_OPTIMIZE_FLAGS"
|
||||
export CPPFLAGS="$ICU_CPPFLAGS"
|
||||
export CXXFLAGS="$HOST_ICU_CXXFLAGS $HOST_OPTIMIZE_FLAGS"
|
||||
export LDFLAGS="$HOST_LDFLAGS"
|
||||
ac_configure_args="$HOST_ICU_BUILD_OPTS"
|
||||
ac_configure_args="$ac_configure_args --enable-static --disable-shared --enable-extras=no --enable-icuio=no --enable-layout=no --enable-tests=no --enable-samples=no"
|
||||
AC_OUTPUT_SUBDIRS(intl/icu/source:intl/icu/host)
|
||||
) || exit 1
|
||||
# generate config/icucross.mk
|
||||
$GMAKE -C $_objdir/intl/icu/host/ config/icucross.mk
|
||||
|
||||
@ -308,29 +285,18 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# We cannot use AC_OUTPUT_SUBDIRS since ICU tree is out of spidermonkey.
|
||||
# When using AC_OUTPUT_SUBDIRS, objdir of ICU is out of objdir
|
||||
# due to relative path.
|
||||
# If building ICU moves into root of mozilla tree, we can use
|
||||
# AC_OUTPUT_SUBDIR instead.
|
||||
mkdir -p $_objdir/intl/icu/target
|
||||
(cd $_objdir/intl/icu/target
|
||||
MOZ_SUBCONFIGURE_WRAP([.],[
|
||||
AR="$AR" CC="$CC" CXX="$CXX" LD="$LD" \
|
||||
ARFLAGS="$ARFLAGS" \
|
||||
CPPFLAGS="$ICU_CPPFLAGS $CPPFLAGS" \
|
||||
CFLAGS="$ICU_CFLAGS" \
|
||||
CXXFLAGS="$ICU_CXXFLAGS" \
|
||||
LDFLAGS="$ICU_LDFLAGS $LDFLAGS" \
|
||||
$SHELL $_topsrcdir/intl/icu/source/configure \
|
||||
$ICU_BUILD_OPTS \
|
||||
$ICU_CROSS_BUILD_OPT \
|
||||
$ICU_LINK_OPTS \
|
||||
${ICU_SRCDIR+"$ICU_SRCDIR"} \
|
||||
$ICU_TARGET_OPT \
|
||||
--disable-extras --disable-icuio --disable-layout \
|
||||
--disable-tests --disable-samples || exit 1
|
||||
])
|
||||
(export AR="$AR"
|
||||
export CC="$CC"
|
||||
export CXX="$CXX"
|
||||
export LD="$LD"
|
||||
export ARFLAGS="$ARFLAGS"
|
||||
export CPPFLAGS="$ICU_CPPFLAGS $CPPFLAGS"
|
||||
export CFLAGS="$ICU_CFLAGS"
|
||||
export CXXFLAGS="$ICU_CXXFLAGS"
|
||||
export LDFLAGS="$ICU_LDFLAGS $LDFLAGS"
|
||||
ac_configure_args="$ICU_BUILD_OPTS $ICU_CROSS_BUILD_OPT $ICU_LINK_OPTS $ICU_TARGET_OPT"
|
||||
ac_configure_args="$ac_configure_args --disable-extras --disable-icuio --disable-layout --disable-tests --disable-samples"
|
||||
AC_OUTPUT_SUBDIRS(intl/icu/source:intl/icu/target)
|
||||
) || exit 1
|
||||
fi
|
||||
|
||||
|
@ -65,9 +65,6 @@ leak:AllocateArrayBufferContents
|
||||
# Bug 1022010 - Small leak under _render_glyph_outline. bc1
|
||||
leak:_render_glyph_outline
|
||||
|
||||
# Bug 1022954 - ScriptSource leaks sourceMapURL_ sometimes. dt
|
||||
leak:ScriptSource::setSourceMapURL
|
||||
|
||||
# Bug 1023548 - Small leak under SECITEM_AllocItem_Util. bc1, bc3
|
||||
leak:SECITEM_AllocItem_Util
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
# This script is used to capture the content of config.status-generated
|
||||
# files and subsequently restore their timestamp if they haven't changed.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
@ -60,24 +61,54 @@ PRECIOUS_VARS = set([
|
||||
# There's no reason not to do the latter automatically instead of failing,
|
||||
# doing the cleanup (which, on buildbots means a full clobber), and
|
||||
# restarting from scratch.
|
||||
def maybe_clear_cache():
|
||||
def maybe_clear_cache(args):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--target', type=str)
|
||||
parser.add_argument('--host', type=str)
|
||||
parser.add_argument('--build', type=str)
|
||||
args, others = parser.parse_known_args(args)
|
||||
env = dict(os.environ)
|
||||
for kind in ('target', 'host', 'build'):
|
||||
arg = getattr(args, kind)
|
||||
if arg is not None:
|
||||
env['%s_alias' % kind] = arg
|
||||
# configure can take variables assignments in its arguments, and that
|
||||
# overrides whatever is in the environment.
|
||||
for arg in others:
|
||||
if arg[:1] != '-' and '=' in arg:
|
||||
key, value = arg.split('=', 1)
|
||||
env[key] = value
|
||||
|
||||
comment = re.compile(r'^\s+#')
|
||||
cache = {}
|
||||
with open('config.cache') as f:
|
||||
for line in f.readlines():
|
||||
for line in f:
|
||||
if not comment.match(line) and '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
key, value = line.rstrip(os.linesep).split('=', 1)
|
||||
# If the value is quoted, unquote it
|
||||
if value[:1] == "'":
|
||||
value = value[1:-1].replace("'\\''", "'")
|
||||
cache[key] = value
|
||||
for precious in PRECIOUS_VARS:
|
||||
entry = 'ac_cv_env_%s_value' % precious
|
||||
if entry in cache and (not precious in os.environ or os.environ[precious] != cache[entry]):
|
||||
# If there is no entry at all for that precious variable, then
|
||||
# its value is not precious for that particular configure.
|
||||
if 'ac_cv_env_%s_set' % precious not in cache:
|
||||
continue
|
||||
is_set = cache.get('ac_cv_env_%s_set' % precious) == 'set'
|
||||
value = cache.get('ac_cv_env_%s_value' % precious) if is_set else None
|
||||
if value != env.get(precious):
|
||||
print 'Removing config.cache because of %s value change from:' \
|
||||
% precious
|
||||
print ' %s' % (value if value is not None else 'undefined')
|
||||
print 'to:'
|
||||
print ' %s' % env.get(precious, 'undefined')
|
||||
os.remove('config.cache')
|
||||
return
|
||||
|
||||
|
||||
def dump(dump_file, shell):
|
||||
def dump(dump_file, shell, args):
|
||||
if os.path.exists('config.cache'):
|
||||
maybe_clear_cache()
|
||||
maybe_clear_cache(args)
|
||||
if not os.path.exists('config.status'):
|
||||
if os.path.exists(dump_file):
|
||||
os.remove(dump_file)
|
||||
@ -132,6 +163,6 @@ CONFIG_DUMP = 'config_files.pkl'
|
||||
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[1] == 'dump':
|
||||
dump(CONFIG_DUMP, sys.argv[2])
|
||||
dump(CONFIG_DUMP, sys.argv[2], sys.argv[3:])
|
||||
elif sys.argv[1] == 'adjust':
|
||||
adjust(CONFIG_DUMP, sys.argv[2] if len(sys.argv) > 2 else None)
|
||||
|
@ -126,6 +126,7 @@ class MachCommands(MachCommandBase):
|
||||
valgrind_args.append('--suppressions=' + supps_file2)
|
||||
|
||||
exitcode = None
|
||||
timeout = 1100
|
||||
try:
|
||||
runner = FirefoxRunner(profile=profile,
|
||||
binary=self.get_binary_path(),
|
||||
@ -133,14 +134,17 @@ class MachCommands(MachCommandBase):
|
||||
env=env,
|
||||
process_args=kp_kwargs)
|
||||
runner.start(debug_args=valgrind_args)
|
||||
exitcode = runner.wait()
|
||||
# This timeout is slightly less than the no-output timeout on
|
||||
# TBPL, so we'll timeout here first and give an informative
|
||||
# message.
|
||||
exitcode = runner.wait(timeout=timeout)
|
||||
|
||||
finally:
|
||||
errs = outputHandler.error_count
|
||||
supps = outputHandler.suppression_count
|
||||
if errs != supps:
|
||||
status = 1 # turns the TBPL job orange
|
||||
print('TEST-UNEXPECTED-FAILURE | valgrind-test | error parsing:', errs, "errors seen, but", supps, "generated suppressions seen")
|
||||
print('TEST-UNEXPECTED-FAIL | valgrind-test | error parsing: {} errors seen, but {} generated suppressions seen'.format(errs, supps))
|
||||
|
||||
elif errs == 0:
|
||||
status = 0
|
||||
@ -149,7 +153,10 @@ class MachCommands(MachCommandBase):
|
||||
status = 1 # turns the TBPL job orange
|
||||
# We've already printed details of the errors.
|
||||
|
||||
if exitcode != 0:
|
||||
if exitcode == None:
|
||||
status = 2 # turns the TBPL job red
|
||||
print('TEST-UNEXPECTED-FAIL | valgrind-test | Valgrind timed out (reached {} second limit)'.format(timeout))
|
||||
elif exitcode != 0:
|
||||
status = 2 # turns the TBPL job red
|
||||
print('TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code from Valgrind')
|
||||
|
||||
|
@ -74,6 +74,7 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
|
||||
|
||||
_DEPRECATED_VARIABLES := \
|
||||
ANDROID_RESFILES \
|
||||
EXPORT_LIBRARY \
|
||||
LIBXUL_LIBRARY \
|
||||
MOCHITEST_A11Y_FILES \
|
||||
MOCHITEST_BROWSER_FILES \
|
||||
@ -345,7 +346,6 @@ endif
|
||||
|
||||
ifdef XPI_NAME
|
||||
ifdef IS_COMPONENT
|
||||
EXPORT_LIBRARY=
|
||||
FORCE_STATIC_LIB=
|
||||
FORCE_SHARED_LIB=1
|
||||
endif
|
||||
|
@ -5,19 +5,6 @@
|
||||
# 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/.
|
||||
|
||||
ifdef EXPORT_LIBRARY
|
||||
ifeq ($(EXPORT_LIBRARY),1)
|
||||
ifdef IS_COMPONENT
|
||||
EXPORT_LIBRARY = $(DEPTH)/staticlib/components
|
||||
else
|
||||
EXPORT_LIBRARY = $(DEPTH)/staticlib
|
||||
endif
|
||||
else
|
||||
# If EXPORT_LIBRARY has a value, we'll be installing there. We also need to cleanup there
|
||||
GARBAGE += $(foreach lib,$(LIBRARY),$(EXPORT_LIBRARY)/$(lib))
|
||||
endif
|
||||
endif # EXPORT_LIBRARY
|
||||
|
||||
binaries libs:: $(SUBMAKEFILES) $(TARGETS)
|
||||
ifndef NO_DIST_INSTALL
|
||||
ifdef SHARED_LIBRARY
|
||||
@ -41,12 +28,6 @@ INSTALL_TARGETS += PROGRAMS
|
||||
endif
|
||||
|
||||
ifdef LIBRARY
|
||||
ifdef EXPORT_LIBRARY
|
||||
LIBRARY_FILES = $(LIBRARY)
|
||||
LIBRARY_DEST ?= $(EXPORT_LIBRARY)
|
||||
LIBRARY_TARGET = binaries libs
|
||||
INSTALL_TARGETS += LIBRARY
|
||||
endif
|
||||
ifdef DIST_INSTALL
|
||||
ifdef IS_COMPONENT
|
||||
$(error Shipping static component libs makes no sense.)
|
||||
|
@ -833,7 +833,7 @@ $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
# When we only build a library descriptor, blow out any existing library
|
||||
$(REPORT_BUILD)
|
||||
$(if $(filter %.$(LIB_SUFFIX),$(LIBRARY)),,$(RM) $(REAL_LIBRARY) $(EXPORT_LIBRARY:%=%/$(REAL_LIBRARY)))
|
||||
$(if $(filter %.$(LIB_SUFFIX),$(LIBRARY)),,$(RM) $(REAL_LIBRARY))
|
||||
$(EXPAND_LIBS_GEN) -o $@ $(OBJS) $(SHARED_LIBRARY_LIBS)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
|
13
configure.in
13
configure.in
@ -8783,7 +8783,6 @@ AC_SUBST(CC_VERSION)
|
||||
AC_SUBST(CXX_VERSION)
|
||||
AC_SUBST(MSMANIFEST_TOOL)
|
||||
AC_SUBST(NS_ENABLE_TSF)
|
||||
AC_SUBST(MOZ_APP_COMPONENT_LIBS)
|
||||
AC_SUBST(MOZ_APP_EXTRA_LIBS)
|
||||
|
||||
AC_SUBST(MOZ_WAVE)
|
||||
@ -9050,8 +9049,6 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
|
||||
if test "$CROSS_COMPILE"; then
|
||||
ac_configure_args="$ac_configure_args je_cv_static_page_shift=12"
|
||||
fi
|
||||
_save_cache_file="$cache_file"
|
||||
cache_file=$_objdir/memory/jemalloc/src/config.cache
|
||||
|
||||
if ! test -e memory/jemalloc; then
|
||||
mkdir -p memory/jemalloc
|
||||
@ -9064,7 +9061,6 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
|
||||
srcdir=`cd $srcdir; pwd`
|
||||
AC_OUTPUT_SUBDIRS(memory/jemalloc/src)
|
||||
srcdir="$_save_srcdir"
|
||||
cache_file="$_save_cache_file"
|
||||
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
|
||||
fi
|
||||
|
||||
@ -9088,7 +9084,7 @@ if test "$MOZ_TREE_FREETYPE"; then
|
||||
mkdir modules
|
||||
fi
|
||||
|
||||
AC_OUTPUT_SUBDIRS(modules/freetype2)
|
||||
AC_OUTPUT_SUBDIRS(modules/freetype2,$cache_file)
|
||||
fi
|
||||
|
||||
if test -z "$direct_nspr_config"; then
|
||||
@ -9180,14 +9176,9 @@ if test -z "$MOZ_NATIVE_NSPR"; then
|
||||
export LDFLAGS="$LDFLAGS $NSPR_LDFLAGS"
|
||||
export CFLAGS="$CFLAGS $MOZ_FRAMEPTR_FLAGS"
|
||||
|
||||
# Use a separate cache file for NSPR since it uses autoconf 2.68.
|
||||
_save_cache_file="$cache_file"
|
||||
cache_file=$_objdir/nsprpub/config.cache
|
||||
|
||||
AC_OUTPUT_SUBDIRS(nsprpub)
|
||||
|
||||
# .. and restore them
|
||||
cache_file="$_save_cache_file"
|
||||
CFLAGS="$_SAVE_CFLAGS"
|
||||
CPPFLAGS="$_SAVE_CPPFLAGS"
|
||||
LDFLAGS="$_SAVE_LDFLAGS"
|
||||
@ -9277,7 +9268,7 @@ if ! test -e js; then
|
||||
mkdir js
|
||||
fi
|
||||
|
||||
AC_OUTPUT_SUBDIRS(js/src)
|
||||
AC_OUTPUT_SUBDIRS(js/src,$cache_file)
|
||||
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
|
||||
|
||||
fi # COMPILE_ENVIRONMENT && !LIBXUL_SDK_DIR
|
||||
|
@ -477,8 +477,7 @@ public:
|
||||
/**
|
||||
* Get the ContentSecurityPolicy for a JS context.
|
||||
**/
|
||||
static bool GetContentSecurityPolicy(JSContext* aCx,
|
||||
nsIContentSecurityPolicy** aCSP);
|
||||
static bool GetContentSecurityPolicy(nsIContentSecurityPolicy** aCSP);
|
||||
|
||||
// Returns the subject principal. Guaranteed to return non-null. May only
|
||||
// be called when nsContentUtils is initialized.
|
||||
|
@ -6425,11 +6425,9 @@ nsContentUtils::FindInternalContentViewer(const char* aType,
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::GetContentSecurityPolicy(JSContext* aCx,
|
||||
nsIContentSecurityPolicy** aCSP)
|
||||
nsContentUtils::GetContentSecurityPolicy(nsIContentSecurityPolicy** aCSP)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aCx == GetCurrentJSContext());
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsresult rv = SubjectPrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
|
@ -940,7 +940,7 @@ public:
|
||||
} else {
|
||||
SHA1Sum sha1;
|
||||
sha1.update(owner->mData, owner->mLength);
|
||||
uint8_t digest[SHA1Sum::HashSize]; // SHA1 digests are 20 bytes long.
|
||||
uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long.
|
||||
sha1.finish(digest);
|
||||
|
||||
nsAutoCString digestString;
|
||||
|
@ -1471,9 +1471,11 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||
}
|
||||
|
||||
nsAutoCString sourceMapURL;
|
||||
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), sourceMapURL);
|
||||
aRequest->mHasSourceMapURL = true;
|
||||
aRequest->mSourceMapURL = NS_ConvertUTF8toUTF16(sourceMapURL);
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), sourceMapURL);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aRequest->mHasSourceMapURL = true;
|
||||
aRequest->mSourceMapURL = NS_ConvertUTF8toUTF16(sourceMapURL);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ sourceMappingURL=bar.js.map
|
||||
//# sourceMappingURL=bar.js.map
|
||||
|
||||
// Define a single function to prevent script source from being gc'd
|
||||
function foo() {}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaDecoderStateMachineScheduler.h"
|
||||
#include "AudioSink.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MediaDecoder.h"
|
||||
@ -168,8 +169,11 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
MediaDecoderReader* aReader,
|
||||
bool aRealTime) :
|
||||
mDecoder(aDecoder),
|
||||
mScheduler(new MediaDecoderStateMachineScheduler(
|
||||
aDecoder->GetReentrantMonitor(),
|
||||
&MediaDecoderStateMachine::TimeoutExpired,
|
||||
MOZ_THIS_IN_INITIALIZER_LIST(), aRealTime)),
|
||||
mState(DECODER_STATE_DECODING_METADATA),
|
||||
mInRunningStateMachine(false),
|
||||
mSyncPointInMediaStream(-1),
|
||||
mSyncPointInDecodedStream(-1),
|
||||
mPlayDuration(0),
|
||||
@ -198,30 +202,24 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
mQuickBuffering(false),
|
||||
mMinimizePreroll(false),
|
||||
mDecodeThreadWaiting(false),
|
||||
mRealTime(aRealTime),
|
||||
mDispatchedDecodeMetadataTask(false),
|
||||
mDropAudioUntilNextDiscontinuity(false),
|
||||
mDropVideoUntilNextDiscontinuity(false),
|
||||
mDecodeToSeekTarget(false),
|
||||
mCurrentTimeBeforeSeek(0),
|
||||
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
|
||||
mTimerId(0)
|
||||
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
// Only enable realtime mode when "media.realtime_decoder.enabled" is true.
|
||||
if (Preferences::GetBool("media.realtime_decoder.enabled", false) == false)
|
||||
mRealTime = false;
|
||||
|
||||
mAmpleVideoFrames =
|
||||
std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
|
||||
|
||||
mBufferingWait = mRealTime ? 0 : BUFFERING_WAIT_S;
|
||||
mLowDataThresholdUsecs = mRealTime ? 0 : LOW_DATA_THRESHOLD_USECS;
|
||||
mBufferingWait = mScheduler->IsRealTime() ? 0 : BUFFERING_WAIT_S;
|
||||
mLowDataThresholdUsecs = mScheduler->IsRealTime() ? 0 : LOW_DATA_THRESHOLD_USECS;
|
||||
|
||||
mVideoPrerollFrames = mRealTime ? 0 : mAmpleVideoFrames / 2;
|
||||
mAudioPrerollUsecs = mRealTime ? 0 : LOW_AUDIO_USECS * 2;
|
||||
mVideoPrerollFrames = mScheduler->IsRealTime() ? 0 : mAmpleVideoFrames / 2;
|
||||
mAudioPrerollUsecs = mScheduler->IsRealTime() ? 0 : LOW_AUDIO_USECS * 2;
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Ensure high precision timers are enabled on Windows, otherwise the state
|
||||
@ -241,8 +239,6 @@ MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
||||
"WakeDecoder should have been revoked already");
|
||||
|
||||
MOZ_ASSERT(!mDecodeTaskQueue, "Should be released in SHUTDOWN");
|
||||
// No need to cancel the timer here for we've done that in SHUTDOWN.
|
||||
MOZ_ASSERT(!mTimer, "Should be released in SHUTDOWN");
|
||||
mReader = nullptr;
|
||||
|
||||
#ifdef XP_WIN
|
||||
@ -1063,10 +1059,6 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
||||
RefPtr<SharedThreadPool> decodePool(GetMediaDecodeThreadPool());
|
||||
NS_ENSURE_TRUE(decodePool, NS_ERROR_FAILURE);
|
||||
|
||||
RefPtr<SharedThreadPool> stateMachinePool(
|
||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
|
||||
NS_ENSURE_TRUE(stateMachinePool, NS_ERROR_FAILURE);
|
||||
|
||||
mDecodeTaskQueue = new MediaTaskQueue(decodePool.forget());
|
||||
NS_ENSURE_TRUE(mDecodeTaskQueue, NS_ERROR_FAILURE);
|
||||
|
||||
@ -1075,12 +1067,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
||||
cloneReader = aCloneDonor->mReader;
|
||||
}
|
||||
|
||||
mStateMachineThreadPool = stateMachinePool;
|
||||
|
||||
nsresult rv;
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mTimer->SetTarget(GetStateMachineThread());
|
||||
nsresult rv = mScheduler->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Note: This creates a cycle, broken in shutdown.
|
||||
@ -1342,8 +1329,8 @@ void MediaDecoderStateMachine::Shutdown()
|
||||
// Change state before issuing shutdown request to threads so those
|
||||
// threads can start exiting cleanly during the Shutdown call.
|
||||
DECODER_LOG(PR_LOG_DEBUG, "Changed state to SHUTDOWN");
|
||||
ScheduleStateMachine();
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
mScheduler->ScheduleAndShutdown();
|
||||
if (mAudioSink) {
|
||||
mAudioSink->PrepareToShutdown();
|
||||
}
|
||||
@ -1753,6 +1740,7 @@ MediaDecoderStateMachine::StartAudioThread()
|
||||
if (NS_FAILED(rv)) {
|
||||
DECODER_LOG(PR_LOG_WARNING, "Changed state to SHUTDOWN because audio sink initialization failed");
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
mScheduler->ScheduleAndShutdown();
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1830,8 +1818,8 @@ MediaDecoderStateMachine::DecodeError()
|
||||
// and the HTMLMediaElement, so that our pipeline can start exiting
|
||||
// cleanly during the sync dispatch below.
|
||||
DECODER_LOG(PR_LOG_WARNING, "Decode error, changed state to SHUTDOWN due to error");
|
||||
ScheduleStateMachine();
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
mScheduler->ScheduleAndShutdown();
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
|
||||
// Dispatch the event to call DecodeError synchronously. This ensures
|
||||
@ -1911,7 +1899,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
||||
VideoQueue().AddPopListener(decodeTask, mDecodeTaskQueue);
|
||||
}
|
||||
|
||||
if (mRealTime) {
|
||||
if (mScheduler->IsRealTime()) {
|
||||
SetStartTime(0);
|
||||
res = FinishDecodeMetadata();
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
@ -1940,7 +1928,7 @@ MediaDecoderStateMachine::FinishDecodeMetadata()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mRealTime) {
|
||||
if (!mScheduler->IsRealTime()) {
|
||||
|
||||
const VideoData* v = VideoQueue().PeekFront();
|
||||
const AudioData* a = AudioQueue().PeekFront();
|
||||
@ -2174,6 +2162,9 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
// Try to decode another frame to detect if we're at the end...
|
||||
DECODER_LOG(PR_LOG_DEBUG, "Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime);
|
||||
|
||||
// Prevent changes in playback position before 'seeked' is fired for we
|
||||
// expect currentTime equals seek target in 'seeked' callback.
|
||||
mScheduler->FreezeScheduling();
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
|
||||
@ -2185,6 +2176,7 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
mQuickBuffering = false;
|
||||
|
||||
ScheduleStateMachine();
|
||||
mScheduler->ThawScheduling();
|
||||
}
|
||||
|
||||
// Runnable to dispose of the decoder and state machine on the main thread.
|
||||
@ -2292,8 +2284,6 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
GetStateMachineThread()->Dispatch(
|
||||
new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL);
|
||||
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2589,7 +2579,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
#endif
|
||||
if (VideoQueue().GetSize() > 0) {
|
||||
VideoData* frame = VideoQueue().PeekFront();
|
||||
while (mRealTime || clock_time >= frame->mTime) {
|
||||
while (mScheduler->IsRealTime() || clock_time >= frame->mTime) {
|
||||
mVideoFrameEndTime = frame->GetEndTime();
|
||||
currentFrame = frame;
|
||||
#ifdef PR_LOGGING
|
||||
@ -2929,24 +2919,13 @@ nsresult MediaDecoderStateMachine::CallRunStateMachine()
|
||||
StopAudioThread();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mInRunningStateMachine, "State machine cycles must run in sequence!");
|
||||
mTimeout = TimeStamp();
|
||||
mInRunningStateMachine = true;
|
||||
nsresult res = RunStateMachine();
|
||||
mInRunningStateMachine = false;
|
||||
return res;
|
||||
return RunStateMachine();
|
||||
}
|
||||
|
||||
nsresult MediaDecoderStateMachine::TimeoutExpired(int aTimerId)
|
||||
nsresult MediaDecoderStateMachine::TimeoutExpired(void* aClosure)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
NS_ASSERTION(OnStateMachineThread(), "Must be on state machine thread");
|
||||
mTimer->Cancel();
|
||||
if (mTimerId == aTimerId) {
|
||||
return CallRunStateMachine();
|
||||
} else {
|
||||
return NS_OK;
|
||||
}
|
||||
MediaDecoderStateMachine* p = static_cast<MediaDecoderStateMachine*>(aClosure);
|
||||
return p->CallRunStateMachine();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
|
||||
@ -2955,75 +2934,8 @@ void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
|
||||
DispatchVideoDecodeTaskIfNeeded();
|
||||
}
|
||||
|
||||
class TimerEvent : public nsITimerCallback, public nsRunnable {
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
public:
|
||||
TimerEvent(MediaDecoderStateMachine* aStateMachine, int aTimerId)
|
||||
: mStateMachine(aStateMachine), mTimerId(aTimerId) {}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE {
|
||||
return mStateMachine->TimeoutExpired(mTimerId);
|
||||
}
|
||||
|
||||
NS_IMETHOD Notify(nsITimer* aTimer) {
|
||||
return mStateMachine->TimeoutExpired(mTimerId);
|
||||
}
|
||||
private:
|
||||
~TimerEvent() {}
|
||||
|
||||
const nsRefPtr<MediaDecoderStateMachine> mStateMachine;
|
||||
int mTimerId;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(TimerEvent, nsITimerCallback, nsIRunnable);
|
||||
|
||||
nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) {
|
||||
AssertCurrentThreadInMonitor();
|
||||
NS_ABORT_IF_FALSE(GetStateMachineThread(),
|
||||
"Must have a state machine thread to schedule");
|
||||
|
||||
if (mState == DECODER_STATE_SHUTDOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aUsecs = std::max<int64_t>(aUsecs, 0);
|
||||
|
||||
TimeStamp timeout = TimeStamp::Now() + UsecsToDuration(aUsecs);
|
||||
if (!mTimeout.IsNull() && timeout >= mTimeout) {
|
||||
// We've already scheduled a timer set to expire at or before this time,
|
||||
// or have an event dispatched to run the state machine.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t ms = static_cast<uint32_t>((aUsecs / USECS_PER_MS) & 0xFFFFFFFF);
|
||||
if (mRealTime && ms > 40) {
|
||||
ms = 40;
|
||||
}
|
||||
|
||||
// Don't cancel the timer here for this function will be called from
|
||||
// different threads.
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsRefPtr<TimerEvent> event = new TimerEvent(this, mTimerId+1);
|
||||
|
||||
if (ms == 0) {
|
||||
// Dispatch a runnable to the state machine thread when delay is 0.
|
||||
// It will has less latency than dispatching a runnable to the state
|
||||
// machine thread which will then schedule a zero-delay timer.
|
||||
rv = GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
} else if (OnStateMachineThread()) {
|
||||
rv = mTimer->InitWithCallback(event, ms, nsITimer::TYPE_ONE_SHOT);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "non-zero delay timer should be only scheduled in state machine thread");
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mTimeout = timeout;
|
||||
++mTimerId;
|
||||
} else {
|
||||
NS_WARNING("Failed to schedule state machine");
|
||||
}
|
||||
|
||||
return rv;
|
||||
return mScheduler->Schedule(aUsecs);
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::OnDecodeThread() const
|
||||
@ -3033,14 +2945,17 @@ bool MediaDecoderStateMachine::OnDecodeThread() const
|
||||
|
||||
bool MediaDecoderStateMachine::OnStateMachineThread() const
|
||||
{
|
||||
bool rv = false;
|
||||
mStateMachineThreadPool->IsOnCurrentThread(&rv);
|
||||
return rv;
|
||||
return mScheduler->OnStateMachineThread();
|
||||
}
|
||||
|
||||
nsIEventTarget* MediaDecoderStateMachine::GetStateMachineThread()
|
||||
nsIEventTarget* MediaDecoderStateMachine::GetStateMachineThread() const
|
||||
{
|
||||
return mStateMachineThreadPool->GetEventTarget();
|
||||
return mScheduler->GetStateMachineThread();
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsStateMachineScheduled() const
|
||||
{
|
||||
return mScheduler->IsScheduled();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate)
|
||||
|
@ -100,6 +100,7 @@ class VideoSegment;
|
||||
class MediaTaskQueue;
|
||||
class SharedThreadPool;
|
||||
class AudioSink;
|
||||
class MediaDecoderStateMachineScheduler;
|
||||
|
||||
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
|
||||
// GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
|
||||
@ -279,7 +280,7 @@ public:
|
||||
}
|
||||
|
||||
// Returns the shared state machine thread.
|
||||
nsIEventTarget* GetStateMachineThread();
|
||||
nsIEventTarget* GetStateMachineThread() const;
|
||||
|
||||
// Calls ScheduleStateMachine() after taking the decoder lock. Also
|
||||
// notifies the decoder thread in case it's waiting on the decoder lock.
|
||||
@ -290,8 +291,9 @@ public:
|
||||
// earlier, in which case the request is discarded.
|
||||
nsresult ScheduleStateMachine(int64_t aUsecs = 0);
|
||||
|
||||
// Timer function to implement ScheduleStateMachine(aUsecs).
|
||||
nsresult TimeoutExpired(int aGeneration);
|
||||
// Callback function registered with MediaDecoderStateMachineScheduler
|
||||
// to run state machine cycles.
|
||||
static nsresult TimeoutExpired(void* aClosure);
|
||||
|
||||
// Set the media fragment end time. aEndTime is in microseconds.
|
||||
void SetFragmentEndTime(int64_t aEndTime);
|
||||
@ -447,7 +449,7 @@ protected:
|
||||
|
||||
// Orders the Reader to stop decoding, and blocks until the Reader
|
||||
// has stopped decoding and finished delivering samples, then calls
|
||||
// ResetPlayback() to discard all enqueued data.
|
||||
// ResetPlayback() to discard all enqueued data.
|
||||
void FlushDecoding();
|
||||
|
||||
// Returns the audio clock, if we have audio, or -1 if we don't.
|
||||
@ -610,10 +612,7 @@ protected:
|
||||
// periodically via timer to ensure the video stays in sync.
|
||||
nsresult RunStateMachine();
|
||||
|
||||
bool IsStateMachineScheduled() const {
|
||||
AssertCurrentThreadInMonitor();
|
||||
return !mTimeout.IsNull();
|
||||
}
|
||||
bool IsStateMachineScheduled() const;
|
||||
|
||||
// Returns true if we're not playing and the decode thread has filled its
|
||||
// decode buffers and is waiting. We can shut the decode thread down in this
|
||||
@ -650,6 +649,10 @@ protected:
|
||||
// state machine, audio and main threads.
|
||||
nsRefPtr<MediaDecoder> mDecoder;
|
||||
|
||||
// Used to schedule state machine cycles. This should never outlive
|
||||
// the life cycle of the state machine.
|
||||
const nsAutoPtr<MediaDecoderStateMachineScheduler> mScheduler;
|
||||
|
||||
// Time at which the last video sample was requested. If it takes too long
|
||||
// before the sample arrives, we will increase the amount of audio we buffer.
|
||||
// This is necessary for legacy synchronous decoders to prevent underruns.
|
||||
@ -674,19 +677,6 @@ protected:
|
||||
// thread every time they're called.
|
||||
RefPtr<MediaTaskQueue> mDecodeTaskQueue;
|
||||
|
||||
RefPtr<SharedThreadPool> mStateMachineThreadPool;
|
||||
|
||||
// Timer to run the state machine cycles. Used by
|
||||
// ScheduleStateMachine(). Access protected by decoder monitor.
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
// Timestamp at which the next state machine cycle will run.
|
||||
// Access protected by decoder monitor.
|
||||
TimeStamp mTimeout;
|
||||
|
||||
// Used to check if there are state machine cycles are running in sequence.
|
||||
DebugOnly<bool> mInRunningStateMachine;
|
||||
|
||||
// The time that playback started from the system clock. This is used for
|
||||
// timing the presentation of video frames when there's no audio.
|
||||
// Accessed only via the state machine thread. Must be set via SetPlayStartTime.
|
||||
@ -911,9 +901,6 @@ protected:
|
||||
// by the decoder monitor.
|
||||
bool mDecodeThreadWaiting;
|
||||
|
||||
// True is we are decoding a realtime stream, like a camera stream
|
||||
bool mRealTime;
|
||||
|
||||
// True if we've dispatched a task to the decode task queue to call
|
||||
// ReadMetadata on the reader. We maintain a flag to ensure that we don't
|
||||
// dispatch multiple tasks to re-do the metadata loading.
|
||||
@ -942,9 +929,6 @@ protected:
|
||||
mozilla::MediaMetadataManager mMetadataManager;
|
||||
|
||||
MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
|
||||
|
||||
// The id of timer tasks, used to ignore tasks that are scheduled previously.
|
||||
int mTimerId;
|
||||
};
|
||||
|
||||
} // namespace mozilla;
|
||||
|
233
content/media/MediaDecoderStateMachineScheduler.cpp
Normal file
233
content/media/MediaDecoderStateMachineScheduler.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
/* 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 "MediaDecoderStateMachineScheduler.h"
|
||||
#include "SharedThreadPool.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
namespace {
|
||||
class TimerEvent : public nsITimerCallback, public nsRunnable {
|
||||
typedef mozilla::MediaDecoderStateMachineScheduler Scheduler;
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
public:
|
||||
TimerEvent(Scheduler* aScheduler, int aTimerId)
|
||||
: mScheduler(aScheduler), mTimerId(aTimerId) {}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE {
|
||||
return mScheduler->TimeoutExpired(mTimerId);
|
||||
}
|
||||
|
||||
NS_IMETHOD Notify(nsITimer* aTimer) MOZ_OVERRIDE {
|
||||
return mScheduler->TimeoutExpired(mTimerId);
|
||||
}
|
||||
private:
|
||||
~TimerEvent() {}
|
||||
Scheduler* const mScheduler;
|
||||
const int mTimerId;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(TimerEvent, nsITimerCallback, nsIRunnable);
|
||||
} // anonymous namespace
|
||||
|
||||
static already_AddRefed<nsIEventTarget>
|
||||
CreateStateMachineThread()
|
||||
{
|
||||
using mozilla::SharedThreadPool;
|
||||
using mozilla::RefPtr;
|
||||
RefPtr<SharedThreadPool> threadPool(
|
||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
|
||||
nsCOMPtr<nsIEventTarget> rv = threadPool.get();
|
||||
return rv.forget();
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaDecoderStateMachineScheduler::MediaDecoderStateMachineScheduler(
|
||||
ReentrantMonitor& aMonitor,
|
||||
nsresult (*aTimeoutCallback)(void*),
|
||||
void* aClosure, bool aRealTime)
|
||||
: mTimeoutCallback(aTimeoutCallback)
|
||||
, mClosure(aClosure)
|
||||
// Only enable realtime mode when "media.realtime_decoder.enabled" is true.
|
||||
, mRealTime(aRealTime &&
|
||||
Preferences::GetBool("media.realtime_decoder.enabled", false))
|
||||
, mMonitor(aMonitor)
|
||||
, mEventTarget(CreateStateMachineThread())
|
||||
, mTimer(do_CreateInstance("@mozilla.org/timer;1"))
|
||||
, mTimerId(0)
|
||||
, mState(SCHEDULER_STATE_NONE)
|
||||
, mInRunningStateMachine(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_CTOR(MediaDecoderStateMachineScheduler);
|
||||
}
|
||||
|
||||
MediaDecoderStateMachineScheduler::~MediaDecoderStateMachineScheduler()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_DTOR(MediaDecoderStateMachineScheduler);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachineScheduler::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(mEventTarget, NS_ERROR_FAILURE);
|
||||
nsresult rv = mTimer->SetTarget(mEventTarget);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachineScheduler::Schedule(int64_t aUsecs)
|
||||
{
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
|
||||
switch(mState) {
|
||||
case SCHEDULER_STATE_SHUTDOWN:
|
||||
return NS_ERROR_FAILURE;
|
||||
case SCHEDULER_STATE_FROZEN:
|
||||
mState = SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK;
|
||||
case SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK:
|
||||
return NS_OK;
|
||||
case SCHEDULER_STATE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
aUsecs = std::max<int64_t>(aUsecs, 0);
|
||||
|
||||
TimeStamp timeout = TimeStamp::Now() +
|
||||
TimeDuration::FromMilliseconds(static_cast<double>(aUsecs) / USECS_PER_MS);
|
||||
|
||||
if (!mTimeout.IsNull() && timeout >= mTimeout) {
|
||||
// We've already scheduled a timer set to expire at or before this time,
|
||||
// or have an event dispatched to run the state machine.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t ms = static_cast<uint32_t>((aUsecs / USECS_PER_MS) & 0xFFFFFFFF);
|
||||
if (IsRealTime() && ms > 40) {
|
||||
ms = 40;
|
||||
}
|
||||
|
||||
// Don't cancel the timer here for this function will be called from
|
||||
// different threads.
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsRefPtr<TimerEvent> event = new TimerEvent(this, mTimerId+1);
|
||||
|
||||
if (ms == 0) {
|
||||
// Dispatch a runnable to the state machine thread when delay is 0.
|
||||
// It will has less latency than dispatching a runnable to the state
|
||||
// machine thread which will then schedule a zero-delay timer.
|
||||
rv = mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
} else if (OnStateMachineThread()) {
|
||||
rv = mTimer->InitWithCallback(event, ms, nsITimer::TYPE_ONE_SHOT);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "non-zero delay timer should be only "
|
||||
"scheduled in state machine thread");
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mTimeout = timeout;
|
||||
++mTimerId;
|
||||
} else {
|
||||
NS_WARNING("Failed to schedule state machine");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachineScheduler::TimeoutExpired(int aTimerId)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
MOZ_ASSERT(OnStateMachineThread());
|
||||
MOZ_ASSERT(!mInRunningStateMachine,
|
||||
"State machine cycles must run in sequence!");
|
||||
|
||||
mInRunningStateMachine = true;
|
||||
// Only run state machine cycles when id matches.
|
||||
nsresult rv = NS_OK;
|
||||
if (mTimerId == aTimerId) {
|
||||
ResetTimer();
|
||||
rv = mTimeoutCallback(mClosure);
|
||||
}
|
||||
mInRunningStateMachine = false;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachineScheduler::ScheduleAndShutdown()
|
||||
{
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
if (IsFrozen()) {
|
||||
ThawScheduling();
|
||||
}
|
||||
// Schedule next cycle to handle SHUTDOWN in state machine thread.
|
||||
Schedule();
|
||||
// This must be set after calling Schedule()
|
||||
// which does nothing in shutdown state.
|
||||
mState = SCHEDULER_STATE_SHUTDOWN;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoderStateMachineScheduler::OnStateMachineThread() const
|
||||
{
|
||||
bool rv = false;
|
||||
mEventTarget->IsOnCurrentThread(&rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoderStateMachineScheduler::IsScheduled() const
|
||||
{
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
return !mTimeout.IsNull();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachineScheduler::ResetTimer()
|
||||
{
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
mTimer->Cancel();
|
||||
mTimeout = TimeStamp();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachineScheduler::FreezeScheduling()
|
||||
{
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
if (mState == SCHEDULER_STATE_SHUTDOWN) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mState == SCHEDULER_STATE_NONE);
|
||||
mState = !IsScheduled() ? SCHEDULER_STATE_FROZEN :
|
||||
SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK;
|
||||
// Nullify pending timer task if any.
|
||||
++mTimerId;
|
||||
mTimeout = TimeStamp();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachineScheduler::ThawScheduling()
|
||||
{
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
if (mState == SCHEDULER_STATE_SHUTDOWN) {
|
||||
return;
|
||||
}
|
||||
// We should be in frozen state and no pending timer task.
|
||||
MOZ_ASSERT(IsFrozen() && !IsScheduled());
|
||||
bool pendingTask = mState == SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK;
|
||||
mState = SCHEDULER_STATE_NONE;
|
||||
if (pendingTask) {
|
||||
Schedule();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
86
content/media/MediaDecoderStateMachineScheduler.h
Normal file
86
content/media/MediaDecoderStateMachineScheduler.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- 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 MediaDecoderStateMachineScheduler_h__
|
||||
#define MediaDecoderStateMachineScheduler_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
class nsITimer;
|
||||
class nsIEventTarget;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ReentrantMonitor;
|
||||
|
||||
class MediaDecoderStateMachineScheduler {
|
||||
enum State {
|
||||
SCHEDULER_STATE_NONE,
|
||||
SCHEDULER_STATE_FROZEN,
|
||||
SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK,
|
||||
SCHEDULER_STATE_SHUTDOWN
|
||||
};
|
||||
public:
|
||||
MediaDecoderStateMachineScheduler(ReentrantMonitor& aMonitor,
|
||||
nsresult (*aTimeoutCallback)(void*),
|
||||
void* aClosure, bool aRealTime);
|
||||
~MediaDecoderStateMachineScheduler();
|
||||
nsresult Init();
|
||||
nsresult Schedule(int64_t aUsecs = 0);
|
||||
void ScheduleAndShutdown();
|
||||
nsresult TimeoutExpired(int aTimerId);
|
||||
void FreezeScheduling();
|
||||
void ThawScheduling();
|
||||
|
||||
bool OnStateMachineThread() const;
|
||||
bool IsScheduled() const;
|
||||
|
||||
bool IsRealTime() const {
|
||||
return mRealTime;
|
||||
}
|
||||
|
||||
nsIEventTarget* GetStateMachineThread() const {
|
||||
return mEventTarget;
|
||||
}
|
||||
|
||||
bool IsFrozen() const {
|
||||
return mState == SCHEDULER_STATE_FROZEN ||
|
||||
mState == SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK;
|
||||
}
|
||||
|
||||
private:
|
||||
void ResetTimer();
|
||||
|
||||
// Callback function provided by MediaDecoderStateMachine to run
|
||||
// state machine cycles.
|
||||
nsresult (*const mTimeoutCallback)(void*);
|
||||
// Since StateMachineScheduler will never outlive the state machine,
|
||||
// it is safe to keep a raw pointer only to avoid reference cycles.
|
||||
void* const mClosure;
|
||||
// True is we are decoding a realtime stream, like a camera stream
|
||||
const bool mRealTime;
|
||||
// Monitor of the decoder
|
||||
ReentrantMonitor& mMonitor;
|
||||
// State machine thread
|
||||
const nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
// Timer to schedule callbacks to run the state machine cycles.
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
// Timestamp at which the next state machine cycle will run.
|
||||
TimeStamp mTimeout;
|
||||
// The id of timer tasks, timer callback will only run if id matches.
|
||||
int mTimerId;
|
||||
// No more state machine cycles in shutdown state.
|
||||
State mState;
|
||||
|
||||
// Used to check if state machine cycles are running in sequence.
|
||||
DebugOnly<bool> mInRunningStateMachine;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MediaDecoderStateMachineScheduler_h__
|
@ -147,6 +147,10 @@ public:
|
||||
mEnd = 0;
|
||||
}
|
||||
|
||||
bool Contains(const MediaByteRange& aByteRange) const {
|
||||
return aByteRange.mStart >= mStart && aByteRange.mEnd <= mEnd;
|
||||
}
|
||||
|
||||
int64_t mStart, mEnd;
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "Layers.h"
|
||||
#include "SharedThreadPool.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
|
||||
using mozilla::layers::Image;
|
||||
using mozilla::layers::LayerManager;
|
||||
@ -553,4 +554,23 @@ MP4Reader::Seek(int64_t aTime,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
||||
{
|
||||
nsTArray<MediaByteRange> ranges;
|
||||
if (NS_FAILED(mDecoder->GetResource()->GetCachedRanges(ranges))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTArray<Interval<Microseconds>> timeRanges;
|
||||
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
|
||||
|
||||
for (size_t i = 0; i < timeRanges.Length(); i++) {
|
||||
aBuffered->Add((timeRanges[i].start - aStartTime) / 1000000.0,
|
||||
(timeRanges[i].end - aStartTime) / 1000000.0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -52,6 +52,9 @@ public:
|
||||
|
||||
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
|
||||
int64_t aStartTime) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
||||
// Destroys all decoder resources.
|
||||
|
@ -71,6 +71,7 @@ FFmpegAACDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
packet.data = aSample->data;
|
||||
packet.size = aSample->size;
|
||||
packet.pos = aSample->byte_offset;
|
||||
|
@ -85,11 +85,14 @@ FFmpegDataDecoder<LIBAV_VER>::Init()
|
||||
mCodecContext.get_format = ChoosePixelFormat;
|
||||
|
||||
mCodecContext.thread_count = PR_GetNumberOfProcessors();
|
||||
mCodecContext.thread_type = FF_THREAD_FRAME;
|
||||
mCodecContext.thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
|
||||
mCodecContext.thread_safe_callbacks = false;
|
||||
|
||||
mCodecContext.extradata = mExtraData.begin();
|
||||
mCodecContext.extradata_size = mExtraData.length();
|
||||
for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) {
|
||||
mExtraData.append(0);
|
||||
}
|
||||
mCodecContext.extradata = mExtraData.begin();
|
||||
|
||||
AVDictionary* opts = nullptr;
|
||||
if (avcodec_open2(&mCodecContext, codec, &opts) < 0) {
|
||||
|
@ -53,6 +53,7 @@ FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
packet.data = aSample->data;
|
||||
packet.size = aSample->size;
|
||||
packet.pts = aSample->composition_timestamp;
|
||||
@ -137,7 +138,11 @@ FFmpegH264Decoder<LIBAV_VER>::AllocateBufferCb(AVCodecContext* aCodecContext,
|
||||
FFmpegH264Decoder<LIBAV_VER>::ReleaseBufferCb(AVCodecContext* aCodecContext,
|
||||
AVFrame* aFrame)
|
||||
{
|
||||
reinterpret_cast<Image*>(aFrame->opaque)->Release();
|
||||
Image* image = reinterpret_cast<Image*>(aFrame->opaque);
|
||||
avcodec_default_release_buffer(aCodecContext, aFrame);
|
||||
if (image) {
|
||||
image->Release();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -7,9 +7,24 @@
|
||||
#define GMPMessageUtils_h_
|
||||
|
||||
#include "gmp-video-codec.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPErr>
|
||||
: public ContiguousEnumSerializer<GMPErr,
|
||||
GMPNoErr,
|
||||
GMPLastErr>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoFrameType>
|
||||
: public ContiguousEnumSerializer<GMPVideoFrameType,
|
||||
kGMPKeyFrame,
|
||||
kGMPSkipFrame>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodecComplexity>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecComplexity,
|
||||
@ -39,57 +54,11 @@ struct ParamTraits<GMPVideoCodecMode>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodecVP8>
|
||||
{
|
||||
typedef GMPVideoCodecVP8 paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mPictureLossIndicationOn);
|
||||
WriteParam(aMsg, aParam.mFeedbackModeOn);
|
||||
WriteParam(aMsg, aParam.mComplexity);
|
||||
WriteParam(aMsg, aParam.mResilience);
|
||||
WriteParam(aMsg, aParam.mNumberOfTemporalLayers);
|
||||
WriteParam(aMsg, aParam.mDenoisingOn);
|
||||
WriteParam(aMsg, aParam.mErrorConcealmentOn);
|
||||
WriteParam(aMsg, aParam.mAutomaticResizeOn);
|
||||
WriteParam(aMsg, aParam.mFrameDroppingOn);
|
||||
WriteParam(aMsg, aParam.mKeyFrameInterval);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &(aResult->mPictureLossIndicationOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mFeedbackModeOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mComplexity)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mResilience)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mNumberOfTemporalLayers)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mDenoisingOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mErrorConcealmentOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mAutomaticResizeOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mFrameDroppingOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mKeyFrameInterval))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%d, %d, %d, %d, %u, %d, %d, %d, %d, %d]",
|
||||
aParam.mPictureLossIndicationOn,
|
||||
aParam.mFeedbackModeOn,
|
||||
aParam.mComplexity,
|
||||
aParam.mResilience,
|
||||
aParam.mNumberOfTemporalLayers,
|
||||
aParam.mDenoisingOn,
|
||||
aParam.mErrorConcealmentOn,
|
||||
aParam.mAutomaticResizeOn,
|
||||
aParam.mFrameDroppingOn,
|
||||
aParam.mKeyFrameInterval));
|
||||
}
|
||||
};
|
||||
struct ParamTraits<GMPBufferType>
|
||||
: public ContiguousEnumSerializer<GMPBufferType,
|
||||
GMP_BufferSingle,
|
||||
GMP_BufferInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPSimulcastStream>
|
||||
@ -136,6 +105,7 @@ struct ParamTraits<GMPVideoCodec>
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mGMPApiVersion);
|
||||
WriteParam(aMsg, aParam.mCodecType);
|
||||
WriteParam(aMsg, nsAutoCString(aParam.mPLName));
|
||||
WriteParam(aMsg, aParam.mPLType);
|
||||
@ -145,11 +115,8 @@ struct ParamTraits<GMPVideoCodec>
|
||||
WriteParam(aMsg, aParam.mMaxBitrate);
|
||||
WriteParam(aMsg, aParam.mMinBitrate);
|
||||
WriteParam(aMsg, aParam.mMaxFramerate);
|
||||
if (aParam.mCodecType == kGMPVideoCodecVP8) {
|
||||
WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Serializing unknown codec type!");
|
||||
}
|
||||
WriteParam(aMsg, aParam.mFrameDroppingOn);
|
||||
WriteParam(aMsg, aParam.mKeyFrameInterval);
|
||||
WriteParam(aMsg, aParam.mQPMax);
|
||||
WriteParam(aMsg, aParam.mNumberOfSimulcastStreams);
|
||||
for (uint32_t i = 0; i < aParam.mNumberOfSimulcastStreams; i++) {
|
||||
@ -160,6 +127,11 @@ struct ParamTraits<GMPVideoCodec>
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
// NOTE: make sure this matches any versions supported
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mGMPApiVersion)) ||
|
||||
aResult->mGMPApiVersion != kGMPVersion33) {
|
||||
return false;
|
||||
}
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
|
||||
return false;
|
||||
}
|
||||
@ -178,16 +150,9 @@ struct ParamTraits<GMPVideoCodec>
|
||||
!ReadParam(aMsg, aIter, &(aResult->mStartBitrate)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMaxBitrate)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMinBitrate)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMaxFramerate))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aResult->mCodecType == kGMPVideoCodecVP8) {
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(false, "De-serializing unknown codec type!");
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMaxFramerate)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mFrameDroppingOn)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mKeyFrameInterval))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -226,104 +191,6 @@ struct ParamTraits<GMPVideoCodec>
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPCodecSpecificInfoVP8>
|
||||
{
|
||||
typedef GMPCodecSpecificInfoVP8 paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mHasReceivedSLI);
|
||||
WriteParam(aMsg, aParam.mPictureIdSLI);
|
||||
WriteParam(aMsg, aParam.mHasReceivedRPSI);
|
||||
WriteParam(aMsg, aParam.mPictureIdRPSI);
|
||||
WriteParam(aMsg, aParam.mPictureId);
|
||||
WriteParam(aMsg, aParam.mNonReference);
|
||||
WriteParam(aMsg, aParam.mSimulcastIdx);
|
||||
WriteParam(aMsg, aParam.mTemporalIdx);
|
||||
WriteParam(aMsg, aParam.mLayerSync);
|
||||
WriteParam(aMsg, aParam.mTL0PicIdx);
|
||||
WriteParam(aMsg, aParam.mKeyIdx);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &(aResult->mHasReceivedSLI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mPictureIdSLI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mHasReceivedRPSI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mPictureIdRPSI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mPictureId)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mNonReference)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mSimulcastIdx)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mTemporalIdx)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mLayerSync)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mTL0PicIdx)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mKeyIdx))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%d, %u, %d, %u, %d, %d, %u, %u, %d, %d, %d]",
|
||||
aParam.mHasReceivedSLI,
|
||||
aParam.mPictureIdSLI,
|
||||
aParam.mHasReceivedRPSI,
|
||||
aParam.mPictureIdRPSI,
|
||||
aParam.mPictureId,
|
||||
aParam.mNonReference,
|
||||
aParam.mSimulcastIdx,
|
||||
aParam.mTemporalIdx,
|
||||
aParam.mLayerSync,
|
||||
aParam.mTL0PicIdx,
|
||||
aParam.mKeyIdx));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPCodecSpecificInfo>
|
||||
{
|
||||
typedef GMPCodecSpecificInfo paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCodecType);
|
||||
if (aParam.mCodecType == kGMPVideoCodecVP8) {
|
||||
WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Serializing unknown codec type!");
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aResult->mCodecType == kGMPVideoCodecVP8) {
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(false, "De-serializing unknown codec type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
const char* codecName = nullptr;
|
||||
if (aParam.mCodecType == kGMPVideoCodecVP8) {
|
||||
codecName = "VP8";
|
||||
}
|
||||
aLog->append(StringPrintf(L"[%s]", codecName));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // GMPMessageUtils_h_
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIFile.h"
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
|
||||
class nsILineInputStream;
|
||||
class nsIThread;
|
||||
@ -38,7 +39,7 @@ enum GMPState {
|
||||
class GMPParent MOZ_FINAL : public PGMPParent
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GMPParent)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(GMPParent)
|
||||
|
||||
GMPParent();
|
||||
|
||||
|
@ -27,6 +27,7 @@ public:
|
||||
void Run()
|
||||
{
|
||||
mTask->Run();
|
||||
mTask->Destroy();
|
||||
mTask = nullptr;
|
||||
}
|
||||
|
||||
@ -35,7 +36,7 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
nsAutoPtr<GMPTask> mTask;
|
||||
GMPTask* mTask;
|
||||
};
|
||||
|
||||
class SyncRunnable MOZ_FINAL
|
||||
@ -71,6 +72,7 @@ public:
|
||||
void Run()
|
||||
{
|
||||
mTask->Run();
|
||||
mTask->Destroy();
|
||||
mTask = nullptr;
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mDone = true;
|
||||
@ -83,7 +85,7 @@ private:
|
||||
}
|
||||
|
||||
bool mDone;
|
||||
nsAutoPtr<GMPTask> mTask;
|
||||
GMPTask* mTask;
|
||||
MessageLoop* mMessageLoop;
|
||||
Monitor mMonitor;
|
||||
};
|
||||
@ -108,7 +110,6 @@ RunOnMainThread(GMPTask* aTask)
|
||||
}
|
||||
|
||||
nsRefPtr<Runnable> r = new Runnable(aTask);
|
||||
|
||||
sMainLoop->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run));
|
||||
|
||||
return GMPNoErr;
|
||||
@ -152,6 +153,9 @@ InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
|
||||
aPlatformAPI.runonmainthread = &RunOnMainThread;
|
||||
aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
|
||||
aPlatformAPI.createmutex = &CreateMutex;
|
||||
aPlatformAPI.createrecord = nullptr;
|
||||
aPlatformAPI.settimer = nullptr;
|
||||
aPlatformAPI.getcurrenttime = nullptr;
|
||||
}
|
||||
|
||||
GMPThreadImpl::GMPThreadImpl()
|
||||
|
@ -13,6 +13,8 @@
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPChild;
|
||||
|
||||
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI);
|
||||
|
||||
class GMPThreadImpl : public GMPThread
|
||||
|
@ -183,7 +183,7 @@ NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
|
||||
const nsAString& aOrigin,
|
||||
GMPVideoHost** aOutVideoHost,
|
||||
GMPVideoDecoder** aGMPVD)
|
||||
GMPVideoDecoderProxy** aGMPVD)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
@ -217,7 +217,7 @@ NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
|
||||
const nsAString& aOrigin,
|
||||
GMPVideoHost** aOutVideoHost,
|
||||
GMPVideoEncoder** aGMPVE)
|
||||
GMPVideoEncoderProxy** aGMPVE)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
@ -364,6 +364,19 @@ GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class CreateGMPParentTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mParent = new GMPParent();
|
||||
return NS_OK;
|
||||
}
|
||||
already_AddRefed<GMPParent> GetParent() {
|
||||
return mParent.forget();
|
||||
}
|
||||
private:
|
||||
nsRefPtr<GMPParent> mParent;
|
||||
};
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::AddOnGMPThread(const nsAString& aDirectory)
|
||||
@ -376,9 +389,16 @@ GeckoMediaPluginService::AddOnGMPThread(const nsAString& aDirectory)
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = new GMPParent();
|
||||
// The GMPParent inherits from IToplevelProtocol, which must be created
|
||||
// on the main thread to be threadsafe. See Bug 1035653.
|
||||
nsRefPtr<CreateGMPParentTask> task(new CreateGMPParentTask());
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
MOZ_ASSERT(mainThread);
|
||||
mozilla::SyncRunnable::DispatchToThread(mainThread, task);
|
||||
nsRefPtr<GMPParent> gmp = task->GetParent();
|
||||
rv = gmp->Init(directory);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Can't Create GMPParent");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#ifndef GMPService_h_
|
||||
#define GMPService_h_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTArray.h"
|
||||
|
116
content/media/gmp/GMPSharedMemManager.cpp
Normal file
116
content/media/gmp/GMPSharedMemManager.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/* -*- 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 "GMPSharedMemManager.h"
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
// Really one set of pools on each side of the plugin API.
|
||||
|
||||
// YUV buffers go from Encoder parent to child; pool there, and then return
|
||||
// with Decoded() frames to the Decoder parent and goes into the parent pool.
|
||||
// Compressed (encoded) data goes from the Decoder parent to the child;
|
||||
// pool there, and then return with Encoded() frames and goes into the parent
|
||||
// pool.
|
||||
static StaticAutoPtr<nsTArray<ipc::Shmem>> sGmpFreelist[GMPSharedMemManager::kGMPNumTypes];
|
||||
static uint32_t sGMPShmemManagerCount = 0;
|
||||
|
||||
GMPSharedMemManager::GMPSharedMemManager()
|
||||
{
|
||||
if (!sGMPShmemManagerCount) {
|
||||
for (uint32_t i = 0; i < GMPSharedMemManager::kGMPNumTypes; i++) {
|
||||
sGmpFreelist[i] = new nsTArray<ipc::Shmem>();
|
||||
}
|
||||
}
|
||||
sGMPShmemManagerCount++;
|
||||
}
|
||||
|
||||
GMPSharedMemManager::~GMPSharedMemManager()
|
||||
{
|
||||
MOZ_ASSERT(sGMPShmemManagerCount > 0);
|
||||
sGMPShmemManagerCount--;
|
||||
if (!sGMPShmemManagerCount) {
|
||||
for (uint32_t i = 0; i < GMPSharedMemManager::kGMPNumTypes; i++) {
|
||||
sGmpFreelist[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static nsTArray<ipc::Shmem>&
|
||||
GetGmpFreelist(GMPSharedMemManager::GMPMemoryClasses aTypes)
|
||||
{
|
||||
return *(sGmpFreelist[aTypes]);
|
||||
}
|
||||
|
||||
static uint32_t sGmpAllocated[GMPSharedMemManager::kGMPNumTypes]; // 0's
|
||||
|
||||
bool
|
||||
GMPSharedMemManager::MgrAllocShmem(GMPMemoryClasses aClass, size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
{
|
||||
CheckThread();
|
||||
|
||||
// first look to see if we have a free buffer large enough
|
||||
for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
|
||||
MOZ_ASSERT(GetGmpFreelist(aClass)[i].IsWritable());
|
||||
if (aSize <= GetGmpFreelist(aClass)[i].Size<uint8_t>()) {
|
||||
*aMem = GetGmpFreelist(aClass)[i];
|
||||
GetGmpFreelist(aClass).RemoveElementAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find a buffer free with enough space; allocate one
|
||||
size_t pagesize = ipc::SharedMemory::SystemPageSize();
|
||||
aSize = (aSize + (pagesize-1)) & ~(pagesize-1); // round up to page size
|
||||
bool retval = Alloc(aSize, aType, aMem);
|
||||
if (retval) {
|
||||
sGmpAllocated[aClass]++;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPSharedMemManager::MgrDeallocShmem(GMPMemoryClasses aClass, ipc::Shmem& aMem)
|
||||
{
|
||||
CheckThread();
|
||||
|
||||
size_t size = aMem.Size<uint8_t>();
|
||||
size_t total = 0;
|
||||
// XXX This works; there are better pool algorithms. We need to avoid
|
||||
// "falling off a cliff" with too low a number
|
||||
if (GetGmpFreelist(aClass).Length() > 10) {
|
||||
Dealloc(GetGmpFreelist(aClass)[0]);
|
||||
GetGmpFreelist(aClass).RemoveElementAt(0);
|
||||
// The allocation numbers will be fubar on the Child!
|
||||
sGmpAllocated[aClass]--;
|
||||
}
|
||||
for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
|
||||
MOZ_ASSERT(GetGmpFreelist(aClass)[i].IsWritable());
|
||||
total += GetGmpFreelist(aClass)[i].Size<uint8_t>();
|
||||
if (size < GetGmpFreelist(aClass)[i].Size<uint8_t>()) {
|
||||
GetGmpFreelist(aClass).InsertElementAt(i, aMem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
GetGmpFreelist(aClass).AppendElement(aMem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPSharedMemManager::NumInUse(GMPMemoryClasses aClass)
|
||||
{
|
||||
return sGmpAllocated[aClass] - GetGmpFreelist(aClass).Length();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
#define GMPSharedMemManager_h_
|
||||
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
@ -14,10 +15,37 @@ namespace gmp {
|
||||
class GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
typedef enum {
|
||||
kGMPFrameData = 0,
|
||||
kGMPEncodedData,
|
||||
kGMPNumTypes
|
||||
} GMPMemoryClasses;
|
||||
|
||||
// This is a heuristic - max of 10 free in the Child pool, plus those
|
||||
// in-use for the encoder and decoder at the given moment and not yet
|
||||
// returned to the parent pool (which is not included). If more than
|
||||
// this are needed, we presume the client has either crashed or hung
|
||||
// (perhaps temporarily).
|
||||
static const uint32_t kGMPBufLimit = 20;
|
||||
|
||||
GMPSharedMemManager();
|
||||
virtual ~GMPSharedMemManager();
|
||||
|
||||
virtual bool MgrAllocShmem(GMPMemoryClasses aClass, size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) = 0;
|
||||
virtual bool MgrDeallocShmem(ipc::Shmem& aMem) = 0;
|
||||
ipc::Shmem* aMem);
|
||||
virtual bool MgrDeallocShmem(GMPMemoryClasses aClass, ipc::Shmem& aMem);
|
||||
|
||||
// So we can know if data is "piling up" for the plugin - I.e. it's hung or crashed
|
||||
virtual uint32_t NumInUse(GMPMemoryClasses aClass);
|
||||
|
||||
// Parent and child impls will differ here
|
||||
virtual void CheckThread() = 0;
|
||||
|
||||
// These have to be implemented using the AllocShmem/etc provided by the IPDL-generated interfaces,
|
||||
// so have the Parent/Child implement them.
|
||||
virtual bool Alloc(size_t aSize, ipc::Shmem::SharedMemory::SharedMemoryType aType, ipc::Shmem* aMem) = 0;
|
||||
virtual void Dealloc(ipc::Shmem& aMem) = 0;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
@ -3,17 +3,20 @@
|
||||
* 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/. */
|
||||
|
||||
using GMPBufferType from "gmp-video-codec.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
struct GMPVideoEncodedFrameData
|
||||
{
|
||||
int64_t mCaptureTime_ms;
|
||||
uint32_t mEncodedWidth;
|
||||
uint32_t mEncodedHeight;
|
||||
uint32_t mTimeStamp;
|
||||
uint64_t mTimestamp; // microseconds
|
||||
uint64_t mDuration; // microseconds
|
||||
uint32_t mFrameType;
|
||||
uint32_t mSize;
|
||||
GMPBufferType mBufferType;
|
||||
Shmem mBuffer;
|
||||
bool mCompleteFrame;
|
||||
};
|
||||
@ -32,8 +35,8 @@ struct GMPVideoi420FrameData
|
||||
GMPPlaneData mVPlane;
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
uint32_t mTimestamp;
|
||||
int64_t mRenderTime_ms;
|
||||
uint64_t mTimestamp; // microseconds
|
||||
uint64_t mDuration; // microseconds
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -80,26 +80,31 @@ GMPVideoDecoderChild::InputDataExhausted()
|
||||
SendInputDataExhausted();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
void
|
||||
GMPVideoDecoderChild::DrainComplete()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
SendDrainComplete();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::MgrDeallocShmem(Shmem& aMem)
|
||||
void
|
||||
GMPVideoDecoderChild::ResetComplete()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
SendResetComplete();
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderChild::CheckThread()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
const int32_t& aCoreCount)
|
||||
{
|
||||
if (!mVideoDecoder) {
|
||||
@ -107,15 +112,18 @@ GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoDecoder->InitDecode(aCodecSettings, this, aCoreCount);
|
||||
|
||||
mVideoDecoder->InitDecode(aCodecSettings,
|
||||
aCodecSpecific.Elements(),
|
||||
aCodecSpecific.Length(),
|
||||
this,
|
||||
aCoreCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
|
||||
const bool& aMissingFrames,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
const int64_t& aRenderTimeMs)
|
||||
{
|
||||
if (!mVideoDecoder) {
|
||||
@ -125,11 +133,25 @@ GMPVideoDecoderChild::RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
|
||||
auto f = new GMPVideoEncodedFrameImpl(aInputFrame, &mVideoHost);
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoDecoder->Decode(f, aMissingFrames, aCodecSpecificInfo, aRenderTimeMs);
|
||||
mVideoDecoder->Decode(f,
|
||||
aMissingFrames,
|
||||
aCodecSpecificInfo.Elements(),
|
||||
aCodecSpecificInfo.Length(),
|
||||
aRenderTimeMs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvChildShmemForPool(Shmem& aFrameBuffer)
|
||||
{
|
||||
if (aFrameBuffer.IsWritable()) {
|
||||
mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPFrameData,
|
||||
aFrameBuffer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvReset()
|
||||
{
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "gmp-video-decode.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
@ -18,7 +19,7 @@ namespace gmp {
|
||||
class GMPChild;
|
||||
|
||||
class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
|
||||
public GMPDecoderCallback,
|
||||
public GMPVideoDecoderCallback,
|
||||
public GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
@ -28,26 +29,47 @@ public:
|
||||
void Init(GMPVideoDecoder* aDecoder);
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPDecoderCallback
|
||||
// GMPVideoDecoderCallback
|
||||
virtual void Decoded(GMPVideoi420Frame* decodedFrame) MOZ_OVERRIDE;
|
||||
virtual void ReceivedDecodedReferenceFrame(const uint64_t pictureId) MOZ_OVERRIDE;
|
||||
virtual void ReceivedDecodedFrame(const uint64_t pictureId) MOZ_OVERRIDE;
|
||||
virtual void InputDataExhausted() MOZ_OVERRIDE;
|
||||
virtual void DrainComplete() MOZ_OVERRIDE;
|
||||
virtual void ResetComplete() MOZ_OVERRIDE;
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
virtual void CheckThread();
|
||||
virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
|
||||
{
|
||||
#ifndef SHMEM_ALLOC_IN_CHILD
|
||||
return CallNeedShmem(aSize, aMem);
|
||||
#else
|
||||
#ifdef GMP_SAFE_SHMEM
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
#else
|
||||
return AllocUnsafeShmem(aSize, aType, aMem);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
virtual void Dealloc(Shmem& aMem)
|
||||
{
|
||||
#ifndef SHMEM_ALLOC_IN_CHILD
|
||||
SendParentShmemForPool(aMem);
|
||||
#else
|
||||
DeallocShmem(aMem);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
// PGMPVideoDecoderChild
|
||||
virtual bool RecvInitDecode(const GMPVideoCodec& codecSettings,
|
||||
const int32_t& coreCount) MOZ_OVERRIDE;
|
||||
virtual bool RecvDecode(const GMPVideoEncodedFrameData& inputFrame,
|
||||
const bool& missingFrames,
|
||||
const GMPCodecSpecificInfo& codecSpecificInfo,
|
||||
const int64_t& renderTimeMs) MOZ_OVERRIDE;
|
||||
virtual bool RecvInitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
const int32_t& aCoreCount) MOZ_OVERRIDE;
|
||||
virtual bool RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
|
||||
const bool& aMissingFrames,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
const int64_t& aRenderTimeMs) MOZ_OVERRIDE;
|
||||
virtual bool RecvChildShmemForPool(Shmem& aFrameBuffer) MOZ_OVERRIDE;
|
||||
virtual bool RecvReset() MOZ_OVERRIDE;
|
||||
virtual bool RecvDrain() MOZ_OVERRIDE;
|
||||
virtual bool RecvDecodingComplete() MOZ_OVERRIDE;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<GMPVideoEncodedFrame> : public nsPointerRefTraits<GMPVideoEncodedFrame>
|
||||
@ -42,60 +43,43 @@ GMPVideoDecoderParent::Host()
|
||||
return mVideoHost;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::MgrDeallocShmem(Shmem& aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
nsresult
|
||||
GMPVideoDecoderParent::InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPDecoderCallback* aCallback,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
GMPVideoDecoderCallback* aCallback,
|
||||
int32_t aCoreCount)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!aCallback) {
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mCallback = aCallback;
|
||||
|
||||
if (!SendInitDecode(aCodecSettings, aCoreCount)) {
|
||||
return GMPVideoGenericErr;
|
||||
if (!SendInitDecode(aCodecSettings, aCodecSpecific, aCoreCount)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
nsresult
|
||||
GMPVideoDecoderParent::Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs)
|
||||
{
|
||||
nsAutoRef<GMPVideoEncodedFrame> autoDestroy(aInputFrame);
|
||||
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
@ -105,60 +89,68 @@ GMPVideoDecoderParent::Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
GMPVideoEncodedFrameData frameData;
|
||||
inputFrameImpl->RelinquishFrameData(frameData);
|
||||
|
||||
// Very rough kill-switch if the plugin stops processing. If it's merely
|
||||
// hung and continues, we'll come back to life eventually.
|
||||
// 3* is because we're using 3 buffers per frame for i420 data for now.
|
||||
if (NumInUse(kGMPFrameData) > 3*GMPSharedMemManager::kGMPBufLimit ||
|
||||
NumInUse(kGMPEncodedData) > GMPSharedMemManager::kGMPBufLimit) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!SendDecode(frameData,
|
||||
aMissingFrames,
|
||||
aCodecSpecificInfo,
|
||||
aRenderTimeMs)) {
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
nsresult
|
||||
GMPVideoDecoderParent::Reset()
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendReset()) {
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
nsresult
|
||||
GMPVideoDecoderParent::Drain()
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendDrain()) {
|
||||
return GMPVideoGenericErr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
|
||||
void
|
||||
nsresult
|
||||
GMPVideoDecoderParent::DecodingComplete()
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
@ -170,6 +162,8 @@ GMPVideoDecoderParent::DecodingComplete()
|
||||
mVideoHost.DoneWithAPI();
|
||||
|
||||
unused << SendDecodingComplete();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: Keep this sync'd up with DecodingComplete
|
||||
@ -186,6 +180,12 @@ GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
mVideoHost.ActorDestroyed();
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderParent::CheckThread()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame)
|
||||
{
|
||||
@ -240,6 +240,59 @@ GMPVideoDecoderParent::RecvInputDataExhausted()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvDrainComplete()
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->DrainComplete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvResetComplete()
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->ResetComplete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvParentShmemForPool(Shmem& aEncodedBuffer)
|
||||
{
|
||||
if (aEncodedBuffer.IsWritable()) {
|
||||
mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPEncodedData,
|
||||
aEncodedBuffer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::AnswerNeedShmem(const uint32_t& aFrameBufferSize,
|
||||
Shmem* aMem)
|
||||
{
|
||||
ipc::Shmem mem;
|
||||
|
||||
if (!mVideoHost.SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPFrameData,
|
||||
aFrameBufferSize,
|
||||
ipc::SharedMemory::TYPE_BASIC, &mem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*aMem = mem;
|
||||
mem = ipc::Shmem();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::Recv__delete__()
|
||||
{
|
||||
|
@ -12,15 +12,16 @@
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "GMPVideoDecoderProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPParent;
|
||||
|
||||
class GMPVideoDecoderParent MOZ_FINAL : public GMPVideoDecoder
|
||||
, public PGMPVideoDecoderParent
|
||||
class GMPVideoDecoderParent MOZ_FINAL : public PGMPVideoDecoderParent
|
||||
, public GMPSharedMemManager
|
||||
, public GMPVideoDecoderProxy
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GMPVideoDecoderParent)
|
||||
@ -29,23 +30,33 @@ public:
|
||||
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoDecoder
|
||||
virtual GMPVideoErr InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPDecoderCallback* aCallback,
|
||||
int32_t aCoreCount) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs = -1) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Reset() MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Drain() MOZ_OVERRIDE;
|
||||
virtual void DecodingComplete() MOZ_OVERRIDE;
|
||||
virtual nsresult InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
GMPVideoDecoderCallback* aCallback,
|
||||
int32_t aCoreCount) MOZ_OVERRIDE;
|
||||
virtual nsresult Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs = -1) MOZ_OVERRIDE;
|
||||
virtual nsresult Reset() MOZ_OVERRIDE;
|
||||
virtual nsresult Drain() MOZ_OVERRIDE;
|
||||
virtual nsresult DecodingComplete() MOZ_OVERRIDE;
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual void CheckThread();
|
||||
virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
|
||||
{
|
||||
#ifdef GMP_SAFE_SHMEM
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
#else
|
||||
return AllocUnsafeShmem(aSize, aType, aMem);
|
||||
#endif
|
||||
}
|
||||
virtual void Dealloc(Shmem& aMem)
|
||||
{
|
||||
DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
private:
|
||||
~GMPVideoDecoderParent();
|
||||
@ -56,11 +67,16 @@ private:
|
||||
virtual bool RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
|
||||
virtual bool RecvReceivedDecodedFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
|
||||
virtual bool RecvInputDataExhausted() MOZ_OVERRIDE;
|
||||
virtual bool RecvDrainComplete() MOZ_OVERRIDE;
|
||||
virtual bool RecvResetComplete() MOZ_OVERRIDE;
|
||||
virtual bool RecvParentShmemForPool(Shmem& aEncodedBuffer) MOZ_OVERRIDE;
|
||||
virtual bool AnswerNeedShmem(const uint32_t& aFrameBufferSize,
|
||||
Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mCanSendMessages;
|
||||
GMPParent* mPlugin;
|
||||
GMPDecoderCallback* mCallback;
|
||||
GMPVideoDecoderCallback* mCallback;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
};
|
||||
|
||||
|
33
content/media/gmp/GMPVideoDecoderProxy.h
Normal file
33
content/media/gmp/GMPVideoDecoderProxy.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- 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 GMPVideoDecoderProxy_h_
|
||||
#define GMPVideoDecoderProxy_h_
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "gmp-video-decode.h"
|
||||
#include "gmp-video-frame-i420.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
|
||||
// A proxy to GMPVideoDecoder in the child process.
|
||||
// GMPVideoDecoderParent exposes this to users the GMP.
|
||||
// This enables Gecko to pass nsTArrays to the child GMP and avoid
|
||||
// an extra copy when doing so.
|
||||
class GMPVideoDecoderProxy {
|
||||
public:
|
||||
virtual nsresult InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
GMPVideoDecoderCallback* aCallback,
|
||||
int32_t aCoreCount) = 0;
|
||||
virtual nsresult Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs = -1) = 0;
|
||||
virtual nsresult Reset() = 0;
|
||||
virtual nsresult Drain() = 0;
|
||||
virtual nsresult DecodingComplete() = 0;
|
||||
};
|
||||
|
||||
#endif
|
@ -14,12 +14,13 @@ namespace gmp {
|
||||
GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost)
|
||||
: mEncodedWidth(0),
|
||||
mEncodedHeight(0),
|
||||
mTimeStamp(0),
|
||||
mCaptureTime_ms(0),
|
||||
mTimeStamp(0ll),
|
||||
mDuration(0ll),
|
||||
mFrameType(kGMPDeltaFrame),
|
||||
mSize(0),
|
||||
mCompleteFrame(false),
|
||||
mHost(aHost)
|
||||
mHost(aHost),
|
||||
mBufferType(GMP_BufferSingle)
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
aHost->EncodedFrameCreated(this);
|
||||
@ -29,13 +30,14 @@ GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameDat
|
||||
GMPVideoHostImpl* aHost)
|
||||
: mEncodedWidth(aFrameData.mEncodedWidth()),
|
||||
mEncodedHeight(aFrameData.mEncodedHeight()),
|
||||
mTimeStamp(aFrameData.mTimeStamp()),
|
||||
mCaptureTime_ms(aFrameData.mCaptureTime_ms()),
|
||||
mTimeStamp(aFrameData.mTimestamp()),
|
||||
mDuration(aFrameData.mDuration()),
|
||||
mFrameType(static_cast<GMPVideoFrameType>(aFrameData.mFrameType())),
|
||||
mSize(aFrameData.mSize()),
|
||||
mCompleteFrame(aFrameData.mCompleteFrame()),
|
||||
mHost(aHost),
|
||||
mBuffer(aFrameData.mBuffer())
|
||||
mBuffer(aFrameData.mBuffer()),
|
||||
mBufferType(aFrameData.mBufferType())
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
aHost->EncodedFrameCreated(this);
|
||||
@ -49,6 +51,12 @@ GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
|
||||
}
|
||||
}
|
||||
|
||||
const GMPEncryptedBufferData*
|
||||
GMPVideoEncodedFrameImpl::GetDecryptionData() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GMPVideoFrameFormat
|
||||
GMPVideoEncodedFrameImpl::GetFrameFormat()
|
||||
{
|
||||
@ -80,12 +88,13 @@ GMPVideoEncodedFrameImpl::RelinquishFrameData(GMPVideoEncodedFrameData& aFrameDa
|
||||
{
|
||||
aFrameData.mEncodedWidth() = mEncodedWidth;
|
||||
aFrameData.mEncodedHeight() = mEncodedHeight;
|
||||
aFrameData.mTimeStamp() = mTimeStamp;
|
||||
aFrameData.mCaptureTime_ms() = mCaptureTime_ms;
|
||||
aFrameData.mTimestamp() = mTimeStamp;
|
||||
aFrameData.mDuration() = mDuration;
|
||||
aFrameData.mFrameType() = mFrameType;
|
||||
aFrameData.mSize() = mSize;
|
||||
aFrameData.mCompleteFrame() = mCompleteFrame;
|
||||
aFrameData.mBuffer() = mBuffer;
|
||||
aFrameData.mBufferType() = mBufferType;
|
||||
|
||||
// This method is called right before Shmem is sent to another process.
|
||||
// We need to effectively zero out our member copy so that we don't
|
||||
@ -99,36 +108,37 @@ void
|
||||
GMPVideoEncodedFrameImpl::DestroyBuffer()
|
||||
{
|
||||
if (mHost && mBuffer.IsWritable()) {
|
||||
mHost->SharedMemMgr()->MgrDeallocShmem(mBuffer);
|
||||
mHost->SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPEncodedData, mBuffer);
|
||||
}
|
||||
mBuffer = ipc::Shmem();
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoEncodedFrameImpl::CreateEmptyFrame(uint32_t aSize)
|
||||
{
|
||||
DestroyBuffer();
|
||||
|
||||
if (aSize != 0) {
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(aSize, ipc::SharedMemory::TYPE_BASIC, &mBuffer) ||
|
||||
if (aSize == 0) {
|
||||
DestroyBuffer();
|
||||
} else if (aSize > AllocatedSize()) {
|
||||
DestroyBuffer();
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPEncodedData, aSize,
|
||||
ipc::SharedMemory::TYPE_BASIC, &mBuffer) ||
|
||||
!Buffer()) {
|
||||
return GMPVideoAllocErr;
|
||||
return GMPAllocErr;
|
||||
}
|
||||
}
|
||||
|
||||
mSize = aSize;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoEncodedFrameImpl::CopyFrame(const GMPVideoEncodedFrame& aFrame)
|
||||
{
|
||||
auto& f = static_cast<const GMPVideoEncodedFrameImpl&>(aFrame);
|
||||
|
||||
if (f.mSize != 0) {
|
||||
GMPVideoErr err = CreateEmptyFrame(f.mSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
GMPErr err = CreateEmptyFrame(f.mSize);
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
memcpy(Buffer(), f.Buffer(), f.mSize);
|
||||
@ -136,13 +146,14 @@ GMPVideoEncodedFrameImpl::CopyFrame(const GMPVideoEncodedFrame& aFrame)
|
||||
mEncodedWidth = f.mEncodedWidth;
|
||||
mEncodedHeight = f.mEncodedHeight;
|
||||
mTimeStamp = f.mTimeStamp;
|
||||
mCaptureTime_ms = f.mCaptureTime_ms;
|
||||
mDuration = f.mDuration;
|
||||
mFrameType = f.mFrameType;
|
||||
mSize = f.mSize;
|
||||
mSize = f.mSize; // already set...
|
||||
mCompleteFrame = f.mCompleteFrame;
|
||||
mBufferType = f.mBufferType;
|
||||
// Don't copy host, that should have been set properly on object creation via host.
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
@ -170,27 +181,27 @@ GMPVideoEncodedFrameImpl::EncodedHeight()
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetTimeStamp(uint32_t aTimeStamp)
|
||||
GMPVideoEncodedFrameImpl::SetTimeStamp(uint64_t aTimeStamp)
|
||||
{
|
||||
mTimeStamp = aTimeStamp;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
uint64_t
|
||||
GMPVideoEncodedFrameImpl::TimeStamp()
|
||||
{
|
||||
return mTimeStamp;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetCaptureTime(int64_t aCaptureTime)
|
||||
GMPVideoEncodedFrameImpl::SetDuration(uint64_t aDuration)
|
||||
{
|
||||
mCaptureTime_ms = aCaptureTime;
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
int64_t
|
||||
GMPVideoEncodedFrameImpl::CaptureTime()
|
||||
uint64_t
|
||||
GMPVideoEncodedFrameImpl::Duration() const
|
||||
{
|
||||
return mCaptureTime_ms;
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
void
|
||||
@ -217,7 +228,8 @@ GMPVideoEncodedFrameImpl::SetAllocatedSize(uint32_t aNewSize)
|
||||
}
|
||||
|
||||
ipc::Shmem new_mem;
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(aNewSize, ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPEncodedData, aNewSize,
|
||||
ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
|
||||
!new_mem.get<uint8_t>()) {
|
||||
return;
|
||||
}
|
||||
@ -282,5 +294,17 @@ GMPVideoEncodedFrameImpl::Destroy()
|
||||
delete this;
|
||||
}
|
||||
|
||||
GMPBufferType
|
||||
GMPVideoEncodedFrameImpl::BufferType() const
|
||||
{
|
||||
return mBufferType;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetBufferType(GMPBufferType aBufferType)
|
||||
{
|
||||
mBufferType = aBufferType;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
@ -31,9 +31,10 @@
|
||||
#ifndef GMPVideoEncodedFrameImpl_h_
|
||||
#define GMPVideoEncodedFrameImpl_h_
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-video-frame.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
#include "gmp-decryption.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -63,16 +64,21 @@ public:
|
||||
virtual void Destroy() MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoEncodedFrame
|
||||
virtual GMPVideoErr CreateEmptyFrame(uint32_t aSize) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CopyFrame(const GMPVideoEncodedFrame& aFrame) MOZ_OVERRIDE;
|
||||
virtual GMPErr CreateEmptyFrame(uint32_t aSize) MOZ_OVERRIDE;
|
||||
virtual GMPErr CopyFrame(const GMPVideoEncodedFrame& aFrame) MOZ_OVERRIDE;
|
||||
virtual void SetEncodedWidth(uint32_t aEncodedWidth) MOZ_OVERRIDE;
|
||||
virtual uint32_t EncodedWidth() MOZ_OVERRIDE;
|
||||
virtual void SetEncodedHeight(uint32_t aEncodedHeight) MOZ_OVERRIDE;
|
||||
virtual uint32_t EncodedHeight() MOZ_OVERRIDE;
|
||||
virtual void SetTimeStamp(uint32_t aTimeStamp) MOZ_OVERRIDE;
|
||||
virtual uint32_t TimeStamp() MOZ_OVERRIDE;
|
||||
virtual void SetCaptureTime(int64_t aCaptureTime) MOZ_OVERRIDE;
|
||||
virtual int64_t CaptureTime() MOZ_OVERRIDE;
|
||||
// Microseconds
|
||||
virtual void SetTimeStamp(uint64_t aTimeStamp) MOZ_OVERRIDE;
|
||||
virtual uint64_t TimeStamp() MOZ_OVERRIDE;
|
||||
// Set frame duration (microseconds)
|
||||
// NOTE: next-frame's Timestamp() != this-frame's TimeStamp()+Duration()
|
||||
// depending on rounding to avoid having to track roundoff errors
|
||||
// and dropped/missing frames(!) (which may leave a large gap)
|
||||
virtual void SetDuration(uint64_t aDuration) MOZ_OVERRIDE;
|
||||
virtual uint64_t Duration() const MOZ_OVERRIDE;
|
||||
virtual void SetFrameType(GMPVideoFrameType aFrameType) MOZ_OVERRIDE;
|
||||
virtual GMPVideoFrameType FrameType() MOZ_OVERRIDE;
|
||||
virtual void SetAllocatedSize(uint32_t aNewSize) MOZ_OVERRIDE;
|
||||
@ -83,19 +89,23 @@ public:
|
||||
virtual bool CompleteFrame() MOZ_OVERRIDE;
|
||||
virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
|
||||
virtual uint8_t* Buffer() MOZ_OVERRIDE;
|
||||
virtual GMPBufferType BufferType() const MOZ_OVERRIDE;
|
||||
virtual void SetBufferType(GMPBufferType aBufferType) MOZ_OVERRIDE;
|
||||
virtual const GMPEncryptedBufferData* GetDecryptionData() const MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
void DestroyBuffer();
|
||||
|
||||
uint32_t mEncodedWidth;
|
||||
uint32_t mEncodedHeight;
|
||||
uint32_t mTimeStamp;
|
||||
int64_t mCaptureTime_ms;
|
||||
uint64_t mTimeStamp;
|
||||
uint64_t mDuration;
|
||||
GMPVideoFrameType mFrameType;
|
||||
uint32_t mSize;
|
||||
bool mCompleteFrame;
|
||||
GMPVideoHostImpl* mHost;
|
||||
ipc::Shmem mBuffer;
|
||||
GMPBufferType mBufferType;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
@ -40,7 +40,8 @@ GMPVideoEncoderChild::Host()
|
||||
|
||||
void
|
||||
GMPVideoEncoderChild::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo)
|
||||
const uint8_t* aCodecSpecificInfo,
|
||||
uint32_t aCodecSpecificInfoLength)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
@ -49,31 +50,22 @@ GMPVideoEncoderChild::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
GMPVideoEncodedFrameData frameData;
|
||||
ef->RelinquishFrameData(frameData);
|
||||
|
||||
SendEncoded(frameData, aCodecSpecificInfo);
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
codecSpecific.AppendElements(aCodecSpecificInfo, aCodecSpecificInfoLength);
|
||||
SendEncoded(frameData, codecSpecific);
|
||||
|
||||
aEncodedFrame->Destroy();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
void
|
||||
GMPVideoEncoderChild::CheckThread()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::MgrDeallocShmem(Shmem& aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
const int32_t& aNumberOfCores,
|
||||
const uint32_t& aMaxPayloadSize)
|
||||
{
|
||||
@ -82,15 +74,20 @@ GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->InitEncode(aCodecSettings, this, aNumberOfCores, aMaxPayloadSize);
|
||||
mVideoEncoder->InitEncode(aCodecSettings,
|
||||
aCodecSpecific.Elements(),
|
||||
aCodecSpecific.Length(),
|
||||
this,
|
||||
aNumberOfCores,
|
||||
aMaxPayloadSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvEncode(const GMPVideoi420FrameData& aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const InfallibleTArray<int>& aFrameTypes)
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
const nsTArray<GMPVideoFrameType>& aFrameTypes)
|
||||
{
|
||||
if (!mVideoEncoder) {
|
||||
return false;
|
||||
@ -98,17 +95,26 @@ GMPVideoEncoderChild::RecvEncode(const GMPVideoi420FrameData& aInputFrame,
|
||||
|
||||
auto f = new GMPVideoi420FrameImpl(aInputFrame, &mVideoHost);
|
||||
|
||||
std::vector<GMPVideoFrameType> frameTypes(aFrameTypes.Length());
|
||||
for (uint32_t i = 0; i < aFrameTypes.Length(); i++) {
|
||||
frameTypes[i] = static_cast<GMPVideoFrameType>(aFrameTypes[i]);
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->Encode(f, aCodecSpecificInfo, frameTypes);
|
||||
mVideoEncoder->Encode(f,
|
||||
aCodecSpecificInfo.Elements(),
|
||||
aCodecSpecificInfo.Length(),
|
||||
aFrameTypes.Elements(),
|
||||
aFrameTypes.Length());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvChildShmemForPool(Shmem& aEncodedBuffer)
|
||||
{
|
||||
if (aEncodedBuffer.IsWritable()) {
|
||||
mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPEncodedData,
|
||||
aEncodedBuffer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvSetChannelParameters(const uint32_t& aPacketLoss,
|
||||
const uint32_t& aRTT)
|
||||
|
@ -18,7 +18,7 @@ namespace gmp {
|
||||
class GMPChild;
|
||||
|
||||
class GMPVideoEncoderChild : public PGMPVideoEncoderChild,
|
||||
public GMPEncoderCallback,
|
||||
public GMPVideoEncoderCallback,
|
||||
public GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
@ -28,24 +28,44 @@ public:
|
||||
void Init(GMPVideoEncoder* aEncoder);
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPEncoderCallback
|
||||
// GMPVideoEncoderCallback
|
||||
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
|
||||
const uint8_t* aCodecSpecificInfo,
|
||||
uint32_t aCodecSpecificInfoLength) MOZ_OVERRIDE;
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
virtual void CheckThread();
|
||||
virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
|
||||
{
|
||||
#ifndef SHMEM_ALLOC_IN_CHILD
|
||||
return CallNeedShmem(aSize, aMem);
|
||||
#else
|
||||
#ifdef GMP_SAFE_SHMEM
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
#else
|
||||
return AllocUnsafeShmem(aSize, aType, aMem);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
virtual void Dealloc(Shmem& aMem)
|
||||
{
|
||||
#ifndef SHMEM_ALLOC_IN_CHILD
|
||||
SendParentShmemForPool(aMem);
|
||||
#else
|
||||
DeallocShmem(aMem);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
// PGMPVideoEncoderChild
|
||||
virtual bool RecvInitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
const int32_t& aNumberOfCores,
|
||||
const uint32_t& aMaxPayloadSize) MOZ_OVERRIDE;
|
||||
virtual bool RecvEncode(const GMPVideoi420FrameData& aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const InfallibleTArray<int>& aFrameTypes) MOZ_OVERRIDE;
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
const nsTArray<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
|
||||
virtual bool RecvChildShmemForPool(Shmem& aEncodedBuffer) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetChannelParameters(const uint32_t& aPacketLoss,
|
||||
const uint32_t& aRTT) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetRates(const uint32_t& aNewBitRate,
|
||||
|
@ -43,60 +43,43 @@ GMPVideoEncoderParent::Host()
|
||||
return mVideoHost;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::MgrDeallocShmem(Shmem& aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoEncoderParent::InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPEncoderCallback* aCallback,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
GMPVideoEncoderCallbackProxy* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!aCallback) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
mCallback = aCallback;
|
||||
|
||||
if (!SendInitEncode(aCodecSettings, aNumberOfCores, aMaxPayloadSize)) {
|
||||
return GMPVideoGenericErr;
|
||||
if (!SendInitEncode(aCodecSettings, aCodecSpecific, aNumberOfCores, aMaxPayloadSize)) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoEncoderParent::Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const std::vector<GMPVideoFrameType>& aFrameTypes)
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
const nsTArray<GMPVideoFrameType>& aFrameTypes)
|
||||
{
|
||||
nsAutoRef<GMPVideoi420Frame> frameRef(aInputFrame);
|
||||
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
@ -106,74 +89,76 @@ GMPVideoEncoderParent::Encode(GMPVideoi420Frame* aInputFrame,
|
||||
GMPVideoi420FrameData frameData;
|
||||
inputFrameImpl->InitFrameData(frameData);
|
||||
|
||||
InfallibleTArray<int> frameTypes;
|
||||
frameTypes.SetCapacity(aFrameTypes.size());
|
||||
for (std::vector<int>::size_type i = 0; i != aFrameTypes.size(); i++) {
|
||||
frameTypes.AppendElement(static_cast<int>(aFrameTypes[i]));
|
||||
// Very rough kill-switch if the plugin stops processing. If it's merely
|
||||
// hung and continues, we'll come back to life eventually.
|
||||
// 3* is because we're using 3 buffers per frame for i420 data for now.
|
||||
if (NumInUse(kGMPFrameData) > 3*GMPSharedMemManager::kGMPBufLimit ||
|
||||
NumInUse(kGMPEncodedData) > GMPSharedMemManager::kGMPBufLimit) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
if (!SendEncode(frameData,
|
||||
aCodecSpecificInfo,
|
||||
frameTypes)) {
|
||||
return GMPVideoGenericErr;
|
||||
aFrameTypes)) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoEncoderParent::SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendSetChannelParameters(aPacketLoss, aRTT)) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoEncoderParent::SetRates(uint32_t aNewBitRate, uint32_t aFrameRate)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendSetRates(aNewBitRate, aFrameRate)) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoEncoderParent::SetPeriodicKeyFrames(bool aEnable)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendSetPeriodicKeyFrames(aEnable)) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
|
||||
@ -210,9 +195,15 @@ GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
mVideoHost.ActorDestroyed();
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncoderParent::CheckThread()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo)
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo)
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
@ -223,6 +214,35 @@ GMPVideoEncoderParent::RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->Encoded(f, aCodecSpecificInfo);
|
||||
|
||||
// Return SHM to sender to recycle
|
||||
//SendEncodedReturn(aEncodedFrame, aCodecSpecificInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::RecvParentShmemForPool(Shmem& aFrameBuffer)
|
||||
{
|
||||
if (aFrameBuffer.IsWritable()) {
|
||||
mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPFrameData,
|
||||
aFrameBuffer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::AnswerNeedShmem(const uint32_t& aEncodedBufferSize,
|
||||
Shmem* aMem)
|
||||
{
|
||||
ipc::Shmem mem;
|
||||
|
||||
if (!mVideoHost.SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPEncodedData,
|
||||
aEncodedBufferSize,
|
||||
ipc::SharedMemory::TYPE_BASIC, &mem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*aMem = mem;
|
||||
mem = ipc::Shmem();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -12,13 +12,14 @@
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "GMPVideoEncoderProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPParent;
|
||||
|
||||
class GMPVideoEncoderParent : public GMPVideoEncoder,
|
||||
class GMPVideoEncoderParent : public GMPVideoEncoderProxy,
|
||||
public PGMPVideoEncoderParent,
|
||||
public GMPSharedMemManager
|
||||
{
|
||||
@ -29,37 +30,50 @@ public:
|
||||
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoEncoder
|
||||
virtual GMPVideoErr InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPEncoderCallback* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const std::vector<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) MOZ_OVERRIDE;
|
||||
// GMPVideoEncoderProxy
|
||||
virtual GMPErr InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
GMPVideoEncoderCallbackProxy* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) MOZ_OVERRIDE;
|
||||
virtual GMPErr Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
const nsTArray<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
|
||||
virtual GMPErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) MOZ_OVERRIDE;
|
||||
virtual GMPErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) MOZ_OVERRIDE;
|
||||
virtual GMPErr SetPeriodicKeyFrames(bool aEnable) MOZ_OVERRIDE;
|
||||
virtual void EncodingComplete() MOZ_OVERRIDE;
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual void CheckThread();
|
||||
virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
|
||||
{
|
||||
#ifdef GMP_SAFE_SHMEM
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
#else
|
||||
return AllocUnsafeShmem(aSize, aType, aMem);
|
||||
#endif
|
||||
}
|
||||
virtual void Dealloc(Shmem& aMem)
|
||||
{
|
||||
DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~GMPVideoEncoderParent();
|
||||
|
||||
// PGMPVideoEncoderParent
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
virtual bool RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo) MOZ_OVERRIDE;
|
||||
virtual bool RecvParentShmemForPool(Shmem& aFrameBuffer) MOZ_OVERRIDE;
|
||||
virtual bool AnswerNeedShmem(const uint32_t& aEncodedBufferSize,
|
||||
Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mCanSendMessages;
|
||||
GMPParent* mPlugin;
|
||||
GMPEncoderCallback* mCallback;
|
||||
GMPVideoEncoderCallbackProxy* mCallback;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
};
|
||||
|
||||
|
40
content/media/gmp/GMPVideoEncoderProxy.h
Normal file
40
content/media/gmp/GMPVideoEncoderProxy.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- 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 GMPVideoEncoderProxy_h_
|
||||
#define GMPVideoEncoderProxy_h_
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "gmp-video-encode.h"
|
||||
#include "gmp-video-frame-i420.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
|
||||
class GMPVideoEncoderCallbackProxy {
|
||||
public:
|
||||
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo) = 0;
|
||||
};
|
||||
|
||||
// A proxy to GMPVideoEncoder in the child process.
|
||||
// GMPVideoEncoderParent exposes this to users the GMP.
|
||||
// This enables Gecko to pass nsTArrays to the child GMP and avoid
|
||||
// an extra copy when doing so.
|
||||
class GMPVideoEncoderProxy {
|
||||
public:
|
||||
virtual GMPErr InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
const nsTArray<uint8_t>& aCodecSpecific,
|
||||
GMPVideoEncoderCallbackProxy* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) = 0;
|
||||
virtual GMPErr Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo,
|
||||
const nsTArray<GMPVideoFrameType>& aFrameTypes) = 0;
|
||||
virtual GMPErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
|
||||
virtual GMPErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
|
||||
virtual GMPErr SetPeriodicKeyFrames(bool aEnable) = 0;
|
||||
virtual void EncodingComplete() = 0;
|
||||
};
|
||||
|
||||
#endif // GMPVideoEncoderProxy_h_
|
@ -20,41 +20,41 @@ GMPVideoHostImpl::~GMPVideoHostImpl()
|
||||
{
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoHostImpl::CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame)
|
||||
{
|
||||
if (!mSharedMemMgr) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
if (!aFrame) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
*aFrame = nullptr;
|
||||
|
||||
switch (aFormat) {
|
||||
case kGMPI420VideoFrame:
|
||||
*aFrame = new GMPVideoi420FrameImpl(this);
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
case kGMPEncodedVideoFrame:
|
||||
*aFrame = new GMPVideoEncodedFrameImpl(this);
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown frame format!");
|
||||
}
|
||||
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoHostImpl::CreatePlane(GMPPlane** aPlane)
|
||||
{
|
||||
if (!mSharedMemMgr) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
if (!aPlane) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
*aPlane = nullptr;
|
||||
|
||||
@ -62,7 +62,7 @@ GMPVideoHostImpl::CreatePlane(GMPPlane** aPlane)
|
||||
|
||||
*aPlane = p;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPSharedMemManager*
|
||||
|
@ -35,8 +35,8 @@ public:
|
||||
void EncodedFrameDestroyed(GMPVideoEncodedFrameImpl* aFrame);
|
||||
|
||||
// GMPVideoHost
|
||||
virtual GMPVideoErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CreatePlane(GMPPlane** aPlane) MOZ_OVERRIDE;
|
||||
virtual GMPErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) MOZ_OVERRIDE;
|
||||
virtual GMPErr CreatePlane(GMPPlane** aPlane) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// All shared memory allocations have to be made by an IPDL actor.
|
||||
|
@ -73,20 +73,21 @@ GMPPlaneImpl::InitPlaneData(GMPPlaneData& aPlaneData)
|
||||
return true;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPPlaneImpl::MaybeResize(int32_t aNewSize) {
|
||||
if (aNewSize <= AllocatedSize()) {
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
if (!mHost) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
ipc::Shmem new_mem;
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(aNewSize, ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPFrameData, aNewSize,
|
||||
ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
|
||||
!new_mem.get<uint8_t>()) {
|
||||
return GMPVideoAllocErr;
|
||||
return GMPAllocErr;
|
||||
}
|
||||
|
||||
if (mBuffer.IsReadable()) {
|
||||
@ -97,43 +98,43 @@ GMPPlaneImpl::MaybeResize(int32_t aNewSize) {
|
||||
|
||||
mBuffer = new_mem;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPPlaneImpl::DestroyBuffer()
|
||||
{
|
||||
if (mHost && mBuffer.IsWritable()) {
|
||||
mHost->SharedMemMgr()->MgrDeallocShmem(mBuffer);
|
||||
mHost->SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPFrameData, mBuffer);
|
||||
}
|
||||
mBuffer = ipc::Shmem();
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPPlaneImpl::CreateEmptyPlane(int32_t aAllocatedSize, int32_t aStride, int32_t aPlaneSize)
|
||||
{
|
||||
if (aAllocatedSize < 1 || aStride < 1 || aPlaneSize < 1) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
GMPVideoErr err = MaybeResize(aAllocatedSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
GMPErr err = MaybeResize(aAllocatedSize);
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mSize = aPlaneSize;
|
||||
mStride = aStride;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPPlaneImpl::Copy(const GMPPlane& aPlane)
|
||||
{
|
||||
auto& planeimpl = static_cast<const GMPPlaneImpl&>(aPlane);
|
||||
|
||||
GMPVideoErr err = MaybeResize(planeimpl.mSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
GMPErr err = MaybeResize(planeimpl.mSize);
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -144,14 +145,14 @@ GMPPlaneImpl::Copy(const GMPPlane& aPlane)
|
||||
mSize = planeimpl.mSize;
|
||||
mStride = planeimpl.mStride;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPPlaneImpl::Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer)
|
||||
{
|
||||
GMPVideoErr err = MaybeResize(aSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
GMPErr err = MaybeResize(aSize);
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -162,7 +163,7 @@ GMPPlaneImpl::Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer)
|
||||
mSize = aSize;
|
||||
mStride = aStride;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -34,13 +34,13 @@ public:
|
||||
bool InitPlaneData(GMPPlaneData& aPlaneData);
|
||||
|
||||
// GMPPlane
|
||||
virtual GMPVideoErr CreateEmptyPlane(int32_t aAllocatedSize,
|
||||
int32_t aStride,
|
||||
int32_t aPlaneSize) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Copy(const GMPPlane& aPlane) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Copy(int32_t aSize,
|
||||
int32_t aStride,
|
||||
const uint8_t* aBuffer) MOZ_OVERRIDE;
|
||||
virtual GMPErr CreateEmptyPlane(int32_t aAllocatedSize,
|
||||
int32_t aStride,
|
||||
int32_t aPlaneSize) MOZ_OVERRIDE;
|
||||
virtual GMPErr Copy(const GMPPlane& aPlane) MOZ_OVERRIDE;
|
||||
virtual GMPErr Copy(int32_t aSize,
|
||||
int32_t aStride,
|
||||
const uint8_t* aBuffer) MOZ_OVERRIDE;
|
||||
virtual void Swap(GMPPlane& aPlane) MOZ_OVERRIDE;
|
||||
virtual int32_t AllocatedSize() const MOZ_OVERRIDE;
|
||||
virtual void ResetSize() MOZ_OVERRIDE;
|
||||
@ -51,7 +51,7 @@ public:
|
||||
virtual void Destroy() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
GMPVideoErr MaybeResize(int32_t aNewSize);
|
||||
GMPErr MaybeResize(int32_t aNewSize);
|
||||
void DestroyBuffer();
|
||||
|
||||
ipc::Shmem mBuffer;
|
||||
|
@ -15,8 +15,8 @@ GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost)
|
||||
mVPlane(aHost),
|
||||
mWidth(0),
|
||||
mHeight(0),
|
||||
mTimestamp(0),
|
||||
mRenderTime_ms(0)
|
||||
mTimestamp(0ll),
|
||||
mDuration(0ll)
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
}
|
||||
@ -29,7 +29,7 @@ GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrame
|
||||
mWidth(aFrameData.mWidth()),
|
||||
mHeight(aFrameData.mHeight()),
|
||||
mTimestamp(aFrameData.mTimestamp()),
|
||||
mRenderTime_ms(aFrameData.mRenderTime_ms())
|
||||
mDuration(aFrameData.mDuration())
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
}
|
||||
@ -47,7 +47,7 @@ GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData)
|
||||
aFrameData.mWidth() = mWidth;
|
||||
aFrameData.mHeight() = mHeight;
|
||||
aFrameData.mTimestamp() = mTimestamp;
|
||||
aFrameData.mRenderTime_ms() = mRenderTime_ms;
|
||||
aFrameData.mDuration() = mDuration;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -106,12 +106,12 @@ GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
|
||||
{
|
||||
if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
int32_t size_y = aStride_y * aHeight;
|
||||
@ -119,28 +119,28 @@ GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
|
||||
int32_t size_u = aStride_u * half_height;
|
||||
int32_t size_v = aStride_v * half_height;
|
||||
|
||||
GMPVideoErr err = mYPlane.CreateEmptyPlane(size_y, aStride_y, size_y);
|
||||
if (err != GMPVideoNoErr) {
|
||||
GMPErr err = mYPlane.CreateEmptyPlane(size_y, aStride_y, size_y);
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mUPlane.CreateEmptyPlane(size_u, aStride_u, size_u);
|
||||
if (err != GMPVideoNoErr) {
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mVPlane.CreateEmptyPlane(size_v, aStride_v, size_v);
|
||||
if (err != GMPVideoNoErr) {
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
mTimestamp = 0;
|
||||
mRenderTime_ms = 0;
|
||||
mTimestamp = 0ll;
|
||||
mDuration = 0ll;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoi420FrameImpl::CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
int32_t aSize_u, const uint8_t* aBuffer_u,
|
||||
int32_t aSize_v, const uint8_t* aBuffer_v,
|
||||
@ -152,58 +152,58 @@ GMPVideoi420FrameImpl::CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
MOZ_ASSERT(aBuffer_v);
|
||||
|
||||
if (aSize_y < 1 || aSize_u < 1 || aSize_v < 1) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
GMPVideoErr err = mYPlane.Copy(aSize_y, aStride_y, aBuffer_y);
|
||||
if (err != GMPVideoNoErr) {
|
||||
GMPErr err = mYPlane.Copy(aSize_y, aStride_y, aBuffer_y);
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mUPlane.Copy(aSize_u, aStride_u, aBuffer_u);
|
||||
if (err != GMPVideoNoErr) {
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mVPlane.Copy(aSize_v, aStride_v, aBuffer_v);
|
||||
if (err != GMPVideoNoErr) {
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame)
|
||||
{
|
||||
auto& f = static_cast<const GMPVideoi420FrameImpl&>(aFrame);
|
||||
|
||||
GMPVideoErr err = mYPlane.Copy(f.mYPlane);
|
||||
if (err != GMPVideoNoErr) {
|
||||
GMPErr err = mYPlane.Copy(f.mYPlane);
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mUPlane.Copy(f.mUPlane);
|
||||
if (err != GMPVideoNoErr) {
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mVPlane.Copy(f.mVPlane);
|
||||
if (err != GMPVideoNoErr) {
|
||||
if (err != GMPNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mWidth = f.mWidth;
|
||||
mHeight = f.mHeight;
|
||||
mTimestamp = f.mTimestamp;
|
||||
mRenderTime_ms = f.mRenderTime_ms;
|
||||
mDuration = f.mDuration;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
@ -216,7 +216,7 @@ GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame)
|
||||
std::swap(mWidth, f->mWidth);
|
||||
std::swap(mHeight, f->mHeight);
|
||||
std::swap(mTimestamp, f->mTimestamp);
|
||||
std::swap(mRenderTime_ms, f->mRenderTime_ms);
|
||||
std::swap(mDuration, f->mDuration);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
@ -259,28 +259,28 @@ GMPVideoi420FrameImpl::Stride(GMPPlaneType aType) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoi420FrameImpl::SetWidth(int32_t aWidth)
|
||||
{
|
||||
if (!CheckDimensions(aWidth, mHeight,
|
||||
mYPlane.Stride(), mUPlane.Stride(),
|
||||
mVPlane.Stride())) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
mWidth = aWidth;
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPErr
|
||||
GMPVideoi420FrameImpl::SetHeight(int32_t aHeight)
|
||||
{
|
||||
if (!CheckDimensions(mWidth, aHeight,
|
||||
mYPlane.Stride(), mUPlane.Stride(),
|
||||
mVPlane.Stride())) {
|
||||
return GMPVideoGenericErr;
|
||||
return GMPGenericErr;
|
||||
}
|
||||
mHeight = aHeight;
|
||||
return GMPVideoNoErr;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
@ -296,27 +296,27 @@ GMPVideoi420FrameImpl::Height() const
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoi420FrameImpl::SetTimestamp(uint32_t aTimestamp)
|
||||
GMPVideoi420FrameImpl::SetTimestamp(uint64_t aTimestamp)
|
||||
{
|
||||
mTimestamp = aTimestamp;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
uint64_t
|
||||
GMPVideoi420FrameImpl::Timestamp() const
|
||||
{
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoi420FrameImpl::SetRenderTime_ms(int64_t aRenderTime_ms)
|
||||
GMPVideoi420FrameImpl::SetDuration(uint64_t aDuration)
|
||||
{
|
||||
mRenderTime_ms = aRenderTime_ms;
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
int64_t
|
||||
GMPVideoi420FrameImpl::RenderTime_ms() const
|
||||
uint64_t
|
||||
GMPVideoi420FrameImpl::Duration() const
|
||||
{
|
||||
return mRenderTime_ms;
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -32,33 +32,33 @@ public:
|
||||
virtual void Destroy() MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoi420Frame
|
||||
virtual GMPVideoErr CreateEmptyFrame(int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aStride_y,
|
||||
int32_t aStride_u,
|
||||
int32_t aStride_v) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
int32_t aSize_u, const uint8_t* aBuffer_u,
|
||||
int32_t aSize_v, const uint8_t* aBuffer_v,
|
||||
int32_t aWidth,
|
||||
virtual GMPErr CreateEmptyFrame(int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aStride_y,
|
||||
int32_t aStride_u,
|
||||
int32_t aStride_v) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CopyFrame(const GMPVideoi420Frame& aFrame) MOZ_OVERRIDE;
|
||||
virtual GMPErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
int32_t aSize_u, const uint8_t* aBuffer_u,
|
||||
int32_t aSize_v, const uint8_t* aBuffer_v,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aStride_y,
|
||||
int32_t aStride_u,
|
||||
int32_t aStride_v) MOZ_OVERRIDE;
|
||||
virtual GMPErr CopyFrame(const GMPVideoi420Frame& aFrame) MOZ_OVERRIDE;
|
||||
virtual void SwapFrame(GMPVideoi420Frame* aFrame) MOZ_OVERRIDE;
|
||||
virtual uint8_t* Buffer(GMPPlaneType aType) MOZ_OVERRIDE;
|
||||
virtual const uint8_t* Buffer(GMPPlaneType aType) const MOZ_OVERRIDE;
|
||||
virtual int32_t AllocatedSize(GMPPlaneType aType) const MOZ_OVERRIDE;
|
||||
virtual int32_t Stride(GMPPlaneType aType) const MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetWidth(int32_t aWidth) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetHeight(int32_t aHeight) MOZ_OVERRIDE;
|
||||
virtual GMPErr SetWidth(int32_t aWidth) MOZ_OVERRIDE;
|
||||
virtual GMPErr SetHeight(int32_t aHeight) MOZ_OVERRIDE;
|
||||
virtual int32_t Width() const MOZ_OVERRIDE;
|
||||
virtual int32_t Height() const MOZ_OVERRIDE;
|
||||
virtual void SetTimestamp(uint32_t aTimestamp) MOZ_OVERRIDE;
|
||||
virtual uint32_t Timestamp() const MOZ_OVERRIDE;
|
||||
virtual void SetRenderTime_ms(int64_t aRenderTime_ms) MOZ_OVERRIDE;
|
||||
virtual int64_t RenderTime_ms() const MOZ_OVERRIDE;
|
||||
virtual void SetTimestamp(uint64_t aTimestamp) MOZ_OVERRIDE;
|
||||
virtual uint64_t Timestamp() const MOZ_OVERRIDE;
|
||||
virtual void SetDuration(uint64_t aDuration) MOZ_OVERRIDE;
|
||||
virtual uint64_t Duration() const MOZ_OVERRIDE;
|
||||
virtual bool IsZeroSize() const MOZ_OVERRIDE;
|
||||
virtual void ResetSize() MOZ_OVERRIDE;
|
||||
|
||||
@ -71,8 +71,8 @@ private:
|
||||
GMPPlaneImpl mVPlane;
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
uint32_t mTimestamp;
|
||||
int64_t mRenderTime_ms;
|
||||
uint64_t mTimestamp;
|
||||
uint64_t mDuration;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
@ -9,13 +9,13 @@ include protocol PGMPVideoEncoder;
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
async protocol PGMP
|
||||
intr protocol PGMP
|
||||
{
|
||||
manages PGMPVideoDecoder;
|
||||
manages PGMPVideoEncoder;
|
||||
child:
|
||||
PGMPVideoDecoder();
|
||||
PGMPVideoEncoder();
|
||||
async PGMPVideoDecoder();
|
||||
async PGMPVideoEncoder();
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
@ -7,32 +7,40 @@ include protocol PGMP;
|
||||
include GMPTypes;
|
||||
|
||||
using GMPVideoCodec from "gmp-video-codec.h";
|
||||
using GMPCodecSpecificInfo from "gmp-video-codec.h";
|
||||
|
||||
include "GMPMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
async protocol PGMPVideoDecoder
|
||||
intr protocol PGMPVideoDecoder
|
||||
{
|
||||
manager PGMP;
|
||||
child:
|
||||
InitDecode(GMPVideoCodec aCodecSettings,
|
||||
int32_t aCoreCount);
|
||||
Decode(GMPVideoEncodedFrameData aInputFrame,
|
||||
bool aMissingFrames,
|
||||
GMPCodecSpecificInfo aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs);
|
||||
Reset();
|
||||
Drain();
|
||||
DecodingComplete();
|
||||
async InitDecode(GMPVideoCodec aCodecSettings,
|
||||
uint8_t[] aCodecSpecific,
|
||||
int32_t aCoreCount);
|
||||
async Decode(GMPVideoEncodedFrameData aInputFrame,
|
||||
bool aMissingFrames,
|
||||
uint8_t[] aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs);
|
||||
async Reset();
|
||||
async Drain();
|
||||
async DecodingComplete();
|
||||
async ChildShmemForPool(Shmem aFrameBuffer);
|
||||
|
||||
parent:
|
||||
__delete__();
|
||||
Decoded(GMPVideoi420FrameData aDecodedFrame);
|
||||
ReceivedDecodedReferenceFrame(uint64_t aPictureId);
|
||||
ReceivedDecodedFrame(uint64_t aPictureId);
|
||||
InputDataExhausted();
|
||||
async __delete__();
|
||||
async Decoded(GMPVideoi420FrameData aDecodedFrame);
|
||||
async ReceivedDecodedReferenceFrame(uint64_t aPictureId);
|
||||
async ReceivedDecodedFrame(uint64_t aPictureId);
|
||||
async InputDataExhausted();
|
||||
async DrainComplete();
|
||||
async ResetComplete();
|
||||
async ParentShmemForPool(Shmem aEncodedBuffer);
|
||||
// MUST be intr - if sync and we create a new Shmem, when the returned
|
||||
// Shmem is received in the Child it will fail to Deserialize
|
||||
intr NeedShmem(uint32_t aFrameBufferSize) returns (Shmem aMem);
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
@ -7,32 +7,38 @@ include protocol PGMP;
|
||||
include GMPTypes;
|
||||
|
||||
using GMPVideoCodec from "gmp-video-codec.h";
|
||||
using GMPCodecSpecificInfo from "gmp-video-codec.h";
|
||||
using GMPVideoFrameType from "gmp-video-frame-encoded.h";
|
||||
|
||||
include "GMPMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
async protocol PGMPVideoEncoder
|
||||
intr protocol PGMPVideoEncoder
|
||||
{
|
||||
manager PGMP;
|
||||
child:
|
||||
InitEncode(GMPVideoCodec aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize);
|
||||
Encode(GMPVideoi420FrameData aInputFrame,
|
||||
GMPCodecSpecificInfo aCodecSpecificInfo,
|
||||
int[] aFrameTypes);
|
||||
SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT);
|
||||
SetRates(uint32_t aNewBitRate, uint32_t aFrameRate);
|
||||
SetPeriodicKeyFrames(bool aEnable);
|
||||
EncodingComplete();
|
||||
async InitEncode(GMPVideoCodec aCodecSettings,
|
||||
uint8_t[] aCodecSpecific,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize);
|
||||
async Encode(GMPVideoi420FrameData aInputFrame,
|
||||
uint8_t[] aCodecSpecificInfo,
|
||||
GMPVideoFrameType[] aFrameTypes);
|
||||
async SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT);
|
||||
async SetRates(uint32_t aNewBitRate, uint32_t aFrameRate);
|
||||
async SetPeriodicKeyFrames(bool aEnable);
|
||||
async EncodingComplete();
|
||||
async ChildShmemForPool(Shmem aEncodedBuffer);
|
||||
|
||||
parent:
|
||||
__delete__();
|
||||
Encoded(GMPVideoEncodedFrameData aEncodedFrame,
|
||||
GMPCodecSpecificInfo aCodecSpecificInfo);
|
||||
async __delete__();
|
||||
async Encoded(GMPVideoEncodedFrameData aEncodedFrame,
|
||||
uint8_t[] aCodecSpecificInfo);
|
||||
async ParentShmemForPool(Shmem aFrameBuffer);
|
||||
// MUST be intr - if sync and we create a new Shmem, when the returned
|
||||
// Shmem is received in the Child it will fail to Deserialize
|
||||
intr NeedShmem(uint32_t aEncodedBufferSize) returns (Shmem aMem);
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
52
content/media/gmp/gmp-api/gmp-async-shutdown.h
Normal file
52
content/media/gmp/gmp-api/gmp-async-shutdown.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* 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 GMP_ASYNC_SHUTDOWN_H_
|
||||
#define GMP_ASYNC_SHUTDOWN_H_
|
||||
|
||||
// API exposed by the plugin library to manage asynchronous shutdown.
|
||||
// Some plugins require special cleanup which may need to make calls
|
||||
// to host services and wait for async responses.
|
||||
//
|
||||
// To enable a plugins to block shutdown until its async shutdown is
|
||||
// complete, implement the GMPAsyncShutdown interface and return it when
|
||||
// your plugin's GMPGetAPI function is called with "async-shutdown".
|
||||
// When your GMPAsyncShutdown's BeginShutdown() implementation is called
|
||||
// by the GMP host, you should initate your async shutdown process.
|
||||
// Once you have completed shutdown, call the ShutdownComplete() function
|
||||
// of the GMPAsyncShutdownHost that is passed as the host argument to the
|
||||
// GMPGetAPI() call.
|
||||
//
|
||||
// Note: Your GMP's GMPShutdown function will still be called after your
|
||||
// call to ShutdownComplete().
|
||||
//
|
||||
// API name: "async-shutdown"
|
||||
// Host API: GMPAsyncShutdownHost
|
||||
class GMPAsyncShutdown {
|
||||
public:
|
||||
virtual ~GMPAsyncShutdown() {}
|
||||
|
||||
virtual void BeginShutdown() = 0;
|
||||
};
|
||||
|
||||
class GMPAsyncShutdownHost {
|
||||
public:
|
||||
virtual ~GMPAsyncShutdownHost() {}
|
||||
|
||||
virtual void ShutdownComplete() = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_ASYNC_SHUTDOWN_H_
|
43
content/media/gmp/gmp-api/gmp-audio-codec.h
Normal file
43
content/media/gmp/gmp-api/gmp-audio-codec.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* 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 GMP_AUDIO_CODEC_h_
|
||||
#define GMP_AUDIO_CODEC_h_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum GMPAudioCodecType
|
||||
{
|
||||
kGMPAudioCodecAAC,
|
||||
kGMPAudioCodecVorbis,
|
||||
kGMPAudioCodecInvalid // Should always be last.
|
||||
};
|
||||
|
||||
struct GMPAudioCodec
|
||||
{
|
||||
GMPAudioCodecType mCodecType;
|
||||
uint32_t mChannelCount;
|
||||
uint32_t mBitsPerChannel;
|
||||
uint32_t mSamplesPerSecond;
|
||||
|
||||
// Codec extra data, such as vorbis setup header, or
|
||||
// AAC AudioSpecificConfig.
|
||||
// These are null/0 if not externally negotiated
|
||||
const uint8_t* mExtraData;
|
||||
size_t mExtraDataLen;
|
||||
};
|
||||
|
||||
#endif // GMP_AUDIO_CODEC_h_
|
72
content/media/gmp/gmp-api/gmp-audio-decode.h
Normal file
72
content/media/gmp/gmp-api/gmp-audio-decode.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* 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 GMP_AUDIO_DECODE_h_
|
||||
#define GMP_AUDIO_DECODE_h_
|
||||
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-audio-samples.h"
|
||||
#include "gmp-audio-codec.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
class GMPAudioDecoderCallback
|
||||
{
|
||||
public:
|
||||
virtual ~GMPAudioDecoderCallback() {}
|
||||
|
||||
virtual void Decoded(GMPAudioSamples* aDecodedSamples) = 0;
|
||||
|
||||
virtual void InputDataExhausted() = 0;
|
||||
|
||||
virtual void DrainComplete() = 0;
|
||||
|
||||
virtual void ResetComplete() = 0;
|
||||
};
|
||||
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
class GMPAudioDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~GMPAudioDecoder() {}
|
||||
|
||||
// aCallback: Subclass should retain reference to it until DecodingComplete
|
||||
// is called. Do not attempt to delete it, host retains ownership.
|
||||
// TODO: Pass AudioHost so decoder can create GMPAudioEncodedFrame objects?
|
||||
virtual GMPErr InitDecode(const GMPAudioCodec& aCodecSettings,
|
||||
GMPAudioDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Decode encoded audio frames (as a part of an audio stream). The decoded
|
||||
// frames must be returned to the user through the decode complete callback.
|
||||
virtual GMPErr Decode(GMPAudioSamples* aEncodedSamples) = 0;
|
||||
|
||||
// Reset decoder state and prepare for a new call to Decode(...).
|
||||
// Flushes the decoder pipeline.
|
||||
// The decoder should enqueue a task to run ResetComplete() on the main
|
||||
// thread once the reset has finished.
|
||||
virtual GMPErr Reset() = 0;
|
||||
|
||||
// Output decoded frames for any data in the pipeline, regardless of ordering.
|
||||
// All remaining decoded frames should be immediately returned via callback.
|
||||
// The decoder should enqueue a task to run DrainComplete() on the main
|
||||
// thread once the reset has finished.
|
||||
virtual GMPErr Drain() = 0;
|
||||
|
||||
// May free decoder memory.
|
||||
virtual void DecodingComplete() = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_VIDEO_DECODE_h_
|
32
content/media/gmp/gmp-api/gmp-audio-host.h
Normal file
32
content/media/gmp/gmp-api/gmp-audio-host.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* 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 GMP_AUDIO_HOST_h_
|
||||
#define GMP_AUDIO_HOST_h_
|
||||
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-audio-samples.h"
|
||||
|
||||
class GMPAudioHost
|
||||
{
|
||||
public:
|
||||
// Construct various Audio API objects. Host does not retain reference,
|
||||
// caller is owner and responsible for deleting.
|
||||
virtual GMPErr CreateSamples(GMPAudioFormat aFormat,
|
||||
GMPAudioSamples** aSamples) = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_AUDIO_HOST_h_
|
57
content/media/gmp/gmp-api/gmp-audio-samples.h
Normal file
57
content/media/gmp/gmp-api/gmp-audio-samples.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* 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 GMP_AUDIO_FRAME_h_
|
||||
#define GMP_AUDIO_FRAME_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
enum GMPAudioFormat
|
||||
{
|
||||
kGMPAudioEncodedSamples, // Raw compressed data, i.e. an AAC/Vorbis packet.
|
||||
kGMPAudioIS16Samples, // Interleaved int16_t PCM samples.
|
||||
kGMPAudioSamplesFormatInvalid // Should always be last.
|
||||
};
|
||||
|
||||
class GMPAudioSamples {
|
||||
public:
|
||||
// The format of the buffer.
|
||||
virtual GMPAudioFormat GetFormat() = 0;
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
// MAIN THREAD ONLY
|
||||
// Buffer size must be exactly what's required to contain all samples in
|
||||
// the buffer; every byte is assumed to be part of a sample.
|
||||
virtual GMPErr SetBufferSize(uint32_t aSize) = 0;
|
||||
|
||||
// Size of the buffer in bytes.
|
||||
virtual uint32_t Size() = 0;
|
||||
|
||||
// Timestamps are in microseconds, and are the playback start time of the
|
||||
// first sample in the buffer.
|
||||
virtual void SetTimeStamp(uint64_t aTimeStamp) = 0;
|
||||
virtual uint64_t TimeStamp() = 0;
|
||||
virtual const uint8_t* Buffer() const = 0;
|
||||
virtual uint8_t* Buffer() = 0;
|
||||
|
||||
// Get data describing how this frame is encrypted, or nullptr if the
|
||||
// buffer is not encrypted.
|
||||
virtual const GMPEncryptedBufferData* GetDecryptionData() const = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_AUDIO_FRAME_h_
|
208
content/media/gmp/gmp-api/gmp-decryption.h
Normal file
208
content/media/gmp/gmp-api/gmp-decryption.h
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* 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 GMP_DECRYPTION_h_
|
||||
#define GMP_DECRYPTION_h_
|
||||
|
||||
#include "gmp-platform.h"
|
||||
|
||||
class GMPEncryptedBufferData {
|
||||
public:
|
||||
// Key ID to identify the decryption key.
|
||||
virtual const uint8_t* KeyId() const = 0;
|
||||
|
||||
// Size (in bytes) of |KeyId()|.
|
||||
virtual uint32_t KeyIdSize() const = 0;
|
||||
|
||||
// Initialization vector.
|
||||
virtual const uint8_t* IV() const = 0;
|
||||
|
||||
// Size (in bytes) of |IV|.
|
||||
virtual uint32_t IVSize() const = 0;
|
||||
|
||||
// Number of enties returned by ClearBytes and CipherBytes().
|
||||
virtual uint32_t NumSubsamples() const = 0;
|
||||
|
||||
virtual const uint32_t* ClearBytes() const = 0;
|
||||
|
||||
virtual const uint32_t* CipherBytes() const = 0;
|
||||
};
|
||||
|
||||
// These match to the DOMException codes as per:
|
||||
// http://www.w3.org/TR/dom/#domexception
|
||||
enum GMPDOMException {
|
||||
kGMPNoModificationAllowedError = 7,
|
||||
kGMPNotFoundError = 8,
|
||||
kGMPNotSupportedError = 9,
|
||||
kGMPInvalidStateError = 11,
|
||||
kGMPSyntaxError = 12,
|
||||
kGMPInvalidModificationError = 13,
|
||||
kGMPInvalidAccessError = 15,
|
||||
kGMPSecurityError = 18,
|
||||
kGMPAbortError = 20,
|
||||
kGMPQuotaExceededError = 22,
|
||||
kGMPTimeoutError = 23
|
||||
};
|
||||
|
||||
// Time in milliseconds, as offset from epoch, 1 Jan 1970.
|
||||
typedef int64_t GMPTimestamp;
|
||||
|
||||
class GMPDecryptorCallback {
|
||||
public:
|
||||
// Resolves a promise for a session created or loaded.
|
||||
// Passes the session id to be exposed to JavaScript.
|
||||
// Must be called before OnSessionMessage().
|
||||
// aSessionId must be null terminated.
|
||||
virtual void OnResolveNewSessionPromise(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Called to resolve a specified promise with "undefined".
|
||||
virtual void OnResolvePromise(uint32_t aPromiseId) = 0;
|
||||
|
||||
// Called to reject a promise with a DOMException.
|
||||
// aMessage is logged to the WebConsole.
|
||||
// aMessage is optional, but if present must be null terminated.
|
||||
virtual void OnRejectPromise(uint32_t aPromiseId,
|
||||
GMPDOMException aException,
|
||||
const char* aMessage,
|
||||
uint32_t aMessageLength) = 0;
|
||||
|
||||
// Called by the CDM when it has a message for session |session_id|.
|
||||
// Length parameters should not include null termination.
|
||||
// aSessionId must be null terminated.
|
||||
virtual void OnSessionMessage(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aMessage,
|
||||
uint32_t aMessageLength,
|
||||
const char* aDestinationURL,
|
||||
uint32_t aDestinationURLLength) = 0;
|
||||
|
||||
// aSessionId must be null terminated.
|
||||
virtual void OnExpirationChange(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
GMPTimestamp aExpiryTime) = 0;
|
||||
|
||||
// Called by the GMP when a session is closed. All file IO
|
||||
// that a session requires should be complete before calling this.
|
||||
// aSessionId must be null terminated.
|
||||
virtual void OnSessionClosed(const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Called by the GMP when an error occurs in a session.
|
||||
// aSessionId must be null terminated.
|
||||
// aMessage is logged to the WebConsole.
|
||||
// aMessage is optional, but if present must be null terminated.
|
||||
virtual void OnSessionError(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
GMPDOMException aException,
|
||||
uint32_t aSystemCode,
|
||||
const char* aMessage,
|
||||
uint32_t aMessageLength) = 0;
|
||||
|
||||
virtual void OnKeyIdUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength) = 0;
|
||||
|
||||
// Marks a key as no longer usable.
|
||||
// Note: Keys are assumed to be not usable when a session is closed or removed.
|
||||
virtual void OnKeyIdNotUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength) = 0;
|
||||
|
||||
};
|
||||
|
||||
// Host interface, passed to GetAPIFunc(), with "decrypt".
|
||||
class GMPDecryptorHost {
|
||||
public:
|
||||
|
||||
// Returns an origin specific string uniquely identifying the device.
|
||||
// The node id contains a random component, and is consistent between
|
||||
// plugin instantiations, unless the user clears it.
|
||||
// Different origins have different node ids.
|
||||
// The node id pointer returned here remains valid for the until shutdown
|
||||
// begins.
|
||||
// *aOutNodeId is null terminated.
|
||||
virtual void GetNodeId(const char** aOutNodeId,
|
||||
uint32_t* aOutNodeIdLength) = 0;
|
||||
|
||||
virtual void GetSandboxVoucher(const uint8_t** aVoucher,
|
||||
uint8_t* aVoucherLength) = 0;
|
||||
|
||||
virtual void GetPluginVoucher(const uint8_t** aVoucher,
|
||||
uint8_t* aVoucherLength) = 0;
|
||||
};
|
||||
|
||||
enum GMPSessionType {
|
||||
kGMPTemporySession = 0,
|
||||
kGMPPersistentSession = 1
|
||||
};
|
||||
|
||||
// API exposed by plugin library to manage decryption sessions.
|
||||
// When the Host requests this by calling GMPGetAPIFunc().
|
||||
//
|
||||
// API name: "eme-decrypt".
|
||||
// Host API: GMPDecryptorHost
|
||||
class GMPDecryptor {
|
||||
public:
|
||||
|
||||
// Sets the callback to use with the decryptor to return results
|
||||
// to Gecko.
|
||||
virtual void Init(GMPDecryptorCallback* aCallback) = 0;
|
||||
|
||||
// Requests the creation of a session given |aType| and |aInitData|.
|
||||
// Decryptor should callback GMPDecryptorCallback::OnSessionCreated()
|
||||
// with the web session ID on success, or OnSessionError() on failure,
|
||||
// and then call OnSessionReady() once all keys for that session are
|
||||
// available.
|
||||
virtual void CreateSession(uint32_t aPromiseId,
|
||||
const char* aInitDataType,
|
||||
uint32_t aInitDataTypeSize,
|
||||
const uint8_t* aInitData,
|
||||
uint32_t aInitDataSize,
|
||||
GMPSessionType aSessionType) = 0;
|
||||
|
||||
// Loads a previously loaded persistent session.
|
||||
virtual void LoadSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Updates the session with |aResponse|.
|
||||
virtual void UpdateSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aResponse,
|
||||
uint32_t aResponseSize) = 0;
|
||||
|
||||
// Releases the resources (keys) for the specified session.
|
||||
virtual void CloseSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Removes the resources (keys) for the specified session.
|
||||
virtual void RemoveSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Resolve/reject promise on completion.
|
||||
virtual void SetServerCertificate(uint32_t aPromiseId,
|
||||
const uint8_t* aServerCert,
|
||||
uint32_t aServerCertSize) = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_DECRYPTION_h_
|
@ -35,7 +35,16 @@
|
||||
|
||||
typedef enum {
|
||||
GMPNoErr = 0,
|
||||
GMPGenericErr = 1
|
||||
GMPGenericErr = 1,
|
||||
GMPClosedErr = 2,
|
||||
GMPAllocErr = 3,
|
||||
GMPNotImplementedErr = 4,
|
||||
GMPNotClosedErr = 5,
|
||||
GMPQuotaExceededErr = 6,
|
||||
GMPLastErr // Placeholder, must be last. This enum's values must remain consecutive!
|
||||
} GMPErr;
|
||||
|
||||
#define GMP_SUCCEEDED(x) ((x) == GMPNoErr)
|
||||
#define GMP_FAILED(x) ((x) != GMPNoErr)
|
||||
|
||||
#endif // GMP_ERRORS_h_
|
||||
|
@ -34,12 +34,14 @@
|
||||
#define GMP_PLATFORM_h_
|
||||
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-storage.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Platform helper API. */
|
||||
|
||||
class GMPTask {
|
||||
public:
|
||||
virtual void Destroy() = 0;
|
||||
virtual ~GMPTask() {}
|
||||
virtual void Run() = 0;
|
||||
};
|
||||
@ -58,10 +60,20 @@ public:
|
||||
virtual void Release() = 0;
|
||||
};
|
||||
|
||||
// Time is defined as the number of milliseconds since the
|
||||
// Epoch (00:00:00 UTC, January 1, 1970).
|
||||
typedef int64_t GMPTimestamp;
|
||||
|
||||
typedef GMPErr (*GMPCreateThreadPtr)(GMPThread** aThread);
|
||||
typedef GMPErr (*GMPRunOnMainThreadPtr)(GMPTask* aTask);
|
||||
typedef GMPErr (*GMPSyncRunOnMainThreadPtr)(GMPTask* aTask);
|
||||
typedef GMPErr (*GMPCreateMutexPtr)(GMPMutex** aMutex);
|
||||
typedef GMPErr (*GMPCreateRecordPtr)(const char* aRecordName,
|
||||
uint32_t aRecordNameSize,
|
||||
GMPRecord** aOutRecord,
|
||||
GMPRecordClient* aClient);
|
||||
typedef GMPErr (*GMPSetTimerOnMainThreadPtr)(GMPTask* aTask, int64_t aTimeoutMS);
|
||||
typedef GMPErr (*GMPGetCurrentTimePtr)(GMPTimestamp* aOutTime);
|
||||
|
||||
struct GMPPlatformAPI {
|
||||
// Increment the version when things change. Can only add to the struct,
|
||||
@ -74,6 +86,9 @@ struct GMPPlatformAPI {
|
||||
GMPRunOnMainThreadPtr runonmainthread;
|
||||
GMPSyncRunOnMainThreadPtr syncrunonmainthread;
|
||||
GMPCreateMutexPtr createmutex;
|
||||
GMPCreateRecordPtr createrecord;
|
||||
GMPSetTimerOnMainThreadPtr settimer;
|
||||
GMPGetCurrentTimePtr getcurrenttime;
|
||||
};
|
||||
|
||||
#endif // GMP_PLATFORM_h_
|
||||
|
90
content/media/gmp/gmp-api/gmp-storage.h
Normal file
90
content/media/gmp/gmp-api/gmp-storage.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* 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 GMP_STORAGE_h_
|
||||
#define GMP_STORAGE_h_
|
||||
|
||||
#include "gmp-errors.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// Provides basic per-origin storage for CDMs. GMPRecord instances can be
|
||||
// retrieved by calling GMPPlatformAPI->openstorage. Multiple GMPRecord
|
||||
// can be open at once. This interface is asynchronous, with results
|
||||
// being returned via callbacks to the GMPRecordClient pointer provided
|
||||
// to the GMPPlatformAPI->openstorage call, on the main thread.
|
||||
class GMPRecord {
|
||||
public:
|
||||
|
||||
// Opens the record. Calls OnOpenComplete() once the record is open.
|
||||
// Note: OnReadComplete() is only called if this returns GMPNoErr.
|
||||
virtual GMPErr Open() = 0;
|
||||
|
||||
// Reads the entire contents of the file, and calls
|
||||
// GMPRecordClient::OnReadComplete() once the operation is complete.
|
||||
// Note: OnReadComplete() is only called if this returns GMPNoErr.
|
||||
virtual GMPErr Read() = 0;
|
||||
|
||||
// Writes aDataSize bytes of aData into the file, overwritting the contents
|
||||
// of the file. Overwriting with 0 bytes "deletes" the file.
|
||||
// Write 0 bytes to "delete" a file.
|
||||
// Note: OnWriteComplete is only called if this returns GMPNoErr.
|
||||
virtual GMPErr Write(const uint8_t* aData, uint32_t aDataSize) = 0;
|
||||
|
||||
// Closes a file. File must not be used after this is called. Cancels all
|
||||
// callbacks.
|
||||
virtual GMPErr Close() = 0;
|
||||
|
||||
virtual ~GMPRecord() {}
|
||||
};
|
||||
|
||||
// Callback object that receives the results of GMPRecord calls. Callbacks
|
||||
// run asynchronously to the GMPRecord call, on the main thread.
|
||||
class GMPRecordClient {
|
||||
public:
|
||||
|
||||
// Response to a GMPRecord::Open() call with the open |status|.
|
||||
// aStatus values:
|
||||
// - GMPNoErr - File opened successfully. File may be empty.
|
||||
// - GMPFileInUse - There file is in use by another client.
|
||||
// - GMPGenericErr - Unspecified error.
|
||||
// Do not use the GMPRecord if aStatus is not GMPNoErr.
|
||||
virtual void OnOpenComplete(GMPErr aStatus) = 0;
|
||||
|
||||
// Response to a GMPRecord::Read() call, where aData is the file contents,
|
||||
// of length aDataSize.
|
||||
// aData is only valid for the duration of the call to OnReadComplete.
|
||||
// Copy it if you want to hang onto it!
|
||||
// aStatus values:
|
||||
// - GMPNoErr - File contents read successfully, aDataSize 0 means file
|
||||
// is empty.
|
||||
// - GMPFileInUse - There are other operations or clients in use on this file.
|
||||
// - GMPGenericErr - Unspecified error.
|
||||
// Do not continue to use the GMPRecord if aStatus is not GMPNoErr.
|
||||
virtual void OnReadComplete(GMPErr aStatus,
|
||||
const uint8_t* aData,
|
||||
uint32_t aDataSize) = 0;
|
||||
|
||||
// Response to a GMPRecord::Write() call.
|
||||
// - GMPNoErr - File contents written successfully.
|
||||
// - GMPFileInUse - There are other operations or clients in use on this file.
|
||||
// - GMPGenericErr - Unspecified error. File should be regarded as corrupt.
|
||||
// Do not continue to use the GMPRecord if aStatus is not GMPNoErr.
|
||||
virtual void OnWriteComplete(GMPErr aStatus) = 0;
|
||||
|
||||
virtual ~GMPRecordClient() {}
|
||||
};
|
||||
|
||||
#endif // GMP_STORAGE_h_
|
@ -72,39 +72,50 @@ struct GMPVideoCodecVP8
|
||||
bool mDenoisingOn;
|
||||
bool mErrorConcealmentOn;
|
||||
bool mAutomaticResizeOn;
|
||||
bool mFrameDroppingOn;
|
||||
int32_t mKeyFrameInterval;
|
||||
};
|
||||
|
||||
// H264 specific
|
||||
struct GMPVideoCodecH264
|
||||
|
||||
// Needs to match a binary spec for this structure.
|
||||
// Note: the mSPS at the end of this structure is variable length.
|
||||
struct GMPVideoCodecH264AVCC
|
||||
{
|
||||
uint8_t mProfile;
|
||||
uint8_t mVersion; // == 0x01
|
||||
uint8_t mProfile; // these 3 are profile_level_id
|
||||
uint8_t mConstraints;
|
||||
uint8_t mLevel;
|
||||
uint8_t mLengthSizeMinusOne; // lower 2 bits (== GMPBufferType-1). Top 6 reserved (1's)
|
||||
|
||||
// SPS/PPS will not generally be present for interactive use unless SDP
|
||||
// parameter-sets are used.
|
||||
uint8_t mNumSPS; // lower 5 bits; top 5 reserved (1's)
|
||||
|
||||
/*** uint8_t mSPS[]; (Not defined due to compiler warnings and warnings-as-errors ...) **/
|
||||
// Following mNumSPS is a variable number of bytes, which is the SPS and PPS.
|
||||
// Each SPS == 16 bit size, ("N"), then "N" bytes,
|
||||
// then uint8_t mNumPPS, then each PPS == 16 bit size ("N"), then "N" bytes.
|
||||
};
|
||||
|
||||
// Codec specific data for H.264 decoding/encoding.
|
||||
// Cast the "aCodecSpecific" parameter of GMPVideoDecoder::InitDecode() and
|
||||
// GMPVideoEncoder::InitEncode() to this structure.
|
||||
struct GMPVideoCodecH264
|
||||
{
|
||||
uint8_t mPacketizationMode; // 0 or 1
|
||||
bool mFrameDroppingOn;
|
||||
int32_t mKeyFrameInterval;
|
||||
// These are null/0 if not externally negotiated
|
||||
const uint8_t* mSPSData;
|
||||
size_t mSPSLen;
|
||||
const uint8_t* mPPSData;
|
||||
size_t mPPSLen;
|
||||
struct GMPVideoCodecH264AVCC mAVCC; // holds a variable-sized struct GMPVideoCodecH264AVCC mAVCC;
|
||||
};
|
||||
|
||||
enum GMPVideoCodecType
|
||||
{
|
||||
kGMPVideoCodecVP8,
|
||||
|
||||
// Encoded frames are in AVCC format; NAL length field of 4 bytes, followed
|
||||
// by frame data. May be multiple NALUs per sample. Codec specific extra data
|
||||
// is the AVCC extra data (in AVCC format).
|
||||
kGMPVideoCodecH264,
|
||||
kGMPVideoCodecInvalid // Should always be last.
|
||||
};
|
||||
|
||||
union GMPVideoCodecUnion
|
||||
{
|
||||
GMPVideoCodecVP8 mVP8;
|
||||
GMPVideoCodecH264 mH264;
|
||||
};
|
||||
|
||||
// Simulcast is when the same stream is encoded multiple times with different
|
||||
// settings such as resolution.
|
||||
struct GMPSimulcastStream
|
||||
@ -121,11 +132,19 @@ struct GMPSimulcastStream
|
||||
enum GMPVideoCodecMode {
|
||||
kGMPRealtimeVideo,
|
||||
kGMPScreensharing,
|
||||
kGMPStreamingVideo,
|
||||
kGMPCodecModeInvalid // Should always be last.
|
||||
};
|
||||
|
||||
enum GMPApiVersion {
|
||||
kGMPVersion32 = 1, // leveraging that V32 had mCodecType first, and only supported H264
|
||||
kGMPVersion33 = 33,
|
||||
};
|
||||
|
||||
struct GMPVideoCodec
|
||||
{
|
||||
uint32_t mGMPApiVersion;
|
||||
|
||||
GMPVideoCodecType mCodecType;
|
||||
char mPLName[kGMPPayloadNameSize]; // Must be NULL-terminated!
|
||||
uint32_t mPLType;
|
||||
@ -138,7 +157,8 @@ struct GMPVideoCodec
|
||||
uint32_t mMinBitrate; // kilobits/sec.
|
||||
uint32_t mMaxFramerate;
|
||||
|
||||
GMPVideoCodecUnion mCodecSpecific;
|
||||
bool mFrameDroppingOn;
|
||||
int32_t mKeyFrameInterval;
|
||||
|
||||
uint32_t mQPMax;
|
||||
uint32_t mNumberOfSimulcastStreams;
|
||||
@ -157,6 +177,7 @@ enum GMPBufferType {
|
||||
GMP_BufferLength16,
|
||||
GMP_BufferLength24,
|
||||
GMP_BufferLength32,
|
||||
GMP_BufferInvalid,
|
||||
};
|
||||
|
||||
struct GMPCodecSpecificInfoGeneric {
|
||||
@ -188,6 +209,7 @@ union GMPCodecSpecificInfoUnion
|
||||
{
|
||||
GMPCodecSpecificInfoGeneric mGeneric;
|
||||
GMPCodecSpecificInfoVP8 mVP8;
|
||||
GMPCodecSpecificInfoH264 mH264;
|
||||
};
|
||||
|
||||
// Note: if any pointers are added to this struct or its sub-structs, it
|
||||
|
@ -34,17 +34,17 @@
|
||||
#ifndef GMP_VIDEO_DECODE_h_
|
||||
#define GMP_VIDEO_DECODE_h_
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-video-frame-i420.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
#include "gmp-video-codec.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
class GMPDecoderCallback
|
||||
class GMPVideoDecoderCallback
|
||||
{
|
||||
public:
|
||||
virtual ~GMPDecoderCallback() {}
|
||||
virtual ~GMPVideoDecoderCallback() {}
|
||||
|
||||
virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) = 0;
|
||||
|
||||
@ -53,6 +53,10 @@ public:
|
||||
virtual void ReceivedDecodedFrame(const uint64_t aPictureId) = 0;
|
||||
|
||||
virtual void InputDataExhausted() = 0;
|
||||
|
||||
virtual void DrainComplete() = 0;
|
||||
|
||||
virtual void ResetComplete() = 0;
|
||||
};
|
||||
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
@ -61,37 +65,48 @@ class GMPVideoDecoder
|
||||
public:
|
||||
virtual ~GMPVideoDecoder() {}
|
||||
|
||||
// aCallback: Subclass should retain reference to it until DecodingComplete
|
||||
// is called. Do not attempt to delete it, host retains ownership.
|
||||
virtual GMPVideoErr InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPDecoderCallback* aCallback,
|
||||
int32_t aCoreCount) = 0;
|
||||
// - aCodecSettings: Details of decoder to create.
|
||||
// - aCodecSpecific: codec specific data, cast to a GMPVideoCodecXXX struct
|
||||
// to get codec specific config data.
|
||||
// - aCodecSpecificLength: number of bytes in aCodecSpecific.
|
||||
// - aCallback: Subclass should retain reference to it until DecodingComplete
|
||||
// is called. Do not attempt to delete it, host retains ownership.
|
||||
// aCoreCount: number of CPU cores.
|
||||
virtual GMPErr InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
const uint8_t* aCodecSpecific,
|
||||
uint32_t aCodecSpecificLength,
|
||||
GMPVideoDecoderCallback* aCallback,
|
||||
int32_t aCoreCount) = 0;
|
||||
|
||||
// Decode encoded frame (as a part of a video stream). The decoded frame
|
||||
// will be returned to the user through the decode complete callback.
|
||||
//
|
||||
// inputFrame: Frame to decode.
|
||||
//
|
||||
// missingFrames: True if one or more frames have been lost since the previous decode call.
|
||||
//
|
||||
// fragmentation: Specifies where the encoded frame can be split into separate fragments.
|
||||
// The meaning of fragment is codec specific, but often means that each
|
||||
// fragment is decodable by itself.
|
||||
//
|
||||
// codecSpecificInfo: Codec-specific data
|
||||
//
|
||||
// renderTimeMs : System time to render in milliseconds. Only used by decoders with internal
|
||||
// rendering.
|
||||
virtual GMPVideoErr Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs = -1) = 0;
|
||||
// - aInputFrame: Frame to decode. Call Destroy() on frame when it's decoded.
|
||||
// - aMissingFrames: True if one or more frames have been lost since the
|
||||
// previous decode call.
|
||||
// - aCodecSpecificInfo : codec specific data, pointer to a
|
||||
// GMPCodecSpecificInfo structure appropriate for
|
||||
// this codec type.
|
||||
// - aCodecSpecificInfoLength : number of bytes in aCodecSpecificInfo
|
||||
// - renderTimeMs : System time to render in milliseconds. Only used by
|
||||
// decoders with internal rendering.
|
||||
virtual GMPErr Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const uint8_t* aCodecSpecificInfo,
|
||||
uint32_t aCodecSpecificInfoLength,
|
||||
int64_t aRenderTimeMs = -1) = 0;
|
||||
|
||||
// Reset decoder state and prepare for a new call to Decode(...). Flushes the decoder pipeline.
|
||||
virtual GMPVideoErr Reset() = 0;
|
||||
// Reset decoder state and prepare for a new call to Decode(...).
|
||||
// Flushes the decoder pipeline.
|
||||
// The decoder should enqueue a task to run ResetComplete() on the main
|
||||
// thread once the reset has finished.
|
||||
virtual GMPErr Reset() = 0;
|
||||
|
||||
// Output decoded frames for any data in the pipeline, regardless of ordering.
|
||||
virtual GMPVideoErr Drain() = 0;
|
||||
// All remaining decoded frames should be immediately returned via callback.
|
||||
// The decoder should enqueue a task to run DrainComplete() on the main
|
||||
// thread once the reset has finished.
|
||||
virtual GMPErr Drain() = 0;
|
||||
|
||||
// May free decoder memory.
|
||||
virtual void DecodingComplete() = 0;
|
||||
|
@ -37,19 +37,20 @@
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-video-frame-i420.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
#include "gmp-video-codec.h"
|
||||
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
class GMPEncoderCallback
|
||||
class GMPVideoEncoderCallback
|
||||
{
|
||||
public:
|
||||
virtual ~GMPEncoderCallback() {}
|
||||
virtual ~GMPVideoEncoderCallback() {}
|
||||
|
||||
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo) = 0;
|
||||
const uint8_t* aCodecSpecificInfo,
|
||||
uint32_t aCodecSpecificInfoLength) = 0;
|
||||
};
|
||||
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
@ -62,26 +63,38 @@ public:
|
||||
//
|
||||
// Input:
|
||||
// - codecSettings : Codec settings
|
||||
// - aCodecSpecific : codec specific data, pointer to a
|
||||
// GMPCodecSpecific structure appropriate for
|
||||
// this codec type.
|
||||
// - aCodecSpecificLength : number of bytes in aCodecSpecific
|
||||
// - aCallback: Subclass should retain reference to it until EncodingComplete
|
||||
// is called. Do not attempt to delete it, host retains ownership.
|
||||
// - numberOfCores : Number of cores available for the encoder
|
||||
// - maxPayloadSize : The maximum size each payload is allowed
|
||||
// - aNnumberOfCores : Number of cores available for the encoder
|
||||
// - aMaxPayloadSize : The maximum size each payload is allowed
|
||||
// to have. Usually MTU - overhead.
|
||||
virtual GMPVideoErr InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPEncoderCallback* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) = 0;
|
||||
virtual GMPErr InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
const uint8_t* aCodecSpecific,
|
||||
uint32_t aCodecSpecificLength,
|
||||
GMPVideoEncoderCallback* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) = 0;
|
||||
|
||||
// Encode an I420 frame (as a part of a video stream). The encoded frame
|
||||
// will be returned to the user through the encode complete callback.
|
||||
//
|
||||
// Input:
|
||||
// - inputFrame : Frame to be encoded
|
||||
// - codecSpecificInfo : Pointer to codec specific data
|
||||
// - frame_types : The frame type to encode
|
||||
virtual GMPVideoErr Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const std::vector<GMPVideoFrameType>& aFrameTypes) = 0;
|
||||
// - aInputFrame : Frame to be encoded
|
||||
// - aCodecSpecificInfo : codec specific data, pointer to a
|
||||
// GMPCodecSpecificInfo structure appropriate for
|
||||
// this codec type.
|
||||
// - aCodecSpecificInfoLength : number of bytes in aCodecSpecific
|
||||
// - aFrameTypes : The frame type to encode
|
||||
// - aFrameTypesLength : The number of elements in aFrameTypes array.
|
||||
virtual GMPErr Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const uint8_t* aCodecSpecificInfo,
|
||||
uint32_t aCodecSpecificInfoLength,
|
||||
const GMPVideoFrameType* aFrameTypes,
|
||||
uint32_t aFrameTypesLength) = 0;
|
||||
|
||||
// Inform the encoder about the packet loss and round trip time on the
|
||||
// network used to decide the best pattern and signaling.
|
||||
@ -89,19 +102,19 @@ public:
|
||||
// - packetLoss : Fraction lost (loss rate in percent =
|
||||
// 100 * packetLoss / 255)
|
||||
// - rtt : Round-trip time in milliseconds
|
||||
virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
|
||||
virtual GMPErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
|
||||
|
||||
// Inform the encoder about the new target bit rate.
|
||||
//
|
||||
// - newBitRate : New target bit rate
|
||||
// - frameRate : The target frame rate
|
||||
virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
|
||||
virtual GMPErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
|
||||
|
||||
// Use this function to enable or disable periodic key frames. Can be useful for codecs
|
||||
// which have other ways of stopping error propagation.
|
||||
//
|
||||
// - enable : Enable or disable periodic key frames
|
||||
virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) = 0;
|
||||
virtual GMPErr SetPeriodicKeyFrames(bool aEnable) = 0;
|
||||
|
||||
// May free Encoder memory.
|
||||
virtual void EncodingComplete() = 0;
|
||||
|
@ -1,43 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* Copyright (c) 2011, The WebRTC project authors. All rights reserved.
|
||||
* Copyright (c) 2014, Mozilla
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
** Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
** Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
** Neither the name of Google nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GMP_VIDEO_ERRORS_h_
|
||||
#define GMP_VIDEO_ERRORS_h_
|
||||
|
||||
enum GMPVideoErr {
|
||||
GMPVideoNoErr = 0,
|
||||
GMPVideoGenericErr = 1,
|
||||
GMPVideoAllocErr = 2
|
||||
};
|
||||
|
||||
#endif // GMP_VIDEO_ERRORS_h_
|
@ -35,6 +35,9 @@
|
||||
#define GMP_VIDEO_FRAME_ENCODED_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gmp-decryption.h"
|
||||
#include "gmp-video-frame.h"
|
||||
#include "gmp-video-codec.h"
|
||||
|
||||
enum GMPVideoFrameType
|
||||
{
|
||||
@ -58,17 +61,22 @@ class GMPVideoEncodedFrame : public GMPVideoFrame
|
||||
{
|
||||
public:
|
||||
// MAIN THREAD ONLY
|
||||
virtual GMPVideoErr CreateEmptyFrame(uint32_t aSize) = 0;
|
||||
virtual GMPErr CreateEmptyFrame(uint32_t aSize) = 0;
|
||||
// MAIN THREAD ONLY
|
||||
virtual GMPVideoErr CopyFrame(const GMPVideoEncodedFrame& aVideoFrame) = 0;
|
||||
virtual GMPErr CopyFrame(const GMPVideoEncodedFrame& aVideoFrame) = 0;
|
||||
virtual void SetEncodedWidth(uint32_t aEncodedWidth) = 0;
|
||||
virtual uint32_t EncodedWidth() = 0;
|
||||
virtual void SetEncodedHeight(uint32_t aEncodedHeight) = 0;
|
||||
virtual uint32_t EncodedHeight() = 0;
|
||||
virtual void SetTimeStamp(uint32_t aTimeStamp) = 0;
|
||||
virtual uint32_t TimeStamp() = 0;
|
||||
virtual void SetCaptureTime(int64_t aCaptureTime) = 0;
|
||||
virtual int64_t CaptureTime() = 0;
|
||||
// Microseconds
|
||||
virtual void SetTimeStamp(uint64_t aTimeStamp) = 0;
|
||||
virtual uint64_t TimeStamp() = 0;
|
||||
// Set frame duration (microseconds)
|
||||
// NOTE: next-frame's Timestamp() != this-frame's TimeStamp()+Duration()
|
||||
// depending on rounding to avoid having to track roundoff errors
|
||||
// and dropped/missing frames(!) (which may leave a large gap)
|
||||
virtual void SetDuration(uint64_t aDuration) = 0;
|
||||
virtual uint64_t Duration() const = 0;
|
||||
virtual void SetFrameType(GMPVideoFrameType aFrameType) = 0;
|
||||
virtual GMPVideoFrameType FrameType() = 0;
|
||||
virtual void SetAllocatedSize(uint32_t aNewSize) = 0;
|
||||
@ -79,6 +87,12 @@ public:
|
||||
virtual bool CompleteFrame() = 0;
|
||||
virtual const uint8_t* Buffer() const = 0;
|
||||
virtual uint8_t* Buffer() = 0;
|
||||
virtual GMPBufferType BufferType() const = 0;
|
||||
virtual void SetBufferType(GMPBufferType aBufferType) = 0;
|
||||
|
||||
// Get data describing how this frame is encrypted, or nullptr if the
|
||||
// frame is not encrypted.
|
||||
virtual const GMPEncryptedBufferData* GetDecryptionData() const = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_VIDEO_FRAME_ENCODED_h_
|
||||
|
@ -34,7 +34,7 @@
|
||||
#ifndef GMP_VIDEO_FRAME_I420_h_
|
||||
#define GMP_VIDEO_FRAME_I420_h_
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-video-frame.h"
|
||||
#include "gmp-video-plane.h"
|
||||
|
||||
@ -63,22 +63,22 @@ public:
|
||||
// on set dimensions - height and plane stride.
|
||||
// If required size is bigger than the allocated one, new buffers of adequate
|
||||
// size will be allocated.
|
||||
virtual GMPVideoErr CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
|
||||
virtual GMPErr CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
|
||||
|
||||
// MAIN THREAD ONLY
|
||||
// CreateFrame: Sets the frame's members and buffers. If required size is
|
||||
// bigger than allocated one, new buffers of adequate size will be allocated.
|
||||
virtual GMPVideoErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
int32_t aSize_u, const uint8_t* aBuffer_u,
|
||||
int32_t aSize_v, const uint8_t* aBuffer_v,
|
||||
int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
|
||||
virtual GMPErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
int32_t aSize_u, const uint8_t* aBuffer_u,
|
||||
int32_t aSize_v, const uint8_t* aBuffer_v,
|
||||
int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
|
||||
|
||||
// MAIN THREAD ONLY
|
||||
// Copy frame: If required size is bigger than allocated one, new buffers of
|
||||
// adequate size will be allocated.
|
||||
virtual GMPVideoErr CopyFrame(const GMPVideoi420Frame& aVideoFrame) = 0;
|
||||
virtual GMPErr CopyFrame(const GMPVideoi420Frame& aVideoFrame) = 0;
|
||||
|
||||
// Swap Frame.
|
||||
virtual void SwapFrame(GMPVideoi420Frame* aVideoFrame) = 0;
|
||||
@ -96,10 +96,10 @@ public:
|
||||
virtual int32_t Stride(GMPPlaneType aType) const = 0;
|
||||
|
||||
// Set frame width.
|
||||
virtual GMPVideoErr SetWidth(int32_t aWidth) = 0;
|
||||
virtual GMPErr SetWidth(int32_t aWidth) = 0;
|
||||
|
||||
// Set frame height.
|
||||
virtual GMPVideoErr SetHeight(int32_t aHeight) = 0;
|
||||
virtual GMPErr SetHeight(int32_t aHeight) = 0;
|
||||
|
||||
// Get frame width.
|
||||
virtual int32_t Width() const = 0;
|
||||
@ -107,17 +107,20 @@ public:
|
||||
// Get frame height.
|
||||
virtual int32_t Height() const = 0;
|
||||
|
||||
// Set frame timestamp (90kHz).
|
||||
virtual void SetTimestamp(uint32_t aTimestamp) = 0;
|
||||
// Set frame timestamp (microseconds)
|
||||
virtual void SetTimestamp(uint64_t aTimestamp) = 0;
|
||||
|
||||
// Get frame timestamp (90kHz).
|
||||
virtual uint32_t Timestamp() const = 0;
|
||||
// Get frame timestamp (microseconds)
|
||||
virtual uint64_t Timestamp() const = 0;
|
||||
|
||||
// Set render time in miliseconds.
|
||||
virtual void SetRenderTime_ms(int64_t aRenderTime_ms) = 0;
|
||||
// Set frame duration (microseconds)
|
||||
// NOTE: next-frame's Timestamp() != this-frame's TimeStamp()+Duration()
|
||||
// depending on rounding to avoid having to track roundoff errors
|
||||
// and dropped/missing frames(!) (which may leave a large gap)
|
||||
virtual void SetDuration(uint64_t aDuration) = 0;
|
||||
|
||||
// Get render time in miliseconds.
|
||||
virtual int64_t RenderTime_ms() const = 0;
|
||||
// Get frame duration (microseconds)
|
||||
virtual uint64_t Duration() const = 0;
|
||||
|
||||
// Return true if underlying plane buffers are of zero size, false if not.
|
||||
virtual bool IsZeroSize() const = 0;
|
||||
|
@ -34,7 +34,6 @@
|
||||
#ifndef GMP_VIDEO_FRAME_h_
|
||||
#define GMP_VIDEO_FRAME_h_
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-video-plane.h"
|
||||
|
||||
enum GMPVideoFrameFormat {
|
||||
|
@ -34,7 +34,7 @@
|
||||
#ifndef GMP_VIDEO_HOST_h_
|
||||
#define GMP_VIDEO_HOST_h_
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-video-frame-i420.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
#include "gmp-video-codec.h"
|
||||
@ -44,8 +44,8 @@ class GMPVideoHost
|
||||
public:
|
||||
// Construct various video API objects. Host does not retain reference,
|
||||
// caller is owner and responsible for deleting.
|
||||
virtual GMPVideoErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) = 0;
|
||||
virtual GMPVideoErr CreatePlane(GMPPlane** aPlane) = 0;
|
||||
virtual GMPErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) = 0;
|
||||
virtual GMPErr CreatePlane(GMPPlane** aPlane) = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_VIDEO_HOST_h_
|
||||
|
@ -34,7 +34,7 @@
|
||||
#ifndef GMP_VIDEO_PLANE_h_
|
||||
#define GMP_VIDEO_PLANE_h_
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-errors.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// The implementation backing this interface uses shared memory for the
|
||||
@ -52,18 +52,18 @@ public:
|
||||
// CreateEmptyPlane - set allocated size, actual plane size and stride:
|
||||
// If current size is smaller than current size, then a buffer of sufficient
|
||||
// size will be allocated.
|
||||
virtual GMPVideoErr CreateEmptyPlane(int32_t aAllocatedSize,
|
||||
int32_t aStride,
|
||||
int32_t aPlaneSize) = 0;
|
||||
virtual GMPErr CreateEmptyPlane(int32_t aAllocatedSize,
|
||||
int32_t aStride,
|
||||
int32_t aPlaneSize) = 0;
|
||||
|
||||
// MAIN THREAD ONLY
|
||||
// Copy the entire plane data.
|
||||
virtual GMPVideoErr Copy(const GMPPlane& aPlane) = 0;
|
||||
virtual GMPErr Copy(const GMPPlane& aPlane) = 0;
|
||||
|
||||
// MAIN THREAD ONLY
|
||||
// Copy buffer: If current size is smaller
|
||||
// than current size, then a buffer of sufficient size will be allocated.
|
||||
virtual GMPVideoErr Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer) = 0;
|
||||
virtual GMPErr Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer) = 0;
|
||||
|
||||
// Swap plane data.
|
||||
virtual void Swap(GMPPlane& aPlane) = 0;
|
||||
|
@ -11,13 +11,19 @@ XPIDL_SOURCES += [
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
'gmp-api/gmp-async-shutdown.h',
|
||||
'gmp-api/gmp-audio-codec.h',
|
||||
'gmp-api/gmp-audio-decode.h',
|
||||
'gmp-api/gmp-audio-host.h',
|
||||
'gmp-api/gmp-audio-samples.h',
|
||||
'gmp-api/gmp-decryption.h',
|
||||
'gmp-api/gmp-entrypoints.h',
|
||||
'gmp-api/gmp-errors.h',
|
||||
'gmp-api/gmp-platform.h',
|
||||
'gmp-api/gmp-storage.h',
|
||||
'gmp-api/gmp-video-codec.h',
|
||||
'gmp-api/gmp-video-decode.h',
|
||||
'gmp-api/gmp-video-encode.h',
|
||||
'gmp-api/gmp-video-errors.h',
|
||||
'gmp-api/gmp-video-frame-encoded.h',
|
||||
'gmp-api/gmp-video-frame-i420.h',
|
||||
'gmp-api/gmp-video-frame.h',
|
||||
@ -33,9 +39,11 @@ EXPORTS += [
|
||||
'GMPSharedMemManager.h',
|
||||
'GMPVideoDecoderChild.h',
|
||||
'GMPVideoDecoderParent.h',
|
||||
'GMPVideoDecoderProxy.h',
|
||||
'GMPVideoEncodedFrameImpl.h',
|
||||
'GMPVideoEncoderChild.h',
|
||||
'GMPVideoEncoderParent.h',
|
||||
'GMPVideoEncoderProxy.h',
|
||||
'GMPVideoHost.h',
|
||||
'GMPVideoi420FrameImpl.h',
|
||||
'GMPVideoPlaneImpl.h',
|
||||
@ -48,6 +56,7 @@ UNIFIED_SOURCES += [
|
||||
'GMPProcessChild.cpp',
|
||||
'GMPProcessParent.cpp',
|
||||
'GMPService.cpp',
|
||||
'GMPSharedMemManager.cpp',
|
||||
'GMPVideoDecoderChild.cpp',
|
||||
'GMPVideoDecoderParent.cpp',
|
||||
'GMPVideoEncodedFrameImpl.cpp',
|
||||
@ -70,6 +79,9 @@ LIBRARY_NAME = 'mozgmp'
|
||||
if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
# comment this out to use Unsafe Shmem for more performance
|
||||
DEFINES['GMP_SAFE_SHMEM'] = True
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
@ -10,18 +10,18 @@
|
||||
%{C++
|
||||
#include "nsTArray.h"
|
||||
#include "nsStringGlue.h"
|
||||
class GMPVideoDecoder;
|
||||
class GMPVideoEncoder;
|
||||
class GMPVideoDecoderProxy;
|
||||
class GMPVideoEncoderProxy;
|
||||
class GMPVideoHost;
|
||||
%}
|
||||
|
||||
[ptr] native GMPVideoDecoder(GMPVideoDecoder);
|
||||
[ptr] native GMPVideoEncoder(GMPVideoEncoder);
|
||||
[ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
|
||||
[ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
|
||||
[ptr] native GMPVideoHost(GMPVideoHost);
|
||||
[ptr] native MessageLoop(MessageLoop);
|
||||
[ptr] native TagArray(nsTArray<nsCString>);
|
||||
|
||||
[scriptable, uuid(63fc797f-9d01-43f4-8b93-5b1fe713c2f8)]
|
||||
[scriptable, uuid(7cef50ca-7a0f-41f2-9560-47abf709f0d7)]
|
||||
interface mozIGeckoMediaPluginService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -36,9 +36,9 @@ interface mozIGeckoMediaPluginService : nsISupports
|
||||
* Callable only on GMP thread.
|
||||
*/
|
||||
[noscript]
|
||||
GMPVideoDecoder getGMPVideoDecoder(in TagArray tags,
|
||||
[optional] in AString origin,
|
||||
out GMPVideoHost outVideoHost);
|
||||
GMPVideoDecoderProxy getGMPVideoDecoder(in TagArray tags,
|
||||
[optional] in AString origin,
|
||||
out GMPVideoHost outVideoHost);
|
||||
|
||||
/**
|
||||
* Get a video encoder that supports the specified tags.
|
||||
@ -47,9 +47,9 @@ interface mozIGeckoMediaPluginService : nsISupports
|
||||
* Callable only on GMP thread.
|
||||
*/
|
||||
[noscript]
|
||||
GMPVideoEncoder getGMPVideoEncoder(in TagArray tags,
|
||||
[optional] in AString origin,
|
||||
out GMPVideoHost outVideoHost);
|
||||
GMPVideoEncoderProxy getGMPVideoEncoder(in TagArray tags,
|
||||
[optional] in AString origin,
|
||||
out GMPVideoHost outVideoHost);
|
||||
|
||||
/**
|
||||
* Add a directory to scan for gecko media plugins.
|
||||
|
@ -18,8 +18,6 @@ if CONFIG['MOZ_WEBM_ENCODER']:
|
||||
'TestWebMWriter.cpp',
|
||||
]
|
||||
|
||||
EXPORT_LIBRARY = True
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
@ -144,6 +144,7 @@ UNIFIED_SOURCES += [
|
||||
'MediaDecoder.cpp',
|
||||
'MediaDecoderReader.cpp',
|
||||
'MediaDecoderStateMachine.cpp',
|
||||
'MediaDecoderStateMachineScheduler.cpp',
|
||||
'MediaRecorder.cpp',
|
||||
'MediaResource.cpp',
|
||||
'MediaShutdownManager.cpp',
|
||||
|
@ -472,4 +472,3 @@ skip-if = wave
|
||||
run-if = wave
|
||||
[test_fragment_play.html]
|
||||
run-if = wave
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' # Intermittent failures - Bug 996465 & bug 924246
|
||||
|
@ -119,11 +119,12 @@ SVGMatrix::Multiply(SVGMatrix& aMatrix)
|
||||
already_AddRefed<SVGMatrix>
|
||||
SVGMatrix::Inverse(ErrorResult& rv)
|
||||
{
|
||||
if (GetMatrix().IsSingular()) {
|
||||
gfxMatrix mat = GetMatrix();
|
||||
if (!mat.Invert()) {
|
||||
rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<SVGMatrix> matrix = new SVGMatrix(gfxMatrix(GetMatrix()).Invert());
|
||||
nsRefPtr<SVGMatrix> matrix = new SVGMatrix(mat);
|
||||
return matrix.forget();
|
||||
}
|
||||
|
||||
|
@ -367,6 +367,17 @@ this.PermissionsTable = { geolocation: {
|
||||
privileged: PROMPT_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
access: ["read", "write", "create"]
|
||||
},
|
||||
"firefox-accounts": {
|
||||
app: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"moz-firefox-accounts": {
|
||||
app: DENY_ACTION,
|
||||
privileged: PROMPT_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
substitute: ["firefox-accounts"]
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2552,6 +2552,19 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
|
||||
|
||||
if (!aData.isPackage) {
|
||||
this.updateAppHandlers(null, app.manifest, app);
|
||||
if (aInstallSuccessCallback) {
|
||||
try {
|
||||
yield aInstallSuccessCallback(app, app.manifest);
|
||||
} catch (e) {
|
||||
// Ignore exceptions during the local installation of
|
||||
// an app. If it fails, the app will anyway be considered
|
||||
// as not installed because isLaunchable will return false.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The presence of a requestID means that we have a page to update.
|
||||
if (aData.isPackage && aData.apkInstall && !aData.requestID) {
|
||||
// Skip directly to onInstallSuccessAck, since there isn't
|
||||
@ -2565,13 +2578,6 @@ this.DOMApplicationRegistry = {
|
||||
this.broadcastMessage("Webapps:Install:Return:OK", aData);
|
||||
}
|
||||
|
||||
if (!aData.isPackage) {
|
||||
this.updateAppHandlers(null, app.manifest, app);
|
||||
if (aInstallSuccessCallback) {
|
||||
aInstallSuccessCallback(app, app.manifest);
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(null, "webapps-installed",
|
||||
JSON.stringify({ manifestURL: app.manifestURL }));
|
||||
|
||||
@ -2642,6 +2648,16 @@ this.DOMApplicationRegistry = {
|
||||
this.updateDataStore(this.webapps[aId].localId, aNewApp.origin,
|
||||
aNewApp.manifestURL, aManifest);
|
||||
|
||||
if (aInstallSuccessCallback) {
|
||||
try {
|
||||
yield aInstallSuccessCallback(aNewApp, aManifest, zipFile.path);
|
||||
} catch (e) {
|
||||
// Ignore exceptions during the local installation of
|
||||
// an app. If it fails, the app will anyway be considered
|
||||
// as not installed because isLaunchable will return false.
|
||||
}
|
||||
}
|
||||
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: aManifest,
|
||||
@ -2655,10 +2671,6 @@ this.DOMApplicationRegistry = {
|
||||
eventType: ["downloadsuccess", "downloadapplied"],
|
||||
manifestURL: aNewApp.manifestURL
|
||||
});
|
||||
|
||||
if (aInstallSuccessCallback) {
|
||||
aInstallSuccessCallback(aNewApp, aManifest, zipFile.path);
|
||||
}
|
||||
}),
|
||||
|
||||
_nextLocalId: function() {
|
||||
|
@ -1242,7 +1242,9 @@ nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
|
||||
|
||||
event.refPoint.x = event.refPoint.y = 0;
|
||||
event.time = PR_IntervalNow();
|
||||
event.mFlags.mIsSynthesizedForTests = true;
|
||||
if (!(aAdditionalFlags & KEY_FLAG_NOT_SYNTHESIZED_FOR_TESTS)) {
|
||||
event.mFlags.mIsSynthesizedForTests = true;
|
||||
}
|
||||
|
||||
if (aAdditionalFlags & KEY_FLAG_PREVENT_DEFAULT) {
|
||||
event.mFlags.mDefaultPrevented = true;
|
||||
|
@ -715,7 +715,6 @@ static const char js_strict_option_str[] = JS_OPTIONS_DOT_STR "strict";
|
||||
#ifdef DEBUG
|
||||
static const char js_strict_debug_option_str[] = JS_OPTIONS_DOT_STR "strict.debug";
|
||||
#endif
|
||||
static const char js_werror_option_str[] = JS_OPTIONS_DOT_STR "werror";
|
||||
#ifdef JS_GC_ZEAL
|
||||
static const char js_zeal_option_str[] = JS_OPTIONS_DOT_STR "gczeal";
|
||||
static const char js_zeal_frequency_str[] = JS_OPTIONS_DOT_STR "gczeal.frequency";
|
||||
@ -753,8 +752,6 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
||||
}
|
||||
#endif
|
||||
|
||||
JS::ContextOptionsRef(cx).setWerror(Preferences::GetBool(js_werror_option_str));
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
int32_t zeal = Preferences::GetInt(js_zeal_option_str, -1);
|
||||
int32_t frequency = Preferences::GetInt(js_zeal_frequency_str, JS_DEFAULT_ZEAL_FREQ);
|
||||
|
@ -1903,11 +1903,10 @@ InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(instance, true));
|
||||
if (unwrapped && jsipc::IsCPOW(unwrapped)) {
|
||||
if (jsipc::IsWrappedCPOW(instance)) {
|
||||
bool boolp = false;
|
||||
if (!jsipc::DOMInstanceOf(cx, unwrapped, clasp->mPrototypeID,
|
||||
clasp->mDepth, &boolp)) {
|
||||
if (!jsipc::DOMInstanceOf(cx, js::CheckedUnwrap(instance), clasp->mPrototypeID,
|
||||
clasp->mDepth, &boolp)) {
|
||||
return false;
|
||||
}
|
||||
*bp = boolp;
|
||||
|
@ -145,8 +145,7 @@ public:
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
||||
|
||||
RemoveWatchers(READ_WATCHER | WRITE_WATCHER);
|
||||
|
||||
Close(); // will also remove fd from I/O loop
|
||||
mShuttingDownOnIOThread = true;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user