--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -537,17 +537,16 @@ pref("ui.click_hold_context_menus.delay"
pref("device.storage.enabled", true);
// Enable pre-installed applications
pref("dom.webapps.useCurrentProfile", true);
// Enable system message
pref("dom.sysmsg.enabled", true);
pref("media.plugins.enabled", false);
-pref("media.omx.enabled", true);
pref("media.rtsp.enabled", true);
pref("media.rtsp.video.enabled", true);
// Disable printing (particularly, window.print())
pref("dom.disable_window_print", true);
// Disable window.showModalDialog
pref("dom.disable_window_showModalDialog", true);
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -254,18 +254,18 @@ function openLinkIn(url, where, params)
}
saveURL(url, null, null, true, true, aNoReferrer ? null : aReferrerURI, aInitiatingDoc);
}
return;
}
if (!w || where == "window") {
// This propagates to window.arguments.
- var sa = Cc["@mozilla.org/supports-array;1"].
- createInstance(Ci.nsISupportsArray);
+ var sa = Cc["@mozilla.org/array;1"].
+ createInstance(Ci.nsIMutableArray);
var wuri = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
wuri.data = url;
let charset = null;
if (aCharset) {
charset = Cc["@mozilla.org/supports-string;1"]
@@ -287,24 +287,24 @@ function openLinkIn(url, where, params)
var referrerPolicySupports = Cc["@mozilla.org/supports-PRUint32;1"].
createInstance(Ci.nsISupportsPRUint32);
referrerPolicySupports.data = aReferrerPolicy;
var userContextIdSupports = Cc["@mozilla.org/supports-PRUint32;1"].
createInstance(Ci.nsISupportsPRUint32);
userContextIdSupports.data = aUserContextId;
- sa.AppendElement(wuri);
- sa.AppendElement(charset);
- sa.AppendElement(referrerURISupports);
- sa.AppendElement(aPostData);
- sa.AppendElement(allowThirdPartyFixupSupports);
- sa.AppendElement(referrerPolicySupports);
- sa.AppendElement(userContextIdSupports);
- sa.AppendElement(aPrincipal);
+ sa.appendElement(wuri, /*weak =*/ false);
+ sa.appendElement(charset, /*weak =*/ false);
+ sa.appendElement(referrerURISupports, /*weak =*/ false);
+ sa.appendElement(aPostData, /*weak =*/ false);
+ sa.appendElement(allowThirdPartyFixupSupports, /*weak =*/ false);
+ sa.appendElement(referrerPolicySupports, /*weak =*/ false);
+ sa.appendElement(userContextIdSupports, /*weak =*/ false);
+ sa.appendElement(aPrincipal, /*weak =*/ false);
let features = "chrome,dialog=no,all";
if (aIsPrivate) {
features += ",private";
}
Services.ww.openWindow(w || window, getBrowserURL(), null, features, sa);
return;
@@ -679,22 +679,22 @@ function openPreferences(paneID, extraAr
}
let preferencesURL = "about:preferences" + (params ? "?" + params : "") +
(friendlyCategoryName ? "#" + friendlyCategoryName : "");
let newLoad = true;
let browser = null;
if (!win) {
const Cc = Components.classes;
const Ci = Components.interfaces;
- let windowArguments = Cc["@mozilla.org/supports-array;1"]
- .createInstance(Ci.nsISupportsArray);
+ let windowArguments = Cc["@mozilla.org/array;1"]
+ .createInstance(Ci.nsIMutableArray);
let supportsStringPrefURL = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
supportsStringPrefURL.data = preferencesURL;
- windowArguments.AppendElement(supportsStringPrefURL);
+ windowArguments.appendElement(supportsStringPrefURL, /*weak =*/ false);
win = Services.ww.openWindow(null, Services.prefs.getCharPref("browser.chromeURL"),
"_blank", "chrome,dialog=no,all", windowArguments);
} else {
let shouldReplaceFragment = friendlyCategoryName ? "whenComparingAndReplace" : "whenComparing";
newLoad = !win.switchToTabHavingURI(preferencesURL, true, { ignoreFragment: shouldReplaceFragment, replaceQueryString: true });
browser = win.gBrowser.selectedBrowser;
}
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -395,35 +395,23 @@ class BasePopup {
}
}
this.panel.style.setProperty("--arrowpanel-background", panelBackground);
this.panel.style.setProperty("--panel-arrow-image-vertical", panelArrow);
// Adjust the size of the browser based on its content's preferred size.
- let width, height;
- try {
- let w = {}, h = {};
- this.browser.docShell.contentViewer.getContentSize(w, h);
-
- width = w.value / this.window.devicePixelRatio;
- height = h.value / this.window.devicePixelRatio;
+ let {contentViewer} = this.browser.docShell;
+ let ratio = this.window.devicePixelRatio;
- // The width calculation is imperfect, and is often a fraction of a pixel
- // too narrow, even after taking the ceiling, which causes lines of text
- // to wrap.
- width += 1;
- } catch (e) {
- // getContentSize can throw
- [width, height] = [400, 400];
- }
-
- width = Math.ceil(Math.min(width, 800));
- height = Math.ceil(Math.min(height, 600));
+ let w = {}, h = {};
+ contentViewer.getContentSizeConstrained(800 * ratio, 600 * ratio, w, h);
+ let width = Math.ceil(w.value / ratio);
+ let height = Math.ceil(h.value / ratio);
this.browser.style.width = `${width}px`;
this.browser.style.height = `${height}px`;
}
let event = new this.window.CustomEvent("WebExtPopupResized");
this.browser.dispatchEvent(event);
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -87,17 +87,17 @@ extensions.registerSchemaAPI("windows",
}
function mkstr(s) {
let result = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
result.data = s;
return result;
}
- let args = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
+ let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
if (createData.tabId !== null) {
if (createData.url !== null) {
return Promise.reject({message: "`tabId` may not be used in conjunction with `url`"});
}
if (createData.allowScriptsToClose) {
return Promise.reject({message: "`tabId` may not be used in conjunction with `allowScriptsToClose`"});
@@ -108,29 +108,29 @@ extensions.registerSchemaAPI("windows",
// Private browsing tabs can only be moved to private browsing
// windows.
let incognito = PrivateBrowsingUtils.isBrowserPrivate(tab.linkedBrowser);
if (createData.incognito !== null && createData.incognito != incognito) {
return Promise.reject({message: "`incognito` property must match the incognito state of tab"});
}
createData.incognito = incognito;
- args.AppendElement(tab);
+ args.appendElement(tab, /*weak =*/ false);
} else if (createData.url !== null) {
if (Array.isArray(createData.url)) {
let array = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
for (let url of createData.url) {
array.AppendElement(mkstr(url));
}
- args.AppendElement(array);
+ args.appendElement(array, /*weak =*/ false);
} else {
- args.AppendElement(mkstr(createData.url));
+ args.appendElement(mkstr(createData.url), /*weak =*/ false);
}
} else {
- args.AppendElement(mkstr(aboutNewTabService.newTabURL));
+ args.appendElement(mkstr(aboutNewTabService.newTabURL), /*weak =*/ false);
}
let features = ["chrome"];
if (createData.type === null || createData.type == "normal") {
features.push("dialog=no", "all");
} else {
// All other types create "popup"-type windows by default.
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_popup_resize.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_popup_resize.js
@@ -1,12 +1,24 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
+function* awaitResize(browser) {
+ // Debouncing code makes this a bit racy.
+ // Try to skip the first, early resize, and catch the resize event we're
+ // looking for, but don't wait longer than a few seconds.
+
+ return Promise.race([
+ BrowserTestUtils.waitForEvent(browser, "WebExtPopupResized")
+ .then(() => BrowserTestUtils.waitForEvent(browser, "WebExtPopupResized")),
+ new Promise(resolve => setTimeout(resolve, 5000)),
+ ]);
+}
+
add_task(function* testPageActionPopupResize() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"page_action": {
"default_popup": "popup.html",
"browser_style": true,
},
},
@@ -16,55 +28,143 @@ add_task(function* testPageActionPopupRe
browser.pageAction.show(tabId).then(() => {
browser.test.sendMessage("action-shown");
});
});
},
files: {
- "popup.html": "<html><head><meta charset=\"utf-8\"></head></html>",
+ "popup.html": `<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><div></div></body></html>`,
},
});
yield extension.startup();
yield extension.awaitMessage("action-shown");
clickPageAction(extension, window);
let {target: panelDocument} = yield BrowserTestUtils.waitForEvent(document, "load", true, (event) => {
info(`Loaded ${event.target.location}`);
return event.target.location && event.target.location.href.endsWith("popup.html");
});
let panelWindow = panelDocument.defaultView;
- let panelBody = panelDocument.body;
+ let panelBody = panelDocument.body.firstChild;
+ let body = panelDocument.body;
+ let root = panelDocument.documentElement;
function checkSize(expected) {
is(panelWindow.innerHeight, expected, `Panel window should be ${expected}px tall`);
- is(panelBody.clientHeight, panelBody.scrollHeight,
+ is(body.clientHeight, body.scrollHeight,
"Panel body should be tall enough to fit its contents");
+ is(root.clientHeight, root.scrollHeight,
+ "Panel root should be tall enough to fit its contents");
// Tolerate if it is 1px too wide, as that may happen with the current resizing method.
ok(Math.abs(panelWindow.innerWidth - expected) <= 1, `Panel window should be ${expected}px wide`);
- is(panelBody.clientWidth, panelBody.scrollWidth,
- "Panel body should be wide enough to fit its contents");
+ is(body.clientWidth, body.scrollWidth,
+ "Panel body should be wide enough to fit its contents");
}
function setSize(size) {
panelBody.style.height = `${size}px`;
panelBody.style.width = `${size}px`;
+
+ return BrowserTestUtils.waitForEvent(panelWindow, "resize");
}
let sizes = [
200,
400,
300,
];
for (let size of sizes) {
- setSize(size);
- yield BrowserTestUtils.waitForEvent(panelWindow, "resize");
+ yield setSize(size);
checkSize(size);
}
+ yield setSize(1400);
+
+ if (AppConstants.platform == "win") {
+ ok(panelWindow.innerWidth >= 750 && panelWindow.innerWidth <= 800,
+ `Panel window width ${panelWindow.innerWidth} is in acceptable range`);
+ } else {
+ is(panelWindow.innerWidth, 800, "Panel window width");
+ }
+ ok(body.clientWidth <= 800, `Panel body width ${body.clientWidth} is less than 800`);
+ is(body.scrollWidth, 1400, "Panel body scroll width");
+
+ is(panelWindow.innerHeight, 600, "Panel window height");
+ ok(root.clientHeight <= 600, `Panel root height (${root.clientHeight}px) is less than 600px`);
+ is(root.scrollHeight, 1400, "Panel root scroll height");
+
yield extension.unload();
});
+
+add_task(function* testPageActionPopupReflow() {
+ let browser;
+
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ "page_action": {
+ "default_popup": "popup.html",
+ "browser_style": true,
+ },
+ },
+ background: function() {
+ browser.tabs.query({active: true, currentWindow: true}, tabs => {
+ const tabId = tabs[0].id;
+
+ browser.pageAction.show(tabId).then(() => {
+ browser.test.sendMessage("action-shown");
+ });
+ });
+ },
+
+ files: {
+ "popup.html": `<!DOCTYPE html><html><head><meta charset="utf-8"></head>
+ <body>
+ The quick mauve fox jumps over the opalescent toad, with its glowing
+ eyes, and its vantablack mouth, and its bottomless chasm where you
+ would hope to find a heart, that looks straight into the deepest
+ pits of hell. The fox shivers, and cowers, and tries to run, but
+ the toad is utterly without pity. It turns, ever so slightly...
+ </body>
+ </html>`,
+ },
+ });
+
+ yield extension.startup();
+ yield extension.awaitMessage("action-shown");
+
+ clickPageAction(extension, window);
+
+ browser = yield awaitExtensionPanel(extension);
+
+ let win = browser.contentWindow;
+ let body = win.document.body;
+ let root = win.document.documentElement;
+
+ function setSize(size) {
+ body.style.fontSize = `${size}px`;
+
+ return awaitResize(browser);
+ }
+
+ yield setSize(18);
+
+ is(win.innerWidth, 800, "Panel window should be 800px wide");
+ is(body.clientWidth, 800, "Panel body should be 800px wide");
+ is(body.clientWidth, body.scrollWidth,
+ "Panel body should be wide enough to fit its contents");
+
+ ok(win.innerHeight > 36,
+ `Panel window height (${win.innerHeight}px) should be taller than two lines of text.`);
+
+ is(body.clientHeight, body.scrollHeight,
+ "Panel body should be tall enough to fit its contents");
+ is(root.clientHeight, root.scrollHeight,
+ "Panel root should be tall enough to fit its contents");
+
+ yield extension.unload();
+});
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -182,18 +182,18 @@ function openWindow(parent, url, target,
.createInstance(nsISupportsString);
argstring.data = args;
}
return Services.ww.openWindow(parent, url, target, features, argstring);
}
// Pass an array to avoid the browser "|"-splitting behavior.
- var argArray = Components.classes["@mozilla.org/supports-array;1"]
- .createInstance(Components.interfaces.nsISupportsArray);
+ var argArray = Components.classes["@mozilla.org/array;1"]
+ .createInstance(Components.interfaces.nsIMutableArray);
// add args to the arguments array
var stringArgs = null;
if (args instanceof Array) // array
stringArgs = args;
else if (args) // string
stringArgs = [args];
@@ -202,81 +202,81 @@ function openWindow(parent, url, target,
var uriArray = Components.classes["@mozilla.org/supports-array;1"]
.createInstance(Components.interfaces.nsISupportsArray);
stringArgs.forEach(function (uri) {
var sstring = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(nsISupportsString);
sstring.data = uri;
uriArray.AppendElement(sstring);
});
- argArray.AppendElement(uriArray);
+ argArray.appendElement(uriArray, /*weak =*/ false);
} else {
- argArray.AppendElement(null);
+ argArray.appendElement(null, /*weak =*/ false);
}
// Pass these as null to ensure that we always trigger the "single URL"
// behavior in browser.js's gBrowserInit.onLoad (which handles the window
// arguments)
- argArray.AppendElement(null); // charset
- argArray.AppendElement(null); // referer
- argArray.AppendElement(null); // postData
- argArray.AppendElement(null); // allowThirdPartyFixup
+ argArray.appendElement(null, /*weak =*/ false); // charset
+ argArray.appendElement(null, /*weak =*/ false); // referer
+ argArray.appendElement(null, /*weak =*/ false); // postData
+ argArray.appendElement(null, /*weak =*/ false); // allowThirdPartyFixup
return Services.ww.openWindow(parent, url, target, features, argArray);
}
function openPreferences() {
- var sa = Components.classes["@mozilla.org/supports-array;1"]
- .createInstance(Components.interfaces.nsISupportsArray);
+ var args = Components.classes["@mozilla.org/array;1"]
+ .createInstance(Components.interfaces.nsIMutableArray);
var wuri = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
wuri.data = "about:preferences";
- sa.AppendElement(wuri);
+ sa.appendElement(wuri, /*weak =*/ false);
Services.ww.openWindow(null, gBrowserContentHandler.chromeURL,
"_blank",
"chrome,dialog=no,all",
- sa);
+ args);
}
function logSystemBasedSearch(engine) {
var countId = (engine.identifier || ("other-" + engine.name)) + ".system";
var count = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
count.add(countId);
}
function doSearch(searchTerm, cmdLine) {
var engine = Services.search.defaultEngine;
logSystemBasedSearch(engine);
var submission = engine.getSubmission(searchTerm, null, "system");
- // fill our nsISupportsArray with uri-as-wstring, null, null, postData
- var sa = Components.classes["@mozilla.org/supports-array;1"]
- .createInstance(Components.interfaces.nsISupportsArray);
+ // fill our nsIMutableArray with uri-as-wstring, null, null, postData
+ var args = Components.classes["@mozilla.org/array;1"]
+ .createInstance(Components.interfaces.nsIMutableArray);
var wuri = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
wuri.data = submission.uri.spec;
- sa.AppendElement(wuri);
- sa.AppendElement(null);
- sa.AppendElement(null);
- sa.AppendElement(submission.postData);
+ args.appendElement(wuri, /*weak =*/ false);
+ args.appendElement(null, /*weak =*/ false);
+ args.appendElement(null, /*weak =*/ false);
+ args.appendElement(submission.postData, /*weak =*/ false);
// XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
// preferences, but need nsIBrowserDOMWindow extensions
return Services.ww.openWindow(null, gBrowserContentHandler.chromeURL,
"_blank",
"chrome,dialog=no,all" +
gBrowserContentHandler.getFeatures(cmdLine),
- sa);
+ args);
}
function nsBrowserContentHandler() {
}
nsBrowserContentHandler.prototype = {
classID: Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}"),
_xpcom_factory: {
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -953,19 +953,19 @@ this.PlacesUIUtils = {
// whereToOpenLink doesn't return "window" when there's no browser window
// open (Bug 630255).
var where = browserWindow ?
browserWindow.whereToOpenLink(aEvent, false, true) : "window";
if (where == "window") {
// There is no browser window open, thus open a new one.
var uriList = PlacesUtils.toISupportsString(urls.join("|"));
- var args = Cc["@mozilla.org/supports-array;1"].
- createInstance(Ci.nsISupportsArray);
- args.AppendElement(uriList);
+ var args = Cc["@mozilla.org/array;1"].
+ createInstance(Ci.nsIMutableArray);
+ args.appendElement(uriList, /*weak =*/ false);
browserWindow = Services.ww.openWindow(aWindow,
"chrome://browser/content/browser.xul",
null, "chrome,dialog=no,all", args);
return;
}
var loadInBackground = where == "tabshifted" ? true : false;
// For consistency, we want all the bookmarks to open in new tabs, instead
--- a/browser/locales/search/list.json
+++ b/browser/locales/search/list.json
@@ -13,17 +13,17 @@
},
"US": {
"visibleDefaultEngines": [
"yahoo", "google-nocodes", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
]
},
"CA": {
"visibleDefaultEngines": [
- "google", "yahoo-en-CA", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
+ "google-nocodes", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
]
}
},
"ach": {
"default": {
"visibleDefaultEngines": [
"google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
]
--- a/build/sanitizers/lsan_suppressions.txt
+++ b/build/sanitizers/lsan_suppressions.txt
@@ -22,74 +22,40 @@ leak:pixman_implementation_lookup_compos
leak:libfontconfig.so
leak:GI___strdup
# The symbol is really __GI___strdup, but if you have the leading _, it doesn't suppress it.
# Bug 1078015 - If the process terminates during a PR_Sleep, LSAN detects a leak
leak:PR_Sleep
###
-### Bug 979928 - WebRTC leaks. m2, m3.
+### Many leaks only affect some test suites. The suite annotations are not checked.
###
-# WebRTC leaks added for Mochitest 2.
+# Bug 979928 - WebRTC leaks in different mochitest suites.
leak:NR_reg_init
-# nr_reg_local_init should be redundant with NR_reg_init, but with 34 on Aurora
-# we get less stack frames for some reason.
+# nr_reg_local_init should be redundant with NR_reg_init, but on Aurora
+# we get fewer stack frames for some reason.
leak:nr_reg_local_init
leak:r_log_register
leak:nr_reg_set
-# Bug 1187518 - SCTP leaks in child process while running WebRTC tests.
-leak:recv_function_udp
-
-
-###
-### Many leaks only affect some test suites. The suite annotations are not checked.
-###
-
-# Bug 987385 - Various plugin leaks. m3
-leak:mozilla::plugins::PPluginInstanceParent::CallNPP_HandleEvent
-leak:mozilla::plugins::PPluginModuleParent::OnCallReceived
-
-# Bug 987925 - Small leak under PK11_ChangePW. m5
-leak:sec_asn1e_allocate_item
-leak:PORT_Strdup_Util
-
-# Bug 1021350 - Small leak under event_base_once. m1, m4, bc3
-leak:event_base_once
-
-# Bug 1022010 - Small leak under _render_glyph_outline. bc1
-leak:_render_glyph_outline
-
-# Bug 1023548 - Small leak under SECITEM_AllocItem_Util. bc1, bc3
-leak:SECITEM_AllocItem_Util
-
-# This is a one-time leak, so it is probably okay to ignore. bc3, oth
+# This is a one-time leak in mochitest-bc, so it is probably okay to ignore.
leak:GlobalPrinters::InitializeGlobalPrinters
leak:nsPSPrinterList::GetPrinterList
-# Bug 1028456 - Various NSPR fd-related leaks. m1-m5, bc1,bc2,bc5,bc7,dt4,dt5.
+# Bug 1028456 - Various NSPR fd-related leaks in different mochitest suites.
leak:_PR_Getfd
-# Bug 1028483 - The XML parser sometimes leaks an object. bc3
+# Bug 1028483 - The XML parser sometimes leaks an object. Mostly happens in toolkit/components/thumbnails.
leak:processInternalEntity
-# Bug 1187421 - With e10s, NSS does not always free the error stack. m1.
+# Bug 1187421 - NSS does not always free the error stack in different mochitest suites.
leak:nss_ClearErrorStack
-# Bug 1189430 - DNS leaks in mochitest-chrome.
-leak:nsDNSService::AsyncResolveExtended
-leak:_GetAddrInfo_Portable
-
-# Bug 1189568 - Indirect leaks of IMContextWrapper and nsIntRect.
-leak:nsWindow::Create
-leak:nsBaseWidget::StoreWindowClipRegion
-
-
###
### Leaks with system libraries in their stacks. These show up across a number of tests.
### Better symbols and disabling fast stackwalking may help diagnose these.
###
leak:libcairo.so
leak:libdl.so
leak:libdricore.so
--- a/devtools/client/shared/components/reps/reps.css
+++ b/devtools/client/shared/components/reps/reps.css
@@ -57,16 +57,17 @@
.objectBox-number,
.objectLink-styleRule,
.objectLink-element,
.objectLink-textNode,
.objectBox-array > .length {
color: var(--number-color);
}
+.objectBox-textNode,
.objectBox-string,
.objectBox-symbol {
color: var(--string-color);
}
.objectLink-function,
.objectBox-stackTrace,
.objectLink-profile {
--- a/devtools/client/shared/components/reps/text-node.js
+++ b/devtools/client/shared/components/reps/text-node.js
@@ -6,54 +6,56 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip, cropMultipleLines } = require("./rep-utils");
+ const { isGrip, cropString } = require("./rep-utils");
// Shortcuts
const DOM = React.DOM;
/**
* Renders DOM #text node.
*/
let TextNode = React.createClass({
displayName: "TextNode",
propTypes: {
object: React.PropTypes.object.isRequired,
mode: React.PropTypes.string,
},
getTextContent: function (grip) {
- return cropMultipleLines(grip.preview.textContent);
+ return cropString(grip.preview.textContent);
},
getTitle: function (grip) {
if (this.props.objectLink) {
return this.props.objectLink({
object: grip
- }, "#text");
+ }, "#text ");
}
return "";
},
render: function () {
let grip = this.props.object;
let mode = this.props.mode || "short";
if (mode == "short" || mode == "tiny") {
return (
DOM.span({className: "objectBox objectBox-textNode"},
this.getTitle(grip),
- "\"" + this.getTextContent(grip) + "\""
+ DOM.span({className: "nodeValue"},
+ "\"" + this.getTextContent(grip) + "\""
+ )
)
);
}
let objectLink = this.props.objectLink || DOM.span;
return (
DOM.span({className: "objectBox objectBox-textNode"},
this.getTitle(grip),
--- a/devtools/client/shared/components/test/mochitest/test_reps_text-node.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_text-node.html
@@ -12,49 +12,102 @@ Test text-node rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {
- try {
- let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
- let { TextNode } = browserRequire("devtools/client/shared/components/reps/text-node");
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { TextNode } = browserRequire("devtools/client/shared/components/reps/text-node");
- let gripStub = {
- "type": "object",
- "class": "Text",
- "actor": "server1.conn1.child1/obj50",
- "extensible": true,
- "frozen": false,
- "sealed": false,
- "ownPropertyLength": 0,
- "preview": {
- "kind": "DOMNode",
- "nodeType": 3,
- "nodeName": "#text",
- "textContent": "hello world"
- }
- };
+ let gripStubs = new Map();
+ gripStubs.set("testRendering", {
+ "class": "Text",
+ "actor": "server1.conn1.child1/obj50",
+ "preview": {
+ "textContent": "hello world"
+ }
+ });
+ gripStubs.set("testRenderingWithEOL", {
+ "class": "Text",
+ "actor": "server1.conn1.child1/obj50",
+ "preview": {
+ "textContent": "hello\nworld"
+ }
+ });
+ try {
// Test that correct rep is chosen
- const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ const renderedRep = shallowRenderComponent(Rep, {
+ object: gripStubs.get("testRendering")
+ });
+
is(renderedRep.type, TextNode.rep,
`Rep correctly selects ${TextNode.rep.displayName}`);
- // Test rendering
- const renderedComponent = renderComponent(TextNode.rep, { object: gripStub });
- is(renderedComponent.className, "objectBox objectBox-textNode",
- "TextNode rep has expected class names");
- is(renderedComponent.textContent, `"hello world"`,
- "TextNode rep has expected text content");
+ yield testRendering();
+ yield testRenderingWithEOL();
} catch (e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally {
SimpleTest.finish();
}
+
+ function testRendering() {
+ const stub = gripStubs.get("testRendering");
+ const defaultShortOutput = `"hello world"`;
+ const defaultLongOutput = `<TextNode textContent="hello world">;`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultLongOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testRendering", TextNode, stub);
+ }
+
+ function testRenderingWithEOL() {
+ const stub = gripStubs.get("testRenderingWithEOL");
+ const defaultShortOutput = `"hello\nworld"`;
+ const defaultLongOutput = `<TextNode textContent="hello\nworld">;`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultLongOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testRenderingWithEOL", TextNode, stub);
+ }
});
</script>
</pre>
</body>
</html>
--- a/docshell/base/nsIContentViewer.idl
+++ b/docshell/base/nsIContentViewer.idl
@@ -229,16 +229,26 @@ interface nsIContentViewer : nsISupports
*/
attribute int32_t hintCharacterSetSource;
/**
* Requests the size of the content to the container.
*/
void getContentSize(out long width, out long height);
+ /**
+ * Returns the preferred width and height of the content, constrained to the
+ * given maximum values. If either maxWidth or maxHeight is less than zero,
+ * that dimension is not constrained.
+ *
+ * All input and output values are in device pixels, rather than CSS pixels.
+ */
+ void getContentSizeConstrained(in long maxWidth, in long maxHeight,
+ out long width, out long height);
+
/** The minimum font size */
attribute long minFontSize;
/**
* Append |this| and all of its descendants to the given array,
* in depth-first pre-order traversal.
*/
[noscript] void appendSubtree(in nsIContentViewerTArray array);
--- a/docshell/test/browser/browser_onbeforeunload_navigation.js
+++ b/docshell/test/browser/browser_onbeforeunload_navigation.js
@@ -111,25 +111,30 @@ function runNextTest() {
currentTest++;
if (currentTest >= testsLength) {
if (!stayingOnPage) {
finish();
return;
}
// Run the same tests again, but this time let the navigation happen:
stayingOnPage = false;
+ // Remove onbeforeunload handler, or this load will trigger the dialog...
+ contentWindow.onbeforeunload = null;
currentTest = 0;
}
if (!stayingOnPage) {
+ // Right now we're on the data: page. Null contentWindow out to
+ // avoid CPOW errors when contentWindow is no longer the correct
+ // outer window proxy object.
+ contentWindow = null;
+
onAfterPageLoad = runCurrentTest;
loadExpected = TEST_PAGE;
- // Remove onbeforeunload handler, or this load will trigger the dialog...
- contentWindow.onbeforeunload = null;
testTab.linkedBrowser.loadURI(TEST_PAGE);
} else {
runCurrentTest();
}
}
function runCurrentTest() {
// Reset things so we're sure the previous tests failings don't influence this one:
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -111,16 +111,18 @@ nsDOMDataChannel::Init(nsPIDOMWindowInne
return rv;
}
NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, open)
NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, error)
NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, close)
NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, message)
+// Most of the GetFoo()/SetFoo()s don't need to touch shared resources and
+// are safe after Close()
NS_IMETHODIMP
nsDOMDataChannel::GetLabel(nsAString& aLabel)
{
mDataChannel->GetLabel(aLabel);
return NS_OK;
}
NS_IMETHODIMP
@@ -175,17 +177,21 @@ nsDOMDataChannel::ReadyState() const
{
return static_cast<RTCDataChannelState>(mDataChannel->GetReadyState());
}
NS_IMETHODIMP
nsDOMDataChannel::GetReadyState(nsAString& aReadyState)
{
- uint16_t readyState = mDataChannel->GetReadyState();
+ // mState is handled on multiple threads and needs locking
+ uint16_t readyState = mozilla::DataChannel::CLOSED;
+ if (!mSentClose) {
+ readyState = mDataChannel->GetReadyState();
+ }
// From the WebRTC spec
const char * stateName[] = {
"connecting",
"open",
"closing",
"closed"
};
MOZ_ASSERT(/*readyState >= mozilla::DataChannel::CONNECTING && */ // Always true due to datatypes
@@ -193,17 +199,20 @@ nsDOMDataChannel::GetReadyState(nsAStrin
aReadyState.AssignASCII(stateName[readyState]);
return NS_OK;
}
uint32_t
nsDOMDataChannel::BufferedAmount() const
{
- return mDataChannel->GetBufferedAmount();
+ if (!mSentClose) {
+ return mDataChannel->GetBufferedAmount();
+ }
+ return 0;
}
uint32_t
nsDOMDataChannel::BufferedAmountLowThreshold() const
{
return mDataChannel->GetBufferedAmountLowThreshold();
}
@@ -323,17 +332,20 @@ nsDOMDataChannel::Send(const ArrayBuffer
void
nsDOMDataChannel::Send(nsIInputStream* aMsgStream,
const nsACString& aMsgString,
uint32_t aMsgLength,
bool aIsBinary,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
- uint16_t state = mDataChannel->GetReadyState();
+ uint16_t state = mozilla::DataChannel::CLOSED;
+ if (!mSentClose) {
+ state = mDataChannel->GetReadyState();
+ }
// In reality, the DataChannel protocol allows this, but we want it to
// look like WebSockets
if (state == mozilla::DataChannel::CONNECTING) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
@@ -460,16 +472,18 @@ nsDOMDataChannel::OnChannelConnected(nsI
nsresult
nsDOMDataChannel::OnChannelClosed(nsISupports* aContext)
{
nsresult rv;
// so we don't have to worry if we're notified from different paths in
// the underlying code
if (!mSentClose) {
+ // Ok, we're done with it.
+ mDataChannel->ReleaseConnection();
LOG(("%p(%p): %s - Dispatching\n",this,(void*)mDataChannel,__FUNCTION__));
rv = OnSimpleEvent(aContext, NS_LITERAL_STRING("close"));
// no more events can happen
mSentClose = true;
} else {
rv = NS_OK;
}
@@ -491,17 +505,19 @@ nsDOMDataChannel::NotBuffered(nsISupport
// In the rare case that we held off GC to let the buffer drain
UpdateMustKeepAlive();
return NS_OK;
}
void
nsDOMDataChannel::AppReady()
{
- mDataChannel->AppReady();
+ if (!mSentClose) { // may not be possible, simpler to just test anyways
+ mDataChannel->AppReady();
+ }
}
//-----------------------------------------------------------------------------
// Methods that keep alive the DataChannel object when:
// 1. the object has registered event listeners that can be triggered
// ("strong event listeners");
// 2. there are outgoing not sent messages.
//-----------------------------------------------------------------------------
--- a/dom/base/test/chrome/cpows_child.js
+++ b/dom/base/test/chrome/cpows_child.js
@@ -361,19 +361,22 @@ function unsafe_test(finish)
function dead_test(finish)
{
if (!is_remote) {
// Only run this test when running out-of-process.
finish();
return;
}
+ let gcTrigger = function() {
+ // Force the GC to dead-ify the thing.
+ content.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .garbageCollect();
+ }
+
{
let thing = { value: "Gonna croak" };
- sendAsyncMessage("cpows:dead", null, { thing });
+ sendAsyncMessage("cpows:dead", null, { thing, gcTrigger });
}
- // Force the GC to dead-ify the thing.
- content.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .garbageCollect();
addMessageListener("cpows:dead_done", finish);
}
--- a/dom/base/test/chrome/cpows_parent.xul
+++ b/dom/base/test/chrome/cpows_parent.xul
@@ -413,24 +413,28 @@
} catch (e if /unsafe CPOW usage forbidden/.test(String(e))) {
ok(false, "cpow failed");
}
opener.wrappedJSObject.SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN);
msg.target.messageManager.sendAsyncMessage("cpows:safe_done");
}
function recvDead(msg) {
- try {
- msg.objects.thing.value;
- ok(false, "Should have been a dead CPOW");
- } catch(e if /dead CPOW/.test(String(e))) {
- ok(true, "Got the expected dead CPOW");
- ok(e.stack, "The exception has a stack");
- }
- msg.target.messageManager.sendAsyncMessage("cpows:dead_done");
+ // Need to do this in a separate turn of the event loop.
+ setTimeout(() => {
+ msg.objects.gcTrigger();
+ try {
+ msg.objects.thing.value;
+ ok(false, "Should have been a dead CPOW");
+ } catch(e if /dead CPOW/.test(String(e))) {
+ ok(true, "Got the expected dead CPOW");
+ ok(e.stack, "The exception has a stack");
+ }
+ msg.target.messageManager.sendAsyncMessage("cpows:dead_done");
+ }, 0);
}
function run_tests(type) {
info("Running tests: " + type);
var node = document.getElementById('cpowbrowser_' + type);
test_state = type;
test_node = node;
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -3532,18 +3532,20 @@ class IDLMaplikeOrSetlikeOrIterableBase(
if (member.identifier.name in self.disallowedMemberNames and
not ((member.isMethod() and member.isMaplikeOrSetlikeOrIterableMethod()) or
(member.isAttr() and member.isMaplikeOrSetlikeAttr()))):
raise WebIDLError("Member '%s' conflicts "
"with reserved %s name." %
(member.identifier.name,
self.maplikeOrSetlikeOrIterableType),
[self.location, member.location])
- # Check that there are no disallowed non-method members
- if (isAncestor or (member.isAttr() or member.isConst()) and
+ # Check that there are no disallowed non-method members.
+ # Ancestor members are always disallowed here; own members
+ # are disallowed only if they're non-methods.
+ if ((isAncestor or member.isAttr() or member.isConst()) and
member.identifier.name in self.disallowedNonMethodNames):
raise WebIDLError("Member '%s' conflicts "
"with reserved %s method." %
(member.identifier.name,
self.maplikeOrSetlikeOrIterableType),
[self.location, member.location])
def addMethod(self, name, members, allowExistingOperations, returnType, args=[],
@@ -3735,16 +3737,17 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSe
"""
# Both maplike and setlike have a size attribute
members.append(IDLAttribute(self.location,
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), "size"),
BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
True,
maplikeOrSetlike=self))
self.reserved_ro_names = ["size"]
+ self.disallowedMemberNames.append("size")
# object entries()
self.addMethod("entries", members, False, BuiltinTypes[IDLBuiltinType.Types.object],
affectsNothing=True, isIteratorAlias=self.isMaplike())
# object keys()
self.addMethod("keys", members, False, BuiltinTypes[IDLBuiltinType.Types.object],
affectsNothing=True)
# object values()
--- a/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
+++ b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
@@ -83,73 +83,170 @@ def WebIDLTest(parser, harness):
valueIterableMembers.append(("length", WebIDL.IDLAttribute))
disallowedIterableNames = ["keys", "entries", "values"]
disallowedMemberNames = ["forEach", "has", "size"] + disallowedIterableNames
mapDisallowedMemberNames = ["get"] + disallowedMemberNames
disallowedNonMethodNames = ["clear", "delete"]
mapDisallowedNonMethodNames = ["set"] + disallowedNonMethodNames
setDisallowedNonMethodNames = ["add"] + disallowedNonMethodNames
+ unrelatedMembers = [("unrelatedAttribute", WebIDL.IDLAttribute),
+ ("unrelatedMethod", WebIDL.IDLMethod)]
#
# Simple Usage Tests
#
shouldPass("Iterable (key only)",
"""
interface Foo1 {
iterable<long>;
readonly attribute unsigned long length;
getter long(unsigned long index);
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
};
- """, valueIterableMembers)
+ """, valueIterableMembers + unrelatedMembers)
+
+ shouldPass("Iterable (key only) inheriting from parent",
+ """
+ interface Foo1 : Foo2 {
+ iterable<long>;
+ readonly attribute unsigned long length;
+ getter long(unsigned long index);
+ };
+ interface Foo2 {
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
+ };
+ """, valueIterableMembers, numProductions=2)
shouldPass("Iterable (key and value)",
"""
interface Foo1 {
iterable<long, long>;
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
+ };
+ """, iterableMembers + unrelatedMembers,
+ # numProductions == 2 because of the generated iterator iface,
+ numProductions=2)
+
+ shouldPass("Iterable (key and value) inheriting from parent",
+ """
+ interface Foo1 : Foo2 {
+ iterable<long, long>;
+ };
+ interface Foo2 {
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
};
""", iterableMembers,
- # numProductions == 2 because of the generated iterator iface,
- numProductions=2)
+ # numProductions == 3 because of the generated iterator iface,
+ numProductions=3)
shouldPass("Maplike (readwrite)",
"""
interface Foo1 {
maplike<long, long>;
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
};
- """, mapRWMembers)
+ """, mapRWMembers + unrelatedMembers)
+
+ shouldPass("Maplike (readwrite) inheriting from parent",
+ """
+ interface Foo1 : Foo2 {
+ maplike<long, long>;
+ };
+ interface Foo2 {
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
+ };
+ """, mapRWMembers, numProductions=2)
shouldPass("Maplike (readwrite)",
"""
interface Foo1 {
maplike<long, long>;
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
};
- """, mapRWMembers)
+ """, mapRWMembers + unrelatedMembers)
+
+ shouldPass("Maplike (readwrite) inheriting from parent",
+ """
+ interface Foo1 : Foo2 {
+ maplike<long, long>;
+ };
+ interface Foo2 {
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
+ };
+ """, mapRWMembers, numProductions=2)
shouldPass("Maplike (readonly)",
"""
interface Foo1 {
readonly maplike<long, long>;
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
};
- """, mapROMembers)
+ """, mapROMembers + unrelatedMembers)
+
+ shouldPass("Maplike (readonly) inheriting from parent",
+ """
+ interface Foo1 : Foo2 {
+ readonly maplike<long, long>;
+ };
+ interface Foo2 {
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
+ };
+ """, mapROMembers, numProductions=2)
shouldPass("Setlike (readwrite)",
"""
interface Foo1 {
setlike<long>;
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
};
- """, setRWMembers)
+ """, setRWMembers + unrelatedMembers)
+
+ shouldPass("Setlike (readwrite) inheriting from parent",
+ """
+ interface Foo1 : Foo2 {
+ setlike<long>;
+ };
+ interface Foo2 {
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
+ };
+ """, setRWMembers, numProductions=2)
shouldPass("Setlike (readonly)",
"""
interface Foo1 {
readonly setlike<long>;
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
};
- """, setROMembers)
+ """, setROMembers + unrelatedMembers)
+
+ shouldPass("Setlike (readonly) inheriting from parent",
+ """
+ interface Foo1 : Foo2 {
+ readonly setlike<long>;
+ };
+ interface Foo2 {
+ attribute long unrelatedAttribute;
+ long unrelatedMethod();
+ };
+ """, setROMembers, numProductions=2)
shouldPass("Inheritance of maplike/setlike",
"""
interface Foo1 {
maplike<long, long>;
};
interface Foo2 : Foo1 {
};
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -266,22 +266,25 @@ const kEventConstructors = {
KeyEvent: { create: function (aName, aProps) {
return new KeyboardEvent(aName, aProps);
},
},
KeyboardEvent: { create: function (aName, aProps) {
return new KeyboardEvent(aName, aProps);
},
},
- MediaEncryptedEvent: { create: function (aName, aProps) {
+ MediaEncryptedEvent: { create: function (aName, aProps) {
return new MediaEncryptedEvent(aName, aProps);
},
},
- MediaKeyMessageEvent: { create: function (aName, aProps) {
- return new MediaKeyMessageEvent(aName, aProps);
+ MediaKeyMessageEvent: { create: function (aName, aProps) {
+ return new MediaKeyMessageEvent(aName, {
+ messageType: "license-request",
+ message: new ArrayBuffer(0)
+ });
},
},
MediaStreamEvent: { create: function (aName, aProps) {
return new MediaStreamEvent(aName, aProps);
},
},
MediaStreamTrackEvent: {
// Difficult to test required arguments.
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2205,25 +2205,21 @@ public:
MediaStreamTrackSource)
explicit StreamCaptureTrackSource(MediaStreamTrackSource* aCapturedTrackSource)
: MediaStreamTrackSource(aCapturedTrackSource->GetPrincipal(),
true,
nsString())
, mCapturedTrackSource(aCapturedTrackSource)
{
- mCapturedTrackSource->RegisterSink(this);
}
void Destroy() override
{
MOZ_ASSERT(mCapturedTrackSource);
- if (mCapturedTrackSource) {
- mCapturedTrackSource->UnregisterSink(this);
- }
}
MediaSourceEnum GetMediaSource() const override
{
return MediaSourceEnum::Other;
}
CORSMode GetCORSMode() const override
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -6,22 +6,22 @@
#include "mozilla/ProcessHangMonitor.h"
#include "mozilla/ProcessHangMonitorIPC.h"
#include "jsapi.h"
#include "js/GCAPI.h"
#include "mozilla/Atomics.h"
+#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/TabParent.h"
-#include "mozilla/HangAnnotations.h"
#include "mozilla/Monitor.h"
#include "mozilla/plugins/PluginBridge.h"
#include "mozilla/Preferences.h"
#include "mozilla/Unused.h"
#include "nsIFrameLoader.h"
#include "nsIHangReport.h"
#include "nsITabParent.h"
@@ -68,17 +68,16 @@ using namespace mozilla::dom;
*/
namespace {
/* Child process objects */
class HangMonitorChild
: public PProcessHangMonitorChild
- , public mozilla::HangMonitor::Annotator
{
public:
explicit HangMonitorChild(ProcessHangMonitor* aMonitor);
virtual ~HangMonitorChild();
void Open(Transport* aTransport, ProcessId aOtherPid,
MessageLoop* aIOLoop);
@@ -111,33 +110,30 @@ class HangMonitorChild
static HangMonitorChild* Get() { return sInstance; }
MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
private:
void ShutdownOnThread();
- virtual void
- AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
-
static Atomic<HangMonitorChild*> sInstance;
+ UniquePtr<BackgroundHangMonitor> mForcePaintMonitor;
const RefPtr<ProcessHangMonitor> mHangMonitor;
Monitor mMonitor;
// Main thread-only.
bool mSentReport;
// These fields must be accessed with mMonitor held.
bool mTerminateScript;
bool mStartDebugger;
bool mFinishedStartingDebugger;
- bool mForcePaintRequested;
- bool mForcePaintInProgress;
+ bool mForcePaint;
TabId mForcePaintTab;
MOZ_INIT_OUTSIDE_CTOR uint64_t mForcePaintEpoch;
JSContext* mContext;
bool mShutdownDone;
// This field is only accessed on the hang thread.
bool mIPCOpen;
};
@@ -272,98 +268,87 @@ private:
HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
: mHangMonitor(aMonitor),
mMonitor("HangMonitorChild lock"),
mSentReport(false),
mTerminateScript(false),
mStartDebugger(false),
mFinishedStartingDebugger(false),
- mForcePaintRequested(false),
- mForcePaintInProgress(false),
+ mForcePaint(false),
mShutdownDone(false),
mIPCOpen(true)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
mContext = danger::GetJSContext();
+ mForcePaintMonitor =
+ MakeUnique<mozilla::BackgroundHangMonitor>("Gecko_Child_ForcePaint",
+ 128, /* ms timeout for microhangs */
+ 8192 /* ms timeout for permahangs */,
+ BackgroundHangMonitor::THREAD_PRIVATE);
}
HangMonitorChild::~HangMonitorChild()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sInstance == this);
+ mForcePaintMonitor = nullptr;
sInstance = nullptr;
}
void
HangMonitorChild::InterruptCallback()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
- bool forcePaintRequested;
+ bool forcePaint;
TabId forcePaintTab;
uint64_t forcePaintEpoch;
{
MonitorAutoLock lock(mMonitor);
- forcePaintRequested = mForcePaintRequested;
+ forcePaint = mForcePaint;
forcePaintTab = mForcePaintTab;
forcePaintEpoch = mForcePaintEpoch;
- mForcePaintRequested = false;
+ mForcePaint = false;
}
- if (forcePaintRequested) {
+ if (forcePaint) {
RefPtr<TabChild> tabChild = TabChild::FindTabChild(forcePaintTab);
if (tabChild) {
JS::AutoAssertOnGC nogc(mContext);
JS::AutoAssertOnBarrier nobarrier(mContext);
tabChild->ForcePaint(forcePaintEpoch);
+ mForcePaintMonitor->NotifyWait();
}
-
- MonitorAutoLock lock(mMonitor);
- mForcePaintInProgress = false;
}
}
void
HangMonitorChild::Shutdown()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
- mozilla::HangMonitor::UnregisterAnnotator(*this);
-
MonitorAutoLock lock(mMonitor);
while (!mShutdownDone) {
mMonitor.Wait();
}
}
void
HangMonitorChild::ShutdownOnThread()
{
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
MonitorAutoLock lock(mMonitor);
mShutdownDone = true;
mMonitor.Notify();
}
-/**
- * This function is always called by the HangMonitor thread.
- */
-void
-HangMonitorChild::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations)
-{
- MonitorAutoLock lock(mMonitor);
- if (mForcePaintInProgress) {
- aAnnotations.AddAnnotation(NS_LITERAL_STRING("ForcePaintInProgress"), true);
- }
-}
-
void
HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
mIPCOpen = false;
// We use a task here to ensure that IPDL is finished with this
@@ -401,20 +386,21 @@ HangMonitorChild::RecvEndStartingDebugge
return true;
}
bool
HangMonitorChild::RecvForcePaint(const TabId& aTabId, const uint64_t& aLayerObserverEpoch)
{
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+ mForcePaintMonitor->NotifyActivity();
+
{
MonitorAutoLock lock(mMonitor);
- mForcePaintRequested = true;
- mForcePaintInProgress = true;
+ mForcePaint = true;
mForcePaintTab = aTabId;
mForcePaintEpoch = aLayerObserverEpoch;
}
JS_RequestInterruptCallback(mContext);
JS::RequestGCInterruptCallback(mContext);
return true;
@@ -1214,18 +1200,16 @@ mozilla::CreateHangMonitorChild(mozilla:
JSContext* cx = danger::GetJSContext();
JS_AddInterruptCallback(cx, InterruptCallback);
JS::AddGCInterruptCallback(cx, InterruptCallback);
ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
HangMonitorChild* child = new HangMonitorChild(monitor);
- mozilla::HangMonitor::RegisterAnnotator(*child);
-
monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod
<mozilla::ipc::Transport*,
base::ProcessId,
MessageLoop*>(child,
&HangMonitorChild::Open,
aTransport, aOtherPid,
XRE_GetIOMessageLoop()));
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -19,22 +19,16 @@
#include "WebMDecoder.h"
#include "WebMDemuxer.h"
#ifdef MOZ_ANDROID_OMX
#include "AndroidMediaDecoder.h"
#include "AndroidMediaReader.h"
#include "AndroidMediaPluginHost.h"
#endif
-#ifdef MOZ_OMX_DECODER
-#include "MediaOmxDecoder.h"
-#include "MediaOmxReader.h"
-#include "nsIPrincipal.h"
-#include "mozilla/dom/HTMLMediaElement.h"
-#endif
#ifdef MOZ_DIRECTSHOW
#include "DirectShowDecoder.h"
#include "DirectShowReader.h"
#endif
#ifdef MOZ_FMP4
#include "MP4Decoder.h"
#include "MP4Demuxer.h"
#endif
@@ -141,99 +135,16 @@ static char const *const gHttpLiveStream
};
static bool
IsHttpLiveStreamingType(const nsACString& aType)
{
return CodecListContains(gHttpLiveStreamingTypes, aType);
}
-#ifdef MOZ_OMX_DECODER
-static const char* const gOmxTypes[] = {
- "audio/mpeg",
- "audio/mp4",
- "audio/amr",
- "audio/3gpp",
- "audio/flac",
- "video/mp4",
- "video/x-m4v",
- "video/3gpp",
- "video/3gpp2",
- "video/quicktime",
-#ifdef MOZ_OMX_WEBM_DECODER
- "video/webm",
- "audio/webm",
-#endif
- "audio/x-matroska",
- "video/mp2t",
- "video/avi",
- "video/x-matroska",
- nullptr
-};
-
-static const char* const gB2GOnlyTypes[] = {
- "audio/3gpp",
- "audio/amr",
- "audio/x-matroska",
- "video/mp2t",
- "video/avi",
- "video/x-matroska",
- nullptr
-};
-
-static bool
-IsOmxSupportedType(const nsACString& aType)
-{
- if (!MediaDecoder::IsOmxEnabled()) {
- return false;
- }
-
- return CodecListContains(gOmxTypes, aType);
-}
-
-static bool
-IsB2GSupportOnlyType(const nsACString& aType)
-{
- return CodecListContains(gB2GOnlyTypes, aType);
-}
-
-static char const *const gH264Codecs[9] = {
- "avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0
- "avc1.42001E", // H.264 Baseline Profile Level 3.0
- "avc1.58A01E", // H.264 Extended Profile Level 3.0
- "avc1.4D401E", // H.264 Main Profile Level 3.0
- "avc1.64001E", // H.264 High Profile Level 3.0
- "avc1.64001F", // H.264 High Profile Level 3.1
- "mp4v.20.3", // 3GPP
- "mp4a.40.2", // AAC-LC
- nullptr
-};
-
-static char const *const gMpegAudioCodecs[2] = {
- "mp3", // MP3
- nullptr
-};
-
-#ifdef MOZ_OMX_WEBM_DECODER
-static char const *const gOMXWebMCodecs[] = {
- "vorbis",
- "vp8",
- "vp8.0",
- // Since Android KK, VP9 SW decoder is supported.
- // http://developer.android.com/guide/appendix/media-formats.html
-#if ANDROID_VERSION > 18
- "vp9",
- "vp9.0",
-#endif
- nullptr
-};
-#endif //MOZ_OMX_WEBM_DECODER
-
-#endif
-
#ifdef MOZ_ANDROID_OMX
static bool
IsAndroidMediaType(const nsACString& aType)
{
if (!MediaDecoder::IsAndroidMediaPluginEnabled()) {
return false;
}
@@ -278,21 +189,17 @@ DecoderTraits::IsMP4TypeAndEnabled(const
return false;
#endif
}
static bool
IsMP3SupportedType(const nsACString& aType,
const nsAString& aCodecs = EmptyString())
{
-#ifdef MOZ_OMX_DECODER
- return false;
-#else
return MP3Decoder::CanHandleMediaType(aType, aCodecs);
-#endif
}
static bool
IsAACSupportedType(const nsACString& aType,
const nsAString& aCodecs = EmptyString())
{
return ADTSDecoder::CanHandleMediaType(aType, aCodecs);
}
@@ -359,30 +266,16 @@ CanHandleCodecsType(const MediaContentTy
return CANPLAY_YES;
}
if (IsAACSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
return CANPLAY_YES;
}
if (IsFlacSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
return CANPLAY_YES;
}
-#ifdef MOZ_OMX_DECODER
- if (IsOmxSupportedType(aType.GetMIMEType())) {
- if (aType.GetMIMEType().EqualsASCII("audio/mpeg")) {
- codecList = gMpegAudioCodecs;
-#ifdef MOZ_OMX_WEBM_DECODER
- } else if (aType.GetMIMEType().EqualsASCII("audio/webm") ||
- aType.GetMIMEType().EqualsASCII("video/webm")) {
- codecList = gOMXWebMCodecs;
-#endif
- } else {
- codecList = gH264Codecs;
- }
- }
-#endif
#ifdef MOZ_DIRECTSHOW
DirectShowDecoder::GetSupportedCodecs(aType.GetMIMEType(), &codecList);
#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaPluginEnabled()) {
EnsureAndroidMediaPluginHost()->FindDecoder(aType.GetMIMEType(), &codecList);
}
#endif
@@ -446,21 +339,16 @@ CanHandleMediaType(const MediaContentTyp
return CANPLAY_MAYBE;
}
if (IsAACSupportedType(aType.GetMIMEType())) {
return CANPLAY_MAYBE;
}
if (IsFlacSupportedType(aType.GetMIMEType())) {
return CANPLAY_MAYBE;
}
-#ifdef MOZ_OMX_DECODER
- if (IsOmxSupportedType(aType.GetMIMEType())) {
- return CANPLAY_MAYBE;
- }
-#endif
#ifdef MOZ_DIRECTSHOW
if (DirectShowDecoder::GetSupportedCodecs(aType.GetMIMEType(), nullptr)) {
return CANPLAY_MAYBE;
}
#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
EnsureAndroidMediaPluginHost()->FindDecoder(aType.GetMIMEType(), nullptr)) {
@@ -542,37 +430,16 @@ InstantiateDecoder(const nsACString& aTy
if (IsWaveType(aType)) {
decoder = new WaveDecoder(aOwner);
return decoder.forget();
}
if (IsFlacSupportedType(aType)) {
decoder = new FlacDecoder(aOwner);
return decoder.forget();
}
-#ifdef MOZ_OMX_DECODER
- if (IsOmxSupportedType(aType)) {
- // we are discouraging Web and App developers from using those formats in
- // gB2GOnlyTypes, thus we only allow them to be played on WebApps.
- if (IsB2GSupportOnlyType(aType)) {
- dom::HTMLMediaElement* element = aOwner->GetMediaElement();
- if (!element) {
- return nullptr;
- }
- nsIPrincipal* principal = element->NodePrincipal();
- if (!principal) {
- return nullptr;
- }
- if (principal->GetAppStatus() < nsIPrincipal::APP_STATUS_PRIVILEGED) {
- return nullptr;
- }
- }
- decoder = new MediaOmxDecoder(aOwner);
- return decoder.forget();
- }
-#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
decoder = new AndroidMediaDecoder(aOwner, aType);
return decoder.forget();
}
#endif
@@ -637,21 +504,16 @@ MediaDecoderReader* DecoderTraits::Creat
if (IsOggSupportedType(aType)) {
decoderReader = MediaPrefs::OggFormatReader() ?
static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()))) :
new OggReader(aDecoder);
} else
if (IsWaveType(aType)) {
decoderReader = new WaveReader(aDecoder);
} else
-#ifdef MOZ_OMX_DECODER
- if (IsOmxSupportedType(aType)) {
- decoderReader = new MediaOmxReader(aDecoder);
- } else
-#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
decoderReader = new AndroidMediaReader(aDecoder, aType);
} else
#endif
if (IsWebMSupportedType(aType)) {
decoderReader =
@@ -675,23 +537,16 @@ bool DecoderTraits::IsSupportedInVideoDo
// catch-all pref.
if (!Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true) ||
!Preferences::GetBool("media.play-stand-alone", true)) {
return false;
}
return
IsOggSupportedType(aType) ||
-#ifdef MOZ_OMX_DECODER
- // We support the formats in gB2GOnlyTypes only inside WebApps on firefoxOS
- // but not in general web content. Ensure we dont create a VideoDocument
- // when accessing those format URLs directly.
- (IsOmxSupportedType(aType) &&
- !IsB2GSupportOnlyType(aType)) ||
-#endif
IsWebMSupportedType(aType) ||
#ifdef MOZ_ANDROID_OMX
(MediaDecoder::IsAndroidMediaPluginEnabled() && IsAndroidMediaType(aType)) ||
#endif
#ifdef MOZ_FMP4
IsMP4SupportedType(aType, /* DecoderDoctorDiagnostics* */ nullptr) ||
#endif
IsMP3SupportedType(aType) ||
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -1,20 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "MediaData.h"
#include "MediaInfo.h"
-#ifdef MOZ_OMX_DECODER
-#include "GrallocImages.h"
-#include "mozilla/layers/TextureClient.h"
-#endif
#include "VideoUtils.h"
#include "ImageContainer.h"
#ifdef MOZ_WIDGET_GONK
#include <cutils/properties.h>
#endif
#include <stdint.h>
@@ -379,62 +375,16 @@ VideoData::CreateFromImage(const VideoIn
aKeyframe,
aTimecode,
aInfo.mDisplay,
0));
v->mImage = aImage;
return v.forget();
}
-#ifdef MOZ_OMX_DECODER
-/* static */
-already_AddRefed<VideoData>
-VideoData::CreateAndCopyIntoTextureClient(const VideoInfo& aInfo,
- int64_t aOffset,
- int64_t aTime,
- int64_t aDuration,
- mozilla::layers::TextureClient* aBuffer,
- bool aKeyframe,
- int64_t aTimecode,
- const IntRect& aPicture)
-{
- // The following situations could be triggered by invalid input
- if (aPicture.width <= 0 || aPicture.height <= 0) {
- NS_WARNING("Empty picture rect");
- return nullptr;
- }
-
- // Ensure the picture size specified in the headers can be extracted out of
- // the frame we've been supplied without indexing out of bounds.
- CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
- CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
- if (!xLimit.isValid() || !yLimit.isValid())
- {
- // The specified picture dimensions can't be contained inside the video
- // frame, we'll stomp memory if we try to copy it. Fail.
- NS_WARNING("Overflowing picture rect");
- return nullptr;
- }
-
- RefPtr<VideoData> v(new VideoData(aOffset,
- aTime,
- aDuration,
- aKeyframe,
- aTimecode,
- aInfo.mDisplay,
- 0));
-
- RefPtr<layers::GrallocImage> image = new layers::GrallocImage();
- image->AdoptData(aBuffer, aPicture.Size());
- v->mImage = image;
-
- return v.forget();
-}
-#endif // MOZ_OMX_DECODER
-
MediaRawData::MediaRawData()
: MediaData(RAW_DATA, 0)
, mCrypto(mCryptoInternal)
{
}
MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize)
: MediaData(RAW_DATA, 0)
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1731,24 +1731,16 @@ MediaDecoder::IsWaveEnabled()
}
bool
MediaDecoder::IsWebMEnabled()
{
return Preferences::GetBool("media.webm.enabled");
}
-#ifdef MOZ_OMX_DECODER
-bool
-MediaDecoder::IsOmxEnabled()
-{
- return Preferences::GetBool("media.omx.enabled", false);
-}
-#endif
-
#ifdef MOZ_ANDROID_OMX
bool
MediaDecoder::IsAndroidMediaPluginEnabled()
{
return AndroidBridge::Bridge() &&
AndroidBridge::Bridge()->GetAPIVersion() < 16 &&
Preferences::GetBool("media.plugins.enabled");
}
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -451,20 +451,16 @@ private:
void EnsureTelemetryReported();
static bool IsOggEnabled();
static bool IsOpusEnabled();
static bool IsWaveEnabled();
static bool IsWebMEnabled();
-#ifdef MOZ_OMX_DECODER
- static bool IsOmxEnabled();
-#endif
-
#ifdef MOZ_ANDROID_OMX
static bool IsAndroidMediaPluginEnabled();
#endif
#ifdef MOZ_WMF
static bool IsWMFEnabled();
#endif
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -1323,27 +1323,16 @@ MediaRecorder::IsTypeSupported(const nsA
}
}
#ifdef MOZ_WEBM_ENCODER
else if (mimeType.EqualsLiteral(VIDEO_WEBM) &&
MediaEncoder::IsWebMEncoderEnabled()) {
codeclist = gWebMVideoEncoderCodecs;
}
#endif
-#ifdef MOZ_OMX_ENCODER
- // We're working on MP4 encoder support for desktop
- else if (mimeType.EqualsLiteral(VIDEO_MP4) ||
- mimeType.EqualsLiteral(AUDIO_3GPP) ||
- mimeType.EqualsLiteral(AUDIO_3GPP2)) {
- if (MediaEncoder::IsOMXEncoderEnabled()) {
- // XXX check codecs for MP4/3GPP
- return true;
- }
- }
-#endif
// codecs don't matter if we don't support the container
if (!codeclist) {
return false;
}
// now filter on codecs, and if needed rescind support
nsAutoString codecstring;
rv = parser.GetParameter("codecs", codecstring);
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -383,26 +383,49 @@ MediaStreamTrack::Clone()
MediaStreamGraph* graph = Graph();
newStream->InitOwnedStreamCommon(graph);
newStream->InitPlaybackStreamCommon(graph);
return newStream->CloneDOMTrack(*this, mTrackID);
}
void
+MediaStreamTrack::SetReadyState(MediaStreamTrackState aState)
+{
+ MOZ_ASSERT(!(mReadyState == MediaStreamTrackState::Ended &&
+ aState == MediaStreamTrackState::Live),
+ "We don't support overriding the ready state from ended to live");
+
+ if (mReadyState == MediaStreamTrackState::Live &&
+ aState == MediaStreamTrackState::Ended &&
+ mSource) {
+ mSource->UnregisterSink(this);
+ }
+
+ mReadyState = aState;
+}
+
+void
MediaStreamTrack::NotifyEnded()
{
MOZ_ASSERT(NS_IsMainThread());
if (Ended()) {
return;
}
LOG(LogLevel::Info, ("MediaStreamTrack %p ended", this));
+ if (!mSource) {
+ MOZ_ASSERT(false);
+ return;
+ }
+
+ mSource->UnregisterSink(this);
+
mReadyState = MediaStreamTrackState::Ended;
DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
}
DOMMediaStream*
MediaStreamTrack::GetInputDOMStream()
{
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -292,17 +292,17 @@ public:
* Convenience (and legacy) method for when ready state is "ended".
*/
bool Ended() const { return mReadyState == MediaStreamTrackState::Ended; }
/**
* Forces the ready state to a particular value, for instance when we're
* cloning an already ended track.
*/
- void SetReadyState(MediaStreamTrackState aState) { mReadyState = aState; }
+ void SetReadyState(MediaStreamTrackState aState);
/**
* Notified by the MediaStreamGraph, through our owning MediaStream on the
* main thread.
*
* Note that this sets the track to ended and raises the "ended" event
* synchronously.
*/
--- a/dom/media/eme/MediaKeyMessageEvent.cpp
+++ b/dom/media/eme/MediaKeyMessageEvent.cpp
@@ -80,25 +80,20 @@ MediaKeyMessageEvent::Constructor(const
const nsAString& aType,
const MediaKeyMessageEventInit& aEventInitDict,
ErrorResult& aRv)
{
nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<MediaKeyMessageEvent> e = new MediaKeyMessageEvent(owner);
bool trusted = e->Init(owner);
e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
- const uint8_t* data = nullptr;
- size_t length = 0;
- if (aEventInitDict.mMessage.WasPassed()) {
- const auto& a = aEventInitDict.mMessage.Value();
- a.ComputeLengthAndData();
- data = a.Data();
- length = a.Length();
- }
- e->mMessage = ArrayBuffer::Create(aGlobal.Context(), length, data);
+ aEventInitDict.mMessage.ComputeLengthAndData();
+ e->mMessage = ArrayBuffer::Create(aGlobal.Context(),
+ aEventInitDict.mMessage.Length(),
+ aEventInitDict.mMessage.Data());
if (!e->mMessage) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
e->mMessageType = aEventInitDict.mMessageType;
e->SetTrusted(trusted);
e->SetComposed(aEventInitDict.mComposed);
return e.forget();
--- a/dom/media/encoder/MediaEncoder.cpp
+++ b/dom/media/encoder/MediaEncoder.cpp
@@ -14,20 +14,16 @@
#include"GeckoProfiler.h"
#include "OggWriter.h"
#include "OpusTrackEncoder.h"
#ifdef MOZ_WEBM_ENCODER
#include "VP8TrackEncoder.h"
#include "WebMWriter.h"
#endif
-#ifdef MOZ_OMX_ENCODER
-#include "OmxTrackEncoder.h"
-#include "ISOMediaWriter.h"
-#endif
#ifdef LOG
#undef LOG
#endif
mozilla::LazyLogModule gMediaEncoderLog("MediaEncoder");
#define LOG(type, msg) MOZ_LOG(gMediaEncoderLog, type, msg)
@@ -175,47 +171,16 @@ MediaEncoder::CreateEncoder(const nsAStr
}
videoEncoder = new VP8TrackEncoder(aTrackRate);
writer = new WebMWriter(aTrackTypes);
NS_ENSURE_TRUE(writer, nullptr);
NS_ENSURE_TRUE(videoEncoder, nullptr);
mimeType = NS_LITERAL_STRING(VIDEO_WEBM);
}
#endif //MOZ_WEBM_ENCODER
-#ifdef MOZ_OMX_ENCODER
- else if (MediaEncoder::IsOMXEncoderEnabled() &&
- (aMIMEType.EqualsLiteral(VIDEO_MP4) ||
- (aTrackTypes & ContainerWriter::CREATE_VIDEO_TRACK))) {
- if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK) {
- audioEncoder = new OmxAACAudioTrackEncoder();
- NS_ENSURE_TRUE(audioEncoder, nullptr);
- }
- videoEncoder = new OmxVideoTrackEncoder(aTrackRate);
- writer = new ISOMediaWriter(aTrackTypes);
- NS_ENSURE_TRUE(writer, nullptr);
- NS_ENSURE_TRUE(videoEncoder, nullptr);
- mimeType = NS_LITERAL_STRING(VIDEO_MP4);
- } else if (MediaEncoder::IsOMXEncoderEnabled() &&
- (aMIMEType.EqualsLiteral(AUDIO_3GPP))) {
- audioEncoder = new OmxAMRAudioTrackEncoder();
- NS_ENSURE_TRUE(audioEncoder, nullptr);
-
- writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3GP);
- NS_ENSURE_TRUE(writer, nullptr);
- mimeType = NS_LITERAL_STRING(AUDIO_3GPP);
- } else if (MediaEncoder::IsOMXEncoderEnabled() &&
- (aMIMEType.EqualsLiteral(AUDIO_3GPP2))) {
- audioEncoder = new OmxEVRCAudioTrackEncoder();
- NS_ENSURE_TRUE(audioEncoder, nullptr);
-
- writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3G2);
- NS_ENSURE_TRUE(writer, nullptr);
- mimeType = NS_LITERAL_STRING(AUDIO_3GPP2) ;
- }
-#endif // MOZ_OMX_ENCODER
else if (MediaDecoder::IsOggEnabled() && MediaDecoder::IsOpusEnabled() &&
(aMIMEType.EqualsLiteral(AUDIO_OGG) ||
(aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK))) {
writer = new OggWriter();
audioEncoder = new OpusTrackEncoder();
NS_ENSURE_TRUE(writer, nullptr);
NS_ENSURE_TRUE(audioEncoder, nullptr);
mimeType = NS_LITERAL_STRING(AUDIO_OGG);
@@ -414,24 +379,16 @@ MediaEncoder::CopyMetadataToMuxer(TrackE
#ifdef MOZ_WEBM_ENCODER
bool
MediaEncoder::IsWebMEncoderEnabled()
{
return Preferences::GetBool("media.encoder.webm.enabled");
}
#endif
-#ifdef MOZ_OMX_ENCODER
-bool
-MediaEncoder::IsOMXEncoderEnabled()
-{
- return Preferences::GetBool("media.encoder.omx.enabled");
-}
-#endif
-
/*
* SizeOfExcludingThis measures memory being used by the Media Encoder.
* Currently it measures the size of the Encoder buffer and memory occupied
* by mAudioEncoder and mVideoEncoder.
*/
size_t
MediaEncoder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
--- a/dom/media/encoder/MediaEncoder.h
+++ b/dom/media/encoder/MediaEncoder.h
@@ -212,20 +212,16 @@ public :
{
return mState == ENCODE_ERROR;
}
#ifdef MOZ_WEBM_ENCODER
static bool IsWebMEncoderEnabled();
#endif
-#ifdef MOZ_OMX_ENCODER
- static bool IsOMXEncoderEnabled();
-#endif
-
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
/*
* Measure the size of the buffer, and memory occupied by mAudioEncoder
* and mVideoEncoder
*/
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
MediaStreamVideoRecorderSink* GetVideoSink() {
deleted file mode 100644
--- a/dom/media/encoder/OmxTrackEncoder.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "OmxTrackEncoder.h"
-#include "OMXCodecWrapper.h"
-#include "VideoUtils.h"
-#include "ISOTrackMetadata.h"
-#include "GeckoProfiler.h"
-
-#ifdef MOZ_WIDGET_GONK
-#include <android/log.h>
-#define OMX_LOG(args...) \
- do { \
- __android_log_print(ANDROID_LOG_INFO, "OmxTrackEncoder", ##args); \
- } while (0)
-#else
-#define OMX_LOG(args, ...)
-#endif
-
-using namespace android;
-
-namespace mozilla {
-
-#define ENCODER_CONFIG_FRAME_RATE 30 // fps
-#define GET_ENCODED_VIDEO_FRAME_TIMEOUT 100000 // microseconds
-
-OmxVideoTrackEncoder::OmxVideoTrackEncoder(TrackRate aTrackRate)
- : VideoTrackEncoder(aTrackRate)
-{}
-
-OmxVideoTrackEncoder::~OmxVideoTrackEncoder()
-{}
-
-nsresult
-OmxVideoTrackEncoder::Init(int aWidth, int aHeight, int aDisplayWidth,
- int aDisplayHeight)
-{
- mFrameWidth = aWidth;
- mFrameHeight = aHeight;
- mDisplayWidth = aDisplayWidth;
- mDisplayHeight = aDisplayHeight;
-
- mEncoder = OMXCodecWrapper::CreateAVCEncoder();
- NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
-
- nsresult rv = mEncoder->Configure(mFrameWidth, mFrameHeight,
- ENCODER_CONFIG_FRAME_RATE);
-
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- mInitialized = (rv == NS_OK);
-
- mReentrantMonitor.NotifyAll();
-
- return rv;
-}
-
-already_AddRefed<TrackMetadataBase>
-OmxVideoTrackEncoder::GetMetadata()
-{
- PROFILER_LABEL("OmxVideoTrackEncoder", "GetMetadata",
- js::ProfileEntry::Category::OTHER);
- {
- // Wait if mEncoder is not initialized nor is being canceled.
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- while (!mCanceled && !mInitialized) {
- mReentrantMonitor.Wait();
- }
- }
-
- if (mCanceled || mEncodingComplete) {
- return nullptr;
- }
-
- RefPtr<AVCTrackMetadata> meta = new AVCTrackMetadata();
- meta->mWidth = mFrameWidth;
- meta->mHeight = mFrameHeight;
- meta->mDisplayWidth = mDisplayWidth;
- meta->mDisplayHeight = mDisplayHeight;
- meta->mFrameRate = ENCODER_CONFIG_FRAME_RATE;
- return meta.forget();
-}
-
-nsresult
-OmxVideoTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
-{
- PROFILER_LABEL("OmxVideoTrackEncoder", "GetEncodedTrack",
- js::ProfileEntry::Category::OTHER);
- VideoSegment segment;
- {
- // Move all the samples from mRawSegment to segment. We only hold the
- // monitor in this block.
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-
- // Wait if mEncoder is not initialized nor is being canceled.
- while (!mCanceled && (!mInitialized ||
- (mRawSegment.GetDuration() == 0 && !mEndOfStream))) {
- mReentrantMonitor.Wait();
- }
-
- if (mCanceled || mEncodingComplete) {
- return NS_ERROR_FAILURE;
- }
-
- segment.AppendFrom(&mRawSegment);
- }
-
- nsresult rv;
- // Start queuing raw frames to the input buffers of OMXCodecWrapper.
- VideoSegment::ChunkIterator iter(segment);
- while (!iter.IsEnded()) {
- VideoChunk chunk = *iter;
-
- uint64_t totalDurationUs = mTotalFrameDuration * USECS_PER_S / mTrackRate;
- layers::Image* img = (chunk.IsNull() || chunk.mFrame.GetForceBlack()) ?
- nullptr : chunk.mFrame.GetImage();
- rv = mEncoder->Encode(img, mFrameWidth, mFrameHeight, totalDurationUs);
- NS_ENSURE_SUCCESS(rv, rv);
-
- mTotalFrameDuration += chunk.GetDuration();
-
- iter.Next();
- }
-
- // Send the EOS signal to OMXCodecWrapper.
- if (mEndOfStream && iter.IsEnded() && !mEosSetInEncoder) {
- uint64_t totalDurationUs = mTotalFrameDuration * USECS_PER_S / mTrackRate;
- layers::Image* img = (!mLastFrame.GetImage() || mLastFrame.GetForceBlack())
- ? nullptr : mLastFrame.GetImage();
- rv = mEncoder->Encode(img, mFrameWidth, mFrameHeight, totalDurationUs,
- OMXCodecWrapper::BUFFER_EOS, &mEosSetInEncoder);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
- // Dequeue an encoded frame from the output buffers of OMXCodecWrapper.
- nsTArray<uint8_t> buffer;
- int outFlags = 0;
- int64_t outTimeStampUs = 0;
- rv = mEncoder->GetNextEncodedFrame(&buffer, &outTimeStampUs, &outFlags,
- GET_ENCODED_VIDEO_FRAME_TIMEOUT);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!buffer.IsEmpty()) {
- RefPtr<EncodedFrame> videoData = new EncodedFrame();
- if (outFlags & OMXCodecWrapper::BUFFER_CODEC_CONFIG) {
- videoData->SetFrameType(EncodedFrame::AVC_CSD);
- } else {
- videoData->SetFrameType((outFlags & OMXCodecWrapper::BUFFER_SYNC_FRAME) ?
- EncodedFrame::AVC_I_FRAME : EncodedFrame::AVC_P_FRAME);
- }
- videoData->SwapInFrameData(buffer);
- videoData->SetTimeStamp(outTimeStampUs);
- aData.AppendEncodedFrame(videoData);
- }
-
- if (outFlags & OMXCodecWrapper::BUFFER_EOS) {
- mEncodingComplete = true;
- OMX_LOG("Done encoding video.");
- }
-
- return NS_OK;
-}
-
-OmxAudioTrackEncoder::OmxAudioTrackEncoder()
- : AudioTrackEncoder()
-{}
-
-OmxAudioTrackEncoder::~OmxAudioTrackEncoder()
-{}
-
-nsresult
-OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
-{
- nsTArray<uint8_t> frameData;
- int outFlags = 0;
- int64_t outTimeUs = -1;
-
- nsresult rv = mEncoder->GetNextEncodedFrame(&frameData, &outTimeUs, &outFlags,
- 3000); // wait up to 3ms
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!frameData.IsEmpty() || outFlags & OMXCodecWrapper::BUFFER_EOS) { // Some hw codec may send out EOS with an empty frame
- bool isCSD = false;
- if (outFlags & OMXCodecWrapper::BUFFER_CODEC_CONFIG) { // codec specific data
- isCSD = true;
- } else if (outFlags & OMXCodecWrapper::BUFFER_EOS) { // last frame
- mEncodingComplete = true;
- }
-
- RefPtr<EncodedFrame> audiodata = new EncodedFrame();
- if (mEncoder->GetCodecType() == OMXCodecWrapper::AAC_ENC) {
- audiodata->SetFrameType(isCSD ?
- EncodedFrame::AAC_CSD : EncodedFrame::AAC_AUDIO_FRAME);
- } else if (mEncoder->GetCodecType() == OMXCodecWrapper::AMR_NB_ENC){
- audiodata->SetFrameType(isCSD ?
- EncodedFrame::AMR_AUDIO_CSD : EncodedFrame::AMR_AUDIO_FRAME);
- } else if (mEncoder->GetCodecType() == OMXCodecWrapper::EVRC_ENC){
- audiodata->SetFrameType(isCSD ?
- EncodedFrame::EVRC_AUDIO_CSD : EncodedFrame::EVRC_AUDIO_FRAME);
- } else {
- MOZ_ASSERT(false, "audio codec not supported");
- }
- audiodata->SetTimeStamp(outTimeUs);
- audiodata->SwapInFrameData(frameData);
- aContainer.AppendEncodedFrame(audiodata);
- }
-
- return NS_OK;
-}
-
-nsresult
-OmxAudioTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
-{
- PROFILER_LABEL("OmxAACAudioTrackEncoder", "GetEncodedTrack",
- js::ProfileEntry::Category::OTHER);
- AudioSegment segment;
- bool EOS;
- // Move all the samples from mRawSegment to segment. We only hold
- // the monitor in this block.
- {
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-
- // Wait if mEncoder is not initialized nor canceled.
- while (!mInitialized && !mCanceled) {
- mReentrantMonitor.Wait();
- }
-
- if (mCanceled || mEncodingComplete) {
- return NS_ERROR_FAILURE;
- }
-
- segment.AppendFrom(&mRawSegment);
- EOS = mEndOfStream;
- }
-
- nsresult rv;
- if (segment.GetDuration() == 0) {
- // Notify EOS at least once, even if segment is empty.
- if (EOS && !mEosSetInEncoder) {
- rv = mEncoder->Encode(segment, OMXCodecWrapper::BUFFER_EOS,
- &mEosSetInEncoder);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- // Nothing to encode but encoder could still have encoded data for earlier
- // input.
- return AppendEncodedFrames(aData);
- }
-
- // OMX encoder has limited input buffers only so we have to feed input and get
- // output more than once if there are too many samples pending in segment.
- while (segment.GetDuration() > 0) {
- rv = mEncoder->Encode(segment, 0);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = AppendEncodedFrames(aData);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
- return NS_OK;
-}
-
-nsresult
-OmxAACAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
-{
- mChannels = aChannels;
- mSamplingRate = aSamplingRate;
-
- mEncoder = OMXCodecWrapper::CreateAACEncoder();
- NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
-
- nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, mSamplingRate);
-
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- mInitialized = (rv == NS_OK);
-
- mReentrantMonitor.NotifyAll();
-
- return NS_OK;
-}
-
-already_AddRefed<TrackMetadataBase>
-OmxAACAudioTrackEncoder::GetMetadata()
-{
- PROFILER_LABEL("OmxAACAudioTrackEncoder", "GetMetadata",
- js::ProfileEntry::Category::OTHER);
- {
- // Wait if mEncoder is not initialized nor is being canceled.
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- while (!mCanceled && !mInitialized) {
- mReentrantMonitor.Wait();
- }
- }
-
- if (mCanceled || mEncodingComplete) {
- return nullptr;
- }
- RefPtr<AACTrackMetadata> meta = new AACTrackMetadata();
- meta->mChannels = mChannels;
- meta->mSampleRate = mSamplingRate;
- meta->mFrameSize = OMXCodecWrapper::kAACFrameSize;
- meta->mFrameDuration = OMXCodecWrapper::kAACFrameDuration;
- return meta.forget();
-}
-
-nsresult
-OmxAMRAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
-{
- mChannels = aChannels;
- mSamplingRate = aSamplingRate;
-
- mEncoder = OMXCodecWrapper::CreateAMRNBEncoder();
- NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
-
- nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, AMR_NB_SAMPLERATE);
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- mInitialized = (rv == NS_OK);
-
- mReentrantMonitor.NotifyAll();
-
- return NS_OK;
-}
-
-already_AddRefed<TrackMetadataBase>
-OmxAMRAudioTrackEncoder::GetMetadata()
-{
- PROFILER_LABEL("OmxAMRAudioTrackEncoder", "GetMetadata",
- js::ProfileEntry::Category::OTHER);
- {
- // Wait if mEncoder is not initialized nor is being canceled.
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- while (!mCanceled && !mInitialized) {
- mReentrantMonitor.Wait();
- }
- }
-
- if (mCanceled || mEncodingComplete) {
- return nullptr;
- }
-
- RefPtr<AMRTrackMetadata> meta = new AMRTrackMetadata();
- return meta.forget();
-}
-
-nsresult
-OmxEVRCAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
-{
- mChannels = aChannels;
- mSamplingRate = aSamplingRate;
-
- mEncoder = OMXCodecWrapper::CreateEVRCEncoder();
- NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
-
- nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, EVRC_SAMPLERATE);
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- mInitialized = (rv == NS_OK);
-
- mReentrantMonitor.NotifyAll();
-
- return NS_OK;
-}
-
-already_AddRefed<TrackMetadataBase>
-OmxEVRCAudioTrackEncoder::GetMetadata()
-{
- PROFILER_LABEL("OmxEVRCAudioTrackEncoder", "GetMetadata",
- js::ProfileEntry::Category::OTHER);
- {
- // Wait if mEncoder is not initialized nor is being canceled.
- ReentrantMonitorAutoEnter mon(mReentrantMonitor);
- while (!mCanceled && !mInitialized) {
- mReentrantMonitor.Wait();
- }
- }
-
- if (mCanceled || mEncodingComplete) {
- return nullptr;
- }
-
- RefPtr<EVRCTrackMetadata> meta = new EVRCTrackMetadata();
- meta->mChannels = mChannels;
- return meta.forget();
-}
-
-}
deleted file mode 100644
--- a/dom/media/encoder/OmxTrackEncoder.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef OmxTrackEncoder_h_
-#define OmxTrackEncoder_h_
-
-#include "nsAutoPtr.h"
-#include "TrackEncoder.h"
-
-namespace android {
-class OMXVideoEncoder;
-class OMXAudioEncoder;
-}
-
-/**
- * There are two major classes defined in file OmxTrackEncoder;
- * OmxVideoTrackEncoder and OmxAudioTrackEncoder, the video and audio track
- * encoder for media type AVC/H.264 and AAC. OMXCodecWrapper wraps and controls
- * an instance of MediaCodec, defined in libstagefright, runs on Android Jelly
- * Bean platform.
- */
-
-namespace mozilla {
-
-class OmxVideoTrackEncoder: public VideoTrackEncoder
-{
-public:
- explicit OmxVideoTrackEncoder(TrackRate aTrackRate);
- ~OmxVideoTrackEncoder();
-
- already_AddRefed<TrackMetadataBase> GetMetadata() override;
-
- nsresult GetEncodedTrack(EncodedFrameContainer& aData) override;
-
-protected:
- nsresult Init(int aWidth, int aHeight,
- int aDisplayWidth, int aDisplayHeight) override;
-
-private:
- nsAutoPtr<android::OMXVideoEncoder> mEncoder;
-};
-
-class OmxAudioTrackEncoder : public AudioTrackEncoder
-{
-public:
- OmxAudioTrackEncoder();
- ~OmxAudioTrackEncoder();
-
- already_AddRefed<TrackMetadataBase> GetMetadata() = 0;
-
- nsresult GetEncodedTrack(EncodedFrameContainer& aData) override;
-
-protected:
- nsresult Init(int aChannels, int aSamplingRate) = 0;
-
- // Append encoded frames to aContainer.
- nsresult AppendEncodedFrames(EncodedFrameContainer& aContainer);
-
- nsAutoPtr<android::OMXAudioEncoder> mEncoder;
-};
-
-class OmxAACAudioTrackEncoder final : public OmxAudioTrackEncoder
-{
-public:
- OmxAACAudioTrackEncoder()
- : OmxAudioTrackEncoder()
- {}
-
- already_AddRefed<TrackMetadataBase> GetMetadata() override;
-
-protected:
- nsresult Init(int aChannels, int aSamplingRate) override;
-};
-
-class OmxAMRAudioTrackEncoder final : public OmxAudioTrackEncoder
-{
-public:
- OmxAMRAudioTrackEncoder()
- : OmxAudioTrackEncoder()
- {}
-
- enum {
- AMR_NB_SAMPLERATE = 8000,
- };
- already_AddRefed<TrackMetadataBase> GetMetadata() override;
-
-protected:
- nsresult Init(int aChannels, int aSamplingRate) override;
-};
-
-class OmxEVRCAudioTrackEncoder final : public OmxAudioTrackEncoder
-{
-public:
- OmxEVRCAudioTrackEncoder()
- : OmxAudioTrackEncoder()
- {}
-
- enum {
- EVRC_SAMPLERATE = 8000,
- };
- already_AddRefed<TrackMetadataBase> GetMetadata() override;
-
-protected:
- nsresult Init(int aChannels, int aSamplingRate) override;
-};
-
-}
-#endif
--- a/dom/media/encoder/moz.build
+++ b/dom/media/encoder/moz.build
@@ -20,20 +20,16 @@ EXPORTS += [
]
UNIFIED_SOURCES += [
'MediaEncoder.cpp',
'OpusTrackEncoder.cpp',
'TrackEncoder.cpp',
]
-if CONFIG['MOZ_OMX_ENCODER']:
- EXPORTS += ['OmxTrackEncoder.h']
- UNIFIED_SOURCES += ['OmxTrackEncoder.cpp']
-
if CONFIG['MOZ_WEBM_ENCODER']:
EXPORTS += ['VP8TrackEncoder.h',
]
UNIFIED_SOURCES += ['VP8TrackEncoder.cpp',
]
LOCAL_INCLUDES += ['/media/libyuv/include']
FINAL_LIBRARY = 'xul'
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -49,19 +49,16 @@ if CONFIG['MOZ_ANDROID_OMX']:
DIRS += ['android']
if CONFIG['MOZ_FMP4']:
DIRS += ['fmp4']
if CONFIG['MOZ_WEBRTC']:
DIRS += ['bridge']
-if CONFIG['MOZ_OMX_DECODER']:
- DIRS += ['omx']
-
TEST_DIRS += [
'compiledtest',
'gtest',
]
MOCHITEST_MANIFESTS += [
'test/mochitest.ini',
'tests/mochitest/identity/mochitest.ini',
@@ -318,19 +315,16 @@ if CONFIG['MOZ_WEBRTC']:
DEFINES['MOZILLA_INTERNAL_API'] = True
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
else:
DEFINES['WEBRTC_POSIX'] = True
-if CONFIG['MOZ_OMX_DECODER']:
- DEFINES['MOZ_OMX_DECODER'] = True
-
if CONFIG['ANDROID_VERSION'] > '15':
DEFINES['MOZ_OMX_WEBM_DECODER'] = True
if CONFIG['MOZ_GONK_MEDIACODEC']:
DEFINES['MOZ_GONK_MEDIACODEC'] = True
include('/ipc/chromium/chromium-config.mozbuild')
deleted file mode 100644
--- a/dom/media/omx/AudioOffloadPlayer.cpp
+++ /dev/null
@@ -1,758 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "AudioOffloadPlayer.h"
-#include "nsComponentManagerUtils.h"
-#include "nsITimer.h"
-#include "MediaOmxCommonDecoder.h"
-#include "mozilla/dom/HTMLMediaElement.h"
-#include "VideoUtils.h"
-#include "mozilla/dom/power/PowerManagerService.h"
-#include "mozilla/dom/WakeLock.h"
-
-#include <binder/IPCThreadState.h>
-#include <stagefright/foundation/ADebug.h>
-#include <stagefright/foundation/ALooper.h>
-#include <stagefright/MediaDefs.h>
-#include <stagefright/MediaErrors.h>
-#include <stagefright/MediaSource.h>
-#include <stagefright/MetaData.h>
-#include <stagefright/Utils.h>
-#include <AudioTrack.h>
-#include <AudioSystem.h>
-#include <AudioParameter.h>
-#include <hardware/audio.h>
-
-using namespace android;
-
-namespace mozilla {
-
-LazyLogModule gAudioOffloadPlayerLog("AudioOffloadPlayer");
-#define AUDIO_OFFLOAD_LOG(type, msg) \
- MOZ_LOG(gAudioOffloadPlayerLog, type, msg)
-
-// maximum time in paused state when offloading audio decompression.
-// When elapsed, the GonkAudioSink is destroyed to allow the audio DSP to power down.
-static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
-
-AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
- mStarted(false),
- mPlaying(false),
- mReachedEOS(false),
- mIsElementVisible(true),
- mSampleRate(0),
- mStartPosUs(0),
- mPositionTimeMediaUs(-1),
- mInputBuffer(nullptr)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- CHECK(aObserver);
-#if ANDROID_VERSION >= 21
- mSessionId = AudioSystem::newAudioUniqueId();
- AudioSystem::acquireAudioSessionId(mSessionId, -1);
-#else
- mSessionId = AudioSystem::newAudioSessionId();
- AudioSystem::acquireAudioSessionId(mSessionId);
-#endif
- mAudioSink = new AudioOutput(mSessionId,
- IPCThreadState::self()->getCallingUid());
-
- nsCOMPtr<nsIThread> thread;
- MOZ_ALWAYS_SUCCEEDS(NS_GetMainThread(getter_AddRefs(thread)));
- mPositionChanged = mOnPositionChanged.Connect(
- thread, aObserver, &MediaOmxCommonDecoder::NotifyOffloadPlayerPositionChanged);
- mPlaybackEnded = mOnPlaybackEnded.Connect(
- thread, aObserver, &MediaDecoder::PlaybackEnded);
- mPlayerTearDown = mOnPlayerTearDown.Connect(
- thread, aObserver, &MediaOmxCommonDecoder::AudioOffloadTearDown);
- mSeekingStarted = mOnSeekingStarted.Connect(
- thread, aObserver, &MediaDecoder::SeekingStarted);
-}
-
-AudioOffloadPlayer::~AudioOffloadPlayer()
-{
- Reset();
-#if ANDROID_VERSION >= 21
- AudioSystem::releaseAudioSessionId(mSessionId, -1);
-#else
- AudioSystem::releaseAudioSessionId(mSessionId);
-#endif
-
- // Disconnect the listeners to prevent notifications from reaching
- // the MediaOmxCommonDecoder object after shutdown.
- mPositionChanged.Disconnect();
- mPlaybackEnded.Disconnect();
- mPlayerTearDown.Disconnect();
- mSeekingStarted.Disconnect();
-}
-
-void AudioOffloadPlayer::SetSource(const sp<MediaSource> &aSource)
-{
- MOZ_ASSERT(NS_IsMainThread());
- CHECK(!mSource.get());
-
- mSource = aSource;
-}
-
-status_t AudioOffloadPlayer::Start(bool aSourceAlreadyStarted)
-{
- MOZ_ASSERT(NS_IsMainThread());
- CHECK(!mStarted);
- CHECK(mSource.get());
-
- status_t err;
- CHECK(mAudioSink.get());
-
- if (!aSourceAlreadyStarted) {
- err = mSource->start();
-
- if (err != OK) {
- return err;
- }
- }
-
- sp<MetaData> format = mSource->getFormat();
- const char* mime;
- int avgBitRate = -1;
- int32_t channelMask;
- int32_t numChannels;
- int64_t durationUs = -1;
- audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
- uint32_t flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
-
- CHECK(format->findCString(kKeyMIMEType, &mime));
- CHECK(format->findInt32(kKeySampleRate, &mSampleRate));
- CHECK(format->findInt32(kKeyChannelCount, &numChannels));
- format->findInt32(kKeyBitRate, &avgBitRate);
- format->findInt64(kKeyDuration, &durationUs);
-
- if(!format->findInt32(kKeyChannelMask, &channelMask)) {
- channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
- }
-
- if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
- AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Couldn't map mime type \"%s\" to a valid "
- "AudioSystem::audio_format", mime));
- audioFormat = AUDIO_FORMAT_INVALID;
- }
-
- offloadInfo.duration_us = durationUs;
- offloadInfo.sample_rate = mSampleRate;
- offloadInfo.channel_mask = channelMask;
- offloadInfo.format = audioFormat;
- offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
- offloadInfo.bit_rate = avgBitRate;
- offloadInfo.has_video = false;
- offloadInfo.is_streaming = false;
-
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("isOffloadSupported: SR=%u, CM=0x%x, "
- "Format=0x%x, StreamType=%d, BitRate=%u, duration=%lld us, has_video=%d",
- offloadInfo.sample_rate, offloadInfo.channel_mask, offloadInfo.format,
- offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
- offloadInfo.has_video));
-
- err = mAudioSink->Open(mSampleRate,
- numChannels,
- channelMask,
- audioFormat,
- &AudioOffloadPlayer::AudioSinkCallback,
- this,
- (audio_output_flags_t) flags,
- &offloadInfo);
- if (err == OK) {
- // If the playback is offloaded to h/w we pass the
- // HAL some metadata information
- // We don't want to do this for PCM because it will be going
- // through the AudioFlinger mixer before reaching the hardware
- SendMetaDataToHal(mAudioSink, format);
- }
- mStarted = true;
- mPlaying = false;
-
- return err;
-}
-
-status_t AudioOffloadPlayer::ChangeState(MediaDecoder::PlayState aState)
-{
- MOZ_ASSERT(NS_IsMainThread());
- mPlayState = aState;
-
- switch (mPlayState) {
- case MediaDecoder::PLAY_STATE_PLAYING: {
- status_t err = Play();
- if (err != OK) {
- return err;
- }
- StartTimeUpdate();
- } break;
-
- case MediaDecoder::PLAY_STATE_PAUSED:
- case MediaDecoder::PLAY_STATE_SHUTDOWN:
- // Just pause here during play state shutdown as well to stop playing
- // offload track immediately. Resources will be freed by
- // MediaOmxCommonDecoder
- Pause();
- break;
-
- case MediaDecoder::PLAY_STATE_ENDED:
- Pause(true);
- break;
-
- default:
- break;
- }
- return OK;
-}
-
-static void ResetCallback(nsITimer* aTimer, void* aClosure)
-{
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __FUNCTION__));
- AudioOffloadPlayer* player = static_cast<AudioOffloadPlayer*>(aClosure);
- if (player) {
- player->Reset();
- }
-}
-
-void AudioOffloadPlayer::Pause(bool aPlayPendingSamples)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mStarted) {
- CHECK(mAudioSink.get());
- WakeLockCreate();
-
- if (aPlayPendingSamples) {
- mAudioSink->Stop();
- } else {
- mAudioSink->Pause();
- }
- mPlaying = false;
- }
-
- if (mResetTimer) {
- return;
- }
- mResetTimer = do_CreateInstance("@mozilla.org/timer;1");
- mResetTimer->InitWithFuncCallback(ResetCallback,
- this,
- OFFLOAD_PAUSE_MAX_MSECS,
- nsITimer::TYPE_ONE_SHOT);
-}
-
-status_t AudioOffloadPlayer::Play()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mResetTimer) {
- mResetTimer->Cancel();
- mResetTimer = nullptr;
- WakeLockRelease();
- }
-
- status_t err = OK;
-
- if (!mStarted) {
- // Last pause timed out and offloaded audio sink was reset. Start it again
- err = Start(false);
- if (err != OK) {
- return err;
- }
- // Seek to last play position only when there was no seek during last pause
- android::Mutex::Autolock autoLock(mLock);
- if (!mSeekTarget.IsValid()) {
- mSeekTarget = SeekTarget(mPositionTimeMediaUs,
- SeekTarget::Accurate,
- MediaDecoderEventVisibility::Suppressed);
- DoSeek();
- }
- }
-
- if (!mPlaying) {
- CHECK(mAudioSink.get());
- err = mAudioSink->Start();
- if (err == OK) {
- mPlaying = true;
- }
- }
-
- return err;
-}
-
-void AudioOffloadPlayer::Reset()
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (!mStarted) {
- return;
- }
-
- CHECK(mAudioSink.get());
-
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("reset: mPlaying=%d mReachedEOS=%d",
- mPlaying, mReachedEOS));
-
- mAudioSink->Stop();
- // If we're closing and have reached EOS, we don't want to flush
- // the track because if it is offloaded there could be a small
- // amount of residual data in the hardware buffer which we must
- // play to give gapless playback.
- // But if we're resetting when paused or before we've reached EOS
- // we can't be doing a gapless playback and there could be a large
- // amount of data queued in the hardware if the track is offloaded,
- // so we must flush to prevent a track switch being delayed playing
- // the buffered data that we don't want now
- if (!mPlaying || !mReachedEOS) {
- mAudioSink->Flush();
- }
-
- mAudioSink->Close();
- // Make sure to release any buffer we hold onto so that the
- // source is able to stop().
-
- if (mInputBuffer) {
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Releasing input buffer"));
-
- mInputBuffer->release();
- mInputBuffer = nullptr;
- }
- mSource->stop();
-
- IPCThreadState::self()->flushCommands();
- StopTimeUpdate();
-
- mReachedEOS = false;
- mStarted = false;
- mPlaying = false;
- mStartPosUs = 0;
-
- WakeLockRelease();
-}
-
-RefPtr<MediaDecoder::SeekPromise> AudioOffloadPlayer::Seek(SeekTarget aTarget)
-{
- MOZ_ASSERT(NS_IsMainThread());
- android::Mutex::Autolock autoLock(mLock);
-
- mSeekPromise.RejectIfExists(true, __func__);
- mSeekTarget = aTarget;
- RefPtr<MediaDecoder::SeekPromise> p = mSeekPromise.Ensure(__func__);
- DoSeek();
- return p;
-}
-
-status_t AudioOffloadPlayer::DoSeek()
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mSeekTarget.IsValid());
- CHECK(mAudioSink.get());
-
- AUDIO_OFFLOAD_LOG(LogLevel::Debug,
- ("DoSeek ( %lld )", mSeekTarget.GetTime().ToMicroseconds()));
-
- mReachedEOS = false;
- mPositionTimeMediaUs = -1;
- mStartPosUs = mSeekTarget.GetTime().ToMicroseconds();
-
- if (!mSeekPromise.IsEmpty() &&
- mSeekTarget.mEventVisibility == MediaDecoderEventVisibility::Observable) {
- mOnSeekingStarted.Notify();
- }
-
- if (mPlaying) {
- mAudioSink->Pause();
- mAudioSink->Flush();
- mAudioSink->Start();
-
- } else {
- if (mStarted) {
- mAudioSink->Flush();
- }
-
- if (!mSeekPromise.IsEmpty()) {
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Fake seek complete during pause"));
- // We do not reset mSeekTarget here.
- MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
- mSeekPromise.Resolve(val, __func__);
- }
- }
-
- return OK;
-}
-
-int64_t AudioOffloadPlayer::GetMediaTimeUs()
-{
- android::Mutex::Autolock autoLock(mLock);
-
- int64_t playPosition = 0;
- if (mSeekTarget.IsValid()) {
- return mSeekTarget.GetTime().ToMicroseconds();
- }
- if (!mStarted) {
- return mPositionTimeMediaUs;
- }
-
- playPosition = GetOutputPlayPositionUs_l();
- if (!mReachedEOS) {
- mPositionTimeMediaUs = playPosition;
- }
-
- return mPositionTimeMediaUs;
-}
-
-int64_t AudioOffloadPlayer::GetOutputPlayPositionUs_l() const
-{
- CHECK(mAudioSink.get());
- uint32_t playedSamples = 0;
-
- mAudioSink->GetPosition(&playedSamples);
-
- const int64_t playedUs = (static_cast<int64_t>(playedSamples) * 1000000 ) /
- mSampleRate;
-
- // HAL position is relative to the first buffer we sent at mStartPosUs
- const int64_t renderedDuration = mStartPosUs + playedUs;
- return renderedDuration;
-}
-
-void AudioOffloadPlayer::NotifyAudioEOS()
-{
- android::Mutex::Autolock autoLock(mLock);
- // We do not reset mSeekTarget here.
- if (!mSeekPromise.IsEmpty()) {
- MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
- mSeekPromise.Resolve(val, __func__);
- }
- mOnPlaybackEnded.Notify();
-}
-
-void AudioOffloadPlayer::NotifyPositionChanged()
-{
- mOnPositionChanged.Notify();
-}
-
-void AudioOffloadPlayer::NotifyAudioTearDown()
-{
- // Fallback to state machine.
- // state machine's seeks will be done with
- // MediaDecoderEventVisibility::Suppressed.
- android::Mutex::Autolock autoLock(mLock);
- // We do not reset mSeekTarget here.
- if (!mSeekPromise.IsEmpty()) {
- MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
- mSeekPromise.Resolve(val, __func__);
- }
- mOnPlayerTearDown.Notify();
-}
-
-// static
-size_t AudioOffloadPlayer::AudioSinkCallback(GonkAudioSink* aAudioSink,
- void* aBuffer,
- size_t aSize,
- void* aCookie,
- GonkAudioSink::cb_event_t aEvent)
-{
- AudioOffloadPlayer* me = (AudioOffloadPlayer*) aCookie;
-
- switch (aEvent) {
-
- case GonkAudioSink::CB_EVENT_FILL_BUFFER:
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Notify Audio position changed"));
- me->NotifyPositionChanged();
- return me->FillBuffer(aBuffer, aSize);
-
- case GonkAudioSink::CB_EVENT_STREAM_END:
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Notify Audio EOS"));
- me->mReachedEOS = true;
- me->NotifyAudioEOS();
- break;
-
- case GonkAudioSink::CB_EVENT_TEAR_DOWN:
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Notify Tear down event"));
- me->NotifyAudioTearDown();
- break;
-
- default:
- AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Unknown event %d from audio sink",
- aEvent));
- break;
- }
- return 0;
-}
-
-size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
-{
- CHECK(mAudioSink.get());
-
- if (mReachedEOS) {
- return 0;
- }
-
- size_t sizeDone = 0;
- size_t sizeRemaining = aSize;
- int64_t seekTimeUs = -1;
- while (sizeRemaining > 0) {
- MediaSource::ReadOptions options;
- bool refreshSeekTime = false;
- {
- android::Mutex::Autolock autoLock(mLock);
-
- if (mSeekTarget.IsValid()) {
- seekTimeUs = mSeekTarget.GetTime().ToMicroseconds();
- options.setSeekTo(seekTimeUs);
- refreshSeekTime = true;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = nullptr;
- }
- }
- }
-
- if (!mInputBuffer) {
- status_t err;
- err = mSource->read(&mInputBuffer, &options);
-
- CHECK((!err && mInputBuffer) || (err && !mInputBuffer));
-
- android::Mutex::Autolock autoLock(mLock);
-
- if (err != OK) {
- if (mSeekTarget.IsValid()) {
- mSeekTarget.Reset();
- }
- AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Error while reading media source %d "
- "Ok to receive EOS error at end", err));
- if (!mReachedEOS) {
- // After seek there is a possible race condition if
- // OffloadThread is observing state_stopping_1 before
- // framesReady() > 0. Ensure sink stop is called
- // after last buffer is released. This ensures the
- // partial buffer is written to the driver before
- // stopping one is observed.The drawback is that
- // there will be an unnecessary call to the parser
- // after parser signalled EOS.
- if (sizeDone > 0) {
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("send Partial buffer down"));
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("skip calling stop till next"
- " fillBuffer"));
- break;
- }
- // no more buffers to push - stop() and wait for STREAM_END
- // don't set mReachedEOS until stream end received
- mAudioSink->Stop();
- }
- break;
- }
-
- if(mInputBuffer->range_length() != 0) {
- CHECK(mInputBuffer->meta_data()->findInt64(
- kKeyTime, &mPositionTimeMediaUs));
- }
-
- if (mSeekTarget.IsValid() &&
- seekTimeUs == mSeekTarget.GetTime().ToMicroseconds()) {
- MOZ_ASSERT(mSeekTarget.IsValid());
- mSeekTarget.Reset();
- if (!mSeekPromise.IsEmpty()) {
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("FillBuffer posting SEEK_COMPLETE"));
- MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
- mSeekPromise.Resolve(val, __func__);
- }
- } else if (mSeekTarget.IsValid()) {
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("seek is updated during unlocking mLock"));
- }
-
- if (refreshSeekTime) {
- NotifyPositionChanged();
-
- // need to adjust the mStartPosUs for offload decoding since parser
- // might not be able to get the exact seek time requested.
- mStartPosUs = mPositionTimeMediaUs;
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Adjust seek time to: %.2f",
- mStartPosUs / 1E6));
- }
- }
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = nullptr;
- continue;
- }
-
- size_t copy = sizeRemaining;
- if (copy > mInputBuffer->range_length()) {
- copy = mInputBuffer->range_length();
- }
-
- memcpy((char *)aData + sizeDone,
- (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
- copy);
-
- mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
- mInputBuffer->range_length() - copy);
-
- sizeDone += copy;
- sizeRemaining -= copy;
- }
- return sizeDone;
-}
-
-void AudioOffloadPlayer::SetElementVisibility(bool aIsVisible)
-{
- MOZ_ASSERT(NS_IsMainThread());
- mIsElementVisible = aIsVisible;
- if (mIsElementVisible) {
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Element is visible. Start time update"));
- StartTimeUpdate();
- }
-}
-
-static void TimeUpdateCallback(nsITimer* aTimer, void* aClosure)
-{
- AudioOffloadPlayer* player = static_cast<AudioOffloadPlayer*>(aClosure);
- player->TimeUpdate();
-}
-
-void AudioOffloadPlayer::TimeUpdate()
-{
- MOZ_ASSERT(NS_IsMainThread());
- TimeStamp now = TimeStamp::Now();
-
- // If TIMEUPDATE_MS has passed since the last fire update event fired, fire
- // another timeupdate event.
- if ((mLastFireUpdateTime.IsNull() ||
- now - mLastFireUpdateTime >=
- TimeDuration::FromMilliseconds(TIMEUPDATE_MS))) {
- mLastFireUpdateTime = now;
- NotifyPositionChanged();
- }
-
- if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING || !mIsElementVisible) {
- StopTimeUpdate();
- }
-}
-
-nsresult AudioOffloadPlayer::StartTimeUpdate()
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (mTimeUpdateTimer) {
- return NS_OK;
- }
-
- mTimeUpdateTimer = do_CreateInstance("@mozilla.org/timer;1");
- return mTimeUpdateTimer->InitWithFuncCallback(TimeUpdateCallback,
- this,
- TIMEUPDATE_MS,
- nsITimer::TYPE_REPEATING_SLACK);
-}
-
-nsresult AudioOffloadPlayer::StopTimeUpdate()
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (!mTimeUpdateTimer) {
- return NS_OK;
- }
-
- nsresult rv = mTimeUpdateTimer->Cancel();
- mTimeUpdateTimer = nullptr;
- return rv;
-}
-
-MediaDecoderOwner::NextFrameStatus AudioOffloadPlayer::GetNextFrameStatus()
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (mSeekTarget.IsValid()) {
- return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING;
- } else if (mPlayState == MediaDecoder::PLAY_STATE_ENDED) {
- return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
- } else {
- return MediaDecoderOwner::NEXT_FRAME_AVAILABLE;
- }
-}
-
-void AudioOffloadPlayer::SendMetaDataToHal(sp<GonkAudioSink>& aSink,
- const sp<MetaData>& aMeta)
-{
- int32_t sampleRate = 0;
- int32_t bitRate = 0;
- int32_t channelMask = 0;
- int32_t delaySamples = 0;
- int32_t paddingSamples = 0;
- CHECK(aSink.get());
-
- AudioParameter param = AudioParameter();
-
- if (aMeta->findInt32(kKeySampleRate, &sampleRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_SAMPLE_RATE), sampleRate);
- }
- if (aMeta->findInt32(kKeyChannelMask, &channelMask)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_NUM_CHANNEL), channelMask);
- }
- if (aMeta->findInt32(kKeyBitRate, &bitRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate);
- }
- if (aMeta->findInt32(kKeyEncoderDelay, &delaySamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
- }
- if (aMeta->findInt32(kKeyEncoderPadding, &paddingSamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
- }
-
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("SendMetaDataToHal: bitRate %d,"
- " sampleRate %d, chanMask %d, delaySample %d, paddingSample %d", bitRate,
- sampleRate, channelMask, delaySamples, paddingSamples));
-
- aSink->SetParameters(param.toString());
- return;
-}
-
-void AudioOffloadPlayer::SetVolume(double aVolume)
-{
- MOZ_ASSERT(NS_IsMainThread());
- CHECK(mAudioSink.get());
- mAudioSink->SetVolume((float) aVolume);
-}
-
-void AudioOffloadPlayer::WakeLockCreate()
-{
- MOZ_ASSERT(NS_IsMainThread());
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __FUNCTION__));
- if (!mWakeLock) {
- RefPtr<dom::power::PowerManagerService> pmService =
- dom::power::PowerManagerService::GetInstance();
- NS_ENSURE_TRUE_VOID(pmService);
-
- ErrorResult rv;
- mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("cpu"), nullptr, rv);
- }
-}
-
-void AudioOffloadPlayer::WakeLockRelease()
-{
- MOZ_ASSERT(NS_IsMainThread());
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __FUNCTION__));
- if (mWakeLock) {
- ErrorResult rv;
- mWakeLock->Unlock(rv);
- mWakeLock = nullptr;
- }
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/omx/AudioOffloadPlayer.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUDIO_OFFLOAD_PLAYER_H_
-#define AUDIO_OFFLOAD_PLAYER_H_
-
-#include <stagefright/MediaBuffer.h>
-#include <stagefright/MediaSource.h>
-#include <stagefright/TimeSource.h>
-#include <utils/threads.h>
-#include <utils/RefBase.h>
-
-#include "AudioOutput.h"
-#include "AudioOffloadPlayerBase.h"
-#include "MediaDecoderOwner.h"
-#include "MediaEventSource.h"
-
-namespace mozilla {
-
-namespace dom {
-class WakeLock;
-}
-
-/**
- * AudioOffloadPlayer adds support for audio tunneling to a digital signal
- * processor (DSP) in the device chipset. With tunneling, audio decoding is
- * off-loaded to the DSP, waking the application processor less often and using
- * less battery
- *
- * This depends on offloading capability provided by Android KK AudioTrack class
- *
- * Audio playback is based on pull mechanism, whenever audio sink needs
- * data, FillBuffer() will read data from compressed audio source and provide
- * it to the sink
- *
- * Also this class passes state changes (play/pause/seek) from
- * MediaOmxCommonDecoder to GonkAudioSink as well as provide GonkAudioSink status
- * (position changed, playback ended, seek complete, audio tear down) back to
- * MediaOmxCommonDecoder
- *
- * It acts as a bridge between MediaOmxCommonDecoder and GonkAudioSink during
- * offload playback
- */
-
-class MediaOmxCommonDecoder;
-
-class AudioOffloadPlayer : public AudioOffloadPlayerBase
-{
- typedef android::Mutex Mutex;
- typedef android::MetaData MetaData;
- typedef android::status_t status_t;
- typedef android::AudioTrack AudioTrack;
- typedef android::MediaBuffer MediaBuffer;
- typedef android::MediaSource MediaSource;
-
-public:
- enum {
- REACHED_EOS,
- SEEK_COMPLETE
- };
-
- AudioOffloadPlayer(MediaOmxCommonDecoder* aDecoder);
-
- ~AudioOffloadPlayer();
-
- // Caller retains ownership of "aSource".
- void SetSource(const android::sp<MediaSource> &aSource) override;
-
- // Start the source if it's not already started and open the GonkAudioSink to
- // create an offloaded audio track
- status_t Start(bool aSourceAlreadyStarted = false) override;
-
- status_t ChangeState(MediaDecoder::PlayState aState) override;
-
- void SetVolume(double aVolume) override;
-
- int64_t GetMediaTimeUs() override;
-
- // To update progress bar when the element is visible
- void SetElementVisibility(bool aIsVisible) override;
-
- // Update ready state based on current play state. Not checking data
- // availability since offloading is currently done only when whole compressed
- // data is available
- MediaDecoderOwner::NextFrameStatus GetNextFrameStatus() override;
-
- RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget) override;
-
- void TimeUpdate();
-
- // Close the audio sink, stop time updates, frees the input buffers
- void Reset();
-
-private:
- // Set when audio source is started and GonkAudioSink is initialized
- // Used only in main thread
- bool mStarted;
-
- // Set when audio sink is started. i.e. playback started
- // Used only in main thread
- bool mPlaying;
-
- // Once playback reached end of stream (last ~100ms), position provided by DSP
- // may be reset/corrupted. This bool is used to avoid that.
- // Used in main thread and offload callback thread, protected by Mutex
- // mLock
- bool mReachedEOS;
-
- // Set when the HTML Audio Element is visible to the user.
- // Used only in main thread
- bool mIsElementVisible;
-
- // Session id given by Android::AudioSystem and used while creating audio sink
- // Used only in main thread
- int mSessionId;
-
- // Sample rate of current audio track. Used only in main thread
- int mSampleRate;
-
- // After seeking, positions returned by offlaoded tracks (DSP) will be
- // relative to the seeked position. And seeked position may be slightly
- // different than given mSeekTimeUs, if audio source cannot find a frame at
- // that position. Store seeked position in mStartPosUs and provide
- // mStartPosUs + GetPosition() (i.e. absolute position) to
- // MediaOmxCommonDecoder
- // Used in main thread and offload callback thread, protected by Mutex
- // mLock
- int64_t mStartPosUs;
-
- // The target of current seek when there is a request to seek
- // Used in main thread and offload callback thread, protected by Mutex
- // mLock
- SeekTarget mSeekTarget;
-
- // MozPromise of current seek.
- // Used in main thread and offload callback thread, protected by Mutex
- // mLock
- MozPromiseHolder<MediaDecoder::SeekPromise> mSeekPromise;
-
- // Positions obtained from offlaoded tracks (DSP)
- // Used in main thread and offload callback thread, protected by Mutex
- // mLock
- int64_t mPositionTimeMediaUs;
-
- // State obtained from MediaOmxCommonDecoder. Used only in main thread
- MediaDecoder::PlayState mPlayState;
-
- // Protect accessing audio position related variables between main thread and
- // offload callback thread
- Mutex mLock;
-
- // Compressed audio source.
- // Used in main thread first and later in offload callback thread
- android::sp<MediaSource> mSource;
-
- // Audio sink wrapper to access offloaded audio tracks
- // Used in main thread and offload callback thread
- // Race conditions are protected in underlying Android::AudioTrack class
- android::sp<GonkAudioSink> mAudioSink;
-
- // Buffer used to get date from audio source. Used in offload callback thread
- MediaBuffer* mInputBuffer;
-
- TimeStamp mLastFireUpdateTime;
-
- // Timer to trigger position changed events
- nsCOMPtr<nsITimer> mTimeUpdateTimer;
-
- // Timer to reset GonkAudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
- // It is triggered in Pause() and canceled when there is a Play() within
- // OFFLOAD_PAUSE_MAX_USECS. Used only from main thread so no lock is needed.
- nsCOMPtr<nsITimer> mResetTimer;
-
- // To avoid device suspend when mResetTimer is going to be triggered.
- // Used only from main thread so no lock is needed.
- RefPtr<mozilla::dom::WakeLock> mWakeLock;
-
- MediaEventProducer<void> mOnPositionChanged;
- MediaEventProducer<void> mOnPlaybackEnded;
- MediaEventProducer<void> mOnPlayerTearDown;
- MediaEventProducer<void> mOnSeekingStarted;
- MediaEventListener mPositionChanged;
- MediaEventListener mPlaybackEnded;
- MediaEventListener mPlayerTearDown;
- MediaEventListener mSeekingStarted;
-
- // Provide the playback position in microseconds from total number of
- // frames played by audio track
- int64_t GetOutputPlayPositionUs_l() const;
-
- // Fill the buffer given by audio sink with data from compressed audio
- // source. Also handles the seek by seeking audio source and stop the sink in
- // case of error
- size_t FillBuffer(void *aData, size_t aSize);
-
- // Called by GonkAudioSink when it needs data, to notify EOS or tear down event
- static size_t AudioSinkCallback(GonkAudioSink *aAudioSink,
- void *aData,
- size_t aSize,
- void *aMe,
- GonkAudioSink::cb_event_t aEvent);
-
- bool IsSeeking();
-
- // Set mSeekTarget to the given position and restart the sink. Actual seek
- // happens in FillBuffer(). If mSeekPromise is not empty, send
- // SeekingStarted event always and SeekingStopped event when the play state is
- // paused to MediaDecoder.
- // When decoding and playing happens separately, if there is a seek during
- // pause, we can decode and keep data ready.
- // In case of offload player, no way to seek during pause. So just fake that
- // seek is done.
- status_t DoSeek();
-
- // Start/Resume the audio sink so that callback will start being called to get
- // compressed data
- status_t Play();
-
- // Stop the audio sink if we need to play till we drain the current buffer.
- // or Pause the sink in case we should stop playing immediately
- void Pause(bool aPlayPendingSamples = false);
-
- // When audio is offloaded, application processor wakes up less frequently
- // (>1sec) But when Player UI is visible we need to update progress bar
- // atleast once in 250ms. Start a timer when player UI becomes visible or
- // audio starts playing to send UpdateLogicalPosition events once in 250ms.
- // Stop the timer when UI goes invisible or play state is not playing.
- // Also make sure timer functions are always called from main thread
- nsresult StartTimeUpdate();
- nsresult StopTimeUpdate();
-
- void WakeLockCreate();
- void WakeLockRelease();
-
- // Notify end of stream by sending PlaybackEnded event to observer
- // (i.e.MediaDecoder)
- void NotifyAudioEOS();
-
- // Notify position changed event by sending UpdateLogicalPosition event to
- // observer
- void NotifyPositionChanged();
-
- // Offloaded audio track is invalidated due to usecase change. Notify
- // MediaDecoder to re-evaluate offloading options
- void NotifyAudioTearDown();
-
- // Send information from MetaData to the HAL via GonkAudioSink
- void SendMetaDataToHal(android::sp<GonkAudioSink>& aSink,
- const android::sp<MetaData>& aMeta);
-
- AudioOffloadPlayer(const AudioOffloadPlayer &);
- AudioOffloadPlayer &operator=(const AudioOffloadPlayer &);
-};
-
-} // namespace mozilla
-
-#endif // AUDIO_OFFLOAD_PLAYER_H_
deleted file mode 100644
--- a/dom/media/omx/AudioOffloadPlayerBase.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUDIO_OFFLOAD_PLAYER_BASE_H_
-#define AUDIO_OFFLOAD_PLAYER_BASE_H_
-
-#include "MediaDecoder.h"
-#include "MediaDecoderOwner.h"
-
-namespace mozilla {
-
-/**
- * AudioOffloadPlayer interface class which has funtions used by MediaOmxDecoder
- * This is to reduce the dependency of AudioOffloadPlayer in MediaOmxDecoder
- */
-class AudioOffloadPlayerBase
-{
- typedef android::status_t status_t;
- typedef android::MediaSource MediaSource;
-
-public:
- virtual ~AudioOffloadPlayerBase() {};
-
- // Caller retains ownership of "aSource".
- virtual void SetSource(const android::sp<MediaSource> &aSource) {}
-
- // Start the source if it's not already started and open the AudioSink to
- // create an offloaded audio track
- virtual status_t Start(bool aSourceAlreadyStarted = false)
- {
- return android::NO_INIT;
- }
-
- virtual status_t ChangeState(MediaDecoder::PlayState aState)
- {
- return android::NO_INIT;
- }
-
- virtual void SetVolume(double aVolume) {}
-
- virtual int64_t GetMediaTimeUs() { return 0; }
-
- // To update progress bar when the element is visible
- virtual void SetElementVisibility(bool aIsVisible) {}
-
- // Update ready state based on current play state. Not checking data
- // availability since offloading is currently done only when whole compressed
- // data is available
- virtual MediaDecoderOwner::NextFrameStatus GetNextFrameStatus()
- {
- return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
- }
-
- virtual RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget) = 0;
-};
-
-} // namespace mozilla
-
-#endif // AUDIO_OFFLOAD_PLAYER_BASE_H_
deleted file mode 100644
--- a/dom/media/omx/AudioOutput.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stagefright/foundation/ADebug.h>
-#include "AudioOutput.h"
-
-#include "mozilla/Logging.h"
-
-namespace mozilla {
-
-extern LazyLogModule gAudioOffloadPlayerLog;
-#define AUDIO_OFFLOAD_LOG(type, msg) \
- MOZ_LOG(gAudioOffloadPlayerLog, type, msg)
-
-using namespace android;
-
-AudioOutput::AudioOutput(int aSessionId, int aUid) :
- mCallbackCookie(nullptr),
- mCallback(nullptr),
- mCallbackData(nullptr),
- mUid(aUid),
- mSessionId(aSessionId)
-{
-}
-
-AudioOutput::~AudioOutput()
-{
- Close();
-}
-
-ssize_t AudioOutput::FrameSize() const
-{
- if (!mTrack.get()) {
- return NO_INIT;
- }
- return mTrack->frameSize();
-}
-
-status_t AudioOutput::GetPosition(uint32_t *aPosition) const
-{
- if (!mTrack.get()) {
- return NO_INIT;
- }
- return mTrack->getPosition(aPosition);
-}
-
-status_t AudioOutput::SetVolume(float aVolume) const
-{
- if (!mTrack.get()) {
- return NO_INIT;
- }
- return mTrack->setVolume(aVolume);
-}
-
-status_t AudioOutput::SetParameters(const String8& aKeyValuePairs)
-{
- if (!mTrack.get()) {
- return NO_INIT;
- }
- return mTrack->setParameters(aKeyValuePairs);
-}
-
-status_t AudioOutput::Open(uint32_t aSampleRate,
- int aChannelCount,
- audio_channel_mask_t aChannelMask,
- audio_format_t aFormat,
- AudioCallback aCb,
- void* aCookie,
- audio_output_flags_t aFlags,
- const audio_offload_info_t *aOffloadInfo)
-{
- mCallback = aCb;
- mCallbackCookie = aCookie;
-
- if (((aFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) || !aCb ||
- !aOffloadInfo) {
- return BAD_VALUE;
- }
-
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("open(%u, %d, 0x%x, 0x%x, %d 0x%x)",
- aSampleRate, aChannelCount, aChannelMask, aFormat, mSessionId, aFlags));
-
- if (aChannelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
- aChannelMask = audio_channel_out_mask_from_count(aChannelCount);
- if (0 == aChannelMask) {
- AUDIO_OFFLOAD_LOG(LogLevel::Error, ("open() error, can\'t derive mask for"
- " %d audio channels", aChannelCount));
- return NO_INIT;
- }
- }
-
- sp<AudioTrack> t;
- CallbackData* newcbd = new CallbackData(this);
-
- t = new AudioTrack(
- AUDIO_STREAM_MUSIC,
- aSampleRate,
- aFormat,
- aChannelMask,
- 0, // Offloaded tracks will get frame count from AudioFlinger
- aFlags,
- CallbackWrapper,
- newcbd,
- 0, // notification frames
- mSessionId,
- AudioTrack::TRANSFER_CALLBACK,
- aOffloadInfo,
- mUid);
-
- if ((!t.get()) || (t->initCheck() != NO_ERROR)) {
- AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Unable to create audio track"));
- delete newcbd;
- return NO_INIT;
- }
-
- mCallbackData = newcbd;
- t->setVolume(1.0);
-
- mTrack = t;
- return NO_ERROR;
-}
-
-status_t AudioOutput::Start()
-{
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__));
- if (!mTrack.get()) {
- return NO_INIT;
- }
- mTrack->setVolume(1.0);
- return mTrack->start();
-}
-
-void AudioOutput::Stop()
-{
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__));
- if (mTrack.get()) {
- mTrack->stop();
- }
-}
-
-void AudioOutput::Flush()
-{
- if (mTrack.get()) {
- mTrack->flush();
- }
-}
-
-void AudioOutput::Pause()
-{
- if (mTrack.get()) {
- mTrack->pause();
- }
-}
-
-void AudioOutput::Close()
-{
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__));
- mTrack.clear();
-
- delete mCallbackData;
- mCallbackData = nullptr;
-}
-
-// static
-void AudioOutput::CallbackWrapper(int aEvent, void* aCookie, void* aInfo)
-{
- CallbackData* data = (CallbackData*) aCookie;
- data->Lock();
- AudioOutput* me = data->GetOutput();
- AudioTrack::Buffer* buffer = (AudioTrack::Buffer*) aInfo;
- if (!me) {
- // no output set, likely because the track was scheduled to be reused
- // by another player, but the format turned out to be incompatible.
- data->Unlock();
- if (buffer) {
- buffer->size = 0;
- }
- return;
- }
-
- switch(aEvent) {
-
- case AudioTrack::EVENT_MORE_DATA: {
-
- size_t actualSize = (*me->mCallback)(me, buffer->raw, buffer->size,
- me->mCallbackCookie, CB_EVENT_FILL_BUFFER);
-
- if (actualSize == 0 && buffer->size > 0) {
- // We've reached EOS but the audio track is not stopped yet,
- // keep playing silence.
- memset(buffer->raw, 0, buffer->size);
- actualSize = buffer->size;
- }
-
- buffer->size = actualSize;
- } break;
-
- case AudioTrack::EVENT_STREAM_END:
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Callback wrapper: EVENT_STREAM_END"));
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_STREAM_END);
- break;
-
- case AudioTrack::EVENT_NEW_IAUDIOTRACK :
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Callback wrapper: EVENT_TEAR_DOWN"));
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
- break;
-
- default:
- AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("received unknown event type: %d in"
- " Callback wrapper!", aEvent));
- break;
- }
-
- data->Unlock();
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/omx/AudioOutput.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUDIOOUTPUT_H_
-#define AUDIOOUTPUT_H_
-
-#include <stagefright/foundation/ABase.h>
-#include <utils/Mutex.h>
-#include <AudioTrack.h>
-
-#include "GonkAudioSink.h"
-
-namespace mozilla {
-
-/**
- * Stripped version of Android KK MediaPlayerService::AudioOutput class
- * Android MediaPlayer uses AudioOutput as a wrapper to handle
- * Android::AudioTrack
- * Similarly to ease handling offloaded tracks, part of AudioOutput is used here
- */
-class AudioOutput : public GonkAudioSink
-{
- typedef android::Mutex Mutex;
- typedef android::String8 String8;
- typedef android::status_t status_t;
- typedef android::AudioTrack AudioTrack;
-
- class CallbackData;
-
-public:
- AudioOutput(int aSessionId, int aUid);
- virtual ~AudioOutput();
-
- ssize_t FrameSize() const override;
- status_t GetPosition(uint32_t* aPosition) const override;
- status_t SetVolume(float aVolume) const override;
- status_t SetParameters(const String8& aKeyValuePairs) override;
-
- // Creates an offloaded audio track with the given parameters
- // TODO: Try to recycle audio tracks instead of creating new audio tracks
- // every time
- status_t Open(uint32_t aSampleRate,
- int aChannelCount,
- audio_channel_mask_t aChannelMask,
- audio_format_t aFormat,
- AudioCallback aCb,
- void* aCookie,
- audio_output_flags_t aFlags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t* aOffloadInfo = nullptr) override;
-
- status_t Start() override;
- void Stop() override;
- void Flush() override;
- void Pause() override;
- void Close() override;
-
-private:
- static void CallbackWrapper(int aEvent, void* aMe, void* aInfo);
-
- android::sp<AudioTrack> mTrack;
- void* mCallbackCookie;
- AudioCallback mCallback;
- CallbackData* mCallbackData;
-
- // Uid of the current process, need to create audio track
- int mUid;
-
- // Session id given by Android::AudioSystem and used to create audio track
- int mSessionId;
-
- // CallbackData is what is passed to the AudioTrack as the "user" data.
- // We need to be able to target this to a different Output on the fly,
- // so we can't use the Output itself for this.
- class CallbackData
- {
- public:
- CallbackData(AudioOutput* aCookie)
- {
- mData = aCookie;
- }
- AudioOutput* GetOutput() { return mData;}
- void SetOutput(AudioOutput* aNewcookie) { mData = aNewcookie; }
- // Lock/Unlock are used by the callback before accessing the payload of
- // this object
- void Lock() { mLock.lock(); }
- void Unlock() { mLock.unlock(); }
- private:
- AudioOutput* mData;
- mutable Mutex mLock;
- DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
- };
-}; // AudioOutput
-
-} // namespace mozilla
-
-#endif /* AUDIOOUTPUT_H_ */
deleted file mode 100644
--- a/dom/media/omx/GonkAudioSink.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef GONK_AUDIO_SINK_H_
-#define GONK_AUDIO_SINK_H_
-
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <system/audio.h>
-
-#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
-#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
-#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
-
-// when the channel mask isn't known, use the channel count to derive a mask in
-// AudioSink::open()
-#define CHANNEL_MASK_USE_CHANNEL_ORDER 0
-
-namespace mozilla {
-
-/**
- * AudioSink: abstraction layer for audio output
- * Stripped version of Android KK MediaPlayerBase::AudioSink class
- */
-
-class GonkAudioSink : public android::RefBase
-{
- typedef android::String8 String8;
- typedef android::status_t status_t;
-
-public:
- enum cb_event_t {
- CB_EVENT_FILL_BUFFER, // Request to write more data to buffer.
- CB_EVENT_STREAM_END, // Sent after all the buffers queued in AF and HW
- // are played back (after stop is called)
- CB_EVENT_TEAR_DOWN // The AudioTrack was invalidated due to usecase
- // change. Need to re-evaluate offloading options
- };
-
- // Callback returns the number of bytes actually written to the buffer.
- typedef size_t (*AudioCallback)(GonkAudioSink* aAudioSink,
- void* aBuffer,
- size_t aSize,
- void* aCookie,
- cb_event_t aEvent);
- virtual ~GonkAudioSink() {}
- virtual ssize_t FrameSize() const = 0;
- virtual status_t GetPosition(uint32_t* aPosition) const = 0;
- virtual status_t SetVolume(float aVolume) const = 0;
- virtual status_t SetParameters(const String8& aKeyValuePairs)
- {
- return android::NO_ERROR;
- }
-
- virtual status_t Open(uint32_t aSampleRate,
- int aChannelCount,
- audio_channel_mask_t aChannelMask,
- audio_format_t aFormat=AUDIO_FORMAT_PCM_16_BIT,
- AudioCallback aCb = nullptr,
- void* aCookie = nullptr,
- audio_output_flags_t aFlags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t* aOffloadInfo = nullptr) = 0;
-
- virtual status_t Start() = 0;
- virtual void Stop() = 0;
- virtual void Flush() = 0;
- virtual void Pause() = 0;
- virtual void Close() = 0;
-};
-
-} // namespace mozilla
-
-#endif // GONK_AUDIO_SINK_H_
deleted file mode 100644
--- a/dom/media/omx/I420ColorConverterHelper.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "I420ColorConverterHelper.h"
-
-#include <dlfcn.h>
-
-#include "mozilla/Logging.h"
-
-mozilla::LazyLogModule gI420ColorConverterHelperLog("I420ColorConverterHelper");
-#define LOG(msg...) MOZ_LOG(gI420ColorConverterHelperLog, mozilla::LogLevel::Warning, (msg))
-
-namespace android {
-
-I420ColorConverterHelper::I420ColorConverterHelper()
- : mHandle(nullptr)
- , mConverter({nullptr, nullptr, nullptr, nullptr, nullptr})
-{
-}
-
-I420ColorConverterHelper::~I420ColorConverterHelper()
-{
- RWLock::AutoWLock awl(mLock);
- unloadLocked();
-}
-
-// Prerequisite: a writer-lock should be held
-bool
-I420ColorConverterHelper::loadLocked()
-{
- if (loadedLocked()) {
- return true;
- }
- unloadLocked();
-
- // Open the shared library
- mHandle = dlopen("libI420colorconvert.so", RTLD_NOW);
- if (mHandle == nullptr) {
- LOG("libI420colorconvert.so not found");
- return false;
- }
-
- // Find the entry point
- // Pointer to function with signature
- // void getI420ColorConverter(II420ColorConverter *converter)
- typedef int (* getConverterFn)(II420ColorConverter *converter);
- getConverterFn getI420ColorConverter =
- (getConverterFn) dlsym(mHandle, "getI420ColorConverter");
- if (getI420ColorConverter == nullptr) {
- LOG("Cannot load getI420ColorConverter from libI420colorconvert.so");
- unloadLocked();
- return false;
- }
-
- // Fill the function pointers.
- getI420ColorConverter(&mConverter);
- if (mConverter.getDecoderOutputFormat == nullptr ||
- mConverter.convertDecoderOutputToI420 == nullptr ||
- mConverter.getEncoderInputFormat == nullptr ||
- mConverter.convertI420ToEncoderInput == nullptr ||
- mConverter.getEncoderInputBufferInfo == nullptr) {
- LOG("Failed to initialize I420 color converter");
- unloadLocked();
- return false;
- }
-
- return true;
-}
-
-// Prerequisite: a reader-lock or a writer-lock should be held
-bool
-I420ColorConverterHelper::loadedLocked() const
-{
- if (mHandle == nullptr ||
- mConverter.getDecoderOutputFormat == nullptr ||
- mConverter.convertDecoderOutputToI420 == nullptr ||
- mConverter.getEncoderInputFormat == nullptr ||
- mConverter.convertI420ToEncoderInput == nullptr ||
- mConverter.getEncoderInputBufferInfo == nullptr) {
- return false;
- }
- return true;
-}
-
-// Prerequisite: a writer-lock should be held
-void
-I420ColorConverterHelper::unloadLocked()
-{
- if (mHandle != nullptr) {
- dlclose(mHandle);
- }
- mHandle = nullptr;
- mConverter.getDecoderOutputFormat = nullptr;
- mConverter.convertDecoderOutputToI420 = nullptr;
- mConverter.getEncoderInputFormat = nullptr;
- mConverter.convertI420ToEncoderInput = nullptr;
- mConverter.getEncoderInputBufferInfo = nullptr;
-}
-
-bool
-I420ColorConverterHelper::ensureLoaded()
-{
- {
- RWLock::AutoRLock arl(mLock);
- // Check whether the library has been loaded or not.
- if (loadedLocked()) {
- return true;
- }
- }
-
- {
- RWLock::AutoWLock awl(mLock);
- // Check whether the library has been loaded or not on other threads.
- if (loadedLocked()) {
- return true;
- }
-
- // Reload the library
- unloadLocked();
- if (loadLocked()) {
- return true;
- }
-
- // Reset the library
- unloadLocked();
- }
-
- return false;
-}
-
-int
-I420ColorConverterHelper::getDecoderOutputFormat()
-{
- if (!ensureLoaded()) {
- return -1;
- }
-
- RWLock::AutoRLock arl(mLock);
- if (mConverter.getDecoderOutputFormat != nullptr) {
- return mConverter.getDecoderOutputFormat();
- }
- return -1;
-}
-
-int
-I420ColorConverterHelper::convertDecoderOutputToI420(
- void* decoderBits, int decoderWidth, int decoderHeight,
- ARect decoderRect, void* dstBits)
-{
- if (!ensureLoaded()) {
- return -1;
- }
-
- RWLock::AutoRLock arl(mLock);
- if (mConverter.convertDecoderOutputToI420 != nullptr) {
- return mConverter.convertDecoderOutputToI420(decoderBits,
- decoderWidth, decoderHeight, decoderRect, dstBits);
- }
- return -1;
-}
-
-int
-I420ColorConverterHelper::getEncoderInputFormat()
-{
- if (!ensureLoaded()) {
- return -1;
- }
-
- RWLock::AutoRLock arl(mLock);
- if (mConverter.getEncoderInputFormat != nullptr) {
- return mConverter.getEncoderInputFormat();
- }
- return -1;
-}
-
-int
-I420ColorConverterHelper::convertI420ToEncoderInput(void* aSrcBits,
- int aSrcWidth,
- int aSrcHeight,
- int aEncoderWidth,
- int aEncoderHeight,
- ARect aEncoderRect,
- void* aEncoderBits)
-{
- if (!ensureLoaded()) {
- return -1;
- }
-
- RWLock::AutoRLock arl(mLock);
- if (mConverter.convertI420ToEncoderInput != nullptr) {
- return mConverter.convertI420ToEncoderInput(aSrcBits, aSrcWidth, aSrcHeight,
- aEncoderWidth, aEncoderHeight, aEncoderRect, aEncoderBits);
- }
- return -1;
-}
-
-int
-I420ColorConverterHelper::getEncoderInputBufferInfo(int aSrcWidth,
- int aSrcHeight,
- int* aEncoderWidth,
- int* aEncoderHeight,
- ARect* aEncoderRect,
- int* aEncoderBufferSize)
-{
- if (!ensureLoaded()) {
- return -1;
- }
-
- RWLock::AutoRLock arl(mLock);
- if (mConverter.getEncoderInputBufferInfo != nullptr) {
- return mConverter.getEncoderInputBufferInfo(aSrcWidth, aSrcHeight,
- aEncoderWidth, aEncoderHeight, aEncoderRect, aEncoderBufferSize);
- }
- return -1;
-}
-
-} // namespace android
deleted file mode 100644
--- a/dom/media/omx/I420ColorConverterHelper.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef I420_COLOR_CONVERTER_HELPER_H
-#define I420_COLOR_CONVERTER_HELPER_H
-
-#include <utils/RWLock.h>
-#include <media/editor/II420ColorConverter.h>
-
-#include <mozilla/Attributes.h>
-
-namespace android {
-
-class I420ColorConverterHelper {
-public:
- I420ColorConverterHelper();
- ~I420ColorConverterHelper();
-
- int getDecoderOutputFormat();
-
- int convertDecoderOutputToI420(void* aDecoderBits,
- int aDecoderWidth,
- int aDecoderHeight,
- ARect aDecoderRect,
- void* aDstBits);
-
- int getEncoderInputFormat();
-
- int convertI420ToEncoderInput(void* aSrcBits,
- int aSrcWidth,
- int aSrcHeight,
- int aEncoderWidth,
- int aEncoderHeight,
- ARect aEncoderRect,
- void* aEncoderBits);
-
- int getEncoderInputBufferInfo(int aSrcWidth,
- int aSrcHeight,
- int* aEncoderWidth,
- int* aEncoderHeight,
- ARect* aEncoderRect,
- int* aEncoderBufferSize);
-
-private:
- mutable RWLock mLock;
- void *mHandle;
- II420ColorConverter mConverter;
-
- bool loadLocked();
- bool loadedLocked() const;
- void unloadLocked();
-
- bool ensureLoaded();
-
- I420ColorConverterHelper(const I420ColorConverterHelper &) = delete;
- const I420ColorConverterHelper &operator=(const I420ColorConverterHelper &) = delete;
-};
-
-} // namespace android
-
-#endif // I420_COLOR_CONVERTER_HELPER_H
deleted file mode 100644
--- a/dom/media/omx/MPAPI.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-#if !defined(MPAPI_h_)
-#define MPAPI_h_
-
-#include <stdint.h>
-#include "mozilla/layers/TextureClient.h"
-
-namespace MPAPI {
-
-struct VideoPlane {
- VideoPlane() :
- mData(nullptr),
- mStride(0),
- mWidth(0),
- mHeight(0),
- mOffset(0),
- mSkip(0)
- {}
-
- void *mData;
- int32_t mStride;
- int32_t mWidth;
- int32_t mHeight;
- int32_t mOffset;
- int32_t mSkip;
-};
-
-struct VideoFrame {
- int64_t mTimeUs;
- bool mKeyFrame;
- bool mShouldSkip;
- void *mData;
- size_t mSize;
- int32_t mStride;
- int32_t mSliceHeight;
- int32_t mRotation;
- VideoPlane Y;
- VideoPlane Cb;
- VideoPlane Cr;
- RefPtr<mozilla::layers::TextureClient> mGraphicBuffer;
-
- VideoFrame() :
- mTimeUs(0),
- mKeyFrame(false),
- mShouldSkip(false),
- mData(nullptr),
- mSize(0),
- mStride(0),
- mSliceHeight(0),
- mRotation(0)
- {}
-
- void Set(int64_t aTimeUs, bool aKeyFrame,
- void *aData, size_t aSize, int32_t aStride, int32_t aSliceHeight, int32_t aRotation,
- void *aYData, int32_t aYStride, int32_t aYWidth, int32_t aYHeight, int32_t aYOffset, int32_t aYSkip,
- void *aCbData, int32_t aCbStride, int32_t aCbWidth, int32_t aCbHeight, int32_t aCbOffset, int32_t aCbSkip,
- void *aCrData, int32_t aCrStride, int32_t aCrWidth, int32_t aCrHeight, int32_t aCrOffset, int32_t aCrSkip)
- {
- mTimeUs = aTimeUs;
- mKeyFrame = aKeyFrame;
- mData = aData;
- mSize = aSize;
- mStride = aStride;
- mSliceHeight = aSliceHeight;
- mRotation = aRotation;
- mGraphicBuffer = nullptr;
- Y.mData = aYData;
- Y.mStride = aYStride;
- Y.mWidth = aYWidth;
- Y.mHeight = aYHeight;
- Y.mOffset = aYOffset;
- Y.mSkip = aYSkip;
- Cb.mData = aCbData;
- Cb.mStride = aCbStride;
- Cb.mWidth = aCbWidth;
- Cb.mHeight = aCbHeight;
- Cb.mOffset = aCbOffset;
- Cb.mSkip = aCbSkip;
- Cr.mData = aCrData;
- Cr.mStride = aCrStride;
- Cr.mWidth = aCrWidth;
- Cr.mHeight = aCrHeight;
- Cr.mOffset = aCrOffset;
- Cr.mSkip = aCrSkip;
- }
-};
-
-struct AudioFrame {
- int64_t mTimeUs;
- void *mData; // 16PCM interleaved
- size_t mSize; // Size of mData in bytes
- int32_t mAudioChannels;
- int32_t mAudioSampleRate;
-
- AudioFrame() :
- mTimeUs(0),
- mData(0),
- mSize(0),
- mAudioChannels(0),
- mAudioSampleRate(0)
- {
- }
-
- void Set(int64_t aTimeUs,
- void *aData, size_t aSize,
- int32_t aAudioChannels, int32_t aAudioSampleRate)
- {
- mTimeUs = aTimeUs;
- mData = aData;
- mSize = aSize;
- mAudioChannels = aAudioChannels;
- mAudioSampleRate = aAudioSampleRate;
- }
-};
-
-struct Decoder;
-
-struct PluginHost {
- bool (*Read)(Decoder *aDecoder, char *aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes);
- uint64_t (*GetLength)(Decoder *aDecoder);
- void (*SetMetaDataReadMode)(Decoder *aDecoder);
- void (*SetPlaybackReadMode)(Decoder *aDecoder);
-};
-
-struct Decoder {
- void *mResource;
- void *mPrivate;
-
- Decoder();
-
- void (*GetDuration)(Decoder *aDecoder, int64_t *durationUs);
- void (*GetVideoParameters)(Decoder *aDecoder, int32_t *aWidth, int32_t *aHeight);
- void (*GetAudioParameters)(Decoder *aDecoder, int32_t *aNumChannels, int32_t *aSampleRate);
- bool (*HasVideo)(Decoder *aDecoder);
- bool (*HasAudio)(Decoder *aDecoder);
- bool (*ReadVideo)(Decoder *aDecoder, VideoFrame *aFrame, int64_t aSeekTimeUs);
- bool (*ReadAudio)(Decoder *aDecoder, AudioFrame *aFrame, int64_t aSeekTimeUs);
- void (*DestroyDecoder)(Decoder *);
-};
-
-struct Manifest {
- bool (*CanDecode)(const char *aMimeChars, size_t aMimeLen, const char* const**aCodecs);
- bool (*CreateDecoder)(PluginHost *aPluginHost, Decoder *aDecoder,
- const char *aMimeChars, size_t aMimeLen);
-};
-
-}
-
-#endif
deleted file mode 100644
--- a/dom/media/omx/MediaCodecProxy.cpp
+++ /dev/null
@@ -1,626 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaCodecProxy.h"
-#include <string.h>
-#include <binder/IPCThreadState.h>
-#include <stagefright/foundation/ABuffer.h>
-#include <stagefright/foundation/ADebug.h>
-#include <stagefright/MetaData.h>
-#include "stagefright/MediaErrors.h"
-
-#include <android/log.h>
-#define MCP_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "MediaCodecProxy", __VA_ARGS__)
-
-namespace android {
-
-// General Template: MediaCodec::getOutputGraphicBufferFromIndex(...)
-template <typename T, bool InterfaceSupported>
-struct OutputGraphicBufferStub
-{
- static status_t GetOutputGraphicBuffer(T *aMediaCodec,
- size_t aIndex,
- sp<GraphicBuffer> *aGraphicBuffer)
- {
- return ERROR_UNSUPPORTED;
- }
-};
-
-// Class Template Specialization: MediaCodec::getOutputGraphicBufferFromIndex(...)
-template <typename T>
-struct OutputGraphicBufferStub<T, true>
-{
- static status_t GetOutputGraphicBuffer(T *aMediaCodec,
- size_t aIndex,
- sp<GraphicBuffer> *aGraphicBuffer)
- {
- if (aMediaCodec == nullptr || aGraphicBuffer == nullptr) {
- return BAD_VALUE;
- }
- *aGraphicBuffer = aMediaCodec->getOutputGraphicBufferFromIndex(aIndex);
- return OK;
- }
-};
-
-// Wrapper class to handle interface-difference of MediaCodec.
-struct MediaCodecInterfaceWrapper
-{
- typedef int8_t Supported;
- typedef int16_t Unsupported;
-
- template <typename T>
- static auto TestOutputGraphicBuffer(T *aMediaCodec) -> decltype(aMediaCodec->getOutputGraphicBufferFromIndex(0), Supported());
-
- template <typename T>
- static auto TestOutputGraphicBuffer(...) -> Unsupported;
-
- // SFINAE: Substitution Failure Is Not An Error
- static const bool OutputGraphicBufferSupported = sizeof(TestOutputGraphicBuffer<MediaCodec>(nullptr)) == sizeof(Supported);
-
- // Class Template Specialization
- static OutputGraphicBufferStub<MediaCodec, OutputGraphicBufferSupported> sOutputGraphicBufferStub;
-
- // Wrapper Function
- static status_t GetOutputGraphicBuffer(MediaCodec *aMediaCodec,
- size_t aIndex,
- sp<GraphicBuffer> *aGraphicBuffer)
- {
- return sOutputGraphicBufferStub.GetOutputGraphicBuffer(aMediaCodec, aIndex, aGraphicBuffer);
- }
-
-};
-
-sp<MediaCodecProxy>
-MediaCodecProxy::CreateByType(sp<ALooper> aLooper,
- const char *aMime,
- bool aEncoder)
-{
- sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper,
- aMime,
- aEncoder);
- return codec;
-}
-
-MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
- const char *aMime,
- bool aEncoder)
- : mCodecLooper(aLooper)
- , mCodecMime(aMime)
- , mCodecEncoder(aEncoder)
- , mPromiseMonitor("MediaCodecProxy::mPromiseMonitor")
-{
- MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
- mCodecPromise.SetMonitor(&mPromiseMonitor);
-}
-
-MediaCodecProxy::~MediaCodecProxy()
-{
- ReleaseMediaCodec();
-}
-
-bool
-MediaCodecProxy::AllocateAudioMediaCodec()
-{
- if (mResourceClient || mCodec.get()) {
- return false;
- }
-
- if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
- if (allocateCodec()) {
- return true;
- }
- }
- return false;
-}
-
-RefPtr<MediaCodecProxy::CodecPromise>
-MediaCodecProxy::AsyncAllocateVideoMediaCodec()
-{
- if (mResourceClient || mCodec.get()) {
- return CodecPromise::CreateAndReject(true, __func__);
- }
-
- if (strncasecmp(mCodecMime.get(), "video/", 6) != 0) {
- return CodecPromise::CreateAndReject(true, __func__);
- }
- // request video codec
- mozilla::MediaSystemResourceType type =
- mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
- mozilla::MediaSystemResourceType::VIDEO_DECODER;
- mResourceClient = new mozilla::MediaSystemResourceClient(type);
- mResourceClient->SetListener(this);
- mResourceClient->Acquire();
-
- mozilla::MonitorAutoLock lock(mPromiseMonitor);
- RefPtr<CodecPromise> p = mCodecPromise.Ensure(__func__);
- return p.forget();
-}
-
-void
-MediaCodecProxy::ReleaseMediaCodec()
-{
- // At first, release mResourceClient's resource to prevent a conflict with
- // mResourceClient's callback.
- if (mResourceClient) {
- mResourceClient->ReleaseResource();
- mResourceClient = nullptr;
- }
-
- mozilla::MonitorAutoLock lock(mPromiseMonitor);
- mCodecPromise.RejectIfExists(true, __func__);
- releaseCodec();
-}
-
-bool
-MediaCodecProxy::allocateCodec()
-{
- if (mCodecLooper == nullptr) {
- return false;
- }
-
- // Write Lock for mCodec
- RWLock::AutoWLock awl(mCodecLock);
-
- // Create MediaCodec
- mCodec = MediaCodec::CreateByType(mCodecLooper, mCodecMime.get(), mCodecEncoder);
- if (mCodec == nullptr) {
- return false;
- }
-
- return true;
-}
-
-void
-MediaCodecProxy::releaseCodec()
-{
- wp<MediaCodec> codec;
-
- {
- // Write Lock for mCodec
- RWLock::AutoWLock awl(mCodecLock);
-
- codec = mCodec;
-
- // Release MediaCodec
- if (mCodec != nullptr) {
- mCodec->stop();
- mCodec->release();
- mCodec = nullptr;
- }
- }
-
- while (codec.promote() != nullptr) {
- // this value come from stagefright's AwesomePlayer.
- usleep(1000);
- }
-
- // Complete all pending Binder ipc transactions
- IPCThreadState::self()->flushCommands();
-
-}
-
-bool
-MediaCodecProxy::allocated() const
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- return mCodec != nullptr;
-}
-
-status_t
-MediaCodecProxy::configure(const sp<AMessage> &aFormat,
- const sp<Surface> &aNativeWindow,
- const sp<ICrypto> &aCrypto,
- uint32_t aFlags)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->configure(aFormat, aNativeWindow, aCrypto, aFlags);
-}
-
-status_t
-MediaCodecProxy::start()
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
-
- return mCodec->start();
-}
-
-status_t
-MediaCodecProxy::stop()
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->stop();
-}
-
-status_t
-MediaCodecProxy::release()
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->release();
-}
-
-status_t
-MediaCodecProxy::flush()
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->flush();
-}
-
-status_t
-MediaCodecProxy::queueInputBuffer(size_t aIndex,
- size_t aOffset,
- size_t aSize,
- int64_t aPresentationTimeUs,
- uint32_t aFlags,
- AString *aErrorDetailMessage)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->queueInputBuffer(aIndex, aOffset, aSize,
- aPresentationTimeUs, aFlags, aErrorDetailMessage);
-}
-
-status_t
-MediaCodecProxy::queueSecureInputBuffer(size_t aIndex,
- size_t aOffset,
- const CryptoPlugin::SubSample *aSubSamples,
- size_t aNumSubSamples,
- const uint8_t aKey[16],
- const uint8_t aIV[16],
- CryptoPlugin::Mode aMode,
- int64_t aPresentationTimeUs,
- uint32_t aFlags,
- AString *aErrorDetailMessage)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->queueSecureInputBuffer(aIndex, aOffset,
- aSubSamples, aNumSubSamples, aKey, aIV, aMode,
- aPresentationTimeUs, aFlags, aErrorDetailMessage);
-}
-
-status_t
-MediaCodecProxy::dequeueInputBuffer(size_t *aIndex,
- int64_t aTimeoutUs)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->dequeueInputBuffer(aIndex, aTimeoutUs);
-}
-
-status_t
-MediaCodecProxy::dequeueOutputBuffer(size_t *aIndex,
- size_t *aOffset,
- size_t *aSize,
- int64_t *aPresentationTimeUs,
- uint32_t *aFlags,
- int64_t aTimeoutUs)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->dequeueOutputBuffer(aIndex, aOffset, aSize,
- aPresentationTimeUs, aFlags, aTimeoutUs);
-}
-
-status_t
-MediaCodecProxy::renderOutputBufferAndRelease(size_t aIndex)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->renderOutputBufferAndRelease(aIndex);
-}
-
-status_t
-MediaCodecProxy::releaseOutputBuffer(size_t aIndex)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->releaseOutputBuffer(aIndex);
-}
-
-status_t
-MediaCodecProxy::signalEndOfInputStream()
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->signalEndOfInputStream();
-}
-
-status_t
-MediaCodecProxy::getOutputFormat(sp<AMessage> *aFormat) const
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->getOutputFormat(aFormat);
-}
-
-status_t
-MediaCodecProxy::getInputBuffers(Vector<sp<ABuffer>> *aBuffers) const
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->getInputBuffers(aBuffers);
-}
-
-status_t
-MediaCodecProxy::getOutputBuffers(Vector<sp<ABuffer>> *aBuffers) const
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return mCodec->getOutputBuffers(aBuffers);
-}
-
-void
-MediaCodecProxy::requestActivityNotification(const sp<AMessage> &aNotify)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return;
- }
- mCodec->requestActivityNotification(aNotify);
-}
-
-status_t
-MediaCodecProxy::getOutputGraphicBufferFromIndex(size_t aIndex,
- sp<GraphicBuffer> *aGraphicBuffer)
-{
- // Read Lock for mCodec
- RWLock::AutoRLock arl(mCodecLock);
-
- if (mCodec == nullptr) {
- return NO_INIT;
- }
- return MediaCodecInterfaceWrapper::GetOutputGraphicBuffer(mCodec.get(), aIndex, aGraphicBuffer);
-}
-
-status_t
-MediaCodecProxy::getCapability(uint32_t *aCapability)
-{
- if (aCapability == nullptr) {
- return BAD_VALUE;
- }
-
- uint32_t capability = kEmptyCapability;
-
- if (MediaCodecInterfaceWrapper::OutputGraphicBufferSupported) {
- capability |= kCanExposeGraphicBuffer;
- }
-
- *aCapability = capability;
-
- return OK;
-}
-
-// Called on ImageBridge thread
-void
-MediaCodecProxy::ResourceReserved()
-{
- MCP_LOG("resourceReserved");
- mozilla::MonitorAutoLock lock(mPromiseMonitor);
- // Create MediaCodec
- if (!allocateCodec()) {
- mCodecPromise.RejectIfExists(true, __func__);
- return;
- }
- mCodecPromise.ResolveIfExists(true, __func__);
-}
-
-// Called on ImageBridge thread
-void
-MediaCodecProxy::ResourceReserveFailed()
-{
- mozilla::MonitorAutoLock lock(mPromiseMonitor);
- mCodecPromise.RejectIfExists(true, __func__);
-}
-
-bool MediaCodecProxy::Prepare()
-{
-
- if (start() != OK) {
- MCP_LOG("Couldn't start MediaCodec");
- return false;
- }
- if (getInputBuffers(&mInputBuffers) != OK) {
- MCP_LOG("Couldn't get input buffers from MediaCodec");
- return false;
- }
- if (getOutputBuffers(&mOutputBuffers) != OK) {
- MCP_LOG("Couldn't get output buffers from MediaCodec");
- return false;
- }
-
- return true;
-}
-
-bool MediaCodecProxy::UpdateOutputBuffers()
-{
- // Read Lock for mCodec
- {
- RWLock::AutoRLock autolock(mCodecLock);
- if (mCodec == nullptr) {
- MCP_LOG("MediaCodec has not been inited from UpdateOutputBuffers");
- return false;
- }
- }
-
- status_t err = getOutputBuffers(&mOutputBuffers);
- if (err != OK){
- MCP_LOG("Couldn't update output buffers from MediaCodec");
- return false;
- }
- return true;
-}
-
-status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize,
- int64_t aTimestampUsecs, uint64_t aflags,
- int64_t aTimeoutUs)
-{
- // Read Lock for mCodec
- {
- RWLock::AutoRLock autolock(mCodecLock);
- if (mCodec == nullptr) {
- MCP_LOG("MediaCodec has not been inited from input!");
- return NO_INIT;
- }
- }
-
- size_t index;
- status_t err = dequeueInputBuffer(&index, aTimeoutUs);
- if (err != OK) {
- if (err != -EAGAIN) {
- MCP_LOG("dequeueInputBuffer returned %d", err);
- }
- return err;
- }
-
- if (aData) {
- const sp<ABuffer> &dstBuffer = mInputBuffers.itemAt(index);
-
- CHECK_LE(aDataSize, dstBuffer->capacity());
- dstBuffer->setRange(0, aDataSize);
-
- memcpy(dstBuffer->data(), aData, aDataSize);
- err = queueInputBuffer(index, 0, dstBuffer->size(), aTimestampUsecs, aflags);
- } else {
- err = queueInputBuffer(index, 0, 0, 0ll, MediaCodec::BUFFER_FLAG_EOS);
- }
-
- if (err != OK) {
- MCP_LOG("queueInputBuffer returned %d", err);
- return err;
- }
- return err;
-}
-
-status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
-{
- // Read Lock for mCodec
- {
- RWLock::AutoRLock autolock(mCodecLock);
- if (mCodec == nullptr) {
- MCP_LOG("MediaCodec has not been inited from output!");
- return NO_INIT;
- }
- }
-
- size_t index = 0;
- size_t offset = 0;
- size_t size = 0;
- int64_t timeUs = 0;
- uint32_t flags = 0;
-
- *aBuffer = nullptr;
-
- status_t err = dequeueOutputBuffer(&index, &offset, &size,
- &timeUs, &flags, aTimeoutUs);
- if (err != OK) {
- return err;
- }
-
- MediaBuffer *buffer;
- sp<GraphicBuffer> graphicBuffer;
-
- if (getOutputGraphicBufferFromIndex(index, &graphicBuffer) == OK &&
- graphicBuffer != nullptr) {
- buffer = new MediaBuffer(graphicBuffer);
- } else {
- buffer = new MediaBuffer(mOutputBuffers.itemAt(index));
- }
- sp<MetaData> metaData = buffer->meta_data();
- metaData->setInt32(kKeyBufferIndex, index);
- metaData->setInt64(kKeyTime, timeUs);
- buffer->set_range(buffer->range_offset(), size);
- *aBuffer = buffer;
- if (flags & MediaCodec::BUFFER_FLAG_EOS) {
- return ERROR_END_OF_STREAM;
- }
- return err;
-}
-
-void MediaCodecProxy::ReleaseMediaResources()
-{
- ReleaseMediaCodec();
-}
-
-void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {
- if (aBuffer) {
- sp<MetaData> metaData = aBuffer->meta_data();
- int32_t index;
- metaData->findInt32(kKeyBufferIndex, &index);
- aBuffer->release();
- releaseOutputBuffer(index);
- }
-}
-
-} // namespace android
deleted file mode 100644
--- a/dom/media/omx/MediaCodecProxy.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef MEDIA_CODEC_PROXY_H
-#define MEDIA_CODEC_PROXY_H
-
-#include <nsString.h>
-#include <stagefright/MediaCodec.h>
-#include <stagefright/MediaBuffer.h>
-#include <utils/threads.h>
-
-#include "mozilla/media/MediaSystemResourceClient.h"
-#include "mozilla/Monitor.h"
-#include "mozilla/MozPromise.h"
-#include "mozilla/RefPtr.h"
-
-namespace android {
-// This class is intended to be a proxy for MediaCodec with codec resource
-// management. Basically user can use it like MediaCodec, but need to handle
-// the listener when Codec is reserved for Async case. A good example is
-// MediaCodecReader.cpp. Another useage is to use configure(), Prepare(),
-// Input(), and Output(). It is used in GonkVideoDecoderManager.cpp which
-// doesn't need to handle the buffers for codec.
-class MediaCodecProxy : public RefBase
- , public mozilla::MediaSystemResourceReservationListener
-{
-public:
- typedef mozilla::MozPromise<bool /* aIgnored */, bool /* aIgnored */, /* IsExclusive = */ true> CodecPromise;
-
- enum Capability {
- kEmptyCapability = 0x00000000,
- kCanExposeGraphicBuffer = 0x00000001,
- };
-
- enum {
- kKeyBufferIndex = 'bfin',
- };
-
- // Check whether MediaCodec has been allocated.
- bool allocated() const;
-
- // Static MediaCodec methods
- // Only support MediaCodec::CreateByType()
- static sp<MediaCodecProxy> CreateByType(sp<ALooper> aLooper,
- const char *aMime,
- bool aEncoder);
-
- // MediaCodec methods
- status_t configure(const sp<AMessage> &aFormat,
- const sp<Surface> &aNativeWindow,
- const sp<ICrypto> &aCrypto,
- uint32_t aFlags);
-
- status_t start();
-
- status_t stop();
-
- status_t release();
-
- status_t flush();
-
- status_t queueInputBuffer(size_t aIndex,
- size_t aOffset,
- size_t aSize,
- int64_t aPresentationTimeUs,
- uint32_t aFlags,
- AString *aErrorDetailMessage=nullptr);
-
- status_t queueSecureInputBuffer(size_t aIndex,
- size_t aOffset,
- const CryptoPlugin::SubSample *aSubSamples,
- size_t aNumSubSamples,
- const uint8_t aKey[16],
- const uint8_t aIV[16],
- CryptoPlugin::Mode aMode,
- int64_t aPresentationTimeUs,
- uint32_t aFlags,
- AString *aErrorDetailMessage=nullptr);
-
- status_t dequeueInputBuffer(size_t *aIndex,
- int64_t aTimeoutUs=INT64_C(0));
-
- status_t dequeueOutputBuffer(size_t *aIndex,
- size_t *aOffset,
- size_t *aSize,
- int64_t *aPresentationTimeUs,
- uint32_t *aFlags,
- int64_t aTimeoutUs=INT64_C(0));
-
- status_t renderOutputBufferAndRelease(size_t aIndex);
-
- status_t releaseOutputBuffer(size_t aIndex);
-
- status_t signalEndOfInputStream();
-
- status_t getOutputFormat(sp<AMessage> *aFormat) const;
-
- status_t getInputBuffers(Vector<sp<ABuffer>> *aBuffers) const;
-
- status_t getOutputBuffers(Vector<sp<ABuffer>> *aBuffers) const;
-
- // Notification will be posted once there "is something to do", i.e.
- // an input/output buffer has become available, a format change is
- // pending, an error is pending.
- void requestActivityNotification(const sp<AMessage> &aNotify);
-
- status_t getOutputGraphicBufferFromIndex(size_t aIndex,
- sp<GraphicBuffer> *aGraphicBuffer);
-
- status_t getCapability(uint32_t *aCapability);
-
- // Utility functions
-
- // If aData is null, will notify decoder input EOS
- status_t Input(const uint8_t* aData, uint32_t aDataSize,
- int64_t aTimestampUsecs, uint64_t flags, int64_t aTimeoutUs = 0);
- status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs);
- bool Prepare();
- void ReleaseMediaResources();
- // This updates mOutputBuffer when receiving INFO_OUTPUT_BUFFERS_CHANGED event.
- bool UpdateOutputBuffers();
-
- void ReleaseMediaBuffer(MediaBuffer* abuffer);
-
- // It allocates audio MediaCodec synchronously.
- bool AllocateAudioMediaCodec();
-
- // It allocates video MediaCodec asynchronously.
- RefPtr<CodecPromise> AsyncAllocateVideoMediaCodec();
-
- // Free the OMX codec so others can allocate it.
- void ReleaseMediaCodec();
-
-protected:
- virtual ~MediaCodecProxy();
-
- // MediaResourceReservationListener
- void ResourceReserved() override;
- void ResourceReserveFailed() override;
-
-private:
- // Forbidden
- MediaCodecProxy() = delete;
- MediaCodecProxy(const MediaCodecProxy &) = delete;
- const MediaCodecProxy &operator=(const MediaCodecProxy &) = delete;
-
- // Constructor for MediaCodecProxy::CreateByType
- MediaCodecProxy(sp<ALooper> aLooper,
- const char *aMime,
- bool aEncoder);
-
- // Allocate Codec Resource
- bool allocateCodec();
- // Release Codec Resource
- void releaseCodec();
-
- // MediaCodec Parameter
- sp<ALooper> mCodecLooper;
- nsCString mCodecMime;
- bool mCodecEncoder;
-
- mozilla::MozPromiseHolder<CodecPromise> mCodecPromise;
- // When mPromiseMonitor is held, mResourceClient's functions should not be called.
- mozilla::Monitor mPromiseMonitor;
-
- // Media Resource Management
- RefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
-
- // MediaCodec instance
- mutable RWLock mCodecLock;
- sp<MediaCodec> mCodec;
-
- //MediaCodec buffers to hold input/output data.
- Vector<sp<ABuffer> > mInputBuffers;
- Vector<sp<ABuffer> > mOutputBuffers;
-};
-
-} // namespace android
-
-#endif // MEDIA_CODEC_PROXY_H
deleted file mode 100644
--- a/dom/media/omx/MediaOmxCommonDecoder.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaOmxCommonDecoder.h"
-
-#include <stagefright/MediaSource.h>
-
-#include "AudioOffloadPlayerBase.h"
-#include "MediaDecoderStateMachine.h"
-#include "MediaOmxCommonReader.h"
-
-#ifdef MOZ_AUDIO_OFFLOAD
-#include "AudioOffloadPlayer.h"
-#endif
-
-using namespace android;
-
-namespace mozilla {
-
-extern LazyLogModule gMediaDecoderLog;
-#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
-
-MediaOmxCommonDecoder::MediaOmxCommonDecoder(MediaDecoderOwner* aOwner)
- : MediaDecoder(aOwner)
- , mReader(nullptr)
- , mCanOffloadAudio(false)
- , mFallbackToStateMachine(false)
- , mIsCaptured(false)
-{
- mDormantSupported = true;
-}
-
-MediaOmxCommonDecoder::~MediaOmxCommonDecoder() {}
-
-void
-MediaOmxCommonDecoder::SetPlatformCanOffloadAudio(bool aCanOffloadAudio)
-{
- if (!aCanOffloadAudio) {
- return;
- }
-
- // Stop MDSM from playing to avoid startup glitch (bug 1053186).
- GetStateMachine()->DispatchAudioOffloading(true);
-
- // Modify mCanOffloadAudio in the main thread.
- RefPtr<MediaOmxCommonDecoder> self = this;
- nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
- self->mCanOffloadAudio = true;
- });
- AbstractThread::MainThread()->Dispatch(r.forget());
-}
-
-void
-MediaOmxCommonDecoder::DisableStateMachineAudioOffloading()
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (mCanOffloadAudio) {
- // mCanOffloadAudio is true implies we've called
- // |GetStateMachine()->DispatchAudioOffloading(true)| in
- // SetPlatformCanOffloadAudio(). We need to turn off audio offloading
- // for MDSM so it can start playback.
- GetStateMachine()->DispatchAudioOffloading(false);
- }
-}
-
-bool
-MediaOmxCommonDecoder::CheckDecoderCanOffloadAudio()
-{
- MOZ_ASSERT(NS_IsMainThread());
- return (mCanOffloadAudio && !mFallbackToStateMachine &&
- !mIsCaptured && mPlaybackRate == 1.0);
-}
-
-void
-MediaOmxCommonDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
- MediaDecoderEventVisibility aEventVisibility)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- MediaDecoder::FirstFrameLoaded(aInfo, aEventVisibility);
-
- if (!CheckDecoderCanOffloadAudio()) {
- DECODER_LOG(LogLevel::Debug, ("In %s Offload Audio check failed",
- __PRETTY_FUNCTION__));
- DisableStateMachineAudioOffloading();
- return;
- }
-
-#ifdef MOZ_AUDIO_OFFLOAD
- mAudioOffloadPlayer = new AudioOffloadPlayer(this);
-#endif
- if (!mAudioOffloadPlayer) {
- DisableStateMachineAudioOffloading();
- return;
- }
-
- mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack());
- status_t err = mAudioOffloadPlayer->Start(false);
- if (err != OK) {
- mAudioOffloadPlayer = nullptr;
- mFallbackToStateMachine = true;
- DECODER_LOG(LogLevel::Debug, ("In %s Unable to start offload audio %d."
- "Switching to normal mode", __PRETTY_FUNCTION__, err));
- DisableStateMachineAudioOffloading();
- return;
- }
- PauseStateMachine();
- if (mLogicallySeeking) {
- SeekTarget target = SeekTarget(mLogicalPosition,
- SeekTarget::Accurate,
- MediaDecoderEventVisibility::Observable);
- mSeekRequest.DisconnectIfExists();
- mSeekRequest.Begin(mAudioOffloadPlayer->Seek(target)
- ->Then(AbstractThread::MainThread(), __func__, static_cast<MediaDecoder*>(this),
- &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
- }
- // Call ChangeState() to run AudioOffloadPlayer since offload state enabled
- ChangeState(mPlayState);
-}
-
-void
-MediaOmxCommonDecoder::PauseStateMachine()
-{
- MOZ_ASSERT(NS_IsMainThread());
- DECODER_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__));
-
- MOZ_ASSERT(GetStateMachine());
- // enter dormant state
- GetStateMachine()->DispatchSetDormant(true);
-}
-
-void
-MediaOmxCommonDecoder::ResumeStateMachine()
-{
- MOZ_ASSERT(NS_IsMainThread());
- DECODER_LOG(LogLevel::Debug, ("%s current time %f", __PRETTY_FUNCTION__, mLogicalPosition));
-
- if (IsShutdown()) {
- return;
- }
-
- if (!GetStateMachine()) {
- return;
- }
-
- GetStateMachine()->DispatchAudioOffloading(false);
-
- mFallbackToStateMachine = true;
- mAudioOffloadPlayer = nullptr;
- SeekTarget target = SeekTarget(mLogicalPosition,
- SeekTarget::Accurate,
- MediaDecoderEventVisibility::Suppressed);
- // Call Seek of MediaDecoderStateMachine to suppress seek events.
- GetStateMachine()->InvokeSeek(target);
-
- // exit dormant state
- GetStateMachine()->DispatchSetDormant(false);
- UpdateLogicalPosition();
-}
-
-void
-MediaOmxCommonDecoder::AudioOffloadTearDown()
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!IsShutdown());
- DECODER_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__));
-
- // mAudioOffloadPlayer can be null here if ResumeStateMachine was called
- // just before because of some other error.
- if (mAudioOffloadPlayer) {
- ResumeStateMachine();
- }
-}
-
-void
-MediaOmxCommonDecoder::AddOutputStream(ProcessedMediaStream* aStream,
- bool aFinishWhenEnded)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mIsCaptured = true;
-
- if (mAudioOffloadPlayer) {
- ResumeStateMachine();
- }
-
- MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded);
-}
-
-void
-MediaOmxCommonDecoder::SetPlaybackRate(double aPlaybackRate)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mAudioOffloadPlayer &&
- ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) {
- ResumeStateMachine();
- }
-
- MediaDecoder::SetPlaybackRate(aPlaybackRate);
-}
-
-void
-MediaOmxCommonDecoder::ChangeState(PlayState aState)
-{
- MOZ_ASSERT(NS_IsMainThread());
- // Keep MediaDecoder state in sync with MediaElement irrespective of offload
- // playback so it will continue to work in normal mode when offloading fails
- // in between
- MediaDecoder::ChangeState(aState);
-
- if (!mAudioOffloadPlayer) {
- return;
- }
-
- status_t err = mAudioOffloadPlayer->ChangeState(aState);
- if (err != OK) {
- ResumeStateMachine();
- return;
- }
-}
-
-void
-MediaOmxCommonDecoder::CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise)
-{
- if (!mAudioOffloadPlayer) {
- MediaDecoder::CallSeek(aTarget, aPromise);
- return;
- }
-
- DiscardOngoingSeekIfExists();
- mSeekDOMPromise = aPromise;
- mSeekRequest.Begin(mAudioOffloadPlayer->Seek(aTarget)
- ->Then(AbstractThread::MainThread(), __func__, static_cast<MediaDecoder*>(this),
- &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
-}
-
-int64_t
-MediaOmxCommonDecoder::CurrentPosition()
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (!mAudioOffloadPlayer) {
- return MediaDecoder::CurrentPosition();
- }
- return mAudioOffloadPlayer->GetMediaTimeUs();
-}
-
-void
-MediaOmxCommonDecoder::SetElementVisibility(bool aIsVisible)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MediaDecoder::SetElementVisibility(aIsVisible);
- if (mAudioOffloadPlayer) {
- mAudioOffloadPlayer->SetElementVisibility(aIsVisible);
- }
-}
-
-MediaDecoderOwner::NextFrameStatus
-MediaOmxCommonDecoder::NextFrameStatus()
-{
- MOZ_ASSERT(NS_IsMainThread());
- return mAudioOffloadPlayer ? mAudioOffloadPlayer->GetNextFrameStatus()
- : MediaDecoder::NextFrameStatus();
-}
-
-void
-MediaOmxCommonDecoder::SetVolume(double aVolume)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (!mAudioOffloadPlayer) {
- MediaDecoder::SetVolume(aVolume);
- return;
- }
- mAudioOffloadPlayer->SetVolume(aVolume);
-}
-
-MediaDecoderStateMachine*
-MediaOmxCommonDecoder::CreateStateMachine()
-{
- mReader = CreateReader();
- if (mReader != nullptr) {
- mReader->SetAudioChannel(GetAudioChannel());
- }
- return CreateStateMachineFromReader(mReader);
-}
-
-void
-MediaOmxCommonDecoder::Shutdown()
-{
- mAudioOffloadPlayer = nullptr;
- MediaDecoder::Shutdown();
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/omx/MediaOmxCommonDecoder.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef MEDIA_OMX_COMMON_DECODER_H
-#define MEDIA_OMX_COMMON_DECODER_H
-
-#include "MediaDecoder.h"
-#include "nsAutoPtr.h"
-
-namespace android {
-struct MOZ_EXPORT MediaSource;
-} // namespace android
-
-namespace mozilla {
-
-class AudioOffloadPlayerBase;
-class MediaOmxCommonReader;
-
-class MediaOmxCommonDecoder : public MediaDecoder
-{
-public:
- explicit MediaOmxCommonDecoder(MediaDecoderOwner* aOwner);
-
- void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
- MediaDecoderEventVisibility aEventVisibility) override;
- void ChangeState(PlayState aState) override;
- void CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise) override;
- void SetVolume(double aVolume) override;
- int64_t CurrentPosition() override;
- MediaDecoderOwner::NextFrameStatus NextFrameStatus() override;
- void SetElementVisibility(bool aIsVisible) override;
- void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) override;
- void AddOutputStream(ProcessedMediaStream* aStream,
- bool aFinishWhenEnded) override;
- void SetPlaybackRate(double aPlaybackRate) override;
-
- void AudioOffloadTearDown();
-
- MediaDecoderStateMachine* CreateStateMachine() override;
-
- virtual MediaOmxCommonReader* CreateReader() = 0;
- virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader) = 0;
-
- void NotifyOffloadPlayerPositionChanged() { UpdateLogicalPosition(); }
-
- void Shutdown() override;
-
-protected:
- virtual ~MediaOmxCommonDecoder();
- void PauseStateMachine();
- void ResumeStateMachine();
- bool CheckDecoderCanOffloadAudio();
- void DisableStateMachineAudioOffloading();
-
- MediaOmxCommonReader* mReader;
-
- // Offloaded audio track
- android::sp<android::MediaSource> mAudioTrack;
-
- nsAutoPtr<AudioOffloadPlayerBase> mAudioOffloadPlayer;
-
- // Set by Media*Reader to denote current track can be offloaded
- bool mCanOffloadAudio;
-
- // Set when offload playback of current track fails in the middle and need to
- // fallback to state machine
- bool mFallbackToStateMachine;
-
- // True if the media element is captured.
- bool mIsCaptured;
-};
-
-} // namespace mozilla
-
-#endif // MEDIA_OMX_COMMON_DECODER_H
deleted file mode 100644
--- a/dom/media/omx/MediaOmxCommonReader.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaOmxCommonReader.h"
-
-#include <stagefright/MediaSource.h>
-
-#include "AbstractMediaDecoder.h"
-#include "AudioChannelService.h"
-#include "MediaStreamSource.h"
-#include "MediaPrefs.h"
-
-#ifdef MOZ_AUDIO_OFFLOAD
-#include <stagefright/Utils.h>
-#include <cutils/properties.h>
-#include <stagefright/MetaData.h>
-#endif
-
-using namespace android;
-
-namespace mozilla {
-
-extern LazyLogModule gMediaDecoderLog;
-#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
-
-MediaOmxCommonReader::MediaOmxCommonReader(AbstractMediaDecoder *aDecoder)
- : MediaDecoderReader(aDecoder)
- , mStreamSource(nullptr)
-{
- mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel();
-}
-
-bool MediaOmxCommonReader::IsMonoAudioEnabled()
-{
- return MediaPrefs::MonoAudio();
-}
-
-#ifdef MOZ_AUDIO_OFFLOAD
-void MediaOmxCommonReader::CheckAudioOffload()
-{
- MOZ_ASSERT(OnTaskQueue());
-
- char offloadProp[128];
- property_get("audio.offload.disable", offloadProp, "0");
- bool offloadDisable = atoi(offloadProp) != 0;
- if (offloadDisable) {
- return;
- }
-
- sp<MediaSource> audioOffloadTrack = GetAudioOffloadTrack();
- sp<MetaData> meta = audioOffloadTrack.get()
- ? audioOffloadTrack->getFormat() : nullptr;
-
- // Supporting audio offload only when there is no video, no streaming
- bool hasNoVideo = !HasVideo();
- bool isNotStreaming
- = mDecoder->GetResource()->IsDataCachedToEndOfResource(0);
-
- // Not much benefit in trying to offload other channel types. Most of them
- // aren't supported and also duration would be less than a minute
- bool isTypeMusic = mAudioChannel == dom::AudioChannel::Content;
-
- DECODER_LOG(LogLevel::Debug, ("%s meta %p, no video %d, no streaming %d,"
- " channel type %d", __FUNCTION__, meta.get(), hasNoVideo,
- isNotStreaming, mAudioChannel));
-
- if ((meta.get()) && hasNoVideo && isNotStreaming && isTypeMusic &&
- canOffloadStream(meta, false, false, AUDIO_STREAM_MUSIC) &&
- !IsMonoAudioEnabled()) {
- DECODER_LOG(LogLevel::Debug, ("Can offload this audio stream"));
- mDecoder->SetPlatformCanOffloadAudio(true);
- }
-}
-#endif
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/omx/MediaOmxCommonReader.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef MEDIA_OMX_COMMON_READER_H
-#define MEDIA_OMX_COMMON_READER_H
-
-#include "MediaDecoderReader.h"
-
-#include <utils/RefBase.h>
-
-#include "mozilla/dom/AudioChannelBinding.h"
-
-namespace android {
-struct MOZ_EXPORT MediaSource;
-class MediaStreamSource;
-} // namespace android
-
-namespace mozilla {
-
-class AbstractMediaDecoder;
-
-class MediaOmxCommonReader : public MediaDecoderReader
-{
-public:
- typedef MozPromise<bool /* aIgnored */, bool /* aIgnored */, /* IsExclusive = */ true> MediaResourcePromise;
-
- MediaOmxCommonReader(AbstractMediaDecoder* aDecoder);
-
- void SetAudioChannel(dom::AudioChannel aAudioChannel) {
- mAudioChannel = aAudioChannel;
- }
-
- virtual android::sp<android::MediaSource> GetAudioOffloadTrack() = 0;
-
-#ifdef MOZ_AUDIO_OFFLOAD
- // Check whether it is possible to offload current audio track. This access
- // canOffloadStream() from libStageFright Utils.cpp, which is not there in
- // ANDROID_VERSION < 19
- void CheckAudioOffload();
-#endif
-
-protected:
- dom::AudioChannel mAudioChannel;
- // Weak reference to the MediaStreamSource that will be created by either
- // MediaOmxReader or MediaCodecReader.
- android::MediaStreamSource* mStreamSource;
- // Get value from the preferece, if true, we stop the audio offload.
- bool IsMonoAudioEnabled();
-
-private:
- virtual bool HasAudio() = 0;
- virtual bool HasVideo() = 0;
-};
-
-} // namespace mozilla
-
-#endif // MEDIA_OMX_COMMON_READER_H
deleted file mode 100644
--- a/dom/media/omx/MediaOmxDecoder.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaOmxDecoder.h"
-#include "MediaOmxReader.h"
-#include "MediaDecoderStateMachine.h"
-
-using namespace android;
-
-namespace mozilla {
-
-MediaDecoder*
-MediaOmxDecoder::Clone(MediaDecoderOwner* aOwner)
-{
- return new MediaOmxDecoder(aOwner);
-}
-
-MediaOmxCommonReader*
-MediaOmxDecoder::CreateReader()
-{
- return new MediaOmxReader(this);
-}
-
-MediaDecoderStateMachine*
-MediaOmxDecoder::CreateStateMachineFromReader(MediaOmxCommonReader* aReader)
-{
- return new MediaDecoderStateMachine(this, aReader);
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/omx/MediaOmxDecoder.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-#if !defined(MediaOmxDecoder_h_)
-#define MediaOmxDecoder_h_
-
-#include "MediaOmxCommonDecoder.h"
-
-namespace mozilla {
-
-class MediaOmxDecoder : public MediaOmxCommonDecoder
-{
-public:
- explicit MediaOmxDecoder(MediaDecoderOwner* aOwner)
- : MediaOmxCommonDecoder(aOwner) {}
- virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner);
- virtual MediaOmxCommonReader* CreateReader();
- virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader);
-};
-
-} // namespace mozilla
-
-#endif
deleted file mode 100644
--- a/dom/media/omx/MediaOmxReader.cpp
+++ /dev/null
@@ -1,622 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaOmxReader.h"
-
-#include "MediaDecoderStateMachine.h"
-#include "mozilla/TimeStamp.h"
-#include "MediaResource.h"
-#include "VideoUtils.h"
-#include "MediaOmxDecoder.h"
-#include "AbstractMediaDecoder.h"
-#include "AudioChannelService.h"
-#include "OmxDecoder.h"
-#include "MPAPI.h"
-#include "gfx2DGlue.h"
-#include "MediaStreamSource.h"
-#include "VideoFrameContainer.h"
-
-#define MAX_DROPPED_FRAMES 25
-// Try not to spend more than this much time in a single call to DecodeVideoFrame.
-#define MAX_VIDEO_DECODE_SECONDS 0.1
-
-using namespace mozilla::gfx;
-using namespace mozilla::media;
-using namespace android;
-
-namespace mozilla {
-
-extern LazyLogModule gMediaDecoderLog;
-#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
-
-class MediaOmxReader::ProcessCachedDataTask : public Runnable
-{
-public:
- ProcessCachedDataTask(MediaOmxReader* aOmxReader, int64_t aOffset)
- : mOmxReader(aOmxReader),
- mOffset(aOffset)
- { }
-
- NS_IMETHOD Run() override
- {
- MOZ_ASSERT(!NS_IsMainThread());
- MOZ_ASSERT(mOmxReader.get());
- mOmxReader->ProcessCachedData(mOffset);
- return NS_OK;
- }
-
-private:
- RefPtr<MediaOmxReader> mOmxReader;
- int64_t mOffset;
-};
-
-// When loading an MP3 stream from a file, we need to parse the file's
-// content to find its duration. Reading files of 100 MiB or more can
-// delay the player app noticably, so the file is read and decoded in
-// smaller chunks.
-//
-// We first read on the decode thread, but parsing must be done on the
-// main thread. After we read the file's initial MiBs in the decode
-// thread, an instance of this class is scheduled to the main thread for
-// parsing the MP3 stream. The decode thread waits until it has finished.
-//
-// If there is more data available from the file, the runnable dispatches
-// a task to the IO thread for retrieving the next chunk of data, and
-// the IO task dispatches a runnable to the main thread for parsing the
-// data. This goes on until all of the MP3 file has been parsed.
-
-class MediaOmxReader::NotifyDataArrivedRunnable : public Runnable
-{
-public:
- NotifyDataArrivedRunnable(MediaOmxReader* aOmxReader,
- uint64_t aLength,
- int64_t aOffset, uint64_t aFullLength)
- : mOmxReader(aOmxReader),
- mLength(aLength),
- mOffset(aOffset),
- mFullLength(aFullLength)
- {
- MOZ_ASSERT(mOmxReader.get());
- }
-
- NS_IMETHOD Run() override
- {
- MOZ_ASSERT(mOmxReader->OnTaskQueue());
- NotifyDataArrived();
- return NS_OK;
- }
-
-private:
- void NotifyDataArrived()
- {
- if (mOmxReader->IsShutdown()) {
- return;
- }
-
- while (mLength) {
- uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
- mOmxReader->NotifyDataArrived();
- mLength -= length;
- mOffset += length;
- }
-
- if (static_cast<uint64_t>(mOffset) < mFullLength) {
- // We cannot read data in the main thread because it
- // might block for too long. Instead we post an IO task
- // to the IO thread if there is more data available.
- RefPtr<Runnable> task = new ProcessCachedDataTask(mOmxReader.get(), mOffset);
- XRE_GetIOMessageLoop()->PostTask(task.forget());
- }
- }
-
- RefPtr<MediaOmxReader> mOmxReader;
- uint64_t mLength;
- int64_t mOffset;
- uint64_t mFullLength;
-};
-
-MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
- : MediaOmxCommonReader(aDecoder)
- , mShutdownMutex("MediaOmxReader.Shutdown")
- , mHasVideo(false)
- , mHasAudio(false)
- , mVideoSeekTimeUs(-1)
- , mAudioSeekTimeUs(-1)
- , mLastParserDuration(-1)
- , mSkipCount(0)
- , mIsShutdown(false)
- , mMP3FrameParser(-1)
-{
- mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel();
-}
-
-MediaOmxReader::~MediaOmxReader()
-{
-}
-
-already_AddRefed<AbstractMediaDecoder>
-MediaOmxReader::SafeGetDecoder() {
- RefPtr<AbstractMediaDecoder> decoder;
- MutexAutoLock lock(mShutdownMutex);
- if (!mIsShutdown) {
- decoder = mDecoder;
- }
- return decoder.forget();
-}
-
-void MediaOmxReader::ReleaseDecoder()
-{
- if (mOmxDecoder.get()) {
- mOmxDecoder->ReleaseDecoder();
- }
- mOmxDecoder.clear();
-}
-
-RefPtr<ShutdownPromise>
-MediaOmxReader::Shutdown()
-{
- {
- MutexAutoLock lock(mShutdownMutex);
- mIsShutdown = true;
- }
-
- RefPtr<ShutdownPromise> p = MediaDecoderReader::Shutdown();
-
- // Wait for the superclass to finish tearing things down before releasing
- // the decoder on the main thread.
- p->Then(AbstractThread::MainThread(), __func__, this, &MediaOmxReader::ReleaseDecoder, &MediaOmxReader::ReleaseDecoder);
-
- return p;
-}
-
-void MediaOmxReader::ReleaseResources()
-{
- mMediaResourceRequest.DisconnectIfExists();
- mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
-
- ResetDecode();
- // Before freeing a video codec, all video buffers needed to be released
- // even from graphics pipeline.
- VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
- if (container) {
- container->ClearCurrentFrame();
- }
- if (mOmxDecoder.get()) {
- mOmxDecoder->ReleaseMediaResources();
- }
-}
-
-nsresult MediaOmxReader::InitOmxDecoder()
-{
- if (!mOmxDecoder.get()) {
- //register sniffers, if they are not registered in this process.
- DataSource::RegisterDefaultSniffers();
-
- sp<DataSource> dataSource = new MediaStreamSource(mDecoder->GetResource());
- dataSource->initCheck();
-
- mExtractor = MediaExtractor::Create(dataSource);
- if (!mExtractor.get()) {
- return NS_ERROR_FAILURE;
- }
- mOmxDecoder = new OmxDecoder(mDecoder, OwnerThread());
- if (!mOmxDecoder->Init(mExtractor)) {
- return NS_ERROR_FAILURE;
- }
- mStreamSource = static_cast<MediaStreamSource*>(dataSource.get());
- }
- return NS_OK;
-}
-
-RefPtr<MediaDecoderReader::MetadataPromise>
-MediaOmxReader::AsyncReadMetadata()
-{
- MOZ_ASSERT(OnTaskQueue());
- EnsureActive();
-
- // Initialize the internal OMX Decoder.
- nsresult rv = InitOmxDecoder();
- if (NS_FAILED(rv)) {
- return MediaDecoderReader::MetadataPromise::CreateAndReject(
- NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
- }
-
- bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
- if (isMP3) {
- // When read sdcard's file on b2g platform at constructor,
- // the mDecoder->GetResource()->GetLength() would return -1.
- // Delay set the total duration on this function.
- mMP3FrameParser.SetLength(mDecoder->GetResource()->GetLength());
- ProcessCachedData(0);
- }
-
- RefPtr<MediaDecoderReader::MetadataPromise> p = mMetadataPromise.Ensure(__func__);
-
- RefPtr<MediaOmxReader> self = this;
- mMediaResourceRequest.Begin(mOmxDecoder->AllocateMediaResources()
- ->Then(OwnerThread(), __func__,
- [self] (bool) -> void {
- self->mMediaResourceRequest.Complete();
- self->HandleResourceAllocated();
- }, [self] (bool) -> void {
- self->mMediaResourceRequest.Complete();
- self->mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
- }));
-
- return p;
-}
-
-void MediaOmxReader::HandleResourceAllocated()
-{
- EnsureActive();
-
- // After resources are available, set the metadata.
- if (!mOmxDecoder->EnsureMetadata()) {
- mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
- return;
- }
-
- bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
- if (isMP3 && mMP3FrameParser.IsMP3()) {
- // Check if the MP3 frame parser found a duration.
- mLastParserDuration = mMP3FrameParser.GetDuration();
- }
-
- if (mLastParserDuration >= 0) {
- // Prefer the parser duration if we have it.
- mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(mLastParserDuration));
- } else {
- // MP3 parser failed to find a duration.
- // Set the total duration (the max of the audio and video track).
- int64_t durationUs;
- mOmxDecoder->GetDuration(&durationUs);
- if (durationUs) {
- mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(durationUs));
- }
- }
-
- if (mOmxDecoder->HasVideo()) {
- int32_t displayWidth, displayHeight, width, height;
- mOmxDecoder->GetVideoParameters(&displayWidth, &displayHeight,
- &width, &height);
- nsIntRect pictureRect(0, 0, width, height);
-
- // Validate the container-reported frame and pictureRect sizes. This ensures
- // that our video frame creation code doesn't overflow.
- nsIntSize displaySize(displayWidth, displayHeight);
- nsIntSize frameSize(width, height);
- if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
- mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
- return;
- }
-
- // Video track's frame sizes will not overflow. Activate the video track.
- mHasVideo = true;
- mInfo.mVideo.mDisplay = displaySize;
- mPicture = pictureRect;
- mInitialFrame = frameSize;
- VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
- if (container) {
- container->ClearCurrentFrame(IntSize(displaySize.width, displaySize.height));
- }
- }
-
- if (mOmxDecoder->HasAudio()) {
- int32_t numChannels, sampleRate;
- mOmxDecoder->GetAudioParameters(&numChannels, &sampleRate);
- mHasAudio = true;
- mInfo.mAudio.mChannels = numChannels;
- mInfo.mAudio.mRate = sampleRate;
- }
-
- mInfo.mMediaSeekable = mExtractor->flags() & MediaExtractor::CAN_SEEK;
-
- RefPtr<MetadataHolder> metadata = new MetadataHolder();
- metadata->mInfo = mInfo;
- metadata->mTags = nullptr;
-
-#ifdef MOZ_AUDIO_OFFLOAD
- CheckAudioOffload();
-#endif
-
- mMetadataPromise.Resolve(metadata, __func__);
-}
-
-bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
- int64_t aTimeThreshold)
-{
- MOZ_ASSERT(OnTaskQueue());
- EnsureActive();
-
- // Record number of frames decoded and parsed. Automatically update the
- // stats counters using the AutoNotifyDecoded stack-based class.
- AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
-
- bool doSeek = mVideoSeekTimeUs != -1;
- if (doSeek) {
- aTimeThreshold = mVideoSeekTimeUs;
- }
-
- TimeStamp start = TimeStamp::Now();
-
- // Read next frame. Don't let this loop run for too long.
- while ((TimeStamp::Now() - start) < TimeDuration::FromSeconds(MAX_VIDEO_DECODE_SECONDS)) {
- MPAPI::VideoFrame frame;
- frame.mGraphicBuffer = nullptr;
- frame.mShouldSkip = false;
- if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) {
- return false;
- }
- doSeek = false;
- mVideoSeekTimeUs = -1;
-
- // Ignore empty buffer which stagefright media read will sporadically return
- if (frame.mSize == 0 && !frame.mGraphicBuffer) {
- continue;
- }
-
- a.mStats.mParsedFrames++;
- if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) {
- mSkipCount++;
- continue;
- }
-
- mSkipCount = 0;
-
- aKeyframeSkip = false;
-
- IntRect picture = mPicture;
- if (frame.Y.mWidth != mInitialFrame.width ||
- frame.Y.mHeight != mInitialFrame.height) {
-
- // Frame size is different from what the container reports. This is legal,
- // and we will preserve the ratio of the crop rectangle as it
- // was reported relative to the picture size reported by the container.
- picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width;
- picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height;
- picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width;
- picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height;
- }
-
- // This is the approximate byte position in the stream.
- int64_t pos = mStreamSource ? mStreamSource->Tell() : 0;
-
- RefPtr<VideoData> v;
- if (!frame.mGraphicBuffer) {
-
- VideoData::YCbCrBuffer b;
- b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData);
- b.mPlanes[0].mStride = frame.Y.mStride;
- b.mPlanes[0].mHeight = frame.Y.mHeight;
- b.mPlanes[0].mWidth = frame.Y.mWidth;
- b.mPlanes[0].mOffset = frame.Y.mOffset;
- b.mPlanes[0].mSkip = frame.Y.mSkip;
-
- b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData);
- b.mPlanes[1].mStride = frame.Cb.mStride;
- b.mPlanes[1].mHeight = frame.Cb.mHeight;
- b.mPlanes[1].mWidth = frame.Cb.mWidth;
- b.mPlanes[1].mOffset = frame.Cb.mOffset;
- b.mPlanes[1].mSkip = frame.Cb.mSkip;
-
- b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData);
- b.mPlanes[2].mStride = frame.Cr.mStride;
- b.mPlanes[2].mHeight = frame.Cr.mHeight;
- b.mPlanes[2].mWidth = frame.Cr.mWidth;
- b.mPlanes[2].mOffset = frame.Cr.mOffset;
- b.mPlanes[2].mSkip = frame.Cr.mSkip;
-
- v = VideoData::CreateAndCopyData(mInfo.mVideo,
- mDecoder->GetImageContainer(),
- pos,
- frame.mTimeUs,
- 1, // We don't know the duration.
- b,
- frame.mKeyFrame,
- -1,
- picture);
- } else {
- v = VideoData::CreateAndCopyIntoTextureClient(
- mInfo.mVideo,
- pos,
- frame.mTimeUs,
- 1, // We don't know the duration.
- frame.mGraphicBuffer,
- frame.mKeyFrame,
- -1,
- picture);
- }
-
- if (!v) {
- NS_WARNING("Unable to create VideoData");
- return false;
- }
-
- a.mStats.mDecodedFrames++;
- NS_ASSERTION(a.mStats.mDecodedFrames <= a.mStats.mParsedFrames, "Expect to decode fewer frames than parsed in OMX decoder...");
-
- mVideoQueue.Push(v);
-
- break;
- }
-
- return true;
-}
-
-void MediaOmxReader::NotifyDataArrivedInternal()
-{
- MOZ_ASSERT(OnTaskQueue());
- RefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
- if (!decoder) { // reader has shut down
- return;
- }
- if (HasVideo()) {
- return;
- }
- if (!mMP3FrameParser.NeedsData()) {
- return;
- }
-
- AutoPinned<MediaResource> resource(mDecoder->GetResource());
- MediaByteRangeSet byteRanges;
- nsresult rv = resource->GetCachedRanges(byteRanges);
-
- if (NS_FAILED(rv)) {
- return;
- }
-
- if (byteRanges == mLastCachedRanges) {
- return;
- }
- MediaByteRangeSet intervals = byteRanges - mLastCachedRanges;
- mLastCachedRanges = byteRanges;
-
- for (const auto& interval : intervals) {
- RefPtr<MediaByteBuffer> bytes =
- resource->MediaReadAt(interval.mStart, interval.Length());
- NS_ENSURE_TRUE_VOID(bytes);
- mMP3FrameParser.Parse(bytes->Elements(), interval.Length(), interval.mStart);
- if (!mMP3FrameParser.IsMP3()) {
- return;
- }
- }
- int64_t duration = mMP3FrameParser.GetDuration();
- if (duration != mLastParserDuration) {
- mLastParserDuration = duration;
- decoder->DispatchUpdateEstimatedMediaDuration(mLastParserDuration);
- }
-}
-
-bool MediaOmxReader::DecodeAudioData()
-{
- MOZ_ASSERT(OnTaskQueue());
- EnsureActive();
-
- // This is the approximate byte position in the stream.
- int64_t pos = mStreamSource ? mStreamSource->Tell() : 0;
-
- // Read next frame
- MPAPI::AudioFrame source;
- if (!mOmxDecoder->ReadAudio(&source, mAudioSeekTimeUs)) {
- return false;
- }
- mAudioSeekTimeUs = -1;
-
- // Ignore empty buffer which stagefright media read will sporadically return
- if (source.mSize == 0) {
- return true;
- }
-
- uint32_t frames = source.mSize / (source.mAudioChannels *
- sizeof(AudioDataValue));
-
- typedef AudioCompactor::NativeCopy OmxCopy;
- return mAudioCompactor.Push(pos,
- source.mTimeUs,
- source.mAudioSampleRate,
- frames,
- source.mAudioChannels,
- OmxCopy(static_cast<uint8_t *>(source.mData),
- source.mSize,
- source.mAudioChannels));
-}
-
-RefPtr<MediaDecoderReader::SeekPromise>
-MediaOmxReader::Seek(SeekTarget aTarget, int64_t aEndTime)
-{
- MOZ_ASSERT(OnTaskQueue());
- EnsureActive();
- RefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
-
- if (mHasAudio && mHasVideo) {
- // The OMXDecoder seeks/demuxes audio and video streams separately. So if
- // we seek both audio and video to aTarget, the audio stream can typically
- // seek closer to the seek target, since typically every audio block is
- // a sync point, whereas for video there are only keyframes once every few
- // seconds. So if we have both audio and video, we must seek the video
- // stream to the preceeding keyframe first, get the stream time, and then
- // seek the audio stream to match the video stream's time. Otherwise, the
- // audio and video streams won't be in sync after the seek.
- mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds();
-
- RefPtr<MediaOmxReader> self = this;
- mSeekRequest.Begin(DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) {
- self->mSeekRequest.Complete();
- self->mAudioSeekTimeUs = v->mTime;
- self->mSeekPromise.Resolve(media::TimeUnit::FromMicroseconds(self->mAudioSeekTimeUs), __func__);
- }, [self, aTarget] () {
- self->mSeekRequest.Complete();
- self->mAudioSeekTimeUs = aTarget.GetTime().ToMicroseconds();
- self->mSeekPromise.Resolve(aTarget.GetTime(), __func__);
- }));
- } else {
- mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds();
- mSeekPromise.Resolve(aTarget.GetTime(), __func__);
- }
-
- return p;
-}
-
-void MediaOmxReader::SetIdle() {
- if (!mOmxDecoder.get()) {
- return;
- }
- mOmxDecoder->Pause();
-}
-
-void MediaOmxReader::EnsureActive() {
- if (!mOmxDecoder.get()) {
- return;
- }
- DebugOnly<nsresult> result = mOmxDecoder->Play();
- NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding");
-}
-
-int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset)
-{
- // Could run on decoder thread or IO thread.
- RefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
- if (!decoder) { // reader has shut down
- return -1;
- }
- // We read data in chunks of 32 KiB. We can reduce this
- // value if media, such as sdcards, is too slow.
- // Because of SD card's slowness, need to keep sReadSize to small size.
- // See Bug 914870.
- static const int64_t sReadSize = 32 * 1024;
-
- NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
-
- MOZ_ASSERT(decoder->GetResource());
- int64_t resourceLength = decoder->GetResource()->GetCachedDataEnd(0);
- NS_ENSURE_TRUE(resourceLength >= 0, -1);
-
- if (aOffset >= resourceLength) {
- return 0; // Cache is empty, nothing to do
- }
-
- int64_t bufferLength = std::min<int64_t>(resourceLength-aOffset, sReadSize);
- RefPtr<NotifyDataArrivedRunnable> runnable(
- new NotifyDataArrivedRunnable(this, bufferLength, aOffset, resourceLength));
-
- if (OnTaskQueue()) {
- runnable->Run();
- } else {
- OwnerThread()->Dispatch(runnable.forget());
- }
-
- return resourceLength - aOffset - bufferLength;
-}
-
-android::sp<android::MediaSource> MediaOmxReader::GetAudioOffloadTrack()
-{
- if (!mOmxDecoder.get()) {
- return nullptr;
- }
- return mOmxDecoder->GetAudioOffloadTrack();
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/omx/MediaOmxReader.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-#if !defined(MediaOmxReader_h_)
-#define MediaOmxReader_h_
-
-#include "MediaOmxCommonReader.h"
-#include "MediaResource.h"
-#include "MediaDecoderReader.h"
-#include "nsMimeTypes.h"
-#include "MP3FrameParser.h"
-#include "nsRect.h"
-
-#include <ui/GraphicBuffer.h>
-#include <stagefright/MediaSource.h>
-
-namespace android {
-class OmxDecoder;
-class MOZ_EXPORT MediaExtractor;
-}
-
-namespace mozilla {
-
-class AbstractMediaDecoder;
-
-class MediaOmxReader : public MediaOmxCommonReader
-{
- typedef MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise;
-
- // This mutex is held when accessing the mIsShutdown variable, which is
- // modified on the decode task queue and read on main and IO threads.
- Mutex mShutdownMutex;
- nsCString mType;
- bool mHasVideo;
- bool mHasAudio;
- nsIntRect mPicture;
- nsIntSize mInitialFrame;
- int64_t mVideoSeekTimeUs;
- int64_t mAudioSeekTimeUs;
- int64_t mLastParserDuration;
- int32_t mSkipCount;
- // If mIsShutdown is false, and mShutdownMutex is held, then
- // AbstractMediaDecoder::mDecoder will be non-null.
- bool mIsShutdown;
- MozPromiseHolder<MediaDecoderReader::MetadataPromise> mMetadataPromise;
- MozPromiseRequestHolder<MediaResourcePromise> mMediaResourceRequest;
-
- MozPromiseHolder<MediaDecoderReader::SeekPromise> mSeekPromise;
- MozPromiseRequestHolder<MediaDecoderReader::MediaDataPromise> mSeekRequest;
-protected:
- android::sp<android::OmxDecoder> mOmxDecoder;
- android::sp<android::MediaExtractor> mExtractor;
- MP3FrameParser mMP3FrameParser;
-
- // Called by ReadMetadata() during MediaDecoderStateMachine::DecodeMetadata()
- // on decode thread. It create and initialize the OMX decoder including
- // setting up custom extractor. The extractor provide the essential
- // information used for creating OMX decoder such as video/audio codec.
- virtual nsresult InitOmxDecoder();
-
- // Called inside DecodeVideoFrame, DecodeAudioData, ReadMetadata and Seek
- // to activate the decoder automatically.
- virtual void EnsureActive();
-
- virtual void HandleResourceAllocated();
-
-public:
- MediaOmxReader(AbstractMediaDecoder* aDecoder);
- ~MediaOmxReader();
-
-protected:
- void NotifyDataArrivedInternal() override;
-public:
-
- nsresult ResetDecode(
- TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
- TrackInfo::kVideoTrack)) override
- {
- mSeekRequest.DisconnectIfExists();
- mSeekPromise.RejectIfExists(NS_OK, __func__);
- return MediaDecoderReader::ResetDecode(aTracks);
- }
-
- bool DecodeAudioData() override;
- bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override;
-
- void ReleaseResources() override;
-
- RefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata() override;
-
- RefPtr<SeekPromise>
- Seek(SeekTarget aTarget, int64_t aEndTime) override;
-
- void SetIdle() override;
-
- RefPtr<ShutdownPromise> Shutdown() override;
-
- android::sp<android::MediaSource> GetAudioOffloadTrack();
-
- // This method is intended only for private use but public only for
- // MozPromise::InvokeCallbackMethod().
- void ReleaseDecoder();
-
-private:
- class ProcessCachedDataTask;
- class NotifyDataArrivedRunnable;
-
- bool HasAudio() override { return mHasAudio; }
- bool HasVideo() override { return mHasVideo; }
-
- bool IsShutdown() {
- MutexAutoLock lock(mShutdownMutex);
- return mIsShutdown;
- }
-
- int64_t ProcessCachedData(int64_t aOffset);
-
- already_AddRefed<AbstractMediaDecoder> SafeGetDecoder();
-
- MediaByteRangeSet mLastCachedRanges;
-};
-
-} // namespace mozilla
-
-#endif
deleted file mode 100644
--- a/dom/media/omx/MediaStreamSource.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaStreamSource.h"
-
-#include <utils/threads.h>
-
-#include "nsISeekableStream.h"
-
-namespace android {
-
-MediaStreamSource::MediaStreamSource(MediaResource *aResource)
- : mResource(aResource)
-{
-}
-
-MediaStreamSource::~MediaStreamSource()
-{
-}
-
-status_t MediaStreamSource::initCheck() const
-{
- return OK;
-}
-
-ssize_t MediaStreamSource::readAt(off64_t offset, void *data, size_t size)
-{
- char *ptr = static_cast<char *>(data);
- size_t todo = size;
- while (todo > 0) {
- Mutex::Autolock autoLock(mLock);
- uint32_t bytesRead;
- if ((offset != mResource.Tell() &&
- NS_FAILED(mResource.Seek(nsISeekableStream::NS_SEEK_SET, offset))) ||
- NS_FAILED(mResource.Read(ptr, todo, &bytesRead))) {
- return ERROR_IO;
- }
-
- if (bytesRead == 0) {
- return size - todo;
- }
-
- offset += bytesRead;
- todo -= bytesRead;
- ptr += bytesRead;
- }
- return size;
-}
-
-status_t MediaStreamSource::getSize(off64_t *size)
-{
- uint64_t length = mResource.GetLength();
- if (length == static_cast<uint64_t>(-1))
- return ERROR_UNSUPPORTED;
-
- *size = length;
-
- return OK;
-}
-
-int64_t
-MediaStreamSource::Tell()
-{
- Mutex::Autolock autoLock(mLock);
- return mResource.Tell();
-}
-
-} // namespace android
deleted file mode 100644
--- a/dom/media/omx/MediaStreamSource.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef MEDIA_STREAM_SOURCE_H
-#define MEDIA_STREAM_SOURCE_H
-
-#include <stdint.h>
-
-#include <stagefright/DataSource.h>
-#include <stagefright/MediaSource.h>
-
-#include "MediaResource.h"
-
-namespace android {
-
-// MediaStreamSource is a DataSource that reads from a MPAPI media stream.
-class MediaStreamSource : public DataSource {
- typedef mozilla::MediaResource MediaResource;
- typedef mozilla::MediaResourceIndex MediaResourceIndex;
-
- Mutex mLock;
- MediaResourceIndex mResource;
-public:
- MediaStreamSource(MediaResource* aResource);
-
- status_t initCheck() const override;
- ssize_t readAt(off64_t offset, void *data, size_t size) override;
- status_t getSize(off64_t *size) override;
- uint32_t flags() override {
- return kWantsPrefetching;
- }
-
- int64_t Tell();
-
- virtual ~MediaStreamSource();
-
-private:
- MediaStreamSource(const MediaStreamSource &);
- MediaStreamSource &operator=(const MediaStreamSource &);
-};
-
-} // namespace android
-
-#endif // MEDIA_STREAM_SOURCE_H
deleted file mode 100644
--- a/dom/media/omx/OMXCodecDescriptorUtil.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "OMXCodecDescriptorUtil.h"
-
-namespace android {
-
-// The utility functions in this file concatenate two AVC/H.264 parameter sets,
-// sequence parameter set(SPS) and picture parameter set(PPS), into byte stream
-// format or construct AVC decoder config descriptor blob from them.
-//
-// * NAL unit defined in ISO/IEC 14496-10 7.3.1
-// * SPS defined ISO/IEC 14496-10 7.3.2.1.1
-// * PPS defined in ISO/IEC 14496-10 7.3.2.2
-//
-// Byte stream format:
-// Start code <0x00 0x00 0x00 0x01> (4 bytes)
-// --- (SPS) NAL unit ---
-// ... (3 bits)
-// NAL unit type <0x07> (5 bits)
-// SPS (3+ bytes)
-// Profile (1 byte)
-// Compatible profiles (1 byte)
-// Level (1 byte)
-// ...
-// --- End ---
-// Start code <0x00 0x00 0x00 0x01> (4 bytes)
-// --- (PPS) NAL unit ---
-// ... (3 bits)
-// NAL unit type <0x08> (5 bits)
-// PPS (1+ bytes)
-// ...
-// --- End ---
-//
-// Descriptor format: (defined in ISO/IEC 14496-15 5.2.4.1.1)
-// --- Header (5 bytes) ---
-// Version <0x01> (1 byte)
-// Profile (1 byte)
-// Compatible profiles (1 byte)
-// Level (1 byte)
-// Reserved <111111> (6 bits)
-// NAL length type (2 bits)
-// --- Parameter sets ---
-// Reserved <111> (3 bits)
-// Number of SPS (5 bits)
-// SPS (3+ bytes)
-// Length (2 bytes)
-// SPS NAL unit (1+ bytes)
-// ...
-// Number of PPS (1 byte)
-// PPS (3+ bytes)
-// Length (2 bytes)
-// PPS NAL unit (1+ bytes)
-// ...
-// --- End ---
-
-// NAL unit start code.
-static const uint8_t kNALUnitStartCode[] = { 0x00, 0x00, 0x00, 0x01 };
-
-// NAL unit types.
-enum {
- kNALUnitTypeSPS = 0x07, // Value for sequence parameter set.
- kNALUnitTypePPS = 0x08, // Value for picture parameter set.
- kNALUnitTypeBad = -1, // Malformed data.
-};
-
-// Sequence parameter set or picture parameter set.
-struct AVCParamSet {
- AVCParamSet(const uint8_t* aPtr, const size_t aSize)
- : mPtr(aPtr)
- , mSize(aSize)
- {
- MOZ_ASSERT(mPtr && mSize > 0);
- }
-
- size_t Size() {
- return mSize + 2; // 2 more bytes for length value.
- }
-
- // Append 2 bytes length value and NAL unit bitstream to aOutputBuf.
- void AppendTo(nsTArray<uint8_t>* aOutputBuf)
- {
- // 2 bytes length value.
- uint8_t size[] = {
- uint8_t((mSize & 0xFF00) >> 8), // MSB.
- uint8_t(mSize & 0x00FF), // LSB.
- };
- aOutputBuf->AppendElements(size, sizeof(size));
-
- aOutputBuf->AppendElements(mPtr, mSize);
- }
-
- const uint8_t* mPtr; // Pointer to NAL unit.
- const size_t mSize; // NAL unit length in bytes.
-};
-
-// Convert SPS and PPS data into decoder config descriptor blob. The generated
-// blob will be appended to aOutputBuf.
-static status_t
-ConvertParamSetsToDescriptorBlob(sp<ABuffer>& aSPS, sp<ABuffer>& aPPS,
- nsTArray<uint8_t>* aOutputBuf)
-{
- // Strip start code in the input.
- AVCParamSet sps(aSPS->data() + sizeof(kNALUnitStartCode),
- aSPS->size() - sizeof(kNALUnitStartCode));
- AVCParamSet pps(aPPS->data() + sizeof(kNALUnitStartCode),
- aPPS->size() - sizeof(kNALUnitStartCode));
- size_t paramSetsSize = sps.Size() + pps.Size();
-
- // Profile/level info in SPS.
- uint8_t* info = aSPS->data() + 5;
-
- uint8_t header[] = {
- 0x01, // Version.
- info[0], // Profile.
- info[1], // Compatible profiles.
- info[2], // Level.
- 0xFF, // 6 bits reserved value <111111> + 2 bits NAL length type <11>
- };
-
- // Reserve 1 byte for number of SPS & another 1 for number of PPS.
- aOutputBuf->SetCapacity(sizeof(header) + paramSetsSize + 2);
- // Build the blob.
- aOutputBuf->AppendElements(header, sizeof(header)); // 5 bytes Header.
- aOutputBuf->AppendElement(0xE0 | 1); // 3 bits <111> + 5 bits number of SPS.
- sps.AppendTo(aOutputBuf); // SPS NALU data.
- aOutputBuf->AppendElement(1); // 1 byte number of PPS.
- pps.AppendTo(aOutputBuf); // PPS NALU data.
-
- return OK;
-}
-
-static int
-NALType(sp<ABuffer>& aBuffer)
-{
- if (aBuffer == nullptr) {
- return kNALUnitTypeBad;
- }
- // Start code?
- uint8_t* data = aBuffer->data();
- if (aBuffer->size() <= 4 ||
- memcmp(data, kNALUnitStartCode, sizeof(kNALUnitStartCode))) {
- return kNALUnitTypeBad;
- }
-
- return data[4] & 0x1F;
-}
-
-// Generate AVC/H.264 decoder config blob.
-// See MPEG4Writer::Track::makeAVCCodecSpecificData() and
-// MPEG4Writer::Track::writeAvccBox() implementation in libstagefright.
-status_t
-GenerateAVCDescriptorBlob(sp<AMessage>& aConfigData,
- nsTArray<uint8_t>* aOutputBuf,
- OMXVideoEncoder::BlobFormat aFormat)
-{
- // Search for parameter sets using key "csd-0" and "csd-1".
- char key[6] = "csd-";
- sp<ABuffer> sps;
- sp<ABuffer> pps;
- for (int i = 0; i < 2; i++) {
- snprintf(key + 4, 2, "%d", i);
- sp<ABuffer> paramSet;
- bool found = aConfigData->findBuffer(key, ¶mSet);
- int type = NALType(paramSet);
- bool valid = ((type == kNALUnitTypeSPS) || (type == kNALUnitTypePPS));
-
- MOZ_ASSERT(found && valid);
- if (!found || !valid) {
- return ERROR_MALFORMED;
- }
-
- switch (type) {
- case kNALUnitTypeSPS:
- sps = paramSet;
- break;
- case kNALUnitTypePPS:
- pps = paramSet;
- break;
- default:
- NS_NOTREACHED("Should not get here!");
- }
- }
-
- MOZ_ASSERT(sps != nullptr && pps != nullptr);
- if (sps == nullptr || pps == nullptr) {
- return ERROR_MALFORMED;
- }
-
- if (aFormat == OMXVideoEncoder::BlobFormat::AVC_NAL) {
- // SPS + PPS.
- aOutputBuf->AppendElements(sps->data(), sps->size());
- aOutputBuf->AppendElements(pps->data(), pps->size());
- return OK;
- } else {
- status_t result = ConvertParamSetsToDescriptorBlob(sps, pps, aOutputBuf);
- MOZ_ASSERT(result == OK);
- return result;
- }
-}
-
-} // namespace android
deleted file mode 100644
--- a/dom/media/omx/OMXCodecDescriptorUtil.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef OMXCodecDescriptorUtil_h_
-#define OMXCodecDescriptorUtil_h_
-
-#include <stagefright/foundation/AMessage.h>
-#include <stagefright/MediaErrors.h>
-
-#include <nsTArray.h>
-
-#include "OMXCodecWrapper.h"
-
-namespace android {
-// Generate decoder config blob using aConfigData provided by encoder.
-// The output will be stored in aOutputBuf.
-// aFormat specifies the output format: AVC_MP4 is for MP4 file, and AVC_NAL is
-// for RTP packet used by WebRTC.
-status_t GenerateAVCDescriptorBlob(sp<AMessage>& aConfigData,
- nsTArray<uint8_t>* aOutputBuf,
- OMXVideoEncoder::BlobFormat aFormat);
-
-}
-
-#endif // OMXCodecDescriptorUtil_h_
deleted file mode 100644
--- a/dom/media/omx/OMXCodecProxy.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMXCodecProxy"
-
-#include <binder/IPCThreadState.h>
-#include <cutils/properties.h>
-#include <stagefright/foundation/ADebug.h>
-#include <stagefright/MetaData.h>
-#include <stagefright/OMXCodec.h>
-#include <utils/Log.h>
-
-#include "nsDebug.h"
-
-#include "OMXCodecProxy.h"
-
-namespace android {
-
-// static
-sp<OMXCodecProxy> OMXCodecProxy::Create(
- const sp<IOMX> &omx,
- const sp<MetaData> &meta, bool createEncoder,
- const sp<MediaSource> &source,
- const char *matchComponentName,
- uint32_t flags,
- const sp<ANativeWindow> &nativeWindow)
-{
- sp<OMXCodecProxy> proxy;
-
- const char *mime;
- if (!meta->findCString(kKeyMIMEType, &mime)) {
- return nullptr;
- }
-
- if (!strncasecmp(mime, "video/", 6)) {
- proxy = new OMXCodecProxy(omx, meta, createEncoder, source, matchComponentName, flags, nativeWindow);
- }
- return proxy;
-}
-
-
-OMXCodecProxy::OMXCodecProxy(
- const sp<IOMX> &omx,
- const sp<MetaData> &meta,
- bool createEncoder,
- const sp<MediaSource> &source,
- const char *matchComponentName,
- uint32_t flags,
- const sp<ANativeWindow> &nativeWindow)
- : mOMX(omx),
- mSrcMeta(meta),
- mComponentName(nullptr),
- mIsEncoder(createEncoder),
- mFlags(flags),
- mNativeWindow(nativeWindow),
- mSource(source),
- mState(ResourceState::START)
-{
-}
-
-OMXCodecProxy::~OMXCodecProxy()
-{
- // At first, release mResourceClient's resource to prevent a conflict with
- // mResourceClient's callback.
- if (mResourceClient) {
- mResourceClient->ReleaseResource();
- mResourceClient = nullptr;
- }
-
- mState = ResourceState::END;
- mCodecPromise.RejectIfExists(true, __func__);
-
- if (mOMXCodec.get()) {
- wp<MediaSource> tmp = mOMXCodec;
- mOMXCodec.clear();
- while (tmp.promote() != nullptr) {
- // this value come from stagefrigh's AwesomePlayer.
- usleep(1000);
- }
- }
- // Complete all pending Binder ipc transactions
- IPCThreadState::self()->flushCommands();
-
- mSource.clear();
- free(mComponentName);
- mComponentName = nullptr;
-}
-
-RefPtr<OMXCodecProxy::CodecPromise>
-OMXCodecProxy::requestResource()
-{
- Mutex::Autolock autoLock(mLock);
-
- if (mResourceClient) {
- return CodecPromise::CreateAndReject(true, __func__);
- }
- mState = ResourceState::WAITING;
-
- mozilla::MediaSystemResourceType type = mIsEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
- mozilla::MediaSystemResourceType::VIDEO_DECODER;
- mResourceClient = new mozilla::MediaSystemResourceClient(type);
- mResourceClient->SetListener(this);
- mResourceClient->Acquire();
-
- RefPtr<CodecPromise> p = mCodecPromise.Ensure(__func__);
- return p.forget();
-}
-
-// Called on ImageBridge thread
-void
-OMXCodecProxy::ResourceReserved()
-{
- Mutex::Autolock autoLock(mLock);
-
- if (mState != ResourceState::WAITING) {
- mCodecPromise.RejectIfExists(true, __func__);
- return;
- }
-
- const char *mime;
- if (!mSrcMeta->findCString(kKeyMIMEType, &mime)) {
- mState = ResourceState::END;
- mCodecPromise.RejectIfExists(true, __func__);
- return;
- }
-
- if (!strncasecmp(mime, "video/", 6)) {
- sp<MediaSource> codec;
- mOMXCodec = OMXCodec::Create(mOMX, mSrcMeta, mIsEncoder, mSource, mComponentName, mFlags, mNativeWindow);
- if (mOMXCodec == nullptr) {
- mState = ResourceState::END;
- mCodecPromise.RejectIfExists(true, __func__);
- return;
- }
- // Check if this video is sized such that we're comfortable
- // possibly using an OMX decoder.
- int32_t maxWidth, maxHeight;
- char propValue[PROPERTY_VALUE_MAX];
- property_get("ro.moz.omx.hw.max_width", propValue, "-1");
- maxWidth = atoi(propValue);
- property_get("ro.moz.omx.hw.max_height", propValue, "-1");
- maxHeight = atoi(propValue);
-
- int32_t width = -1, height = -1;
- if (maxWidth > 0 && maxHeight > 0 &&
- !(mOMXCodec->getFormat()->findInt32(kKeyWidth, &width) &&
- mOMXCodec->getFormat()->findInt32(kKeyHeight, &height) &&
- width * height <= maxWidth * maxHeight)) {
- printf_stderr("Failed to get video size, or it was too large for HW decoder (<w=%d, h=%d> but <maxW=%d, maxH=%d>)",
- width, height, maxWidth, maxHeight);
- mOMXCodec.clear();
- mState = ResourceState::END;
- mCodecPromise.RejectIfExists(true, __func__);
- return;
- }
-
- if (mOMXCodec->start() != OK) {
- NS_WARNING("Couldn't start OMX video source");
- mOMXCodec.clear();
- mState = ResourceState::END;
- mCodecPromise.RejectIfExists(true, __func__);
- return;
- }
- }
-
- mState = ResourceState::ACQUIRED;
- mCodecPromise.ResolveIfExists(true, __func__);
-}
-
-// Called on ImageBridge thread
-void
-OMXCodecProxy::ResourceReserveFailed()
-{
- Mutex::Autolock autoLock(mLock);
- mState = ResourceState::NOT_ACQUIRED;
- mCodecPromise.RejectIfExists(true, __func__);
-}
-
-status_t
-OMXCodecProxy::start(MetaData *params)
-{
- Mutex::Autolock autoLock(mLock);
-
- if (mState != ResourceState::ACQUIRED) {
- return NO_INIT;
- }
- CHECK(mOMXCodec.get() != nullptr);
- return mOMXCodec->start();
-}
-
-status_t
-OMXCodecProxy::stop()
-{
- Mutex::Autolock autoLock(mLock);
-
- if (mState != ResourceState::ACQUIRED) {
- return NO_INIT;
- }
- CHECK(mOMXCodec.get() != nullptr);
- return mOMXCodec->stop();
-}
-
-sp<MetaData>
-OMXCodecProxy::getFormat()
-{
- Mutex::Autolock autoLock(mLock);
-
- if (mState != ResourceState::ACQUIRED) {
- sp<MetaData> meta = new MetaData;
- return meta;
- }
- CHECK(mOMXCodec.get() != nullptr);
- return mOMXCodec->getFormat();
-}
-
-status_t
-OMXCodecProxy::read(MediaBuffer **buffer, const ReadOptions *options)
-{
- Mutex::Autolock autoLock(mLock);
-
- if (mState != ResourceState::ACQUIRED) {
- return NO_INIT;
- }
- CHECK(mOMXCodec.get() != nullptr);
- return mOMXCodec->read(buffer, options);
-}
-
-status_t
-OMXCodecProxy::pause()
-{
- Mutex::Autolock autoLock(mLock);
-
- if (mState != ResourceState::ACQUIRED) {
- return NO_INIT;
- }
- CHECK(mOMXCodec.get() != nullptr);
- return mOMXCodec->pause();
-}
-
-} // namespace android
deleted file mode 100644
--- a/dom/media/omx/OMXCodecProxy.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef OMX_CODEC_PROXY_DECODER_H_
-#define OMX_CODEC_PROXY_DECODER_H_
-
-
-#include <android/native_window.h>
-#include <media/IOMX.h>
-#include <stagefright/MediaBuffer.h>
-#include <stagefright/MediaSource.h>
-#include <utils/threads.h>
-
-#include "mozilla/media/MediaSystemResourceClient.h"
-#include "mozilla/MozPromise.h"
-#include "mozilla/RefPtr.h"
-
-namespace android {
-
-struct MetaData;
-
-class OMXCodecProxy : public MediaSource
- , public mozilla::MediaSystemResourceReservationListener
-{
-public:
- typedef mozilla::MozPromise<bool /* aIgnored */, bool /* aIgnored */, /* IsExclusive = */ true> CodecPromise;
-
- // Enumeration for the valid resource allcoation states
- enum class ResourceState : int8_t {
- START,
- WAITING,
- ACQUIRED,
- NOT_ACQUIRED,
- END
- };
-
- static sp<OMXCodecProxy> Create(
- const sp<IOMX> &omx,
- const sp<MetaData> &meta, bool createEncoder,
- const sp<MediaSource> &source,
- const char *matchComponentName = nullptr,
- uint32_t flags = 0,
- const sp<ANativeWindow> &nativeWindow = nullptr);
-
- RefPtr<CodecPromise> requestResource();
-
- // MediaSystemResourceReservationListener
- void ResourceReserved() override;
- void ResourceReserveFailed() override;
-
- // MediaSource
- status_t start(MetaData *params = nullptr) override;
- status_t stop() override;
-
- sp<MetaData> getFormat() override;
-
- status_t read(
- MediaBuffer **buffer, const ReadOptions *options = nullptr) override;
-
- status_t pause() override;
-
-protected:
- OMXCodecProxy(
- const sp<IOMX> &omx,
- const sp<MetaData> &meta,
- bool createEncoder,
- const sp<MediaSource> &source,
- const char *matchComponentName,
- uint32_t flags,
- const sp<ANativeWindow> &nativeWindow);
-
- virtual ~OMXCodecProxy();
-
-private:
- OMXCodecProxy(const OMXCodecProxy &);
- OMXCodecProxy &operator=(const OMXCodecProxy &);
-
- Mutex mLock;
-
- sp<IOMX> mOMX;
- sp<MetaData> mSrcMeta;
- char *mComponentName;
- bool mIsEncoder;
- // Flags specified in the creation of the codec.
- uint32_t mFlags;
- sp<ANativeWindow> mNativeWindow;
-
- sp<MediaSource> mSource;
-
- sp<MediaSource> mOMXCodec;
-
- RefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
- ResourceState mState;
- mozilla::MozPromiseHolder<CodecPromise> mCodecPromise;
-};
-
-} // namespace android
-
-#endif // OMX_CODEC_PROXY_DECODER_H_
deleted file mode 100644
--- a/dom/media/omx/OMXCodecWrapper.cpp
+++ /dev/null
@@ -1,1132 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "OMXCodecWrapper.h"
-#include "OMXCodecDescriptorUtil.h"
-#include "TrackEncoder.h"
-
-#include <binder/ProcessState.h>
-#include <cutils/properties.h>
-#include <media/ICrypto.h>
-#include <media/IOMX.h>
-#include <OMX_Component.h>
-#include <stagefright/MediaDefs.h>
-#include <stagefright/MediaErrors.h>
-
-#include "AudioChannelFormat.h"
-#include "GrallocImages.h"
-#include "LayersLogging.h"
-#include "libyuv.h"
-#include "mozilla/Monitor.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/layers/GrallocTextureClient.h"
-#include "nsAutoPtr.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::layers;
-
-#define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll)
-// AMR NB kbps
-#define AMRNB_BITRATE 12200
-#define EVRC_BITRATE 8755
-
-#define CODEC_ERROR(args...) \
- do { \
- __android_log_print(ANDROID_LOG_ERROR, "OMXCodecWrapper", ##args); \
- } while (0)
-
-namespace android {
-
-const char *MEDIA_MIMETYPE_AUDIO_EVRC = "audio/evrc";
-
-enum BufferState
-{
- BUFFER_OK,
- BUFFER_FAIL,
- WAIT_FOR_NEW_BUFFER
-};
-
-bool
-OMXCodecReservation::ReserveOMXCodec()
-{
- if (!mClient) {
- mClient = new mozilla::MediaSystemResourceClient(mType);
- } else {
- if (mOwned) {
- //CODEC_ERROR("OMX Reservation: (%d) already owned", (int) mType);
- return true;
- }
- //CODEC_ERROR("OMX Reservation: (%d) already NOT owned", (int) mType);
- }
- mOwned = mClient->AcquireSyncNoWait(); // don't wait if resource is not available
- //CODEC_ERROR("OMX Reservation: (%d) Acquire was %s", (int) mType, mOwned ? "Successful" : "Failed");
- return mOwned;
-}
-
-void
-OMXCodecReservation::ReleaseOMXCodec()
-{
- if (!mClient) {
- return;
- }
- //CODEC_ERROR("OMX Reservation: Releasing resource: (%d) %s", (int) mType, mOwned ? "Owned" : "Not owned");
- if (mOwned) {
- mClient->ReleaseResource();
- mClient = nullptr;
- mOwned = false;
- }
-}
-
-OMXAudioEncoder*
-OMXCodecWrapper::CreateAACEncoder()
-{
- nsAutoPtr<OMXAudioEncoder> aac(new OMXAudioEncoder(CodecType::AAC_ENC));
- // Return the object only when media codec is valid.
- NS_ENSURE_TRUE(aac->IsValid(), nullptr);
-
- return aac.forget();
-}
-
-OMXAudioEncoder*
-OMXCodecWrapper::CreateAMRNBEncoder()
-{
- nsAutoPtr<OMXAudioEncoder> amr(new OMXAudioEncoder(CodecType::AMR_NB_ENC));
- // Return the object only when media codec is valid.
- NS_ENSURE_TRUE(amr->IsValid(), nullptr);
-
- return amr.forget();
-}
-
-OMXAudioEncoder*
-OMXCodecWrapper::CreateEVRCEncoder()
-{
- nsAutoPtr<OMXAudioEncoder> evrc(new OMXAudioEncoder(CodecType::EVRC_ENC));
- // Return the object only when media codec is valid.
- NS_ENSURE_TRUE(evrc->IsValid(), nullptr);
-
- return evrc.forget();
-}
-
-OMXVideoEncoder*
-OMXCodecWrapper::CreateAVCEncoder()
-{
- nsAutoPtr<OMXVideoEncoder> avc(new OMXVideoEncoder(CodecType::AVC_ENC));
- // Return the object only when media codec is valid.
- NS_ENSURE_TRUE(avc->IsValid(), nullptr);
-
- return avc.forget();
-}
-
-OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType)
- : mCodecType(aCodecType)
- , mStarted(false)
- , mAMRCSDProvided(false)
- , mEVRCCSDProvided(false)
-{
- ProcessState::self()->startThreadPool();
-
- mLooper = new ALooper();
- mLooper->start();
-
- if (aCodecType == CodecType::AVC_ENC) {
- mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_VIDEO_AVC, true);
- } else if (aCodecType == CodecType::AMR_NB_ENC) {
- mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AMR_NB, true);
- } else if (aCodecType == CodecType::AAC_ENC) {
- mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AAC, true);
- } else if (aCodecType == CodecType::EVRC_ENC) {
- mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_EVRC, true);
- } else {
- NS_ERROR("Unknown codec type.");
- }
-}
-
-OMXCodecWrapper::~OMXCodecWrapper()
-{
- if (mCodec.get()) {
- Stop();
- mCodec->release();
- }
- mLooper->stop();
-}
-
-status_t
-OMXCodecWrapper::Start()
-{
- // Already started.
- NS_ENSURE_FALSE(mStarted, OK);
-
- status_t result = mCodec->start();
- mStarted = (result == OK);
-
- // Get references to MediaCodec buffers.
- if (result == OK) {
- mCodec->getInputBuffers(&mInputBufs);
- mCodec->getOutputBuffers(&mOutputBufs);
- }
-
- return result;
-}
-
-status_t
-OMXCodecWrapper::Stop()
-{
- // Already stopped.
- NS_ENSURE_TRUE(mStarted, OK);
-
- status_t result = mCodec->stop();
- mStarted = !(result == OK);
-
- return result;
-}
-
-// Check system property to see if we're running on emulator.
-static bool
-IsRunningOnEmulator()
-{
- char qemu[PROPERTY_VALUE_MAX];
- property_get("ro.kernel.qemu", qemu, "");
- return strncmp(qemu, "1", 1) == 0;
-}
-
-#define ENCODER_CONFIG_BITRATE 2000000 // bps
-// How many seconds between I-frames.
-#define ENCODER_CONFIG_I_FRAME_INTERVAL 1
-// Wait up to 5ms for input buffers.
-
-nsresult
-OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate,
- BlobFormat aBlobFormat)
-{
- NS_ENSURE_TRUE(aWidth > 0 && aHeight > 0 && aFrameRate > 0,
- NS_ERROR_INVALID_ARG);
-
- OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevel3;
- OMX_VIDEO_CONTROLRATETYPE bitrateMode = OMX_Video_ControlRateConstant;
-
- // Set up configuration parameters for AVC/H.264 encoder.
- sp<AMessage> format = new AMessage;
- // Fixed values
- format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
- format->setInt32("bitrate", ENCODER_CONFIG_BITRATE);
- format->setInt32("i-frame-interval", ENCODER_CONFIG_I_FRAME_INTERVAL);
- // See mozilla::layers::GrallocImage, supports YUV 4:2:0, CbCr width and
- // height is half that of Y
- format->setInt32("color-format", OMX_COLOR_FormatYUV420SemiPlanar);
- format->setInt32("profile", OMX_VIDEO_AVCProfileBaseline);
- format->setInt32("level", level);
- format->setInt32("bitrate-mode", bitrateMode);
- format->setInt32("store-metadata-in-buffers", 0);
- format->setInt32("prepend-sps-pps-to-idr-frames", 0);
- // Input values.
- format->setInt32("width", aWidth);
- format->setInt32("height", aHeight);
- format->setInt32("stride", aWidth);
- format->setInt32("slice-height", aHeight);
- format->setInt32("frame-rate", aFrameRate);
-
- return ConfigureDirect(format, aBlobFormat);
-}
-
-nsresult
-OMXVideoEncoder::ConfigureDirect(sp<AMessage>& aFormat,
- BlobFormat aBlobFormat)
-{
- // We now allow re-configuration to handle resolution/framerate/etc changes
- if (mStarted) {
- Stop();
- }
- MOZ_ASSERT(!mStarted, "OMX Stop() failed?");
-
- int width = 0;
- int height = 0;
- int frameRate = 0;
- aFormat->findInt32("width", &width);
- aFormat->findInt32("height", &height);
- aFormat->findInt32("frame-rate", &frameRate);
- NS_ENSURE_TRUE(width > 0 && height > 0 && frameRate > 0,
- NS_ERROR_INVALID_ARG);
-
- // Limitation of soft AVC/H.264 encoder running on emulator in stagefright.
- static bool emu = IsRunningOnEmulator();
- if (emu) {
- if (width > 352 || height > 288) {
- CODEC_ERROR("SoftAVCEncoder doesn't support resolution larger than CIF");
- return NS_ERROR_INVALID_ARG;
- }
- aFormat->setInt32("level", OMX_VIDEO_AVCLevel2);
- aFormat->setInt32("bitrate-mode", OMX_Video_ControlRateVariable);
- }
-
-
- status_t result = mCodec->configure(aFormat, nullptr, nullptr,
- MediaCodec::CONFIGURE_FLAG_ENCODE);
- NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
-
- mWidth = width;
- mHeight = height;
- mBlobFormat = aBlobFormat;
-
- result = Start();
-
- return result == OK ? NS_OK : NS_ERROR_FAILURE;
-}
-
-// Copy pixels from planar YUV (4:4:4/4:2:2/4:2:0) or NV21 (semi-planar 4:2:0)
-// format to NV12 (semi-planar 4:2:0) format for QCOM HW encoder.
-// Planar YUV: YYY...UUU...VVV...
-// NV21: YYY...VUVU...
-// NV12: YYY...UVUV...
-// For 4:4:4/4:2:2 -> 4:2:0, subsample using odd row/column without
-// interpolation.
-// aSource contains info about source image data, and the result will be stored
-// in aDestination, whose size needs to be >= Y plane size * 3 / 2.
-static void
-ConvertPlanarYCbCrToNV12(const PlanarYCbCrData* aSource, uint8_t* aDestination)
-{
- // Fill Y plane.
- uint8_t* y = aSource->mYChannel;
- IntSize ySize = aSource->mYSize;
-
- // Y plane.
- for (int i = 0; i < ySize.height; i++) {
- memcpy(aDestination, y, ySize.width);
- aDestination += ySize.width;
- y += aSource->mYStride;
- }
-
- // Fill interleaved UV plane.
- uint8_t* u = aSource->mCbChannel;
- uint8_t* v = aSource->mCrChannel;
- IntSize uvSize = aSource->mCbCrSize;
- // Subsample to 4:2:0 if source is 4:4:4 or 4:2:2.
- // Y plane width & height should be multiple of U/V plane width & height.
- MOZ_ASSERT(ySize.width % uvSize.width == 0 &&
- ySize.height % uvSize.height == 0);
- size_t uvWidth = ySize.width / 2;
- size_t uvHeight = ySize.height / 2;
- size_t horiSubsample = uvSize.width / uvWidth;
- size_t uPixStride = horiSubsample * (1 + aSource->mCbSkip);
- size_t vPixStride = horiSubsample * (1 + aSource->mCrSkip);
- size_t lineStride = uvSize.height / uvHeight * aSource->mCbCrStride;
-
- for (size_t i = 0; i < uvHeight; i++) {
- // 1st pixel per line.
- uint8_t* uSrc = u;
- uint8_t* vSrc = v;
- for (size_t j = 0; j < uvWidth; j++) {
- *aDestination++ = *uSrc;
- *aDestination++ = *vSrc;
- // Pick next source pixel.
- uSrc += uPixStride;
- vSrc += vPixStride;
- }
- // Pick next source line.
- u += lineStride;
- v += lineStride;
- }
-}
-
-// Convert pixels in graphic buffer to NV12 format. aSource is the layer image
-// containing source graphic buffer, and aDestination is the destination of
-// conversion. Currently 3 source format are supported:
-// - NV21/HAL_PIXEL_FORMAT_YCrCb_420_SP (from camera preview window).
-// - YV12/HAL_PIXEL_FORMAT_YV12 (from video decoder).
-// - QCOM proprietary/HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS (from Flame HW video decoder)
-static void
-ConvertGrallocImageToNV12(GrallocImage* aSource, uint8_t* aDestination)
-{
- // Get graphic buffer.
- sp<GraphicBuffer> graphicBuffer = aSource->GetGraphicBuffer();
-
- int pixelFormat = graphicBuffer->getPixelFormat();
-
- void* imgPtr = nullptr;
- graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &imgPtr);
- // Build PlanarYCbCrData for NV21 or YV12 buffer.
- PlanarYCbCrData yuv;
- switch (pixelFormat) {
- case HAL_PIXEL_FORMAT_YCrCb_420_SP: // From camera.
- yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
- yuv.mYSkip = 0;
- yuv.mYSize.width = graphicBuffer->getWidth();
- yuv.mYSize.height = graphicBuffer->getHeight();
- yuv.mYStride = graphicBuffer->getStride();
- // 4:2:0.
- yuv.mCbCrSize.width = yuv.mYSize.width / 2;
- yuv.mCbCrSize.height = yuv.mYSize.height / 2;
- // Interleaved VU plane.
- yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
- yuv.mCrSkip = 1;
- yuv.mCbChannel = yuv.mCrChannel + 1;
- yuv.mCbSkip = 1;
- yuv.mCbCrStride = yuv.mYStride;
- ConvertPlanarYCbCrToNV12(&yuv, aDestination);
- break;
- case HAL_PIXEL_FORMAT_YV12: // From video decoder.
- // Android YV12 format is defined in system/core/include/system/graphics.h
- yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
- yuv.mYSkip = 0;
- yuv.mYSize.width = graphicBuffer->getWidth();
- yuv.mYSize.height = graphicBuffer->getHeight();
- yuv.mYStride = graphicBuffer->getStride();
- // 4:2:0.
- yuv.mCbCrSize.width = yuv.mYSize.width / 2;
- yuv.mCbCrSize.height = yuv.mYSize.height / 2;
- yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
- // Aligned to 16 bytes boundary.
- yuv.mCbCrStride = (yuv.mYStride / 2 + 15) & ~0x0F;
- yuv.mCrSkip = 0;
- yuv.mCbChannel = yuv.mCrChannel + (yuv.mCbCrStride * yuv.mCbCrSize.height);
- yuv.mCbSkip = 0;
- ConvertPlanarYCbCrToNV12(&yuv, aDestination);
- break;
- // From QCOM video decoder on Flame. See bug 997593.
- case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
- // Venus formats are doucmented in kernel/include/media/msm_media_info.h:
- yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
- yuv.mYSkip = 0;
- yuv.mYSize.width = graphicBuffer->getWidth();
- yuv.mYSize.height = graphicBuffer->getHeight();
- // - Y & UV Width aligned to 128
- yuv.mYStride = (yuv.mYSize.width + 127) & ~127;
- yuv.mCbCrSize.width = yuv.mYSize.width / 2;
- yuv.mCbCrSize.height = yuv.mYSize.height / 2;
- // - Y height aligned to 32
- yuv.mCbChannel = yuv.mYChannel + (yuv.mYStride * ((yuv.mYSize.height + 31) & ~31));
- // Interleaved VU plane.
- yuv.mCbSkip = 1;
- yuv.mCrChannel = yuv.mCbChannel + 1;
- yuv.mCrSkip = 1;
- yuv.mCbCrStride = yuv.mYStride;
- ConvertPlanarYCbCrToNV12(&yuv, aDestination);
- break;
- default:
- NS_ERROR("Unsupported input gralloc image type. Should never be here.");
- }
-
- graphicBuffer->unlock();
-}
-
-static nsresult
-ConvertSourceSurfaceToNV12(const RefPtr<SourceSurface>& aSurface, uint8_t* aDestination)
-{
- if (!aSurface) {
- CODEC_ERROR("Getting surface from image failed");
- return NS_ERROR_FAILURE;
- }
-
- uint32_t width = aSurface->GetSize().width;
- uint32_t height = aSurface->GetSize().height;
-
- uint8_t* y = aDestination;
- int yStride = width;
-
- uint8_t* uv = y + (yStride * height);
- int uvStride = width / 2;
-
- RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
- if (!data) {
- CODEC_ERROR("Getting data surface from %s image with %s surface failed",
- Stringify(aSurface->GetFormat()).c_str(),
- Stringify(aSurface->GetType()).c_str());
- return NS_ERROR_FAILURE;
- }
-
- DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
- if (!map.IsMapped()) {
- CODEC_ERROR("Reading DataSourceSurface from %s image with %s surface failed",
- Stringify(aSurface->GetFormat()).c_str(),
- Stringify(aSurface->GetType()).c_str());
- return NS_ERROR_FAILURE;
- }
-
- int rv;
- switch (aSurface->GetFormat()) {
- case SurfaceFormat::B8G8R8A8:
- case SurfaceFormat::B8G8R8X8:
- rv = libyuv::ARGBToNV12(static_cast<uint8*>(map.GetData()),
- map.GetStride(),
- y, yStride,
- uv, uvStride,
- width, height);
- break;
- default:
- CODEC_ERROR("Unsupported SourceSurface format %s",
- Stringify(aSurface->GetFormat()).c_str());
- NS_ASSERTION(false, "Unsupported SourceSurface format");
- return NS_ERROR_NOT_IMPLEMENTED;
- }
-
- if (rv != 0) {
- CODEC_ERROR("%s to I420 conversion failed",
- Stringify(aSurface->GetFormat()).c_str());
- return NS_ERROR_FAILURE;
- }
-
- return NS_OK;
-}
-
-nsresult
-OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight,
- int64_t aTimestamp, int aInputFlags, bool* aSendEOS)
-{
- MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");
-
- NS_ENSURE_TRUE(aWidth == mWidth && aHeight == mHeight && aTimestamp >= 0,
- NS_ERROR_INVALID_ARG);
-
- Image* img = const_cast<Image*>(aImage);
- ImageFormat format = ImageFormat::PLANAR_YCBCR;
- if (img) {
- format = img->GetFormat();
- gfx::IntSize size = img->GetSize();
- // Validate input image.
- NS_ENSURE_TRUE(aWidth == size.width, NS_ERROR_INVALID_ARG);
- NS_ENSURE_TRUE(aHeight == size.height, NS_ERROR_INVALID_ARG);
- if (format == ImageFormat::PLANAR_YCBCR) {
- // Test for data, allowing AdoptData() on an image without an mBuffer
- // (as used from WebrtcOMXH264VideoCodec, and a few other places) - bug 1067442
- const PlanarYCbCrData* yuv = static_cast<PlanarYCbCrImage*>(img)->GetData();
- NS_ENSURE_TRUE(yuv->mYChannel, NS_ERROR_INVALID_ARG);
- } else if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
- // Reject unsupported gralloc-ed buffers.
- int halFormat = static_cast<GrallocImage*>(img)->GetGraphicBuffer()->getPixelFormat();
- NS_ENSURE_TRUE(halFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
- halFormat == HAL_PIXEL_FORMAT_YV12 ||
- halFormat == GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS,
- NS_ERROR_INVALID_ARG);
- } else {
- RefPtr<SourceSurface> surface = img->GetAsSourceSurface();
- NS_ENSURE_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
- surface->GetFormat() == SurfaceFormat::B8G8R8X8,
- NS_ERROR_INVALID_ARG);
- }
- }
-
- status_t result;
-
- // Dequeue an input buffer.
- uint32_t index;
- result = mCodec->dequeueInputBuffer(&index, INPUT_BUFFER_TIMEOUT_US);
- if (result == -EAGAIN) {
- // Drop the frame when out of input buffer.
- return NS_OK;
- }
- NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
-
- const sp<ABuffer>& inBuf = mInputBufs.itemAt(index);
- uint8_t* dst = inBuf->data();
- size_t dstSize = inBuf->capacity();
-
- size_t yLen = aWidth * aHeight;
- size_t uvLen = yLen / 2;
- // Buffer should be large enough to hold input image data.
- MOZ_ASSERT(dstSize >= yLen + uvLen);
-
- dstSize = yLen + uvLen;
- inBuf->setRange(0, dstSize);
- if (!img) {
- // Generate muted/black image directly in buffer.
- // Fill Y plane.
- memset(dst, 0x10, yLen);
- // Fill UV plane.
- memset(dst + yLen, 0x80, uvLen);
- } else {
- if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
- ConvertGrallocImageToNV12(static_cast<GrallocImage*>(img), dst);
- } else if (format == ImageFormat::PLANAR_YCBCR) {
- ConvertPlanarYCbCrToNV12(static_cast<PlanarYCbCrImage*>(img)->GetData(),
- dst);
- } else {
- RefPtr<SourceSurface> surface = img->GetAsSourceSurface();
- nsresult rv = ConvertSourceSurfaceToNV12(surface, dst);
-
- if (rv != NS_OK) {
- return NS_ERROR_FAILURE;
- }
- }
- }
-
- // Queue this input buffer.
- result = mCodec->queueInputBuffer(index, 0, dstSize, aTimestamp, aInputFlags);
-
- if (aSendEOS && (aInputFlags & BUFFER_EOS) && result == OK) {
- *aSendEOS = true;
- }
- return result == OK ? NS_OK : NS_ERROR_FAILURE;
-}
-
-status_t
-OMXVideoEncoder::AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
- ABuffer* aData)
-{
- // Codec already parsed aData. Using its result makes generating config blob
- // much easier.
- sp<AMessage> format;
- mCodec->getOutputFormat(&format);
-
- // NAL unit format is needed by WebRTC for RTP packets; AVC/H.264 decoder
- // config descriptor is needed to construct MP4 'avcC' box.
- status_t result = GenerateAVCDescriptorBlob(format, aOutputBuf, mBlobFormat);
-
- return result;
-}
-
-// Override to replace NAL unit start code with 4-bytes unit length.
-// See ISO/IEC 14496-15 5.2.3.
-void
-OMXVideoEncoder::AppendFrame(nsTArray<uint8_t>* aOutputBuf,
- const uint8_t* aData, size_t aSize)
-{
- aOutputBuf->SetCapacity(aSize);
-
- if (mBlobFormat == BlobFormat::AVC_NAL) {
- // Append NAL format data without modification.
- aOutputBuf->AppendElements(aData, aSize);
- return;
- }
- // Replace start code with data length.
- uint8_t length[] = {
- uint8_t((aSize >> 24) & 0xFF),
- uint8_t((aSize >> 16) & 0xFF),
- uint8_t((aSize >> 8) & 0xFF),
- uint8_t(aSize & 0xFF),
- };
- aOutputBuf->AppendElements(length, sizeof(length));
- aOutputBuf->AppendElements(aData + sizeof(length), aSize);
-}
-
-// MediaCodec::setParameters() is available only after API level 18.
-#if ANDROID_VERSION >= 18
-nsresult
-OMXVideoEncoder::SetBitrate(int32_t aKbps)
-{
- sp<AMessage> msg = new AMessage();
-#if ANDROID_VERSION >= 19
- // XXX Do we need a runtime check here?
- msg->setInt32("video-bitrate", aKbps * 1000 /* kbps -> bps */);
-#else
- msg->setInt32("videoBitrate", aKbps * 1000 /* kbps -> bps */);
-#endif
- status_t result = mCodec->setParameters(msg);
- MOZ_ASSERT(result == OK);
- return result == OK ? NS_OK : NS_ERROR_FAILURE;
-}
-#endif
-
-nsresult
-OMXVideoEncoder::RequestIDRFrame()
-{
- MOZ_ASSERT(mStarted, "Configure() should be called before RequestIDRFrame().");
- return mCodec->requestIDRFrame() == OK ? NS_OK : NS_ERROR_FAILURE;
-}
-
-nsresult
-OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate,
- int aEncodedSampleRate)
-{
- MOZ_ASSERT(!mStarted);
-
- NS_ENSURE_TRUE(aChannels > 0 && aInputSampleRate > 0 && aEncodedSampleRate >= 0,
- NS_ERROR_INVALID_ARG);
-
- if (aInputSampleRate != aEncodedSampleRate) {
- int error;
- mResampler = speex_resampler_init(aChannels,
- aInputSampleRate,
- aEncodedSampleRate,
- SPEEX_RESAMPLER_QUALITY_DEFAULT,
- &error);
-
- if (error != RESAMPLER_ERR_SUCCESS) {
- return NS_ERROR_FAILURE;
- }
- speex_resampler_skip_zeros(mResampler);
- }
- // Set up configuration parameters for AAC encoder.
- sp<AMessage> format = new AMessage;
- // Fixed values.
- if (mCodecType == AAC_ENC) {
- format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
- format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
- format->setInt32("bitrate", kAACBitrate);
- format->setInt32("sample-rate", aInputSampleRate);
- } else if (mCodecType == AMR_NB_ENC) {
- format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
- format->setInt32("bitrate", AMRNB_BITRATE);
- format->setInt32("sample-rate", aEncodedSampleRate);
- } else if (mCodecType == EVRC_ENC) {
- format->setString("mime", MEDIA_MIMETYPE_AUDIO_EVRC);
- format->setInt32("bitrate", EVRC_BITRATE);
- format->setInt32("sample-rate", aEncodedSampleRate);
- } else {
- MOZ_ASSERT(false, "Can't support this codec type!!");
- }
- // Input values.
- format->setInt32("channel-count", aChannels);
-
- status_t result = mCodec->configure(format, nullptr, nullptr,
- MediaCodec::CONFIGURE_FLAG_ENCODE);
- NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
-
- mChannels = aChannels;
- mSampleDuration = 1000000 / aInputSampleRate;
- mResamplingRatio = aEncodedSampleRate > 0 ? 1.0 *
- aEncodedSampleRate / aInputSampleRate : 1.0;
- result = Start();
-
- return result == OK ? NS_OK : NS_ERROR_FAILURE;
-}
-
-class InputBufferHelper final {
-public:
- InputBufferHelper(sp<MediaCodec>& aCodec, Vector<sp<ABuffer> >& aBuffers,
- OMXAudioEncoder& aEncoder, int aInputFlags)
- : mCodec(aCodec)
- , mBuffers(aBuffers)
- , mOMXAEncoder(aEncoder)
- , mInputFlags(aInputFlags)
- , mIndex(0)
- , mData(nullptr)
- , mCapicity(0)
- , mOffset(0)
- {}
-
- ~InputBufferHelper()
- {
- // Unflushed data in buffer.
- MOZ_ASSERT(!mData);
- }
-
- status_t Dequeue()
- {
- // Shouldn't have dequeued buffer.
- MOZ_ASSERT(!mData);
-
- status_t result = mCodec->dequeueInputBuffer(&mIndex,
- INPUT_BUFFER_TIMEOUT_US);
- NS_ENSURE_TRUE(result == OK, result);
- sp<ABuffer> inBuf = mBuffers.itemAt(mIndex);
- mData = inBuf->data();
- mCapicity = inBuf->capacity();
- mOffset = 0;
-
- return OK;
- }
-
- status_t Enqueue(int64_t aTimestamp, int aFlags)
- {
- // Should have dequeued buffer.
- MOZ_ASSERT(mData);
-
- // Queue this buffer.
- status_t result = mCodec->queueInputBuffer(mIndex, 0, mOffset, aTimestamp,
- aFlags);
- NS_ENSURE_TRUE(result == OK, result);
- mData = nullptr;
-
- return OK;
- }
-
- // Read audio data in aChunk, resample them if needed,
- // and then send the result to OMX input buffer (or buffers if one buffer is not enough).
- // aSamplesRead will be the number of samples that have been read from aChunk.
- BufferState ReadChunk(AudioChunk& aChunk, size_t* aSamplesRead)
- {
- size_t chunkSamples = aChunk.GetDuration();
- size_t bytesToCopy = chunkSamples * mOMXAEncoder.mResamplingRatio
- * mOMXAEncoder.mChannels * sizeof(AudioDataValue);
- size_t bytesCopied = 0;
- if (bytesToCopy <= AvailableSize()) {
- if (aChunk.IsNull()) {
- bytesCopied = SendSilenceToBuffer(chunkSamples);
- } else {
- bytesCopied = SendChunkToBuffer(aChunk, chunkSamples);
- }
- UpdateAfterSendChunk(chunkSamples, bytesCopied, aSamplesRead);
- } else {
- // Interleave data to a temporary buffer.
- AutoTArray<AudioDataValue, 9600> pcm;
- pcm.SetLength(bytesToCopy);
- AudioDataValue* interleavedSource = pcm.Elements();
- AudioTrackEncoder::InterleaveTrackData(aChunk, chunkSamples,
- mOMXAEncoder.mChannels,
- interleavedSource);
-
- // When the data size of chunk is larger than the buffer capacity,
- // we split it into sub-chunks to fill up buffers.
- size_t subChunkSamples = 0;
- while(GetNextSubChunk(bytesToCopy, subChunkSamples)) {
- // To avoid enqueueing an empty buffer, we follow the order that
- // clear up buffer first, then create one, send data to it in the end.
- if (!IsEmpty()) {
- // Submit the filled-up buffer and request a new buffer.
- status_t result = Enqueue(mOMXAEncoder.mTimestamp,
- mInputFlags & ~OMXCodecWrapper::BUFFER_EOS);
- if (result != OK) {
- return BUFFER_FAIL;
- }
-
- result = Dequeue();
- if (result == -EAGAIN) {
- return WAIT_FOR_NEW_BUFFER;
- }
- if (result != OK) {
- return BUFFER_FAIL;
- }
- }
- if (aChunk.IsNull()) {
- bytesCopied = SendSilenceToBuffer(subChunkSamples);
- } else {
- bytesCopied = SendInterleavedSubChunkToBuffer(interleavedSource, subChunkSamples);
- }
- UpdateAfterSendChunk(subChunkSamples, bytesCopied, aSamplesRead);
- // Move to the position where samples are not yet send to the buffer.
- interleavedSource += subChunkSamples * mOMXAEncoder.mChannels;
- }
- }
- return BUFFER_OK;
- }
-
- // No audio data left in segment but we still have to feed something to
- // MediaCodec in order to notify EOS.
- void SendEOSToBuffer(size_t* aSamplesRead)
- {
- size_t bytesToCopy = SendSilenceToBuffer(1);
- IncreaseOffset(bytesToCopy);
- *aSamplesRead = 1;
- }
-
-private:
- uint8_t* GetPointer() { return mData + mOffset; }
-
- size_t AvailableSize() const { return mCapicity - mOffset; }
-
- void IncreaseOffset(size_t aValue)
- {
- // Should never out of bound.
- MOZ_ASSERT(mOffset + aValue <= mCapicity);
- mOffset += aValue;
- }
-
- bool IsEmpty() const
- {
- return (mOffset == 0);
- }
-
- size_t GetCapacity() const
- {
- return mCapicity;
- }
-
- // Update buffer offset, timestamp and the total number of copied samples.
- void UpdateAfterSendChunk(size_t aSamplesNum, size_t aBytesToCopy,
- size_t* aSourceSamplesCopied)
- {
- *aSourceSamplesCopied += aSamplesNum;
- mOMXAEncoder.mTimestamp += aSamplesNum * mOMXAEncoder.mSampleDuration;
- IncreaseOffset(aBytesToCopy);
- }
-
- // Send slince auido data when the chunk is null,
- // and return the copied bytes number of audio data.
- size_t SendSilenceToBuffer(size_t aSamplesNum)
- {
- AudioDataValue* dst = reinterpret_cast<AudioDataValue*>(GetPointer());
- size_t bytesToCopy = aSamplesNum * mOMXAEncoder.mResamplingRatio
- * mOMXAEncoder.mChannels * sizeof(AudioDataValue);
- memset(dst, 0, bytesToCopy);
- return bytesToCopy;
- }
-
- // Interleave chunk data and send it to buffer,
- // and return the copied bytes number of audio data.
- size_t SendChunkToBuffer(AudioChunk& aSource, size_t aSamplesNum)
- {
- AudioDataValue* dst = reinterpret_cast<AudioDataValue*>(GetPointer());
- size_t bytesToCopy = aSamplesNum * mOMXAEncoder.mResamplingRatio
- * mOMXAEncoder.mChannels * sizeof(AudioDataValue);
- uint32_t dstSamplesCopied = aSamplesNum;
- if (mOMXAEncoder.mResampler) {
- AutoTArray<AudioDataValue, 9600> pcm;
- pcm.SetLength(bytesToCopy);
- AudioTrackEncoder::InterleaveTrackData(aSource, aSamplesNum,
- mOMXAEncoder.mChannels,
- pcm.Elements());
- int16_t* tempSource = reinterpret_cast<int16_t*>(pcm.Elements());
- speex_resampler_process_interleaved_int(mOMXAEncoder.mResampler, tempSource,
- &aSamplesNum, dst,
- &dstSamplesCopied);
- } else {
- AudioTrackEncoder::InterleaveTrackData(aSource, aSamplesNum,
- mOMXAEncoder.mChannels, dst);
- }
- return dstSamplesCopied * mOMXAEncoder.mChannels * sizeof(AudioDataValue);
- }
-
- // Send the interleaved data of the sub chunk to buffer,
- // and return the copied bytes number of audio data.
- size_t SendInterleavedSubChunkToBuffer(AudioDataValue* aSource,
- size_t aSamplesNum)
- {
- AudioDataValue* dst = reinterpret_cast<AudioDataValue*>(GetPointer());
- uint32_t dstSamplesCopied = aSamplesNum;
- if (mOMXAEncoder.mResampler) {
- int16_t* tempSource = reinterpret_cast<int16_t*>(aSource);
- speex_resampler_process_interleaved_int(mOMXAEncoder.mResampler,
- tempSource, &aSamplesNum,
- dst, &dstSamplesCopied);
- } else {
- // Directly copy interleaved data into buffer
- memcpy(dst, aSource,
- aSamplesNum * mOMXAEncoder.mChannels * sizeof(AudioDataValue));
- }
- return dstSamplesCopied * mOMXAEncoder.mChannels * sizeof(AudioDataValue);
- }
-
- // Determine the size of sub-chunk (aSamplesToCopy) according to buffer capacity.
- // For subsequent call, the number of bytes remain to be copied will also be updated in this function.
- bool GetNextSubChunk(size_t& aBytesToCopy, size_t& aSamplesToCopy)
- {
- size_t bufferCapabity = GetCapacity();
- size_t sampleBytes = mOMXAEncoder.mChannels * mOMXAEncoder.mResamplingRatio
- * sizeof(AudioDataValue);
- if (aBytesToCopy) {
- if (aBytesToCopy > bufferCapabity) {
- aSamplesToCopy = bufferCapabity / sampleBytes;
- aBytesToCopy -= aSamplesToCopy * sampleBytes;
- } else {
- aSamplesToCopy = aBytesToCopy / sampleBytes;
- aBytesToCopy = 0;
- }
- return true;
- }
- return false;
- }
-
- sp<MediaCodec>& mCodec;
- Vector<sp<ABuffer> >& mBuffers;
- OMXAudioEncoder& mOMXAEncoder;
- int mInputFlags;
- size_t mIndex;
- uint8_t* mData;
- size_t mCapicity;
- size_t mOffset;
-};
-
-OMXAudioEncoder::~OMXAudioEncoder()
-{
- if (mResampler) {
- speex_resampler_destroy(mResampler);
- mResampler = nullptr;
- }
-}
-
-nsresult
-OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags,
- bool* aSendEOS)
-{
-#ifndef MOZ_SAMPLE_TYPE_S16
-#error MediaCodec accepts only 16-bit PCM data.
-#endif
-
- MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");
-
- size_t numSamples = aSegment.GetDuration();
-
- // Get input buffer.
- InputBufferHelper buffer(mCodec, mInputBufs, *this, aInputFlags);
- status_t result = buffer.Dequeue();
- if (result == -EAGAIN) {
- // All input buffers are full. Caller can try again later after consuming
- // some output buffers.
- return NS_OK;
- }
- NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
-
- size_t sourceSamplesCopied = 0; // Number of copied samples.
-
- if (numSamples > 0) {
- // Copy input PCM data to input buffer until queue is empty.
- AudioSegment::ChunkIterator iter(const_cast<AudioSegment&>(aSegment));
- while (!iter.IsEnded()) {
- BufferState result = buffer.ReadChunk(*iter, &sourceSamplesCopied);
- if (result == WAIT_FOR_NEW_BUFFER) {
- // All input buffers are full. Caller can try again later after
- // consuming some output buffers.
- aSegment.RemoveLeading(sourceSamplesCopied);
- return NS_OK;
- } else if (result == BUFFER_FAIL) {
- return NS_ERROR_FAILURE;
- } else {
- iter.Next();
- }
- }
- // Remove the samples already been copied into buffer
- if (sourceSamplesCopied > 0) {
- aSegment.RemoveLeading(sourceSamplesCopied);
- }
- } else if (aInputFlags & BUFFER_EOS) {
- buffer.SendEOSToBuffer(&sourceSamplesCopied);
- }
-
- // Enqueue the remaining data to buffer
- MOZ_ASSERT(sourceSamplesCopied > 0, "No data needs to be enqueued!");
- int flags = aInputFlags;
- if (aSegment.GetDuration() > 0) {
- // Don't signal EOS until source segment is empty.
- flags &= ~BUFFER_EOS;
- }
- result = buffer.Enqueue(mTimestamp, flags);
- NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
- if (aSendEOS && (aInputFlags & BUFFER_EOS)) {
- *aSendEOS = true;
- }
- return NS_OK;
-}
-
-// Generate decoder config descriptor (defined in ISO/IEC 14496-1 8.3.4.1) for
-// AAC. The hard-coded bytes are copied from
-// MPEG4Writer::Track::writeMp4aEsdsBox() implementation in libstagefright.
-status_t
-OMXAudioEncoder::AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
- ABuffer* aData)
-{
- MOZ_ASSERT(aData);
-
- const size_t csdSize = aData->size();
-
- // See
- // http://wiki.multimedia.cx/index.php?title=Understanding_AAC#Packaging.2FEncapsulation_And_Setup_Data
- // AAC decoder specific descriptor contains 2 bytes.
- NS_ENSURE_TRUE(csdSize == 2, ERROR_MALFORMED);
- // Encoder output must be consistent with kAACFrameDuration:
- // 14th bit (frame length flag) == 0 => 1024 (kAACFrameDuration) samples.
- NS_ENSURE_TRUE((aData->data()[1] & 0x04) == 0, ERROR_MALFORMED);
-
- // Decoder config descriptor
- const uint8_t decConfig[] = {
- 0x04, // Decoder config descriptor tag.
- uint8_t(15 + csdSize), // Size: following bytes + csd size.
- 0x40, // Object type: MPEG-4 audio.
- 0x15, // Stream type: audio, reserved: 1.
- 0x00, 0x03, 0x00, // Buffer size: 768 (kAACFrameSize).
- 0x00, 0x01, 0x77, 0x00, // Max bitrate: 96000 (kAACBitrate).
- 0x00, 0x01, 0x77, 0x00, // Avg bitrate: 96000 (kAACBitrate).
- 0x05, // Decoder specific descriptor tag.
- uint8_t(csdSize), // Data size.
- };
- // SL config descriptor.
- const uint8_t slConfig[] = {
- 0x06, // SL config descriptor tag.
- 0x01, // Size.
- 0x02, // Fixed value.
- };
-
- aOutputBuf->SetCapacity(sizeof(decConfig) + csdSize + sizeof(slConfig));
- aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
- aOutputBuf->AppendElements(aData->data(), csdSize);
- aOutputBuf->AppendElements(slConfig, sizeof(slConfig));
-
- return OK;
-}
-
-nsresult
-OMXCodecWrapper::GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
- int64_t* aOutputTimestamp,
- int* aOutputFlags, int64_t aTimeOut)
-{
- MOZ_ASSERT(mStarted,
- "Configure() should be called before GetNextEncodedFrame().");
-
- // Dequeue a buffer from output buffers.
- size_t index = 0;
- size_t outOffset = 0;
- size_t outSize = 0;
- int64_t outTimeUs = 0;
- uint32_t outFlags = 0;
- bool retry = false;
- do {
- status_t result = mCodec->dequeueOutputBuffer(&index, &outOffset, &outSize,
- &outTimeUs, &outFlags,
- aTimeOut);
- switch (result) {
- case OK:
- break;
- case INFO_OUTPUT_BUFFERS_CHANGED:
- // Update our references to new buffers.
- result = mCodec->getOutputBuffers(&mOutputBufs);
- // Get output from a new buffer.
- retry = true;
- break;
- case INFO_FORMAT_CHANGED:
- // It's okay: for encoder, MediaCodec reports this only to inform caller
- // that there will be a codec config buffer next.
- return NS_OK;
- case -EAGAIN:
- // Output buffer not available. Caller can try again later.
- return NS_OK;
- default:
- CODEC_ERROR("MediaCodec error:%d", result);
- MOZ_ASSERT(false, "MediaCodec error.");
- return NS_ERROR_FAILURE;
- }
- } while (retry);
-
- if (aOutputBuf) {
- aOutputBuf->Clear();
- const sp<ABuffer> omxBuf = mOutputBufs.itemAt(index);
- if (outFlags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
- // Codec specific data.
- if (AppendDecoderConfig(aOutputBuf, omxBuf.get()) != OK) {
- mCodec->releaseOutputBuffer(index);
- return NS_ERROR_FAILURE;
- }
- } else if ((mCodecType == AMR_NB_ENC) && !mAMRCSDProvided){
- // OMX AMR codec won't provide csd data, need to generate a fake one.
- RefPtr<EncodedFrame> audiodata = new EncodedFrame();
- // Decoder config descriptor
- const uint8_t decConfig[] = {
- 0x0, 0x0, 0x0, 0x0, // vendor: 4 bytes
- 0x0, // decoder version
- 0x83, 0xFF, // mode set: all enabled
- 0x00, // mode change period
- 0x01, // frames per sample
- };
- aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
- outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
- mAMRCSDProvided = true;
- } else if ((mCodecType == EVRC_ENC) && !mEVRCCSDProvided){
- // OMX EVRC codec won't provide csd data, need to generate a fake one.
- RefPtr<EncodedFrame> audiodata = new EncodedFrame();
- // Decoder config descriptor
- const uint8_t decConfig[] = {
- 0x0, 0x0, 0x0, 0x0, // vendor: 4 bytes
- 0x0, // decoder version
- 0x01, // frames per sample
- };
- aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
- outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
- mEVRCCSDProvided = true;
- } else {
- AppendFrame(aOutputBuf, omxBuf->data(), omxBuf->size());
- }
- }
- mCodec->releaseOutputBuffer(index);
-
- if (aOutputTimestamp) {
- *aOutputTimestamp = outTimeUs;
- }
-
- if (aOutputFlags) {
- *aOutputFlags = outFlags;
- }
-
- return NS_OK;
-}
-
-}
deleted file mode 100644
--- a/dom/media/omx/OMXCodecWrapper.h
+++ /dev/null
@@ -1,368 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef OMXCodecWrapper_h_
-#define OMXCodecWrapper_h_
-
-#include <gui/Surface.h>
-#include <utils/RefBase.h>
-#include <stagefright/foundation/ABuffer.h>
-#include <stagefright/foundation/AMessage.h>
-#include <stagefright/MediaCodec.h>
-
-#include "AudioSegment.h"
-#include "GonkNativeWindow.h"
-#include "mozilla/media/MediaSystemResourceClient.h"
-#include "mozilla/RefPtr.h"
-
-#include <speex/speex_resampler.h>
-
-namespace android {
-
-// Wrapper class for managing HW codec reservations
-class OMXCodecReservation : public RefBase
-{
-public:
- OMXCodecReservation(bool aEncoder) : mOwned(false)
- {
- mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
- mozilla::MediaSystemResourceType::VIDEO_DECODER;
- }
-
- virtual ~OMXCodecReservation()
- {
- ReleaseOMXCodec();
- }
-
- /** Reserve the Encode or Decode resource for this instance */
- virtual bool ReserveOMXCodec();
-
- /** Release the Encode or Decode resource for this instance */
- virtual void ReleaseOMXCodec();
-
-private:
- mozilla::MediaSystemResourceType mType;
- bool mOwned; // We already own this resource
-
- RefPtr<mozilla::MediaSystemResourceClient> mClient;
-};
-
-
-class OMXAudioEncoder;
-class OMXVideoEncoder;
-
-/**
- * This class (and its subclasses) wraps the video and audio codec from
- * MediaCodec API in libstagefright. Currently only AVC/H.264 video encoder and
- * AAC audio encoder are supported.
- *
- * OMXCodecWrapper has static creator functions that returns actual codec
- * instances for different types of codec supported and serves as superclass to
- * provide a function to read encoded data as byte array from codec. Two
- * subclasses, OMXAudioEncoder and OMXVideoEncoder, respectively provides
- * functions for encoding data from audio and video track.
- *
- * A typical usage is as follows:
- * - Call one of the creator function Create...() to get either a
- * OMXAudioEncoder or OMXVideoEncoder object.
- * - Configure codec by providing characteristics of input raw data, such as
- * video frame width and height, using Configure().
- * - Send raw data (and notify end of stream) with Encode().
- * - Get encoded data through GetNextEncodedFrame().
- * - Repeat previous 2 steps until end of stream.
- * - Destroy the object.
- *
- * The lifecycle of underlying OMX codec is binded with construction and
- * destruction of OMXCodecWrapper and subclass objects. For some types of
- * codecs, such as HW accelerated AVC/H.264 encoder, there can be only one
- * instance system-wise at a time, attempting to create another instance will
- * fail.
- */
-class OMXCodecWrapper
-{
-public:
- // Codec types.
- enum CodecType {
- AAC_ENC, // AAC encoder.
- AMR_NB_ENC, // AMR_NB encoder.
- AVC_ENC, // AVC/H.264 encoder.
- EVRC_ENC, // EVRC encoder
- TYPE_COUNT
- };
-
- // Input and output flags.
- enum {
- // For Encode() and Encode, it indicates the end of input stream;
- // For GetNextEncodedFrame(), it indicates the end of output
- // stream.
- BUFFER_EOS = MediaCodec::BUFFER_FLAG_EOS,
- // For GetNextEncodedFrame(). It indicates the output buffer is an I-frame.
- BUFFER_SYNC_FRAME = MediaCodec::BUFFER_FLAG_SYNCFRAME,
- // For GetNextEncodedFrame(). It indicates that the output buffer contains
- // codec specific configuration info. (SPS & PPS for AVC/H.264;
- // DecoderSpecificInfo for AAC)
- BUFFER_CODEC_CONFIG = MediaCodec::BUFFER_FLAG_CODECCONFIG,
- };
-
- // Hard-coded values for AAC DecoderConfigDescriptor in libstagefright.
- // See MPEG4Writer::Track::writeMp4aEsdsBox()
- // Exposed for the need of MP4 container writer.
- enum {
- kAACBitrate = 96000, // kbps
- kAACFrameSize = 768, // bytes
- kAACFrameDuration = 1024, // How many samples per AAC frame.
- };
-
- /** Create a AAC audio encoder. Returns nullptr when failed. */
- static OMXAudioEncoder* CreateAACEncoder();
-
- /** Create a AMR audio encoder. Returns nullptr when failed. */
- static OMXAudioEncoder* CreateAMRNBEncoder();
-
- /** Create a EVRC audio encoder. Returns nullptr when failed. */
- static OMXAudioEncoder* CreateEVRCEncoder();
-
- /** Create a AVC/H.264 video encoder. Returns nullptr when failed. */
- static OMXVideoEncoder* CreateAVCEncoder();
-
- virtual ~OMXCodecWrapper();
-
- /**
- * Get the next available encoded data from MediaCodec. The data will be
- * copied into aOutputBuf array, with its timestamp (in microseconds) in
- * aOutputTimestamp.
- * Wait at most aTimeout microseconds to dequeue a output buffer.
- */
- nsresult GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
- int64_t* aOutputTimestamp, int* aOutputFlags,
- int64_t aTimeOut);
- /*
- * Get the codec type
- */
- int GetCodecType() { return mCodecType; }
-protected:
- /**
- * See whether the object has been initialized successfully and is ready to
- * use.
- */
- virtual bool IsValid() { return mCodec != nullptr; }
-
- /**
- * Construct codec specific configuration blob with given data aData generated
- * by media codec and append it into aOutputBuf. Needed by MP4 container
- * writer for generating decoder config box, or WebRTC for generating RTP
- * packets. Returns OK if succeed.
- */
- virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
- ABuffer* aData) = 0;
-
- /**
- * Append encoded frame data generated by media codec (stored in aData and
- * is aSize bytes long) into aOutputBuf. Subclasses can override this function
- * to process the data for specific container writer.
- */
- virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf,
- const uint8_t* aData, size_t aSize)
- {
- aOutputBuf->AppendElements(aData, aSize);
- }
-
-private:
- // Hide these. User should always use creator functions to get a media codec.
- OMXCodecWrapper() = delete;
- OMXCodecWrapper(const OMXCodecWrapper&) = delete;
- OMXCodecWrapper& operator=(const OMXCodecWrapper&) = delete;
-
- /**
- * Create a media codec of given type. It will be a AVC/H.264 video encoder if
- * aCodecType is CODEC_AVC_ENC, or AAC audio encoder if aCodecType is
- * CODEC_AAC_ENC.
- */
- OMXCodecWrapper(CodecType aCodecType);
-
- // For subclasses to access hidden constructor and implementation details.
- friend class OMXAudioEncoder;
- friend class OMXVideoEncoder;
-
- /**
- * Start the media codec.
- */
- status_t Start();
-
- /**
- * Stop the media codec.
- */
- status_t Stop();
-
- // The actual codec instance provided by libstagefright.
- sp<MediaCodec> mCodec;
-
- // A dedicate message loop with its own thread used by MediaCodec.
- sp<ALooper> mLooper;
-
- Vector<sp<ABuffer> > mInputBufs; // MediaCodec buffers to hold input data.
- Vector<sp<ABuffer> > mOutputBufs; // MediaCodec buffers to hold output data.
-
- int mCodecType;
- bool mStarted; // Has MediaCodec been started?
- bool mAMRCSDProvided;
- bool mEVRCCSDProvided;
-};
-
-/**
- * Audio encoder.
- */
-class OMXAudioEncoder final : public OMXCodecWrapper
-{
-public:
- /**
- * Configure audio codec parameters and start media codec. It must be called
- * before calling Encode() and GetNextEncodedFrame().
- * aReSamplingRate = 0 means no resampler required
- */
- nsresult Configure(int aChannelCount, int aInputSampleRate, int aEncodedSampleRate);
-
- /**
- * Encode 16-bit PCM audio samples stored in aSegment. To notify end of
- * stream, set aInputFlags to BUFFER_EOS. Since encoder has limited buffers,
- * this function might not be able to encode all chunks in one call, however
- * it will remove chunks it consumes from aSegment.
- * aSendEOS is the output to tell the caller EOS signal sent into MediaCodec
- * because the signal might not be sent due to the dequeueInputBuffer timeout.
- * And the value of aSendEOS won't be set to any default value, only set to
- * true when EOS signal sent into MediaCodec.
- */
- nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0,
- bool* aSendEOS = nullptr);
-
- ~OMXAudioEncoder();
-protected:
- virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
- ABuffer* aData) override;
-private:
- // Hide these. User should always use creator functions to get a media codec.
- OMXAudioEncoder() = delete;
- OMXAudioEncoder(const OMXAudioEncoder&) = delete;
- OMXAudioEncoder& operator=(const OMXAudioEncoder&) = delete;
-
- /**
- * Create a audio codec. It will be a AAC encoder if aCodecType is
- * CODEC_AAC_ENC.
- */
- OMXAudioEncoder(CodecType aCodecType)
- : OMXCodecWrapper(aCodecType)
- , mResampler(nullptr)
- , mChannels(0)
- , mResamplingRatio(0)
- , mTimestamp(0)
- , mSampleDuration(0) {}
-
- // For creator function to access hidden constructor.
- friend class OMXCodecWrapper;
- friend class InputBufferHelper;
-
- /**
- * If the input sample rate does not divide 48kHz evenly, the input data are
- * resampled.
- */
- SpeexResamplerState* mResampler;
- // Number of audio channels.
- size_t mChannels;
-
- float mResamplingRatio;
- // The total duration of audio samples that have been encoded in microseconds.
- int64_t mTimestamp;
- // Time per audio sample in microseconds.
- int64_t mSampleDuration;
-};
-
-/**
- * Video encoder.
- */
-class OMXVideoEncoder final : public OMXCodecWrapper
-{
-public:
- // Types of output blob format.
- enum BlobFormat {
- AVC_MP4, // MP4 file config descripter (defined in ISO/IEC 14496-15 5.2.4.1.1)
- AVC_NAL // NAL (Network Abstract Layer) (defined in ITU-T H.264 7.4.1)
- };
-
- /**
- * Configure video codec parameters and start media codec. It must be called
- * before calling Encode() and GetNextEncodedFrame().
- * aBlobFormat specifies output blob format provided by encoder. It can be
- * AVC_MP4 or AVC_NAL.
- * Configure sets up most format value to values appropriate for camera use.
- * ConfigureDirect lets the caller determine all the defaults.
- */
- nsresult Configure(int aWidth, int aHeight, int aFrameRate,
- BlobFormat aBlobFormat = BlobFormat::AVC_MP4);
- nsresult ConfigureDirect(sp<AMessage>& aFormat,
- BlobFormat aBlobFormat = BlobFormat::AVC_MP4);
-
- /**
- * Encode a aWidth pixels wide and aHeight pixels tall video frame of
- * semi-planar YUV420 format stored in the buffer of aImage. aTimestamp gives
- * the frame timestamp/presentation time (in microseconds). To notify end of
- * stream, set aInputFlags to BUFFER_EOS.
- * aSendEOS is the output to tell the caller EOS signal sent into MediaCodec
- * because the signal might not be sent due to the dequeueInputBuffer timeout.
- * And the value of aSendEOS won't be set to any default value, only set to
- * true when EOS signal sent into MediaCodec.
- */
- nsresult Encode(const mozilla::layers::Image* aImage, int aWidth, int aHeight,
- int64_t aTimestamp, int aInputFlags = 0,
- bool* aSendEOS = nullptr);
-
-#if ANDROID_VERSION >= 18
- /** Set encoding bitrate (in kbps). */
- nsresult SetBitrate(int32_t aKbps);
-#endif
-
- /**
- * Ask codec to generate an instantaneous decoding refresh (IDR) frame
- * (defined in ISO/IEC 14496-10).
- */
- nsresult RequestIDRFrame();
-
-protected:
- virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
- ABuffer* aData) override;
-
- // If configured to output MP4 format blob, AVC/H.264 encoder has to replace
- // NAL unit start code with the unit length as specified in
- // ISO/IEC 14496-15 5.2.3.
- virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf,
- const uint8_t* aData, size_t aSize) override;
-
-private:
- // Hide these. User should always use creator functions to get a media codec.
- OMXVideoEncoder() = delete;
- OMXVideoEncoder(const OMXVideoEncoder&) = delete;
- OMXVideoEncoder& operator=(const OMXVideoEncoder&) = delete;
-
- /**
- * Create a video codec. It will be a AVC/H.264 encoder if aCodecType is
- * CODEC_AVC_ENC.
- */
- OMXVideoEncoder(CodecType aCodecType)
- : OMXCodecWrapper(aCodecType)
- , mWidth(0)
- , mHeight(0)
- , mBlobFormat(BlobFormat::AVC_MP4)
- {}
-
- // For creator function to access hidden constructor.
- friend class OMXCodecWrapper;
-
- int mWidth;
- int mHeight;
- BlobFormat mBlobFormat;
-};
-
-} // namespace android
-
-#endif // OMXCodecWrapper_h_
deleted file mode 100644
--- a/dom/media/omx/OmxDecoder.cpp
+++ /dev/null
@@ -1,940 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "base/basictypes.h"
-#include <cutils/properties.h>
-#include <stagefright/foundation/ADebug.h>
-#include <stagefright/foundation/AMessage.h>
-#include <stagefright/MediaExtractor.h>
-#include <stagefright/MetaData.h>
-#include <stagefright/OMXClient.h>
-#include <stagefright/OMXCodec.h>
-#include <OMX.h>
-#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
-#include <ui/Fence.h>
-#endif
-
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
-#include <gui/Surface.h>
-#else
-#include <gui/SurfaceTextureClient.h>
-#endif
-
-#include "mozilla/layers/GrallocTextureClient.h"
-#include "mozilla/layers/TextureClient.h"
-#include "mozilla/Types.h"
-#include "mozilla/Monitor.h"
-#include "nsMimeTypes.h"
-#include "MPAPI.h"
-#include "mozilla/Logging.h"
-
-#include "GonkNativeWindow.h"
-#include "OMXCodecProxy.h"
-#include "OmxDecoder.h"
-
-#include <android/log.h>
-#define OD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "OmxDecoder", __VA_ARGS__)
-
-#undef LOG
-mozilla::LazyLogModule gOmxDecoderLog("OmxDecoder");
-#define LOG(type, msg...) MOZ_LOG(gOmxDecoderLog, type, (msg))
-
-using namespace MPAPI;
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::layers;
-using namespace android;
-
-OmxDecoder::OmxDecoder(AbstractMediaDecoder *aDecoder,
- mozilla::TaskQueue* aTaskQueue) :
- mDecoder(aDecoder),
- mDisplayWidth(0),
- mDisplayHeight(0),
- mVideoWidth(0),
- mVideoHeight(0),
- mVideoColorFormat(0),
- mVideoStride(0),
- mVideoSliceHeight(0),
- mVideoRotation(0),
- mAudioChannels(-1),
- mAudioSampleRate(-1),
- mDurationUs(-1),
- mLastSeekTime(-1),
- mVideoBuffer(nullptr),
- mAudioBuffer(nullptr),
- mIsVideoSeeking(false),
- mAudioMetadataRead(false),
- mTaskQueue(aTaskQueue),
- mAudioPaused(false),
- mVideoPaused(false)
-{
- mLooper = new ALooper;
- mLooper->setName("OmxDecoder");
-
- mReflector = new AHandlerReflector<OmxDecoder>(this);
- // Register AMessage handler to ALooper.
- mLooper->registerHandler(mReflector);
- // Start ALooper thread.
- mLooper->start();
-}
-
-OmxDecoder::~OmxDecoder()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- ReleaseMediaResources();
-
- // unregister AMessage handler from ALooper.
- mLooper->unregisterHandler(mReflector->id());
- // Stop ALooper thread.
- mLooper->stop();
-}
-
-static sp<IOMX> sOMX = nullptr;
-static sp<IOMX> GetOMX()
-{
- if(sOMX.get() == nullptr) {
- sOMX = new OMX;
- }
- return sOMX;
-}
-
-bool
-OmxDecoder::Init(sp<MediaExtractor>& extractor) {
- sp<MetaData> meta = extractor->getMetaData();
-
- ssize_t audioTrackIndex = -1;
- ssize_t videoTrackIndex = -1;
-
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- int32_t bitRate;
- if (!meta->findInt32(kKeyBitRate, &bitRate))
- bitRate = 0;
-
- const char *mime;
- if (!meta->findCString(kKeyMIMEType, &mime)) {
- continue;
- }
-
- if (videoTrackIndex == -1 && !strncasecmp(mime, "video/", 6)) {
- videoTrackIndex = i;
- } else if (audioTrackIndex == -1 && !strncasecmp(mime, "audio/", 6)) {
- audioTrackIndex = i;
- }
- }
-
- if (videoTrackIndex == -1 && audioTrackIndex == -1) {
- NS_WARNING("OMX decoder could not find video or audio tracks");
- return false;
- }
-
- if (videoTrackIndex != -1 && mDecoder->GetImageContainer()) {
- mVideoTrack = extractor->getTrack(videoTrackIndex);
- }
-
- if (audioTrackIndex != -1) {
- mAudioTrack = extractor->getTrack(audioTrackIndex);
-
-#ifdef MOZ_AUDIO_OFFLOAD
- // mAudioTrack is be used by OMXCodec. For offloaded audio track, using same
- // object gives undetermined behavior. So get a new track
- mAudioOffloadTrack = extractor->getTrack(audioTrackIndex);
-#endif
- }
- return true;
-}
-
-bool
-OmxDecoder::EnsureMetadata() {
- // calculate duration
- int64_t totalDurationUs = 0;
- int64_t durationUs = 0;
- if (mVideoTrack.get() && mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > totalDurationUs)
- totalDurationUs = durationUs;
- }
- if (mAudioTrack.get()) {
- durationUs = -1;
- sp<MetaData> meta = mAudioTrack->getFormat();
-
- if ((durationUs == -1) && meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > totalDurationUs) {
- totalDurationUs = durationUs;
- }
- }
- }
- mDurationUs = totalDurationUs;
-
- // read video metadata
- if (mVideoSource.get() && !SetVideoFormat()) {
- NS_WARNING("Couldn't set OMX video format");
- return false;
- }
-
- // read audio metadata
- if (mAudioSource.get()) {
- // To reliably get the channel and sample rate data we need to read from the
- // audio source until we get a INFO_FORMAT_CHANGE status
- status_t err = mAudioSource->read(&mAudioBuffer);
- if (err != INFO_FORMAT_CHANGED) {
- if (err != OK) {
- NS_WARNING("Couldn't read audio buffer from OMX decoder");
- return false;
- }
- sp<MetaData> meta = mAudioSource->getFormat();
- if (!meta->findInt32(kKeyChannelCount, &mAudioChannels) ||
- !meta->findInt32(kKeySampleRate, &mAudioSampleRate)) {
- NS_WARNING("Couldn't get audio metadata from OMX decoder");
- return false;
- }
- mAudioMetadataRead = true;
- }
- else if (!SetAudioFormat()) {
- NS_WARNING("Couldn't set audio format");
- return false;
- }
- }
-
- return true;
-}
-
-static bool isInEmulator()
-{
- char propQemu[PROPERTY_VALUE_MAX];
- property_get("ro.kernel.qemu", propQemu, "");
- return !strncmp(propQemu, "1", 1);
-}
-
-RefPtr<mozilla::MediaOmxCommonReader::MediaResourcePromise>
-OmxDecoder::AllocateMediaResources()
-{
- RefPtr<MediaResourcePromise> p = mMediaResourcePromise.Ensure(__func__);
-
- if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) {
- // OMXClient::connect() always returns OK and abort's fatally if
- // it can't connect.
- OMXClient client;
- DebugOnly<status_t> err = client.connect();
- NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
- sp<IOMX> omx = client.interface();
-
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
- sp<IGraphicBufferProducer> producer;
- sp<IGonkGraphicBufferConsumer> consumer;
- GonkBufferQueue::createBufferQueue(&producer, &consumer);
- mNativeWindow = new GonkNativeWindow(consumer);
-#else
- mNativeWindow = new GonkNativeWindow();
-#endif
-
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
- mNativeWindowClient = new Surface(producer);
-#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
- mNativeWindowClient = new Surface(mNativeWindow->getBufferQueue());
-#else
- mNativeWindowClient = new SurfaceTextureClient(mNativeWindow);
-#endif
-
- // Experience with OMX codecs is that only the HW decoders are
- // worth bothering with, at least on the platforms where this code
- // is currently used, and for formats this code is currently used
- // for (h.264). So if we don't get a hardware decoder, just give
- // up.
-#ifdef MOZ_OMX_WEBM_DECODER
- int flags = 0;//fallback to omx sw decoder if there is no hw decoder
-#else
- int flags = kHardwareCodecsOnly;
-#endif//MOZ_OMX_WEBM_DECODER
-
- if (isInEmulator()) {
- // If we are in emulator, allow to fall back to software.
- flags = 0;
- }
- mVideoSource =
- OMXCodecProxy::Create(omx,
- mVideoTrack->getFormat(),
- false, // decoder
- mVideoTrack,
- nullptr,
- flags,
- mNativeWindowClient);
- if (mVideoSource == nullptr) {
- NS_WARNING("Couldn't create OMX video source");
- mMediaResourcePromise.Reject(true, __func__);
- return p;
- } else {
- sp<OmxDecoder> self = this;
- mVideoCodecRequest.Begin(mVideoSource->requestResource()
- ->Then(OwnerThread(), __func__,
- [self] (bool) -> void {
- self->mVideoCodecRequest.Complete();
- self->mMediaResourcePromise.ResolveIfExists(true, __func__);
- }, [self] (bool) -> void {
- self->mVideoCodecRequest.Complete();
- self->mMediaResourcePromise.RejectIfExists(true, __func__);
- }));
- }
- }
-
- if ((mAudioTrack != nullptr) && (mAudioSource == nullptr)) {
- // OMXClient::connect() always returns OK and abort's fatally if
- // it can't connect.
- OMXClient client;
- DebugOnly<status_t> err = client.connect();
- NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
- sp<IOMX> omx = client.interface();
-
- const char *audioMime = nullptr;
- sp<MetaData> meta = mAudioTrack->getFormat();
- if (!meta->findCString(kKeyMIMEType, &audioMime)) {
- mMediaResourcePromise.Reject(true, __func__);
- return p;
- }
- if (!strcasecmp(audioMime, "audio/raw")) {
- mAudioSource = mAudioTrack;
- } else {
- // try to load hardware codec in mediaserver process.
- int flags = kHardwareCodecsOnly;
- mAudioSource = OMXCodec::Create(omx,
- mAudioTrack->getFormat(),
- false, // decoder
- mAudioTrack,
- nullptr,
- flags);
- }
-
- if (mAudioSource == nullptr) {
- // try to load software codec in this process.
- int flags = kSoftwareCodecsOnly;
- mAudioSource = OMXCodec::Create(GetOMX(),
- mAudioTrack->getFormat(),
- false, // decoder
- mAudioTrack,
- nullptr,
- flags);
- if (mAudioSource == nullptr) {
- NS_WARNING("Couldn't create OMX audio source");
- mMediaResourcePromise.Reject(true, __func__);
- return p;
- }
- }
- if (mAudioSource->start() != OK) {
- NS_WARNING("Couldn't start OMX audio source");
- mAudioSource.clear();
- mMediaResourcePromise.Reject(true, __func__);
- return p;
- }
- }
- if (!mVideoSource.get()) {
- // No resource allocation wait.
- mMediaResourcePromise.Resolve(true, __func__);
- }
- return p;
-}
-
-
-void
-OmxDecoder::ReleaseMediaResources() {
- mVideoCodecRequest.DisconnectIfExists();
- mMediaResourcePromise.RejectIfExists(true, __func__);
-
- ReleaseVideoBuffer();
- ReleaseAudioBuffer();
-
- {
- Mutex::Autolock autoLock(mPendingVideoBuffersLock);
- MOZ_ASSERT(mPendingRecycleTexutreClients.empty());
- // Release all pending recycle TextureClients, if they are not recycled yet.
- // This should not happen. See Bug 1042308.
- if (!mPendingRecycleTexutreClients.empty()) {
- printf_stderr("OmxDecoder::ReleaseMediaResources -- TextureClients are not recycled yet\n");
- for (std::set<TextureClient*>::iterator it=mPendingRecycleTexutreClients.begin();
- it!=mPendingRecycleTexutreClients.end(); it++)
- {
- GrallocTextureData* client = static_cast<GrallocTextureData*>((*it)->GetInternalData());
- (*it)->ClearRecycleCallback();
- if (client->GetMediaBuffer()) {
- mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), (*it)->GetAndResetReleaseFenceHandle()));
- }
- }
- mPendingRecycleTexutreClients.clear();
- }
- }
-
- {
- // Free all pending video buffers.
- Mutex::Autolock autoLock(mSeekLock);
- ReleaseAllPendingVideoBuffersLocked();
- }
-
- if (mVideoSource.get()) {
- mVideoSource->stop();
- mVideoSource.clear();
- }
-
- if (mAudioSource.get()) {
- mAudioSource->stop();
- mAudioSource.clear();
- }
-
- mNativeWindowClient.clear();
- mNativeWindow.clear();
-
- // Reset this variable to make the first seek go to the previous keyframe
- // when resuming
- mLastSeekTime = -1;
-}
-
-bool
-OmxDecoder::SetVideoFormat() {
- const char *componentName;
-
- if (!mVideoSource->getFormat()->findInt32(kKeyWidth, &mVideoWidth) ||
- !mVideoSource->getFormat()->findInt32(kKeyHeight, &mVideoHeight) ||
- !mVideoSource->getFormat()->findCString(kKeyDecoderComponent, &componentName) ||
- !mVideoSource->getFormat()->findInt32(kKeyColorFormat, &mVideoColorFormat) ) {
- return false;
- }
-
- if (!mVideoTrack.get() || !mVideoTrack->getFormat()->findInt32(kKeyDisplayWidth, &mDisplayWidth)) {
- mDisplayWidth = mVideoWidth;
- NS_WARNING("display width not available, assuming width");
- }
-
- if (!mVideoTrack.get() || !mVideoTrack->getFormat()->findInt32(kKeyDisplayHeight, &mDisplayHeight)) {
- mDisplayHeight = mVideoHeight;
- NS_WARNING("display height not available, assuming height");
- }
-
- if (!mVideoSource->getFormat()->findInt32(kKeyStride, &mVideoStride)) {
- mVideoStride = mVideoWidth;
- NS_WARNING("stride not available, assuming width");
- }
-
- if (!mVideoSource->getFormat()->findInt32(kKeySliceHeight, &mVideoSliceHeight)) {
- mVideoSliceHeight = mVideoHeight;
- NS_WARNING("slice height not available, assuming height");
- }
-
- // Since ICS, valid video side is caluculated from kKeyCropRect.
- // kKeyWidth means decoded video buffer width.
- // kKeyHeight means decoded video buffer height.
- // On some hardwares, decoded video buffer and valid video size are different.
- int32_t crop_left, crop_top, crop_right, crop_bottom;
- if (mVideoSource->getFormat()->findRect(kKeyCropRect,
- &crop_left,
- &crop_top,
- &crop_right,
- &crop_bottom)) {
- mVideoWidth = crop_right - crop_left + 1;
- mVideoHeight = crop_bottom - crop_top + 1;
- }
-
- if (!mVideoSource->getFormat()->findInt32(kKeyRotation, &mVideoRotation)) {
- mVideoRotation = 0;
- NS_WARNING("rotation not available, assuming 0");
- }
-
- LOG(LogLevel::Debug, "display width: %d display height %d width: %d height: %d component: %s format: %d stride: %d sliceHeight: %d rotation: %d",
- mDisplayWidth, mDisplayHeight, mVideoWidth, mVideoHeight, componentName,
- mVideoColorFormat, mVideoStride, mVideoSliceHeight, mVideoRotation);
-
- return true;
-}
-
-bool
-OmxDecoder::SetAudioFormat() {
- // If the format changed, update our cached info.
- if (!mAudioSource->getFormat()->findInt32(kKeyChannelCount, &mAudioChannels) ||
- !mAudioSource->getFormat()->findInt32(kKeySampleRate, &mAudioSampleRate)) {
- return false;
- }
-
- LOG(LogLevel::Debug, "channelCount: %d sampleRate: %d",
- mAudioChannels, mAudioSampleRate);
-
- return true;
-}
-
-void
-OmxDecoder::ReleaseDecoder()
-{
- mDecoder = nullptr;
-}
-
-void
-OmxDecoder::ReleaseVideoBuffer() {
- if (mVideoBuffer) {
- mVideoBuffer->release();
- mVideoBuffer = nullptr;
- }
-}
-
-void
-OmxDecoder::ReleaseAudioBuffer() {
- if (mAudioBuffer) {
- mAudioBuffer->release();
- mAudioBuffer = nullptr;
- }
-}
-
-void
-OmxDecoder::PlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
- void *y = aData;
- void *u = static_cast<uint8_t *>(y) + mVideoStride * mVideoSliceHeight;
- void *v = static_cast<uint8_t *>(u) + mVideoStride/2 * mVideoSliceHeight/2;
-
- aFrame->Set(aTimeUs, aKeyFrame,
- aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation,
- y, mVideoStride, mVideoWidth, mVideoHeight, 0, 0,
- u, mVideoStride/2, mVideoWidth/2, mVideoHeight/2, 0, 0,
- v, mVideoStride/2, mVideoWidth/2, mVideoHeight/2, 0, 0);
-}
-
-void
-OmxDecoder::CbYCrYFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
- aFrame->Set(aTimeUs, aKeyFrame,
- aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation,
- aData, mVideoStride, mVideoWidth, mVideoHeight, 1, 1,
- aData, mVideoStride, mVideoWidth/2, mVideoHeight/2, 0, 3,
- aData, mVideoStride, mVideoWidth/2, mVideoHeight/2, 2, 3);
-}
-
-void
-OmxDecoder::SemiPlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
- void *y = aData;
- void *uv = static_cast<uint8_t *>(y) + (mVideoStride * mVideoSliceHeight);
-
- aFrame->Set(aTimeUs, aKeyFrame,
- aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation,
- y, mVideoStride, mVideoWidth, mVideoHeight, 0, 0,
- uv, mVideoStride, mVideoWidth/2, mVideoHeight/2, 0, 1,
- uv, mVideoStride, mVideoWidth/2, mVideoHeight/2, 1, 1);
-}
-
-void
-OmxDecoder::SemiPlanarYVU420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
- SemiPlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
- aFrame->Cb.mOffset = 1;
- aFrame->Cr.mOffset = 0;
-}
-
-bool
-OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
- const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
-
- aFrame->mGraphicBuffer = nullptr;
-
- switch (mVideoColorFormat) {
- case OMX_COLOR_FormatYUV420Planar:
- PlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
- break;
- case OMX_COLOR_FormatCbYCrY:
- CbYCrYFrame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
- break;
- case OMX_COLOR_FormatYUV420SemiPlanar:
- SemiPlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
- break;
- case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
- SemiPlanarYVU420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
- break;
- default:
- LOG(LogLevel::Debug, "Unknown video color format %08x", mVideoColorFormat);
- return false;
- }
- return true;
-}
-
-bool
-OmxDecoder::ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize, int32_t aAudioChannels, int32_t aAudioSampleRate)
-{
- aFrame->Set(aTimeUs, static_cast<char *>(aData) + aDataOffset, aSize, aAudioChannels, aAudioSampleRate);
- return true;
-}
-
-bool
-OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
- bool aKeyframeSkip, bool aDoSeek)
-{
- if (!mVideoSource.get())
- return false;
-
- ReleaseVideoBuffer();
-
- status_t err;
-
- if (aDoSeek) {
- {
- Mutex::Autolock autoLock(mSeekLock);
- ReleaseAllPendingVideoBuffersLocked();
- mIsVideoSeeking = true;
- }
- MediaSource::ReadOptions options;
- MediaSource::ReadOptions::SeekMode seekMode;
- // If the last timestamp of decoded frame is smaller than seekTime,
- // seek to next key frame. Otherwise seek to the previos one.
- OD_LOG("SeekTime: %lld, mLastSeekTime:%lld", aTimeUs, mLastSeekTime);
- if (mLastSeekTime == -1 || mLastSeekTime > aTimeUs) {
- seekMode = MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
- } else {
- seekMode = MediaSource::ReadOptions::SEEK_NEXT_SYNC;
- }
- mLastSeekTime = aTimeUs;
- bool findNextBuffer = true;
- while (findNextBuffer) {
- options.setSeekTo(aTimeUs, seekMode);
- findNextBuffer = false;
- if (mIsVideoSeeking) {
- err = mVideoSource->read(&mVideoBuffer, &options);
- Mutex::Autolock autoLock(mSeekLock);
- mIsVideoSeeking = false;
- PostReleaseVideoBuffer(nullptr, FenceHandle());
- }
- else {
- err = mVideoSource->read(&mVideoBuffer);
- }
-
- // If there is no next Keyframe, jump to the previous key frame.
- if (err == ERROR_END_OF_STREAM && seekMode == MediaSource::ReadOptions::SEEK_NEXT_SYNC) {
- seekMode = MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
- findNextBuffer = true;
- {
- Mutex::Autolock autoLock(mSeekLock);
- mIsVideoSeeking = true;
- }
- continue;
- } else if (err != OK) {
- OD_LOG("Unexpected error when seeking to %lld", aTimeUs);
- break;
- }
- // For some codecs, the length of first decoded frame after seek is 0.
- // Need to ignore it and continue to find the next one
- if (mVideoBuffer->range_length() == 0) {
- PostReleaseVideoBuffer(mVideoBuffer, FenceHandle());
- findNextBuffer = true;
- }
- }
- aDoSeek = false;
- } else {
- err = mVideoSource->read(&mVideoBuffer);
- }
-
- aFrame->mSize = 0;
-
- if (err == OK) {
- int64_t timeUs;
- int32_t unreadable;
- int32_t keyFrame;
-
- size_t length = mVideoBuffer->range_length();
-
- if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) {
- NS_WARNING("OMX decoder did not return frame time");
- return false;
- }
-
- if (!mVideoBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) {
- keyFrame = 0;
- }
-
- if (!mVideoBuffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)) {
- unreadable = 0;
- }
-
- RefPtr<mozilla::layers::TextureClient> textureClient;
- if ((mVideoBuffer->graphicBuffer().get())) {
- textureClient = mNativeWindow->getTextureClientFromBuffer(mVideoBuffer->graphicBuffer().get());
- }
-
- if (textureClient) {
- // Manually increment reference count to keep MediaBuffer alive
- // during TextureClient is in use.
- mVideoBuffer->add_ref();
- static_cast<GrallocTextureData*>(textureClient->GetInternalData())->SetMediaBuffer(mVideoBuffer);
- // Set recycle callback for TextureClient
- textureClient->SetRecycleCallback(OmxDecoder::RecycleCallback, this);
- {
- Mutex::Autolock autoLock(mPendingVideoBuffersLock);
- // Store pending recycle TextureClient.
- MOZ_ASSERT(mPendingRecycleTexutreClients.find(textureClient) == mPendingRecycleTexutreClients.end());
- mPendingRecycleTexutreClients.insert(textureClient);
- }
-
- aFrame->mGraphicBuffer = textureClient;
- aFrame->mRotation = mVideoRotation;
- aFrame->mTimeUs = timeUs;
- aFrame->mKeyFrame = keyFrame;
- aFrame->Y.mWidth = mVideoWidth;
- aFrame->Y.mHeight = mVideoHeight;
- // Release to hold video buffer in OmxDecoder more.
- // MediaBuffer's ref count is changed from 2 to 1.
- ReleaseVideoBuffer();
- } else if (length > 0) {
- char *data = static_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
-
- if (unreadable) {
- LOG(LogLevel::Debug, "video frame is unreadable");
- }
-
- if (!ToVideoFrame(aFrame, timeUs, data, length, keyFrame)) {
- return false;
- }
- }
- // Check if this frame is valid or not. If not, skip it.
- if ((aKeyframeSkip && timeUs < aTimeUs) || length == 0) {
- aFrame->mShouldSkip = true;
- }
- }
- else if (err == INFO_FORMAT_CHANGED) {
- // If the format changed, update our cached info.
- if (!SetVideoFormat()) {
- return false;
- } else {
- return ReadVideo(aFrame, aTimeUs, aKeyframeSkip, aDoSeek);
- }
- }
- else if (err == ERROR_END_OF_STREAM) {
- return false;
- }
- else if (err == -ETIMEDOUT) {
- LOG(LogLevel::Debug, "OmxDecoder::ReadVideo timed out, will retry");
- return true;
- }
- else {
- // UNKNOWN_ERROR is sometimes is used to mean "out of memory", but
- // regardless, don't keep trying to decode if the decoder doesn't want to.
- LOG(LogLevel::Debug, "OmxDecoder::ReadVideo failed, err=%d", err);
- return false;
- }
-
- return true;
-}
-
-bool
-OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
-{
- status_t err;
-
- if (mAudioMetadataRead && aSeekTimeUs == -1) {
- // Use the data read into the buffer during metadata time
- err = OK;
- }
- else {
- ReleaseAudioBuffer();
- if (aSeekTimeUs != -1) {
- MediaSource::ReadOptions options;
- options.setSeekTo(aSeekTimeUs);
- err = mAudioSource->read(&mAudioBuffer, &options);
- } else {
- err = mAudioSource->read(&mAudioBuffer);
- }
- }
- mAudioMetadataRead = false;
-
- aSeekTimeUs = -1;
- aFrame->mSize = 0;
-
- if (err == OK && mAudioBuffer && mAudioBuffer->range_length() != 0) {
- int64_t timeUs;
- if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs))
- return false;
-
- return ToAudioFrame(aFrame, timeUs,
- mAudioBuffer->data(),
- mAudioBuffer->range_offset(),
- mAudioBuffer->range_length(),
- mAudioChannels, mAudioSampleRate);
- }
- else if (err == INFO_FORMAT_CHANGED) {
- // If the format changed, update our cached info.
- if (!SetAudioFormat()) {
- return false;
- } else {
- return ReadAudio(aFrame, aSeekTimeUs);
- }
- }
- else if (err == ERROR_END_OF_STREAM) {
- if (aFrame->mSize == 0) {
- return false;
- }
- }
- else if (err == -ETIMEDOUT) {
- LOG(LogLevel::Debug, "OmxDecoder::ReadAudio timed out, will retry");
- return true;
- }
- else if (err != OK) {
- LOG(LogLevel::Debug, "OmxDecoder::ReadAudio failed, err=%d", err);
- return false;
- }
-
- return true;
-}
-
-nsresult
-OmxDecoder::Play()
-{
- if (!mVideoPaused && !mAudioPaused) {
- return NS_OK;
- }
-
- if (mVideoPaused && mVideoSource.get() && mVideoSource->start() != OK) {
- return NS_ERROR_UNEXPECTED;
- }
- mVideoPaused = false;
-
- if (mAudioPaused && mAudioSource.get() && mAudioSource->start() != OK) {
- return NS_ERROR_UNEXPECTED;
- }
- mAudioPaused = false;
-
- return NS_OK;
-}
-
-// AOSP didn't give implementation on OMXCodec::Pause() and not define
-// OMXCodec::Start() should be called for resuming the decoding. Currently
-// it is customized by a specific open source repository only.
-// ToDo The one not supported OMXCodec::Pause() should return error code here,
-// so OMXCodec::Start() doesn't be called again for resuming. But if someone
-// implement the OMXCodec::Pause() and need a following OMXCodec::Read() with
-// seek option (define in MediaSource.h) then it is still not supported here.
-// We need to fix it until it is really happened.
-void
-OmxDecoder::Pause()
-{
- /* The implementation of OMXCodec::pause is flawed.
- * OMXCodec::start will not restore from the paused state and result in
- * buffer timeout which causes timeouts in mochitests.
- * Since there is not power consumption problem in emulator, we will just
- * return when running in emulator to fix timeouts in mochitests.
- */
- if (isInEmulator()) {
- return;
- }
-
- if (mVideoPaused || mAudioPaused) {
- return;
- }
-
- if (mVideoSource.get() && mVideoSource->pause() == OK) {
- mVideoPaused = true;
- }
-
- if (mAudioSource.get() && mAudioSource->pause() == OK) {
- mAudioPaused = true;
- }
-}
-
-// Called on ALooper thread.
-void
-OmxDecoder::onMessageReceived(const sp<AMessage> &msg)
-{
- switch (msg->what()) {
- case kNotifyPostReleaseVideoBuffer:
- {
- Mutex::Autolock autoLock(mSeekLock);
- // Free pending video buffers when OmxDecoder is not seeking video.
- // If OmxDecoder is seeking video, the buffers are freed on seek exit.
- if (!mIsVideoSeeking) {
- ReleaseAllPendingVideoBuffersLocked();
- }
- break;
- }
- default:
- TRESPASS();
- break;
- }
-}
-
-void
-OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle)
-{
- {
- Mutex::Autolock autoLock(mPendingVideoBuffersLock);
- if (aBuffer) {
- mPendingVideoBuffers.push(BufferItem(aBuffer, aReleaseFenceHandle));
- }
- }
-
- sp<AMessage> notify =
- new AMessage(kNotifyPostReleaseVideoBuffer, mReflector->id());
- // post AMessage to OmxDecoder via ALooper.
- notify->post();
-}
-
-void
-OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
-{
- Vector<BufferItem> releasingVideoBuffers;
- {
- Mutex::Autolock autoLock(mPendingVideoBuffersLock);
-
- int size = mPendingVideoBuffers.size();
- for (int i = 0; i < size; i++) {
- releasingVideoBuffers.push(mPendingVideoBuffers[i]);
- }
- mPendingVideoBuffers.clear();
- }
- // Free all pending video buffers without holding mPendingVideoBuffersLock.
- int size = releasingVideoBuffers.size();
- for (int i = 0; i < size; i++) {
- MediaBuffer *buffer;
- buffer = releasingVideoBuffers[i].mMediaBuffer;
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
- RefPtr<FenceHandle::FdObj> fdObj = releasingVideoBuffers.editItemAt(i).mReleaseFenceHandle.GetAndResetFdObj();
- int fenceFd = fdObj->GetAndResetFd();