зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. r=merge a=merge on a CLOSED TREE
This commit is contained in:
Коммит
8e9610529d
|
@ -2,40 +2,36 @@
|
|||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"command": "${workspaceRoot}/mach",
|
||||
"windows": {
|
||||
"command": "\"\\mozilla-build\\start-shell.bat mach\""
|
||||
},
|
||||
"osx": {
|
||||
"command": "${workspaceRoot}/mach"
|
||||
},
|
||||
"linux": {
|
||||
"command": "${workspaceRoot}/mach"
|
||||
},
|
||||
"isShellCommand": true,
|
||||
"args": ["--log-no-times"],
|
||||
"showOutput": "silent",
|
||||
"echoCommand": true,
|
||||
"suppressTaskName": false,
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "clobber"
|
||||
"label": "clobber-python",
|
||||
"type":"shell",
|
||||
"command": "${workspaceRoot}/mach",
|
||||
"windows": {
|
||||
"command": "\"\\mozilla-build\\start-shell.bat mach\""
|
||||
},
|
||||
"args": ["clobber", "python"],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"taskName": "clobber-python",
|
||||
"suppressTaskName": true,
|
||||
"args": ["clobber", "python"]
|
||||
"label": "configure",
|
||||
"type":"shell",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"taskName": "configure"
|
||||
},
|
||||
{
|
||||
"taskName": "build",
|
||||
"isBuildCommand": true,
|
||||
"label": "build",
|
||||
"type":"shell",
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": "absolute",
|
||||
"pattern": {
|
||||
"regexp": "^.*?tools([^\\s]*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
|
||||
"regexp": "^.*?([^\\s]*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
|
@ -45,9 +41,38 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"taskName": "build-binaries",
|
||||
"suppressTaskName": true,
|
||||
"args": ["build", "binaries"],
|
||||
"label": "build-binaries",
|
||||
"type":"shell",
|
||||
"command": "${workspaceRoot}/mach",
|
||||
"windows": {
|
||||
"command": "\"\\mozilla-build\\start-shell.bat mach\""
|
||||
},
|
||||
"args": ["--log-no-times", "build", "binaries"],
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": "absolute",
|
||||
"pattern": {
|
||||
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "build-faster",
|
||||
"type":"shell",
|
||||
"command": "${workspaceRoot}/mach",
|
||||
"windows": {
|
||||
"command": "\"\\mozilla-build\\start-shell.bat mach\""
|
||||
},
|
||||
"args": ["--log-no-times", "build", "faster"],
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": "absolute",
|
||||
|
@ -62,53 +87,50 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"taskName": "build-faster",
|
||||
"suppressTaskName": true,
|
||||
"args": ["build", "faster"],
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": "absolute",
|
||||
"pattern": {
|
||||
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"taskName": "run",
|
||||
"label": "run",
|
||||
"type":"shell",
|
||||
"args": ["-purgecaches"],
|
||||
"showOutput": "always"
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"taskName": "lint-wo",
|
||||
"suppressTaskName": true,
|
||||
"label": "lint-wo",
|
||||
"type":"shell",
|
||||
"command": "${workspaceRoot}/mach",
|
||||
"windows": {
|
||||
"command": "\"\\mozilla-build\\start-shell.bat mach\""
|
||||
},
|
||||
"args": ["lint", "-wo"],
|
||||
"problemMatcher": ["$eslint-stylish"]
|
||||
},
|
||||
{
|
||||
"taskName": "eslint",
|
||||
"label": "eslint",
|
||||
"type": "shell",
|
||||
"problemMatcher": ["$eslint-stylish"]
|
||||
},
|
||||
{
|
||||
"taskName": "eslint-fix",
|
||||
"suppressTaskName": true,
|
||||
"label": "eslint-fix",
|
||||
"type":"shell",
|
||||
"command": "${workspaceRoot}/mach",
|
||||
"windows": {
|
||||
"command": "\"\\mozilla-build\\start-shell.bat mach\""
|
||||
},
|
||||
"args": ["eslint", "--fix", "${file}"],
|
||||
"problemMatcher": ["$eslint-stylish"]
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"label": "test",
|
||||
"type":"shell",
|
||||
"args": ["${relativeFile}"],
|
||||
"isTestCommand": true,
|
||||
"showOutput": "always"
|
||||
"group":"test",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "new"
|
||||
}
|
||||
},
|
||||
{
|
||||
"taskName": "mochitest",
|
||||
"label": "mochitest",
|
||||
"type":"shell",
|
||||
"args": ["${relativeFile}"],
|
||||
"showOutput": "always",
|
||||
"problemMatcher": {
|
||||
"fileLocation": ["relative", "${workspaceRoot}"],
|
||||
"pattern": {
|
||||
|
@ -117,12 +139,16 @@
|
|||
"file": 2,
|
||||
"message": 3
|
||||
}
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "new"
|
||||
}
|
||||
},
|
||||
{
|
||||
"taskName": "reftest",
|
||||
"label": "reftest",
|
||||
"type":"shell",
|
||||
"args": ["${relativeFile}"],
|
||||
"showOutput": "always",
|
||||
"problemMatcher": {
|
||||
"fileLocation": ["absolute"],
|
||||
"pattern": {
|
||||
|
@ -131,12 +157,16 @@
|
|||
"file": 2,
|
||||
"message": 3
|
||||
}
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "new"
|
||||
}
|
||||
},
|
||||
{
|
||||
"taskName": "xpcshell-test",
|
||||
"label": "xpcshell-test",
|
||||
"type":"shell",
|
||||
"args": ["${relativeFile}", "--sequential"],
|
||||
"showOutput": "always",
|
||||
"problemMatcher": {
|
||||
"fileLocation": ["relative", "${workspaceRoot}"],
|
||||
"pattern": {
|
||||
|
@ -146,6 +176,10 @@
|
|||
"location": 3,
|
||||
"message": 4
|
||||
}
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "new"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1419362 - a11y IDL changes not correctly handled by build system
|
||||
Bug 1416465 - Old track files may cause problems if they have wildcards.
|
||||
|
|
|
@ -520,8 +520,6 @@ pref("javascript.options.showInConsole", true);
|
|||
pref("general.warnOnAboutConfig", false);
|
||||
#endif
|
||||
|
||||
pref("intl.locale.requested", "@AB_CD@");
|
||||
|
||||
// This is the pref to control the location bar, change this to true to
|
||||
// force this - this makes the origin of popup windows more obvious to avoid
|
||||
// spoofing. We would rather not do it by default because it affects UE for web
|
||||
|
|
|
@ -118,9 +118,6 @@
|
|||
<vbox id="experimental" hidden="true">
|
||||
<description class="text-blurb" id="warningDesc">
|
||||
&warningDesc.version;
|
||||
#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
|
||||
&warningDesc.telemetryDesc;
|
||||
#endif
|
||||
</description>
|
||||
<description class="text-blurb" id="communityExperimentalDesc">
|
||||
&community.exp.start;<label class="text-link" href="http://www.mozilla.org/">&community.exp.mozillaLink;</label>&community.exp.middle;<label class="text-link" useoriginprincipal="true" href="about:credits">&community.exp.creditsLink;</label>&community.exp.end;
|
||||
|
|
|
@ -477,12 +477,17 @@
|
|||
key="key_openAddons"
|
||||
command="Tools:Addons"/>
|
||||
|
||||
<!-- only one of sync-setup, sync-syncnowitem or sync-reauthitem will be showing at once -->
|
||||
<!-- only one of sync-setup, sync-unverifieditem, sync-syncnowitem or sync-reauthitem will be showing at once -->
|
||||
<menuitem id="sync-setup"
|
||||
label="&syncSignIn.label;"
|
||||
accesskey="&syncSignIn.accesskey;"
|
||||
observes="sync-setup-state"
|
||||
oncommand="gSync.openPrefs('menubar')"/>
|
||||
<menuitem id="sync-unverifieditem"
|
||||
label="&syncSignIn.label;"
|
||||
accesskey="&syncSignIn.accesskey;"
|
||||
observes="sync-unverified-state"
|
||||
oncommand="gSync.openPrefs('menubar')"/>
|
||||
<menuitem id="sync-syncnowitem"
|
||||
label="&syncSyncNowItem.label;"
|
||||
accesskey="&syncSyncNowItem.accesskey;"
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
<!-- broadcasters of the "hidden" attribute to reflect setup state for
|
||||
menus -->
|
||||
<broadcaster id="sync-setup-state"/>
|
||||
<broadcaster id="sync-unverified-state" hidden="true"/>
|
||||
<broadcaster id="sync-syncnow-state" hidden="true"/>
|
||||
<broadcaster id="sync-reauth-state" hidden="true"/>
|
||||
<broadcaster id="viewTabsSidebar" autoCheck="false" sidebartitle="&syncedTabs.sidebar.label;"
|
||||
|
|
|
@ -218,13 +218,15 @@ var gSync = {
|
|||
document.getElementById("sync-reauth-state").hidden = true;
|
||||
document.getElementById("sync-setup-state").hidden = true;
|
||||
document.getElementById("sync-syncnow-state").hidden = true;
|
||||
document.getElementById("sync-unverified-state").hidden = true;
|
||||
|
||||
if (status == UIState.STATUS_LOGIN_FAILED) {
|
||||
// unhiding this element makes the menubar show the login failure state.
|
||||
document.getElementById("sync-reauth-state").hidden = false;
|
||||
} else if (status == UIState.STATUS_NOT_CONFIGURED ||
|
||||
status == UIState.STATUS_NOT_VERIFIED) {
|
||||
} else if (status == UIState.STATUS_NOT_CONFIGURED) {
|
||||
document.getElementById("sync-setup-state").hidden = false;
|
||||
} else if (status == UIState.STATUS_NOT_VERIFIED) {
|
||||
document.getElementById("sync-unverified-state").hidden = false;
|
||||
} else {
|
||||
document.getElementById("sync-syncnow-state").hidden = false;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
# set during early startup to have an impact as a canvas will be used by
|
||||
# startupRecorder.js
|
||||
prefs =
|
||||
# Skip migration work in BG__migrateUI for browser_startup.js since it isn't
|
||||
# representative of common startup.
|
||||
browser.migration.version=9999999
|
||||
browser.startup.record=true
|
||||
gfx.canvas.willReadFrequently.enable=true
|
||||
support-files =
|
||||
|
|
|
@ -108,8 +108,8 @@ add_task(async function test_ui_state_unverified() {
|
|||
syncing: false,
|
||||
syncNowTooltip: tooltipText
|
||||
});
|
||||
checkRemoteTabsPanel("PanelUI-remotetabs-setupsync", false);
|
||||
checkMenuBarItem("sync-setup");
|
||||
checkRemoteTabsPanel("PanelUI-remotetabs-unverified", false);
|
||||
checkMenuBarItem("sync-unverifieditem");
|
||||
});
|
||||
|
||||
add_task(async function test_ui_state_loginFailed() {
|
||||
|
@ -176,7 +176,8 @@ function checkPanelUIStatusBar({label, tooltip, fxastatus, avatarURL, syncing, s
|
|||
function checkRemoteTabsPanel(expectedShownItemId, syncing, syncNowTooltip) {
|
||||
checkItemsVisiblities(["PanelUI-remotetabs-main",
|
||||
"PanelUI-remotetabs-setupsync",
|
||||
"PanelUI-remotetabs-reauthsync"],
|
||||
"PanelUI-remotetabs-reauthsync",
|
||||
"PanelUI-remotetabs-unverified"],
|
||||
expectedShownItemId);
|
||||
|
||||
if (syncing != undefined && syncNowTooltip != undefined) {
|
||||
|
@ -185,7 +186,7 @@ function checkRemoteTabsPanel(expectedShownItemId, syncing, syncNowTooltip) {
|
|||
}
|
||||
|
||||
function checkMenuBarItem(expectedShownItemId) {
|
||||
checkItemsVisiblities(["sync-setup", "sync-syncnowitem", "sync-reauthitem"],
|
||||
checkItemsVisiblities(["sync-setup", "sync-syncnowitem", "sync-reauthitem", "sync-unverifieditem"],
|
||||
expectedShownItemId);
|
||||
}
|
||||
|
||||
|
|
|
@ -491,6 +491,17 @@
|
|||
label="&appMenuRemoteTabs.signin.label;"
|
||||
oncommand="gSync.openPrefs('synced-tabs');"/>
|
||||
</vbox>
|
||||
<vbox id="PanelUI-remotetabs-unverified"
|
||||
flex="1"
|
||||
align="center"
|
||||
class="PanelUI-remotetabs-instruction-box"
|
||||
observes="sync-unverified-state">
|
||||
<image class="fxaSyncIllustrationIssue"/>
|
||||
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.unverified.label;</label>
|
||||
<toolbarbutton class="PanelUI-remotetabs-button"
|
||||
label="&appMenuRemoteTabs.signin.label;"
|
||||
oncommand="gSync.openPrefs('synced-tabs');"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</panelview>
|
||||
|
|
|
@ -139,6 +139,13 @@ add_task(async function() {
|
|||
});
|
||||
add_task(asyncCleanup);
|
||||
|
||||
// When Sync is configured in an unverified state.
|
||||
add_task(async function() {
|
||||
gSync.updateAllUI({ status: UIState.STATUS_NOT_VERIFIED, email: "foo@bar.com" });
|
||||
await openPrefsFromMenuPanel("PanelUI-remotetabs-unverified", "synced-tabs");
|
||||
});
|
||||
add_task(asyncCleanup);
|
||||
|
||||
// When Sync is configured in a "needs reauthentication" state.
|
||||
add_task(async function() {
|
||||
gSync.updateAllUI({ status: UIState.STATUS_LOGIN_FAILED, email: "foo@bar.com" });
|
||||
|
|
|
@ -44,7 +44,7 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
|||
Services.logins.addLogin(myLogin)
|
||||
""", script_args=(self._username, self._password))
|
||||
|
||||
def createBookmark(self):
|
||||
def createBookmarkInMenu(self):
|
||||
self.marionette.execute_script("""
|
||||
let url = arguments[0];
|
||||
let title = arguments[1];
|
||||
|
@ -52,6 +52,14 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
|||
makeURI(url), 0, title);
|
||||
""", script_args=(self._bookmarkURL, self._bookmarkText))
|
||||
|
||||
def createBookmarksOnToolbar(self):
|
||||
self.marionette.execute_script("""
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.toolbarFolderId,
|
||||
makeURI(`about:rights?p=${i}`), 0, `Bookmark ${i}`);
|
||||
}
|
||||
""")
|
||||
|
||||
def createHistory(self):
|
||||
error = self.runAsyncCode("""
|
||||
// Copied from PlacesTestUtils, which isn't available in Marionette tests.
|
||||
|
@ -200,7 +208,7 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
|||
# Note that we expect 2 logins - one from us, one from sync.
|
||||
self.assertEqual(loginCount, 2, "No other logins are present")
|
||||
|
||||
def checkBookmark(self):
|
||||
def checkBookmarkInMenu(self):
|
||||
titleInBookmarks = self.marionette.execute_script("""
|
||||
let url = arguments[0];
|
||||
let bookmarkIds = PlacesUtils.bookmarks.getBookmarkIdsForURI(makeURI(url), {}, {});
|
||||
|
@ -208,6 +216,14 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
|||
""", script_args=(self._bookmarkURL,))
|
||||
self.assertEqual(titleInBookmarks, self._bookmarkText)
|
||||
|
||||
def checkBookmarkToolbarVisibility(self):
|
||||
toolbarVisible = self.marionette.execute_script("""
|
||||
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
|
||||
let xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
|
||||
return xulStore.getValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed")
|
||||
""")
|
||||
self.assertEqual(toolbarVisible, "false")
|
||||
|
||||
def checkHistory(self):
|
||||
historyResult = self.runAsyncCode("""
|
||||
PlacesUtils.history.fetch(arguments[0]).then(pageInfo => {
|
||||
|
@ -378,18 +394,20 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
|||
|
||||
def checkProfile(self, hasMigrated=False):
|
||||
self.checkPassword()
|
||||
self.checkBookmark()
|
||||
self.checkBookmarkInMenu()
|
||||
self.checkHistory()
|
||||
self.checkFormHistory()
|
||||
self.checkFormAutofill()
|
||||
self.checkCookie()
|
||||
self.checkSync(hasMigrated);
|
||||
if hasMigrated:
|
||||
self.checkBookmarkToolbarVisibility()
|
||||
self.checkSession()
|
||||
|
||||
def createProfileData(self):
|
||||
self.savePassword()
|
||||
self.createBookmark()
|
||||
self.createBookmarkInMenu()
|
||||
self.createBookmarksOnToolbar()
|
||||
self.createHistory()
|
||||
self.createFormHistory()
|
||||
self.createFormAutofill()
|
||||
|
|
|
@ -1745,6 +1745,35 @@ BrowserGlue.prototype = {
|
|||
this.AlertsService.showAlertNotification(null, title, body, true, null, clickCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Uncollapses PersonalToolbar if its collapsed status is not
|
||||
* persisted, and user customized it or changed default bookmarks.
|
||||
*
|
||||
* If the user does not have a persisted value for the toolbar's
|
||||
* "collapsed" attribute, try to determine whether it's customized.
|
||||
*/
|
||||
_maybeToggleBookmarkToolbarVisibility() {
|
||||
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
|
||||
const NUM_TOOLBAR_BOOKMARKS_TO_UNHIDE = 3;
|
||||
let xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
|
||||
|
||||
if (!xulStore.hasValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed")) {
|
||||
// We consider the toolbar customized if it has more than NUM_TOOLBAR_BOOKMARKS_TO_UNHIDE
|
||||
// children, or if it has a persisted currentset value.
|
||||
let toolbarIsCustomized = xulStore.hasValue(BROWSER_DOCURL, "PersonalToolbar", "currentset");
|
||||
let getToolbarFolderCount = () => {
|
||||
let toolbarFolder = PlacesUtils.getFolderContents(PlacesUtils.toolbarFolderId).root;
|
||||
let toolbarChildCount = toolbarFolder.childCount;
|
||||
toolbarFolder.containerOpen = false;
|
||||
return toolbarChildCount;
|
||||
};
|
||||
|
||||
if (toolbarIsCustomized || getToolbarFolderCount() > NUM_TOOLBAR_BOOKMARKS_TO_UNHIDE) {
|
||||
xulStore.setValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed", "false");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
_migrateUI: function BG__migrateUI() {
|
||||
const UI_VERSION = 59;
|
||||
|
@ -1756,6 +1785,15 @@ BrowserGlue.prototype = {
|
|||
} else {
|
||||
// This is a new profile, nothing to migrate.
|
||||
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||
|
||||
try {
|
||||
// New profiles may have existing bookmarks (imported from another browser or
|
||||
// copied into the profile) and we want to show the bookmark toolbar for them
|
||||
// in some cases.
|
||||
this._maybeToggleBookmarkToolbarVisibility();
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ SyncedTabsDeckComponent.prototype = {
|
|||
NOT_AUTHED_INFO: "notAuthedInfo",
|
||||
SINGLE_DEVICE_INFO: "singleDeviceInfo",
|
||||
TABS_DISABLED: "tabs-disabled",
|
||||
UNVERIFIED: "unverified"
|
||||
},
|
||||
|
||||
get container() {
|
||||
|
@ -130,9 +131,12 @@ SyncedTabsDeckComponent.prototype = {
|
|||
|
||||
getPanelStatus() {
|
||||
return this._getSignedInUser().then(user => {
|
||||
if (!user || !user.verified || this._SyncedTabs.loginFailed) {
|
||||
if (!user || this._SyncedTabs.loginFailed) {
|
||||
return this.PANELS.NOT_AUTHED_INFO;
|
||||
}
|
||||
if (!user.verified) {
|
||||
return this.PANELS.UNVERIFIED;
|
||||
}
|
||||
if (!this._SyncedTabs.isConfiguredToSyncTabs) {
|
||||
return this.PANELS.TABS_DISABLED;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,11 @@
|
|||
<p class="instructions">&syncedTabs.sidebar.notsignedin.label;</p>
|
||||
<button class="button sync-prefs">&fxaSignIn.label;</button>
|
||||
</div>
|
||||
<div class="unverified sync-state">
|
||||
<div class="syncIllustration"></div>
|
||||
<p class="instructions">&syncedTabs.sidebar.unverified.label;</p>
|
||||
<button class="button sync-prefs">&syncedTabs.sidebar.openprefs.label;</button>
|
||||
</div>
|
||||
<div class="singleDeviceInfo sync-state">
|
||||
<div class="syncIllustrationIssue"></div>
|
||||
<p class="instructions">&syncedTabs.sidebar.noclients.subtitle;</p>
|
||||
|
|
|
@ -228,6 +228,12 @@ add_task(async function testSyncedTabsSidebarStatus() {
|
|||
Assert.ok(selectedPanel.classList.contains("notAuthedInfo"),
|
||||
"not-authed panel is selected");
|
||||
|
||||
account = {verified: false};
|
||||
await syncedTabsDeckComponent.updatePanel();
|
||||
selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("unverified"),
|
||||
"unverified panel is selected");
|
||||
|
||||
account = {verified: true};
|
||||
await syncedTabsDeckComponent.updatePanel();
|
||||
selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
|
|
|
@ -159,7 +159,7 @@ add_task(async function testPanelStatus() {
|
|||
account = {verified: false};
|
||||
|
||||
result = await component.getPanelStatus();
|
||||
Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
|
||||
Assert.equal(result, component.PANELS.UNVERIFIED);
|
||||
|
||||
account = {verified: true};
|
||||
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
skip-if = !updater
|
||||
reason = test depends on update channel
|
||||
[browser_contentpermissionprompt.js]
|
||||
[browser_default_bookmark_toolbar_visibility.js]
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test _maybeToggleBookmarkToolbarVisibility() code running for new profiles.
|
||||
* Ensure that the bookmarks toolbar is hidden in a default configuration.
|
||||
* If new default bookmarks are added to the toolbar then the threshold of > 3
|
||||
* in NUM_TOOLBAR_BOOKMARKS_TO_UNHIDE may need to be adjusted there.
|
||||
*/
|
||||
add_task(async function test_default_bookmark_toolbar_visibility() {
|
||||
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
|
||||
let xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
|
||||
|
||||
is(xulStore.getValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed"), "",
|
||||
"Check that @collapsed isn't persisted");
|
||||
ok(document.getElementById("PersonalToolbar").collapsed,
|
||||
"The bookmarks toolbar should be collapsed by default");
|
||||
});
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
<!-- LOCALIZATION NOTE (warningDesc.version): This is a warning about the experimental nature of Nightly and Aurora builds. It is only shown in those versions. -->
|
||||
<!ENTITY warningDesc.version "&brandShortName; is experimental and may be unstable.">
|
||||
<!-- LOCALIZATION NOTE (warningDesc.telemetryDesc): This is a notification that Nightly/Aurora builds automatically send Telemetry data back to Mozilla. It is only shown in those versions. "It" refers to brandShortName. -->
|
||||
<!ENTITY warningDesc.telemetryDesc "It automatically sends information about performance, hardware, usage and customizations back to &vendorShortName; to help make &brandShortName; better.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (community.exp.*) This paragraph is shown in "experimental" builds, i.e. Nightly and Aurora builds, instead of the other "community.*" strings below. -->
|
||||
<!ENTITY community.exp.start "">
|
||||
|
|
|
@ -381,6 +381,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||
<!ENTITY appMenuRemoteTabs.noclients.subtitle "Want to see your tabs from other devices here?">
|
||||
<!ENTITY appMenuRemoteTabs.openprefs.label "Sync Preferences">
|
||||
<!ENTITY appMenuRemoteTabs.notsignedin.label "Sign in to view a list of tabs from your other devices.">
|
||||
<!ENTITY appMenuRemoteTabs.unverified.label "Your account needs to be verified.">
|
||||
<!ENTITY appMenuRemoteTabs.signin.label "Sign in to Sync">
|
||||
<!ENTITY appMenuRemoteTabs.managedevices.label "Manage Devices…">
|
||||
<!ENTITY appMenuRemoteTabs.sidebar.label "View Synced Tabs Sidebar">
|
||||
|
@ -794,6 +795,7 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
<!ENTITY syncedTabs.sidebar.noclients.label "Sign in to Firefox from your other devices to view their tabs here.">
|
||||
<!ENTITY syncedTabs.sidebar.noclients.subtitle "Want to see your tabs from other devices here?">
|
||||
<!ENTITY syncedTabs.sidebar.notsignedin.label "Sign in to view a list of tabs from your other devices.">
|
||||
<!ENTITY syncedTabs.sidebar.unverified.label "Your account needs to be verified.">
|
||||
<!ENTITY syncedTabs.sidebar.notabs.label "No open tabs">
|
||||
<!ENTITY syncedTabs.sidebar.openprefs.label "Open &syncBrand.shortName.label; Preferences">
|
||||
<!-- LOCALIZATION NOTE (syncedTabs.sidebar.tabsnotsyncing.label): This is shown
|
||||
|
|
|
@ -36,6 +36,7 @@ function mockSyncedTabs() {
|
|||
// configure our broadcasters so we are in the right state.
|
||||
document.getElementById("sync-reauth-state").hidden = true;
|
||||
document.getElementById("sync-setup-state").hidden = true;
|
||||
document.getElementById("sync-unverified-state").hidden = true;
|
||||
document.getElementById("sync-syncnow-state").hidden = false;
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
|
@ -43,6 +44,7 @@ function mockSyncedTabs() {
|
|||
|
||||
document.getElementById("sync-reauth-state").hidden = true;
|
||||
document.getElementById("sync-setup-state").hidden = false;
|
||||
document.getElementById("sync-unverified-state").hidden = true;
|
||||
document.getElementById("sync-syncnow-state").hidden = true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -718,6 +718,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton
|
|||
*/
|
||||
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync,
|
||||
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-reauthsync,
|
||||
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-unverified,
|
||||
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-nodevicespane,
|
||||
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-tabsdisabledpane {
|
||||
min-height: calc(var(--panel-ui-sync-illustration-height) +
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 173.9 156.5">
|
||||
<style>
|
||||
.st0{opacity:0.1;fill:#0C0C0D;enable-background:new ;} .st1{fill:#FFFFFF;} .st2{fill:url(#SVGID_1_);} .st3{fill:#F9F9FA;} .st4{fill:url(#SVGID_2_);} .st5{fill:url(#SVGID_3_);} .st6{fill:url(#SVGID_4_);} .st7{fill:url(#SVGID_5_);} .st8{fill:url(#SVGID_6_);} .st9{fill:url(#SVGID_7_);}
|
||||
.st0{opacity:0.1;fill:#0C0C0D;} .st1{fill:#FFFFFF;} .st2{fill:url(#SVGID_1_);} .st3{fill:#F9F9FA;} .st4{fill:url(#SVGID_2_);} .st5{fill:url(#SVGID_3_);} .st6{fill:url(#SVGID_4_);} .st7{fill:url(#SVGID_5_);} .st8{fill:url(#SVGID_6_);} .st9{fill:url(#SVGID_7_);}
|
||||
</style>
|
||||
<path class="st0" d="M140.9 152h-69c-.6 0-1-.4-1-1s.4-1 1-1H141c.6 0 1 .4 1 1s-.5 1-1.1 1zm-9.3-5.1h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-15.7 9.6h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-20 0h-3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h3c.3 0 .5.2.5.5s-.2.5-.5.5zm-7 0h-1c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h1c.3 0 .5.2.5.5s-.2.5-.5.5zm-10 0h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-20 0h-3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h3c.3 0 .5.2.5.5s-.2.5-.5.5zm-7 0h-1c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h1c.3 0 .5.2.5.5s-.2.5-.5.5zm-10 0h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-20 0h-3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h3c.3 0 .5.2.5.5s-.2.5-.5.5zm-7 0h-1c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h1c.3 0 .5.2.5.5s-.2.5-.5.5z"/>
|
||||
<path class="st1" d="M85 20.4h21.3s-6.7-14.9 7.5-16.8c12.6-1.7 17.6 11.3 17.6 11.3s1.5-7.5 9-6.1 12.9 13.3 12.9 13.3h18.6"/>
|
||||
|
|
До Ширина: | Высота: | Размер: 11 KiB После Ширина: | Высота: | Размер: 11 KiB |
|
@ -3,7 +3,7 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 173.9 156.5">
|
||||
<style>
|
||||
.st0{opacity:0.1;fill:#0C0C0D;enable-background:new ;} .st1{fill:#FFFFFF;} .st2{fill:url(#SVGID_1_);} .st3{fill:#F9F9FA;} .st4{fill:url(#SVGID_2_);} .st5{fill:url(#SVGID_3_);} .st6{fill:url(#SVGID_4_);} .st7{fill:url(#SVGID_5_);} .st8{fill:url(#SVGID_6_);} .st9{fill:url(#SVGID_7_);}
|
||||
.st0{opacity:0.1;fill:#0C0C0D;} .st1{fill:#FFFFFF;} .st2{fill:url(#SVGID_1_);} .st3{fill:#F9F9FA;} .st4{fill:url(#SVGID_2_);} .st5{fill:url(#SVGID_3_);} .st6{fill:url(#SVGID_4_);} .st7{fill:url(#SVGID_5_);} .st8{fill:url(#SVGID_6_);} .st9{fill:url(#SVGID_7_);}
|
||||
</style>
|
||||
<path class="st0" d="M140.9 152h-69c-.6 0-1-.4-1-1s.4-1 1-1H141c.6 0 1 .4 1 1s-.5 1-1.1 1zm-9.3-5.1h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-15.7 9.6h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-20 0h-3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h3c.3 0 .5.2.5.5s-.2.5-.5.5zm-7 0h-1c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h1c.3 0 .5.2.5.5s-.2.5-.5.5zm-10 0h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-20 0h-3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h3c.3 0 .5.2.5.5s-.2.5-.5.5zm-7 0h-1c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h1c.3 0 .5.2.5.5s-.2.5-.5.5zm-10 0h-12c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h12c.3 0 .5.2.5.5s-.2.5-.5.5zm-20 0h-3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h3c.3 0 .5.2.5.5s-.2.5-.5.5zm-7 0h-1c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h1c.3 0 .5.2.5.5s-.2.5-.5.5z"/>
|
||||
<path class="st1" d="M85 20.4h21.3s-6.7-14.9 7.5-16.8c12.6-1.7 17.6 11.3 17.6 11.3s1.5-7.5 9-6.1 12.9 13.3 12.9 13.3h18.6"/>
|
||||
|
|
До Ширина: | Высота: | Размер: 11 KiB После Ширина: | Высота: | Размер: 11 KiB |
|
@ -45,10 +45,8 @@
|
|||
#pragma GCC visibility pop
|
||||
|
||||
#ifdef MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
|
||||
// See if we're in code that can use mozalloc. NB: this duplicates
|
||||
// code in nscore.h because nscore.h pulls in prtypes.h, and chromium
|
||||
// can't build with that being included before base/basictypes.h.
|
||||
# if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
|
||||
// See if we're in code that can use mozalloc.
|
||||
# if !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
|
||||
# include "mozilla/mozalloc.h"
|
||||
# else
|
||||
# error "STL code can only be used with infallible ::operator new()"
|
||||
|
|
|
@ -62,10 +62,8 @@
|
|||
#pragma warning( pop )
|
||||
|
||||
#ifdef MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
|
||||
// See if we're in code that can use mozalloc. NB: this duplicates
|
||||
// code in nscore.h because nscore.h pulls in prtypes.h, and chromium
|
||||
// can't build with that being included before base/basictypes.h.
|
||||
# if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
|
||||
// See if we're in code that can use mozalloc.
|
||||
# if !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
|
||||
# include "mozilla/mozalloc.h"
|
||||
# else
|
||||
# error "STL code can only be used with infallible ::operator new()"
|
||||
|
|
|
@ -747,6 +747,7 @@ AnimationsTimeline.prototype = {
|
|||
|
||||
for (let {value, offset, easing, distance} of values) {
|
||||
distance = distance ? distance : 0;
|
||||
offset = parseFloat(offset.toFixed(3));
|
||||
tracks[name].push({value, offset, easing, distance});
|
||||
}
|
||||
}
|
||||
|
@ -776,7 +777,7 @@ AnimationsTimeline.prototype = {
|
|||
|
||||
tracks[propertyCSSName].push({
|
||||
value: frame[name],
|
||||
offset: frame.computedOffset,
|
||||
offset: parseFloat(frame.computedOffset.toFixed(3)),
|
||||
easing: frame.easing,
|
||||
distance: 0
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
const {createNode, createSVGNode} =
|
||||
require("devtools/client/animationinspector/utils");
|
||||
const {ProgressGraphHelper, getPreferredKeyframesProgressThreshold} =
|
||||
const { ProgressGraphHelper, } =
|
||||
require("devtools/client/animationinspector/graph-helper.js");
|
||||
|
||||
// Counter for linearGradient ID.
|
||||
|
@ -64,8 +64,7 @@ Keyframes.prototype = {
|
|||
const graphHelper =
|
||||
new ProgressGraphHelper(win, propertyName, animationType, keyframes, totalDuration);
|
||||
|
||||
renderPropertyGraph(graphEl, totalDuration, minSegmentDuration,
|
||||
getPreferredKeyframesProgressThreshold(keyframes), graphHelper);
|
||||
renderPropertyGraph(graphEl, totalDuration, minSegmentDuration, graphHelper);
|
||||
|
||||
// Destroy ProgressGraphHelper resources.
|
||||
graphHelper.destroy();
|
||||
|
@ -105,13 +104,10 @@ Keyframes.prototype = {
|
|||
* @param {Element} parentEl - Parent element of this appended path element.
|
||||
* @param {Number} duration - Duration of one iteration.
|
||||
* @param {Number} minSegmentDuration - Minimum segment duration.
|
||||
* @param {Number} minProgressThreshold - Minimum progress threshold.
|
||||
* @param {ProgressGraphHelper} graphHelper - The object of ProgressGraphHalper.
|
||||
*/
|
||||
function renderPropertyGraph(parentEl, duration, minSegmentDuration,
|
||||
minProgressThreshold, graphHelper) {
|
||||
const segments = graphHelper.createPathSegments(0, duration, minSegmentDuration,
|
||||
minProgressThreshold);
|
||||
function renderPropertyGraph(parentEl, duration, minSegmentDuration, graphHelper) {
|
||||
const segments = graphHelper.createPathSegments(duration, minSegmentDuration);
|
||||
|
||||
const graphType = graphHelper.getGraphType();
|
||||
if (graphType !== "color") {
|
||||
|
@ -168,32 +164,17 @@ function renderEasingHint(parentEl, segments, helper) {
|
|||
// Split segments for each keyframe.
|
||||
for (let i = 0, indexOfSegments = 0; i < keyframes.length - 1; i++) {
|
||||
const startKeyframe = keyframes[i];
|
||||
const startTime = startKeyframe.offset * duration;
|
||||
const endKeyframe = keyframes[i + 1];
|
||||
const endTime = endKeyframe.offset * duration;
|
||||
|
||||
const keyframeSegments = [];
|
||||
for (; indexOfSegments < segments.length; indexOfSegments++) {
|
||||
const segment = segments[indexOfSegments];
|
||||
if (segment.x < startTime) {
|
||||
// If previous easings were linear, we need to increment the indexOfSegments.
|
||||
continue;
|
||||
}
|
||||
if (segment.x > endTime) {
|
||||
indexOfSegments -= 1;
|
||||
keyframeSegments.push(segment);
|
||||
|
||||
if (segment.x === endTime) {
|
||||
break;
|
||||
}
|
||||
keyframeSegments.push(segment);
|
||||
}
|
||||
|
||||
// If keyframeSegments does not have segment which is at startTime,
|
||||
// get and set the segment.
|
||||
if (keyframeSegments[0].x !== startTime) {
|
||||
keyframeSegments.unshift(helper.getSegment(startTime));
|
||||
}
|
||||
// Also, endTime.
|
||||
if (keyframeSegments[keyframeSegments.length - 1].x !== endTime) {
|
||||
keyframeSegments.push(helper.getSegment(endTime));
|
||||
}
|
||||
|
||||
// Append easing hint as text and emphasis path.
|
||||
|
|
|
@ -248,19 +248,38 @@ ProgressGraphHelper.prototype = {
|
|||
|
||||
/**
|
||||
* Create the path segments from given parameters.
|
||||
* @param {Number} startTime - Starting time of animation.
|
||||
* @param {Number} endTime - Ending time of animation.
|
||||
*
|
||||
* @param {Number} duration - Duration of animation.
|
||||
* @param {Number} minSegmentDuration - Minimum segment duration.
|
||||
* @param {Number} minProgressThreshold - Minimum progress threshold.
|
||||
* @return {Array} path segments -
|
||||
* [{x: {Number} time, y: {Number} progress}, ...]
|
||||
*/
|
||||
createPathSegments: function (startTime, endTime,
|
||||
minSegmentDuration, minProgressThreshold) {
|
||||
return !this.valueHelperFunction
|
||||
? createKeyframesPathSegments(endTime - startTime, this.devtoolsKeyframes)
|
||||
: createPathSegments(startTime, endTime,
|
||||
minSegmentDuration, minProgressThreshold, this);
|
||||
createPathSegments: function (duration, minSegmentDuration, minProgressThreshold) {
|
||||
if (!this.valueHelperFunction) {
|
||||
return createKeyframesPathSegments(duration, this.devtoolsKeyframes);
|
||||
}
|
||||
|
||||
const segments = [];
|
||||
|
||||
for (let i = 0; i < this.devtoolsKeyframes.length - 1; i++) {
|
||||
const startKeyframe = this.devtoolsKeyframes[i];
|
||||
const endKeyframe = this.devtoolsKeyframes[i + 1];
|
||||
|
||||
let threshold = getPreferredProgressThreshold(startKeyframe.easing);
|
||||
if (threshold !== DEFAULT_MIN_PROGRESS_THRESHOLD) {
|
||||
// We should consider the keyframe's duration.
|
||||
threshold *= (endKeyframe.offset - startKeyframe.offset);
|
||||
}
|
||||
|
||||
const startTime = parseFloat((startKeyframe.offset * duration).toFixed(3));
|
||||
const endTime = parseFloat((endKeyframe.offset * duration).toFixed(3));
|
||||
|
||||
segments.push(...createPathSegments(startTime, endTime,
|
||||
minSegmentDuration, threshold, this));
|
||||
}
|
||||
|
||||
return segments;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -354,12 +373,24 @@ SummaryGraphHelper.prototype = {
|
|||
*/
|
||||
setKeyframes: function (keyframes) {
|
||||
let frames = null;
|
||||
// We need to change the duration resolution in case of interval of keyframes offset
|
||||
// was narrow.
|
||||
let durationResolution = DURATION_RESOLUTION;
|
||||
|
||||
if (keyframes) {
|
||||
let previousOffset = 0;
|
||||
|
||||
// Create new keyframes for opacity as computed style.
|
||||
// The reason why we use computed value instead of computed timing progress is to
|
||||
// include the easing in keyframes as well. Although the computed timing progress
|
||||
// is not affected by the easing in keyframes at all, computed value reflects that.
|
||||
frames = keyframes.map(keyframe => {
|
||||
if (previousOffset) {
|
||||
const interval = keyframe.offset - previousOffset;
|
||||
durationResolution = Math.max(durationResolution, Math.ceil(1 / interval));
|
||||
}
|
||||
previousOffset = keyframe.offset;
|
||||
|
||||
return {
|
||||
opacity: keyframe.offset,
|
||||
offset: keyframe.offset,
|
||||
|
@ -371,6 +402,8 @@ SummaryGraphHelper.prototype = {
|
|||
// during the delay phase and it is not filling backwards, we get zero.
|
||||
this.targetEl.style.opacity = 0;
|
||||
}
|
||||
|
||||
this.durationResolution = durationResolution;
|
||||
this.animation.effect.setKeyframes(frames);
|
||||
this.hasFrames = !!frames;
|
||||
},
|
||||
|
@ -436,14 +469,12 @@ SummaryGraphHelper.prototype = {
|
|||
* Create the path segments from given parameters.
|
||||
* @param {Number} startTime - Starting time of animation.
|
||||
* @param {Number} endTime - Ending time of animation.
|
||||
* @param {Number} minSegmentDuration - Minimum segment duration.
|
||||
* @param {Number} minProgressThreshold - Minimum progress threshold.
|
||||
* @return {Array} path segments -
|
||||
* [{x: {Number} time, y: {Number} progress}, ...]
|
||||
*/
|
||||
createPathSegments: function (startTime, endTime) {
|
||||
return createPathSegments(startTime, endTime,
|
||||
this.minSegmentDuration, this.minProgressThreshold, this);
|
||||
return createPathSegments(startTime, endTime, this.minSegmentDuration,
|
||||
this.minProgressThreshold, this, this.durationResolution);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -484,13 +515,16 @@ exports.SummaryGraphHelper = SummaryGraphHelper;
|
|||
* @param {Number} minSegmentDuration - Minimum segment duration.
|
||||
* @param {Number} minProgressThreshold - Minimum progress threshold.
|
||||
* @param {Object} segmentHelper
|
||||
* @param {Number} resolution - Duration resolution for first time.
|
||||
* If null, use DURATION_RESOLUTION.
|
||||
* - getSegment(time): Helper function that, given a time,
|
||||
* will calculate the animation progress.
|
||||
* @return {Array} path segments -
|
||||
* [{x: {Number} time, y: {Number} progress}, ...]
|
||||
*/
|
||||
function createPathSegments(startTime, endTime, minSegmentDuration,
|
||||
minProgressThreshold, segmentHelper) {
|
||||
minProgressThreshold, segmentHelper,
|
||||
resolution = DURATION_RESOLUTION) {
|
||||
// If the duration is too short, early return.
|
||||
if (endTime - startTime < minSegmentDuration) {
|
||||
return [segmentHelper.getSegment(startTime),
|
||||
|
@ -507,8 +541,8 @@ function createPathSegments(startTime, endTime, minSegmentDuration,
|
|||
|
||||
// Split the duration in equal intervals, and iterate over them.
|
||||
// See the definition of DURATION_RESOLUTION for more information about this.
|
||||
const interval = (endTime - startTime) / DURATION_RESOLUTION;
|
||||
for (let index = 1; index <= DURATION_RESOLUTION; index++) {
|
||||
const interval = (endTime - startTime) / resolution;
|
||||
for (let index = 1; index <= resolution; index++) {
|
||||
// Create a segment for this interval.
|
||||
const currentSegment =
|
||||
segmentHelper.getSegment(startTime + index * interval);
|
||||
|
|
|
@ -300,6 +300,21 @@ const TEST_CASES = [
|
|||
{ x: 1000, y: 1 },
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"opacity": {
|
||||
expectedClass: "opacity",
|
||||
expectedValues: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 100, y: 1 },
|
||||
{ x: 110, y: 1 },
|
||||
{ x: 114.9, y: 1 },
|
||||
{ x: 115, y: 0.5 },
|
||||
{ x: 129.9, y: 0.5 },
|
||||
{ x: 130, y: 0 },
|
||||
{ x: 1000, y: 1 },
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -115,7 +115,21 @@ const TEST_CASES = {
|
|||
{ x: 100000, y: 0 },
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"narrow-keyframes": {
|
||||
expectedKeyframeEasingGraphs: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 10000, y: 0.1 },
|
||||
{ x: 11000, y: 0.1 },
|
||||
{ x: 11500, y: 0.1 },
|
||||
{ x: 12999, y: 0.1 },
|
||||
{ x: 13000, y: 0.13 },
|
||||
{ x: 13500, y: 0.135 },
|
||||
{ x: 14000, y: 0.14 },
|
||||
]
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* () {
|
||||
|
|
|
@ -128,6 +128,27 @@
|
|||
duration: DURATION,
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "narrow-keyframes",
|
||||
frames: [
|
||||
{
|
||||
offset: 0,
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
offset: 0.1,
|
||||
easing: "steps(1)",
|
||||
opacity: 1,
|
||||
},
|
||||
{
|
||||
offset: 0.13,
|
||||
opacity: 0,
|
||||
},
|
||||
],
|
||||
timing: {
|
||||
duration: DURATION,
|
||||
}
|
||||
},
|
||||
].forEach(({ id, frames, timing }) => {
|
||||
const target = document.createElement("div");
|
||||
document.body.appendChild(target);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<div id=target4>4</div>
|
||||
<div id=target5>5</div>
|
||||
<div id=target6>6</div>
|
||||
<div id=target7>7</div>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
@ -104,6 +105,22 @@
|
|||
timing.easing = "linear";
|
||||
document.querySelector("#target6").animate(
|
||||
[{ opacity: 0, easing: "frames(5)" }, { opacity: 1 }], timing).pause();
|
||||
|
||||
document.querySelector("#target7").animate(
|
||||
[
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
opacity: 1,
|
||||
easing: "steps(2)",
|
||||
offset: 0.1,
|
||||
},
|
||||
{
|
||||
opacity: 0,
|
||||
offset: 0.13,
|
||||
},
|
||||
], timing).pause();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -89,12 +89,23 @@ function waitForWheelEvent(aTarget) {
|
|||
});
|
||||
}
|
||||
|
||||
// Returns true if |aAnimation| begins at the current timeline time. We
|
||||
// sometimes need to detect this case because if we started an animation
|
||||
// asynchronously (e.g. using play()) and then ended up running the next frame
|
||||
// at precisely the time the animation started (due to aligning with vsync
|
||||
// refresh rate) then we won't end up restyling in that frame.
|
||||
function startsRightNow(aAnimation) {
|
||||
return aAnimation.startTime === aAnimation.timeline.currentTime &&
|
||||
aAnimation.currentTime === 0;
|
||||
}
|
||||
|
||||
var omtaEnabled = isOMTAEnabled();
|
||||
|
||||
var isAndroid = !!navigator.userAgent.includes("Android");
|
||||
var isServo = isStyledByServo();
|
||||
var offscreenThrottlingEnabled =
|
||||
SpecialPowers.getBoolPref('dom.animations.offscreen-throttling');
|
||||
var hasMicroTaskCheckpointForAnimation;
|
||||
|
||||
function add_task_if_omta_enabled(test) {
|
||||
if (!omtaEnabled) {
|
||||
|
@ -107,6 +118,38 @@ function add_task_if_omta_enabled(test) {
|
|||
// We need to wait for all paints before running tests to avoid contaminations
|
||||
// from styling of this document itself.
|
||||
waitForAllPaints(() => {
|
||||
// Drop this once we have the micro task checkpoint for animations
|
||||
// (bug 1416966).
|
||||
add_task(async function check_micro_task_checkpoint_for_animations() {
|
||||
const div = addDiv(null);
|
||||
|
||||
async function checkMicroTaskCheckpoint() {
|
||||
return new Promise(resolve => {
|
||||
let didRequestAnimationFrame = false;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
const animation = div.animate({ }, 100 * MS_PER_SEC);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
didRequestAnimationFrame = true;
|
||||
});
|
||||
|
||||
animation.ready.then(() => {
|
||||
// If the animation.ready.then callback is called before the next
|
||||
// requestAnimationFrame callback, that means that there is a
|
||||
// micro task checkpoint between animation tick and
|
||||
// requestAnimationFrame callbacks.
|
||||
resolve(!didRequestAnimationFrame);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
hasMicroTaskCheckpointForAnimation = await checkMicroTaskCheckpoint();
|
||||
|
||||
await ensureElementRemoval(div);
|
||||
});
|
||||
|
||||
add_task(async function restyling_for_main_thread_animations() {
|
||||
var div = addDiv(null, { style: 'animation: background-color 100s' });
|
||||
var animation = div.getAnimations()[0];
|
||||
|
@ -114,8 +157,26 @@ waitForAllPaints(() => {
|
|||
await animation.ready;
|
||||
ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
|
||||
|
||||
// Normally we expect one restyling for each requestAnimationFrame (as
|
||||
// called by observeRestyling) PLUS one for the last frame becasue of bug
|
||||
// 1193394. However, we won't observe that initial restyling unless BOTH of
|
||||
// the following two conditions hold:
|
||||
//
|
||||
// 1. We are running *before* restyling happens. This only happens if we
|
||||
// perform a micro task checkpoint after resolving the 'ready' promise
|
||||
// above (bug 1416966).
|
||||
// 2. The animation actually needs a restyle because it started prior to
|
||||
// this frame. Even if (1) is true, in some cases due to aligning with
|
||||
// the refresh driver, the animation fame in which the ready promise is
|
||||
// resolved happens to coincide perfectly with the start time of the
|
||||
// animation. In this case no restyling is needed so we won't observe
|
||||
// an additional restyle.
|
||||
const expectedRestyleCount =
|
||||
hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
|
||||
? 6
|
||||
: 5;
|
||||
var markers = await observeStyling(5);
|
||||
is(markers.length, 5,
|
||||
is(markers.length, expectedRestyleCount,
|
||||
'CSS animations running on the main-thread should update style ' +
|
||||
'on the main thread');
|
||||
await ensureElementRemoval(div);
|
||||
|
@ -507,8 +568,13 @@ waitForAllPaints(() => {
|
|||
|
||||
await animation.ready;
|
||||
|
||||
var markers = await observeStyling(5);
|
||||
is(markers.length, 0,
|
||||
'Animations running on the main-thread which is in scrolled out ' +
|
||||
'elements should not update restyling');
|
||||
|
||||
parentElement.style.height = '100px';
|
||||
var markers = await observeStyling(1);
|
||||
markers = await observeStyling(1);
|
||||
|
||||
is(markers.length, 1,
|
||||
'Animations running on the main-thread which was in scrolled out ' +
|
||||
|
@ -867,9 +933,13 @@ waitForAllPaints(() => {
|
|||
|
||||
await animation.ready;
|
||||
|
||||
const expectedRestyleCount =
|
||||
hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
|
||||
? 6
|
||||
: 5;
|
||||
var markers = await observeStyling(5);
|
||||
|
||||
is(markers.length, 5,
|
||||
is(markers.length, expectedRestyleCount,
|
||||
'Discrete animation has has no keyframe whose offset is 0 or 1 in an ' +
|
||||
'out-of-view element should not be throttled');
|
||||
await ensureElementRemoval(div);
|
||||
|
@ -934,8 +1004,12 @@ waitForAllPaints(() => {
|
|||
var animation = rect.animate({ fill: ['blue', 'lime'] }, 100 * MS_PER_SEC);
|
||||
await animation.ready;
|
||||
|
||||
const expectedRestyleCount =
|
||||
hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
|
||||
? 6
|
||||
: 5;
|
||||
var markers = await observeStyling(5);
|
||||
is(markers.length, 5,
|
||||
is(markers.length, expectedRestyleCount,
|
||||
'CSS animations on an in-view svg element with post-transform should ' +
|
||||
'not be throttled.');
|
||||
|
||||
|
@ -994,8 +1068,12 @@ waitForAllPaints(() => {
|
|||
var animation = targetDiv.getAnimations()[0];
|
||||
await animation.ready;
|
||||
|
||||
const expectedRestyleCount =
|
||||
hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
|
||||
? 6
|
||||
: 5;
|
||||
var markers = await observeStyling(5);
|
||||
is(markers.length, 5,
|
||||
is(markers.length, expectedRestyleCount,
|
||||
'CSS animation on an in-view element with pre-transform should not ' +
|
||||
'be throttled.');
|
||||
|
||||
|
|
|
@ -9138,7 +9138,17 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
|
|||
|
||||
uint32_t lifetimePolicy;
|
||||
uint32_t behavior;
|
||||
GetCookieBehaviorForPrincipal(aPrincipal, &lifetimePolicy, &behavior);
|
||||
|
||||
// WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
|
||||
// and ACCEPT_NORMALLY as lifetimePolicy (See Bug 1406675 for rationale).
|
||||
auto policy = BasePrincipal::Cast(aPrincipal)->AddonPolicy();
|
||||
|
||||
if (policy) {
|
||||
behavior = nsICookieService::BEHAVIOR_ACCEPT;
|
||||
lifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
|
||||
} else {
|
||||
GetCookieBehaviorForPrincipal(aPrincipal, &lifetimePolicy, &behavior);
|
||||
}
|
||||
|
||||
// Check if we should only allow storage for the session, and record that fact
|
||||
if (lifetimePolicy == nsICookieService::ACCEPT_SESSION) {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
[DEFAULT]
|
||||
# Skip migration work in BG__migrateUI for browser_startup.js since it increases
|
||||
# the occurrence of the leak reported in bug 1398563 with test_bug1327798.html.
|
||||
prefs = browser.migration.version=9999999
|
||||
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||
support-files =
|
||||
bug226361_iframe.xhtml
|
||||
|
|
|
@ -30,10 +30,12 @@ NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
|
|||
HTMLAudioElement::HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo)
|
||||
: HTMLMediaElement(aNodeInfo)
|
||||
{
|
||||
DecoderDoctorLogger::LogConstruction(this);
|
||||
}
|
||||
|
||||
HTMLAudioElement::~HTMLAudioElement()
|
||||
{
|
||||
DecoderDoctorLogger::LogDestruction(this);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
#include "nsIContentPolicy.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "DecoderDoctorDiagnostics.h"
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "MediaContainerType.h"
|
||||
#include "MP4Decoder.h"
|
||||
|
@ -1608,6 +1609,31 @@ HTMLMediaElement::MozRequestDebugInfo(ErrorResult& aRv)
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
HTMLMediaElement::MozEnableDebugLog(const GlobalObject&)
|
||||
{
|
||||
DecoderDoctorLogger::EnableLogging();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::MozRequestDebugLog(ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<Promise> promise = CreateDOMPromise(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DecoderDoctorLogger::RetrieveMessages(this)->Then(
|
||||
mAbstractMainThread,
|
||||
__func__,
|
||||
[promise](const nsACString& aString) {
|
||||
promise->MaybeResolve(NS_ConvertUTF8toUTF16(aString));
|
||||
},
|
||||
[promise](nsresult rv) { promise->MaybeReject(rv); });
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::MozDumpDebugInfo()
|
||||
{
|
||||
|
@ -1729,6 +1755,7 @@ void HTMLMediaElement::ShutdownDecoder()
|
|||
mMediaSource->CompletePendingTransactions();
|
||||
}
|
||||
mDecoder->Shutdown();
|
||||
DDUNLINKCHILD(mDecoder.get());
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1781,6 +1808,8 @@ void HTMLMediaElement::AbortExistingLoads()
|
|||
RemoveMediaElementFromURITable();
|
||||
mLoadingSrc = nullptr;
|
||||
mLoadingSrcTriggeringPrincipal = nullptr;
|
||||
DDLOG(DDLogCategory::Property, "loading_src", "");
|
||||
DDUNLINKCHILD(mMediaSource.get());
|
||||
mMediaSource = nullptr;
|
||||
|
||||
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
|
||||
|
@ -2053,7 +2082,11 @@ void HTMLMediaElement::SelectResource()
|
|||
RemoveMediaElementFromURITable();
|
||||
mLoadingSrc = uri;
|
||||
mLoadingSrcTriggeringPrincipal = mSrcAttrTriggeringPrincipal;
|
||||
DDLOG(DDLogCategory::Property,
|
||||
"loading_src",
|
||||
nsCString(NS_ConvertUTF16toUTF8(src)));
|
||||
mMediaSource = mSrcMediaSource;
|
||||
DDLINKCHILD("mediasource", mMediaSource.get());
|
||||
UpdatePreloadAction();
|
||||
if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE &&
|
||||
!IsMediaStreamURI(mLoadingSrc) && !mMediaSource) {
|
||||
|
@ -2377,7 +2410,11 @@ void HTMLMediaElement::LoadFromSourceChildren()
|
|||
RemoveMediaElementFromURITable();
|
||||
mLoadingSrc = uri;
|
||||
mLoadingSrcTriggeringPrincipal = childSrc->GetSrcTriggeringPrincipal();
|
||||
DDLOG(DDLogCategory::Property,
|
||||
"loading_src",
|
||||
nsCString(NS_ConvertUTF16toUTF8(src)));
|
||||
mMediaSource = childSrc->GetSrcMediaSource();
|
||||
DDLINKCHILD("mediasource", mMediaSource.get());
|
||||
NS_ASSERTION(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING,
|
||||
"Network state should be loading");
|
||||
|
||||
|
@ -4050,6 +4087,8 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
|||
MOZ_ASSERT(mMainThreadEventTarget);
|
||||
MOZ_ASSERT(mAbstractMainThread);
|
||||
|
||||
DecoderDoctorLogger::LogConstruction(this);
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
double defaultVolume = Preferences::GetFloat("media.default_volume", 1.0);
|
||||
|
@ -4125,6 +4164,8 @@ HTMLMediaElement::~HTMLMediaElement()
|
|||
}
|
||||
|
||||
WakeLockRelease();
|
||||
|
||||
DecoderDoctorLogger::LogDestruction(this);
|
||||
}
|
||||
|
||||
void HTMLMediaElement::StopSuspendingAfterFirstFrame()
|
||||
|
@ -6090,6 +6131,8 @@ HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
|||
LOG(LogLevel::Debug,
|
||||
("%p Ready state changed to %s", this, gReadyStateToString[aState]));
|
||||
|
||||
DDLOG(DDLogCategory::Property, "ready_state", gReadyStateToString[aState]);
|
||||
|
||||
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
|
||||
return;
|
||||
}
|
||||
|
@ -6156,6 +6199,8 @@ void HTMLMediaElement::ChangeNetworkState(nsMediaNetworkState aState)
|
|||
nsMediaNetworkState oldState = mNetworkState;
|
||||
mNetworkState = aState;
|
||||
LOG(LogLevel::Debug, ("%p Network state changed to %s", this, gNetworkStateToString[aState]));
|
||||
DDLOG(
|
||||
DDLogCategory::Property, "network_state", gNetworkStateToString[aState]);
|
||||
|
||||
if (oldState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
|
||||
// Stop progress notification when exiting NETWORK_LOADING.
|
||||
|
@ -6373,6 +6418,9 @@ HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
|
|||
{
|
||||
LOG_EVENT(LogLevel::Debug, ("%p Queuing event %s", this,
|
||||
NS_ConvertUTF16toUTF8(aName).get()));
|
||||
DDLOG(DDLogCategory::Event,
|
||||
"HTMLMediaElement",
|
||||
nsCString(NS_ConvertUTF16toUTF8(aName)));
|
||||
|
||||
// Save events that occur while in the bfcache. These will be dispatched
|
||||
// if the page comes out of the bfcache.
|
||||
|
@ -6623,6 +6671,7 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
|
|||
// If the owning document has become inactive we should shutdown the CDM.
|
||||
if (!OwnerDoc()->IsCurrentActiveDocument() && mMediaKeys) {
|
||||
mMediaKeys->Shutdown();
|
||||
DDUNLINKCHILD(mMediaKeys.get());
|
||||
mMediaKeys = nullptr;
|
||||
if (mDecoder) {
|
||||
ShutdownDecoder();
|
||||
|
@ -7523,6 +7572,7 @@ HTMLMediaElement::SetDecoder(MediaDecoder* aDecoder)
|
|||
ShutdownDecoder();
|
||||
}
|
||||
mDecoder = aDecoder;
|
||||
DDLINKCHILD("decoder", mDecoder.get());
|
||||
}
|
||||
|
||||
float
|
||||
|
|
|
@ -631,6 +631,13 @@ public:
|
|||
// data from decoder/reader/MDSM. Used for debugging purposes.
|
||||
already_AddRefed<Promise> MozRequestDebugInfo(ErrorResult& aRv);
|
||||
|
||||
// Enables DecoderDoctorLogger logging. Used for debugging purposes.
|
||||
static void MozEnableDebugLog(const GlobalObject&);
|
||||
|
||||
// Returns a promise which will be resolved after collecting debugging
|
||||
// log associated with this element. Used for debugging purposes.
|
||||
already_AddRefed<Promise> MozRequestDebugLog(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> MozDumpDebugInfo();
|
||||
|
||||
// For use by mochitests. Enabling pref "media.test.video-suspend"
|
||||
|
|
|
@ -48,10 +48,12 @@ HTMLVideoElement::HTMLVideoElement(already_AddRefed<NodeInfo>& aNodeInfo)
|
|||
: HTMLMediaElement(aNodeInfo)
|
||||
, mIsOrientationLocked(false)
|
||||
{
|
||||
DecoderDoctorLogger::LogConstruction(this);
|
||||
}
|
||||
|
||||
HTMLVideoElement::~HTMLVideoElement()
|
||||
{
|
||||
DecoderDoctorLogger::LogDestruction(this);
|
||||
}
|
||||
|
||||
nsresult HTMLVideoElement::GetVideoSize(nsIntSize* size)
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
extern mozilla::LazyLogModule gMediaDemuxerLog;
|
||||
#define ADTSLOG(msg, ...) \
|
||||
MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("ADTSDemuxer " msg, ##__VA_ARGS__))
|
||||
#define ADTSLOGV(msg, ...) \
|
||||
MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, ("ADTSDemuxer " msg, ##__VA_ARGS__))
|
||||
#define ADTSLOG(msg, ...) \
|
||||
DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
|
||||
#define ADTSLOGV(msg, ...) \
|
||||
DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
namespace adts {
|
||||
|
@ -263,6 +263,7 @@ using media::TimeUnit;
|
|||
ADTSDemuxer::ADTSDemuxer(MediaResource* aSource)
|
||||
: mSource(aSource)
|
||||
{
|
||||
DDLINKCHILD("source", aSource);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -270,6 +271,7 @@ ADTSDemuxer::InitInternal()
|
|||
{
|
||||
if (!mTrackDemuxer) {
|
||||
mTrackDemuxer = new ADTSTrackDemuxer(mSource);
|
||||
DDLINKCHILD("track demuxer", mTrackDemuxer.get());
|
||||
}
|
||||
return mTrackDemuxer->Init();
|
||||
}
|
||||
|
@ -326,6 +328,7 @@ ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource* aSource)
|
|||
, mSamplesPerSecond(0)
|
||||
, mChannels(0)
|
||||
{
|
||||
DDLINKCHILD("source", aSource);
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,11 @@ class FrameParser;
|
|||
|
||||
class ADTSTrackDemuxer;
|
||||
|
||||
class ADTSDemuxer : public MediaDataDemuxer
|
||||
DDLoggedTypeDeclNameAndBase(ADTSDemuxer, MediaDataDemuxer);
|
||||
|
||||
class ADTSDemuxer
|
||||
: public MediaDataDemuxer
|
||||
, public DecoderDoctorLifeLogger<ADTSDemuxer>
|
||||
{
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
|
@ -42,7 +46,11 @@ private:
|
|||
RefPtr<ADTSTrackDemuxer> mTrackDemuxer;
|
||||
};
|
||||
|
||||
class ADTSTrackDemuxer : public MediaTrackDemuxer
|
||||
DDLoggedTypeNameAndBase(ADTSTrackDemuxer, MediaTrackDemuxer);
|
||||
|
||||
class ADTSTrackDemuxer
|
||||
: public MediaTrackDemuxer
|
||||
, public DecoderDoctorLifeLogger<ADTSTrackDemuxer>
|
||||
{
|
||||
public:
|
||||
explicit ADTSTrackDemuxer(MediaResource* aSource);
|
||||
|
|
|
@ -17,7 +17,11 @@ class nsIPrincipal;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
class BaseMediaResource : public MediaResource
|
||||
DDLoggedTypeDeclNameAndBase(BaseMediaResource, MediaResource);
|
||||
|
||||
class BaseMediaResource
|
||||
: public MediaResource
|
||||
, public DecoderDoctorLifeLogger<BaseMediaResource>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -12,11 +12,15 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
DDLoggedTypeDeclNameAndBase(BufferMediaResource, MediaResource);
|
||||
|
||||
// A simple MediaResource based on an in memory buffer. This class accepts
|
||||
// the address and the length of the buffer, and simulates a read/seek API
|
||||
// on top of it. The Read implementation involves copying memory, which is
|
||||
// unfortunate, but the MediaResource interface mandates that.
|
||||
class BufferMediaResource : public MediaResource
|
||||
class BufferMediaResource
|
||||
: public MediaResource
|
||||
, public DecoderDoctorLifeLogger<BufferMediaResource>
|
||||
{
|
||||
public:
|
||||
BufferMediaResource(const uint8_t* aBuffer, uint32_t aLength)
|
||||
|
|
|
@ -15,14 +15,23 @@ namespace mozilla {
|
|||
|
||||
extern LazyLogModule gMediaDecoderLog;
|
||||
#define LOG(x, ...) \
|
||||
MOZ_LOG( \
|
||||
gMediaDecoderLog, LogLevel::Debug, ("Decoder=%p " x, this, ##__VA_ARGS__))
|
||||
DDMOZ_LOG(gMediaDecoderLog, LogLevel::Debug, x, ##__VA_ARGS__)
|
||||
|
||||
ChannelMediaDecoder::ResourceCallback::ResourceCallback(
|
||||
AbstractThread* aMainThread)
|
||||
: mAbstractMainThread(aMainThread)
|
||||
{
|
||||
MOZ_ASSERT(aMainThread);
|
||||
DecoderDoctorLogger::LogConstructionAndBase(
|
||||
"ChannelMediaDecoder::ResourceCallback",
|
||||
this,
|
||||
static_cast<const MediaResourceCallback*>(this));
|
||||
}
|
||||
|
||||
ChannelMediaDecoder::ResourceCallback::~ResourceCallback()
|
||||
{
|
||||
DecoderDoctorLogger::LogDestruction("ChannelMediaDecoder::ResourceCallback",
|
||||
this);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -30,6 +39,8 @@ ChannelMediaDecoder::ResourceCallback::Connect(ChannelMediaDecoder* aDecoder)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mDecoder = aDecoder;
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
"ChannelMediaDecoder::ResourceCallback", this, "decoder", mDecoder);
|
||||
mTimer = NS_NewTimer(mAbstractMainThread->AsEventTarget());
|
||||
}
|
||||
|
||||
|
@ -38,6 +49,8 @@ ChannelMediaDecoder::ResourceCallback::Disconnect()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mDecoder) {
|
||||
DecoderDoctorLogger::UnlinkParentAndChild(
|
||||
"ChannelMediaDecoder::ResourceCallback", this, mDecoder);
|
||||
mDecoder = nullptr;
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
|
@ -62,6 +75,11 @@ ChannelMediaDecoder::ResourceCallback::NotifyNetworkError(
|
|||
const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"network_error",
|
||||
aError);
|
||||
if (mDecoder) {
|
||||
mDecoder->NetworkError(aError);
|
||||
}
|
||||
|
@ -82,6 +100,12 @@ void
|
|||
ChannelMediaDecoder::ResourceCallback::NotifyDataArrived()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"data_arrived",
|
||||
true);
|
||||
|
||||
if (!mDecoder) {
|
||||
return;
|
||||
}
|
||||
|
@ -104,6 +128,11 @@ ChannelMediaDecoder::ResourceCallback::NotifyDataArrived()
|
|||
void
|
||||
ChannelMediaDecoder::ResourceCallback::NotifyDataEnded(nsresult aStatus)
|
||||
{
|
||||
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"data_ended",
|
||||
aStatus);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mDecoder) {
|
||||
mDecoder->NotifyDownloadEnded(aStatus);
|
||||
|
@ -114,6 +143,11 @@ void
|
|||
ChannelMediaDecoder::ResourceCallback::NotifyPrincipalChanged()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"principal_changed",
|
||||
true);
|
||||
if (mDecoder) {
|
||||
mDecoder->NotifyPrincipalChanged();
|
||||
}
|
||||
|
@ -124,6 +158,11 @@ ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged(
|
|||
bool aSuspendedByCache)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"suspended_status_changed",
|
||||
aSuspendedByCache);
|
||||
MediaDecoderOwner* owner = GetMediaOwner();
|
||||
if (owner) {
|
||||
AbstractThread::AutoEnter context(owner->AbstractMainThread());
|
||||
|
@ -246,6 +285,7 @@ ChannelMediaDecoder::Load(nsIChannel* aChannel,
|
|||
if (!mResource) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DDLINKCHILD("resource", mResource.get());
|
||||
|
||||
nsresult rv = MediaShutdownManager::Instance().Register(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -271,6 +311,7 @@ ChannelMediaDecoder::Load(BaseMediaResource* aOriginal)
|
|||
if (!mResource) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DDLINKCHILD("resource", mResource.get());
|
||||
|
||||
nsresult rv = MediaShutdownManager::Instance().Register(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
|
|
@ -18,7 +18,11 @@ namespace mozilla {
|
|||
|
||||
class BaseMediaResource;
|
||||
|
||||
class ChannelMediaDecoder : public MediaDecoder
|
||||
DDLoggedTypeDeclNameAndBase(ChannelMediaDecoder, MediaDecoder);
|
||||
|
||||
class ChannelMediaDecoder
|
||||
: public MediaDecoder
|
||||
, public DecoderDoctorLifeLogger<ChannelMediaDecoder>
|
||||
{
|
||||
// Used to register with MediaResource to receive notifications which will
|
||||
// be forwarded to MediaDecoder.
|
||||
|
@ -36,6 +40,8 @@ class ChannelMediaDecoder : public MediaDecoder
|
|||
void Disconnect();
|
||||
|
||||
private:
|
||||
~ResourceCallback();
|
||||
|
||||
/* MediaResourceCallback functions */
|
||||
AbstractThread* AbstractMainThread() const override;
|
||||
MediaDecoderOwner* GetMediaOwner() const override;
|
||||
|
|
|
@ -19,8 +19,8 @@ static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416;
|
|||
|
||||
mozilla::LazyLogModule gMediaResourceLog("MediaResource");
|
||||
// Debug logging macro with object pointer and class name.
|
||||
#define LOG(msg, ...) MOZ_LOG(gMediaResourceLog, mozilla::LogLevel::Debug, \
|
||||
("%p " msg, this, ##__VA_ARGS__))
|
||||
#define LOG(msg, ...) \
|
||||
DDMOZ_LOG(gMediaResourceLog, mozilla::LogLevel::Debug, msg, ##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ private:
|
|||
bool mIsChannelSuspended = false;
|
||||
};
|
||||
|
||||
DDLoggedTypeDeclNameAndBase(ChannelMediaResource, BaseMediaResource);
|
||||
|
||||
/**
|
||||
* This is the MediaResource implementation that wraps Necko channels.
|
||||
* Much of its functionality is actually delegated to MediaCache via
|
||||
|
@ -61,7 +63,9 @@ private:
|
|||
* All synchronization is performed by MediaCacheStream; all off-main-
|
||||
* thread operations are delegated directly to that object.
|
||||
*/
|
||||
class ChannelMediaResource : public BaseMediaResource
|
||||
class ChannelMediaResource
|
||||
: public BaseMediaResource
|
||||
, public DecoderDoctorLifeLogger<ChannelMediaResource>
|
||||
{
|
||||
public:
|
||||
ChannelMediaResource(MediaResourceCallback* aDecoder,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef MediaCache_h_
|
||||
#define MediaCache_h_
|
||||
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "Intervals.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
@ -181,13 +182,16 @@ class ReentrantMonitorAutoEnter;
|
|||
*/
|
||||
class MediaCache;
|
||||
|
||||
DDLoggedTypeDeclName(MediaCacheStream);
|
||||
|
||||
/**
|
||||
* If the cache fails to initialize then Init will fail, so nonstatic
|
||||
* methods of this class can assume gMediaCache is non-null.
|
||||
*
|
||||
* This class can be directly embedded as a value.
|
||||
*/
|
||||
class MediaCacheStream {
|
||||
class MediaCacheStream : public DecoderDoctorLifeLogger<MediaCacheStream>
|
||||
{
|
||||
using AutoLock = ReentrantMonitorAutoEnter;
|
||||
|
||||
public:
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#if !defined(MediaDataDemuxer_h)
|
||||
#define MediaDataDemuxer_h
|
||||
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
|
@ -23,11 +24,14 @@ namespace mozilla {
|
|||
class MediaTrackDemuxer;
|
||||
class TrackMetadataHolder;
|
||||
|
||||
DDLoggedTypeDeclName(MediaDataDemuxer);
|
||||
DDLoggedTypeName(MediaTrackDemuxer);
|
||||
|
||||
// Allows reading the media data: to retrieve the metadata and demux samples.
|
||||
// MediaDataDemuxer isn't designed to be thread safe.
|
||||
// When used by the MediaFormatDecoder, care is taken to ensure that the demuxer
|
||||
// will never be called from more than one thread at once.
|
||||
class MediaDataDemuxer
|
||||
class MediaDataDemuxer : public DecoderDoctorLifeLogger<MediaDataDemuxer>
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDataDemuxer)
|
||||
|
@ -94,7 +98,7 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
class MediaTrackDemuxer
|
||||
class MediaTrackDemuxer : public DecoderDoctorLifeLogger<MediaTrackDemuxer>
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTrackDemuxer)
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace mozilla {
|
|||
#undef DUMP
|
||||
|
||||
LazyLogModule gMediaDecoderLog("MediaDecoder");
|
||||
#define LOG(x, ...) \
|
||||
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("Decoder=%p " x, this, ##__VA_ARGS__))
|
||||
#define LOG(x, ...) \
|
||||
DDMOZ_LOG(gMediaDecoderLog, LogLevel::Debug, x, ##__VA_ARGS__)
|
||||
|
||||
#define DUMP(x, ...) printf_stderr(x "\n", ##__VA_ARGS__)
|
||||
|
||||
|
@ -840,7 +840,9 @@ MediaDecoder::ChangeState(PlayState aState)
|
|||
mNextState = PLAY_STATE_PAUSED;
|
||||
}
|
||||
|
||||
LOG("ChangeState %s => %s", PlayStateStr(), ToPlayStateStr(aState));
|
||||
if (mPlayState != aState) {
|
||||
DDLOG(DDLogCategory::Property, "play_state", ToPlayStateStr(aState));
|
||||
}
|
||||
mPlayState = aState;
|
||||
|
||||
if (mPlayState == PLAY_STATE_PLAYING) {
|
||||
|
@ -862,6 +864,7 @@ MediaDecoder::UpdateLogicalPositionInternal()
|
|||
}
|
||||
bool logicalPositionChanged = mLogicalPosition != currentPosition;
|
||||
mLogicalPosition = currentPosition;
|
||||
DDLOG(DDLogCategory::Property, "currentTime", mLogicalPosition);
|
||||
|
||||
// Invalidate the frame so any video data is displayed.
|
||||
// Do this before the timeupdate event so that if that
|
||||
|
@ -1151,11 +1154,14 @@ MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT_IF(aStateMachine, !mDecoderStateMachine);
|
||||
mDecoderStateMachine = aStateMachine;
|
||||
if (aStateMachine) {
|
||||
mDecoderStateMachine = aStateMachine;
|
||||
DDLINKCHILD("decoder state machine", mDecoderStateMachine.get());
|
||||
ConnectMirrors(aStateMachine);
|
||||
UpdateVideoDecodeMode();
|
||||
} else {
|
||||
} else if (mDecoderStateMachine) {
|
||||
DDUNLINKCHILD(mDecoderStateMachine.get());
|
||||
mDecoderStateMachine = nullptr;
|
||||
DisconnectMirrors();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,9 @@ struct MOZ_STACK_CLASS MediaDecoderInit
|
|||
}
|
||||
};
|
||||
|
||||
class MediaDecoder
|
||||
DDLoggedTypeDeclName(MediaDecoder);
|
||||
|
||||
class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder>
|
||||
{
|
||||
public:
|
||||
typedef MozPromise<bool /* aIgnored */, bool /* aIgnored */,
|
||||
|
|
|
@ -59,14 +59,30 @@ using namespace mozilla::media;
|
|||
#undef SLOGE
|
||||
|
||||
#define FMT(x, ...) "Decoder=%p " x, mDecoderID, ##__VA_ARGS__
|
||||
#define LOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (FMT(x, ##__VA_ARGS__)))
|
||||
#define LOGV(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, (FMT(x, ##__VA_ARGS__)))
|
||||
#define LOG(x, ...) \
|
||||
DDMOZ_LOG(gMediaDecoderLog, \
|
||||
LogLevel::Debug, \
|
||||
"Decoder=%p " x, \
|
||||
mDecoderID, \
|
||||
##__VA_ARGS__)
|
||||
#define LOGV(x, ...) \
|
||||
DDMOZ_LOG(gMediaDecoderLog, \
|
||||
LogLevel::Verbose, \
|
||||
"Decoder=%p " x, \
|
||||
mDecoderID, \
|
||||
##__VA_ARGS__)
|
||||
#define LOGW(x, ...) NS_WARNING(nsPrintfCString(FMT(x, ##__VA_ARGS__)).get())
|
||||
#define LOGE(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(FMT(x, ##__VA_ARGS__)).get(), nullptr, __FILE__, __LINE__)
|
||||
|
||||
// Used by StateObject and its sub-classes
|
||||
#define SFMT(x, ...) "Decoder=%p state=%s " x, mMaster->mDecoderID, ToStateStr(GetState()), ##__VA_ARGS__
|
||||
#define SLOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (SFMT(x, ##__VA_ARGS__)))
|
||||
#define SLOG(x, ...) \
|
||||
DDMOZ_LOGEX(mMaster, \
|
||||
gMediaDecoderLog, \
|
||||
LogLevel::Debug, \
|
||||
"state=%s " x, \
|
||||
ToStateStr(GetState()), \
|
||||
##__VA_ARGS__)
|
||||
#define SLOGW(x, ...) NS_WARNING(nsPrintfCString(SFMT(x, ##__VA_ARGS__)).get())
|
||||
#define SLOGE(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(SFMT(x, ##__VA_ARGS__)).get(), nullptr, __FILE__, __LINE__)
|
||||
|
||||
|
@ -1931,6 +1947,10 @@ public:
|
|||
if (mMaster->mDuration.Ref()->IsInfinite()) {
|
||||
// We have a finite duration when playback reaches the end.
|
||||
mMaster->mDuration = Some(clockTime);
|
||||
DDLOGEX(mMaster,
|
||||
DDLogCategory::Property,
|
||||
"duration_us",
|
||||
mMaster->mDuration.Ref()->ToMicroseconds());
|
||||
}
|
||||
mMaster->UpdatePlaybackPosition(clockTime);
|
||||
|
||||
|
@ -2173,6 +2193,11 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder&& aMetadata)
|
|||
mMaster->mDuration = Some(TimeUnit::FromInfinity());
|
||||
}
|
||||
|
||||
DDLOGEX(mMaster,
|
||||
DDLogCategory::Property,
|
||||
"duration_us",
|
||||
mMaster->mDuration.Ref()->ToMicroseconds());
|
||||
|
||||
if (mMaster->HasVideo()) {
|
||||
SLOG("Video decode HWAccel=%d videoQueueSize=%d",
|
||||
Reader()->VideoIsHardwareAccelerated(),
|
||||
|
@ -2687,6 +2712,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
InitVideoQueuePrefs();
|
||||
|
||||
DDLINKCHILD("reader", aReader);
|
||||
}
|
||||
|
||||
#undef INIT_WATCHABLE
|
||||
|
@ -2961,7 +2988,12 @@ MediaDecoderStateMachine::UpdatePlaybackPositionInternal(const TimeUnit& aTime)
|
|||
mCurrentPosition = aTime;
|
||||
NS_ASSERTION(mCurrentPosition.Ref() >= TimeUnit::Zero(),
|
||||
"CurrentTime should be positive!");
|
||||
mDuration = Some(std::max(mDuration.Ref().ref(), mCurrentPosition.Ref()));
|
||||
if (mDuration.Ref().ref() < mCurrentPosition.Ref()) {
|
||||
mDuration = Some(mCurrentPosition.Ref());
|
||||
DDLOG(DDLogCategory::Property,
|
||||
"duration_us",
|
||||
mDuration.Ref()->ToMicroseconds());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3114,6 +3146,9 @@ void MediaDecoderStateMachine::BufferedRangeUpdated()
|
|||
if (mDuration.Ref().isNothing() || mDuration.Ref()->IsInfinite() ||
|
||||
end > mDuration.Ref().ref()) {
|
||||
mDuration = Some(end);
|
||||
DDLOG(DDLogCategory::Property,
|
||||
"duration_us",
|
||||
mDuration.Ref()->ToMicroseconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -156,6 +156,8 @@ enum class VideoDecodeMode : uint8_t
|
|||
Suspend
|
||||
};
|
||||
|
||||
DDLoggedTypeDeclName(MediaDecoderStateMachine);
|
||||
|
||||
/*
|
||||
The state machine class. This manages the decoding and seeking in the
|
||||
MediaDecoderReader on the decode task queue, and A/V sync on the shared
|
||||
|
@ -168,6 +170,7 @@ enum class VideoDecodeMode : uint8_t
|
|||
See MediaDecoder.h for more details.
|
||||
*/
|
||||
class MediaDecoderStateMachine
|
||||
: public DecoderDoctorLifeLogger<MediaDecoderStateMachine>
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
|
||||
|
||||
|
|
|
@ -31,8 +31,18 @@ using namespace mozilla::media;
|
|||
static mozilla::LazyLogModule sFormatDecoderLog("MediaFormatReader");
|
||||
mozilla::LazyLogModule gMediaDemuxerLog("MediaDemuxer");
|
||||
|
||||
#define LOG(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Debug, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define LOGV(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Verbose, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define LOG(arg, ...) \
|
||||
DDMOZ_LOG(sFormatDecoderLog, \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define LOGV(arg, ...) \
|
||||
DDMOZ_LOG(sFormatDecoderLog, \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
|
||||
|
||||
|
@ -529,29 +539,45 @@ MediaFormatReader::DecoderData::Flush()
|
|||
mShutdownPromise = new SharedShutdownPromiseHolder();
|
||||
RefPtr<SharedShutdownPromiseHolder> p = mShutdownPromise;
|
||||
RefPtr<MediaDataDecoder> d = mDecoder;
|
||||
mDecoder->Flush()
|
||||
->Then(mOwner->OwnerThread(), __func__,
|
||||
[type, this, p, d]() {
|
||||
if (!p->IsEmpty()) {
|
||||
// Shutdown happened before flush completes. Let's continue to
|
||||
// shut down the decoder. Note we don't access |this| because
|
||||
// this decoder is no longer managed by MFR::DecoderData.
|
||||
d->Shutdown()->ChainTo(p->Steal(), __func__);
|
||||
return;
|
||||
}
|
||||
mFlushing = false;
|
||||
mShutdownPromise = nullptr;
|
||||
mOwner->ScheduleUpdate(type);
|
||||
},
|
||||
[type, this, p, d](const MediaResult& aError) {
|
||||
if (!p->IsEmpty()) {
|
||||
d->Shutdown()->ChainTo(p->Steal(), __func__);
|
||||
return;
|
||||
}
|
||||
mFlushing = false;
|
||||
mShutdownPromise = nullptr;
|
||||
mOwner->NotifyError(type, aError);
|
||||
});
|
||||
DDLOGEX2("MediaFormatReader::DecoderData",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"flushing",
|
||||
DDNoValue{});
|
||||
mDecoder->Flush()->Then(mOwner->OwnerThread(),
|
||||
__func__,
|
||||
[type, this, p, d]() {
|
||||
DDLOGEX2("MediaFormatReader::DecoderData",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"flushed",
|
||||
DDNoValue{});
|
||||
if (!p->IsEmpty()) {
|
||||
// Shutdown happened before flush completes.
|
||||
// Let's continue to shut down the decoder. Note
|
||||
// we don't access |this| because this decoder
|
||||
// is no longer managed by MFR::DecoderData.
|
||||
d->Shutdown()->ChainTo(p->Steal(), __func__);
|
||||
return;
|
||||
}
|
||||
mFlushing = false;
|
||||
mShutdownPromise = nullptr;
|
||||
mOwner->ScheduleUpdate(type);
|
||||
},
|
||||
[type, this, p, d](const MediaResult& aError) {
|
||||
DDLOGEX2("MediaFormatReader::DecoderData",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"flush_error",
|
||||
aError);
|
||||
if (!p->IsEmpty()) {
|
||||
d->Shutdown()->ChainTo(p->Steal(), __func__);
|
||||
return;
|
||||
}
|
||||
mFlushing = false;
|
||||
mShutdownPromise = nullptr;
|
||||
mOwner->NotifyError(type, aError);
|
||||
});
|
||||
}
|
||||
mFlushed = true;
|
||||
}
|
||||
|
@ -566,7 +592,19 @@ public:
|
|||
explicit DecoderFactory(MediaFormatReader* aOwner)
|
||||
: mAudio(aOwner->mAudio, TrackInfo::kAudioTrack, aOwner->OwnerThread())
|
||||
, mVideo(aOwner->mVideo, TrackInfo::kVideoTrack, aOwner->OwnerThread())
|
||||
, mOwner(WrapNotNull(aOwner)) { }
|
||||
, mOwner(WrapNotNull(aOwner))
|
||||
{
|
||||
DecoderDoctorLogger::LogConstruction("MediaFormatReader::DecoderFactory",
|
||||
this);
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
aOwner, "decoder factory", "MediaFormatReader::DecoderFactory", this);
|
||||
}
|
||||
|
||||
~DecoderFactory()
|
||||
{
|
||||
DecoderDoctorLogger::LogDestruction("MediaFormatReader::DecoderFactory",
|
||||
this);
|
||||
}
|
||||
|
||||
void CreateDecoder(TrackType aTrack);
|
||||
|
||||
|
@ -637,7 +675,25 @@ class MediaFormatReader::DecoderFactory::Wrapper : public MediaDataDecoder
|
|||
public:
|
||||
Wrapper(already_AddRefed<MediaDataDecoder> aDecoder,
|
||||
already_AddRefed<Token> aToken)
|
||||
: mDecoder(aDecoder), mToken(aToken) {}
|
||||
: mDecoder(aDecoder)
|
||||
, mToken(aToken)
|
||||
{
|
||||
DecoderDoctorLogger::LogConstructionAndBase(
|
||||
"MediaFormatReader::DecoderFactory::Wrapper",
|
||||
this,
|
||||
static_cast<const MediaDataDecoder*>(this));
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
"MediaFormatReader::DecoderFactory::Wrapper",
|
||||
this,
|
||||
"decoder",
|
||||
mDecoder.get());
|
||||
}
|
||||
|
||||
~Wrapper()
|
||||
{
|
||||
DecoderDoctorLogger::LogDestruction(
|
||||
"MediaFormatReader::DecoderFactory::Wrapper", this);
|
||||
}
|
||||
|
||||
RefPtr<InitPromise> Init() override { return mDecoder->Init(); }
|
||||
RefPtr<DecodePromise> Decode(MediaRawData* aSample) override
|
||||
|
@ -717,11 +773,22 @@ MediaFormatReader::DecoderFactory::RunStage(Data& aData)
|
|||
aData.mToken = nullptr;
|
||||
aData.mStage = Stage::None;
|
||||
aData.mOwnerData.mDescription = rv.Description();
|
||||
DDLOGEX2("MediaFormatReader::DecoderFactory",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"create_decoder_error",
|
||||
rv);
|
||||
mOwner->NotifyError(aData.mTrack, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
aData.mDecoder = new Wrapper(aData.mDecoder.forget(), aData.mToken.forget());
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
aData.mDecoder.get(),
|
||||
"decoder",
|
||||
"MediaFormatReader::DecoderFactory",
|
||||
this);
|
||||
|
||||
DoInitDecoder(aData);
|
||||
aData.mStage = Stage::WaitForInit;
|
||||
break;
|
||||
|
@ -806,6 +873,11 @@ MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData)
|
|||
{
|
||||
auto& ownerData = aData.mOwnerData;
|
||||
|
||||
DDLOGEX2("MediaFormatReader::DecoderFactory",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"initialize_decoder",
|
||||
DDNoValue{});
|
||||
aData.mDecoder->Init()
|
||||
->Then(mOwner->OwnerThread(), __func__,
|
||||
[this, &aData, &ownerData](TrackType aTrack) {
|
||||
|
@ -814,6 +886,16 @@ MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData)
|
|||
MutexAutoLock lock(ownerData.mMutex);
|
||||
ownerData.mDecoder = aData.mDecoder.forget();
|
||||
ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
|
||||
DDLOGEX2("MediaFormatReader::DecoderFactory",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"decoder_initialized",
|
||||
DDNoValue{});
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
"MediaFormatReader::DecoderData",
|
||||
&ownerData,
|
||||
"decoder",
|
||||
ownerData.mDecoder.get());
|
||||
mOwner->SetVideoDecodeThreshold();
|
||||
mOwner->ScheduleUpdate(aTrack);
|
||||
},
|
||||
|
@ -823,6 +905,11 @@ MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData)
|
|||
"Can't have a decoder already set");
|
||||
aData.mStage = Stage::None;
|
||||
mOwner->mShutdownPromisePool->ShutdownDecoder(aData.mDecoder.forget());
|
||||
DDLOGEX2("MediaFormatReader::DecoderFactory",
|
||||
this,
|
||||
DDLogCategory::Log,
|
||||
"initialize_decoder_error",
|
||||
aError);
|
||||
mOwner->NotifyError(aData.mTrack, aError);
|
||||
})
|
||||
->Track(aData.mInitRequest);
|
||||
|
@ -974,6 +1061,15 @@ public:
|
|||
, mInfo(aTrackDemuxer->GetInfo())
|
||||
, mTrackDemuxer(aTrackDemuxer)
|
||||
{
|
||||
DecoderDoctorLogger::LogConstructionAndBase(
|
||||
"MediaFormatReader::DemuxerProxy::Wrapper",
|
||||
this,
|
||||
static_cast<const MediaTrackDemuxer*>(this));
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
"MediaFormatReader::DemuxerProxy::Wrapper",
|
||||
this,
|
||||
"track demuxer",
|
||||
aTrackDemuxer);
|
||||
}
|
||||
|
||||
UniquePtr<TrackInfo> GetInfo() const override
|
||||
|
@ -1093,6 +1189,8 @@ private:
|
|||
"MediaFormatReader::DemuxerProxy::Wrapper::~Wrapper",
|
||||
[trackDemuxer]() { trackDemuxer->BreakCycles(); }));
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
DecoderDoctorLogger::LogDestruction(
|
||||
"MediaFormatReader::DemuxerProxy::Wrapper", this);
|
||||
}
|
||||
|
||||
void UpdateRandomAccessPoint()
|
||||
|
@ -1150,6 +1248,11 @@ MediaFormatReader::DemuxerProxy::Init()
|
|||
new DemuxerProxy::Wrapper(d, taskQueue);
|
||||
wrapper->UpdateBuffered();
|
||||
data->mAudioDemuxer = wrapper;
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
data->mDemuxer.get(),
|
||||
"decoder factory wrapper",
|
||||
"MediaFormatReader::DecoderFactory::Wrapper",
|
||||
wrapper.get());
|
||||
}
|
||||
}
|
||||
data->mNumVideoTrack =
|
||||
|
@ -1162,6 +1265,11 @@ MediaFormatReader::DemuxerProxy::Init()
|
|||
new DemuxerProxy::Wrapper(d, taskQueue);
|
||||
wrapper->UpdateBuffered();
|
||||
data->mVideoDemuxer = wrapper;
|
||||
DecoderDoctorLogger::LinkParentAndChild(
|
||||
data->mDemuxer.get(),
|
||||
"decoder factory wrapper",
|
||||
"MediaFormatReader::DecoderFactory::Wrapper",
|
||||
wrapper.get());
|
||||
}
|
||||
}
|
||||
data->mCrypto = data->mDemuxer->GetCrypto();
|
||||
|
@ -1227,6 +1335,11 @@ MediaFormatReader::MediaFormatReader(MediaFormatReaderInit& aInit,
|
|||
{
|
||||
MOZ_ASSERT(aDemuxer);
|
||||
MOZ_COUNT_CTOR(MediaFormatReader);
|
||||
DDLINKCHILD(
|
||||
"audio decoder data", "MediaFormatReader::DecoderDataWithPromise", &mAudio);
|
||||
DDLINKCHILD(
|
||||
"video decoder data", "MediaFormatReader::DecoderDataWithPromise", &mVideo);
|
||||
DDLINKCHILD("demuxer", aDemuxer);
|
||||
mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
|
||||
mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
|
||||
}
|
||||
|
@ -1751,23 +1864,39 @@ MediaFormatReader::OnDemuxFailed(TrackType aTrack, const MediaResult& aError)
|
|||
decoder.mDemuxRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
DDLOG(DDLogCategory::Log,
|
||||
aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
|
||||
: "audio_demux_interruption",
|
||||
aError);
|
||||
if (!decoder.mWaitingForData) {
|
||||
decoder.RequestDrain();
|
||||
}
|
||||
NotifyEndOfStream(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
DDLOG(DDLogCategory::Log,
|
||||
aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
|
||||
: "audio_demux_interruption",
|
||||
aError);
|
||||
if (!decoder.mWaitingForData) {
|
||||
decoder.RequestDrain();
|
||||
}
|
||||
NotifyWaitingForData(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
DDLOG(DDLogCategory::Log,
|
||||
aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
|
||||
: "audio_demux_interruption",
|
||||
aError);
|
||||
if (decoder.HasPromise()) {
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DDLOG(DDLogCategory::Log,
|
||||
aTrack == TrackType::kVideoTrack ? "video_demux_error"
|
||||
: "audio_demux_error",
|
||||
aError);
|
||||
NotifyError(aTrack, aError);
|
||||
break;
|
||||
}
|
||||
|
@ -1778,19 +1907,26 @@ MediaFormatReader::DoDemuxVideo()
|
|||
{
|
||||
using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
|
||||
|
||||
DDLOG(DDLogCategory::Log, "video_demuxing", DDNoValue{});
|
||||
auto p = mVideo.mTrackDemuxer->GetSamples(1);
|
||||
|
||||
if (mVideo.mFirstDemuxedSampleTime.isNothing()) {
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
p = p->Then(OwnerThread(), __func__,
|
||||
[self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
|
||||
self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
|
||||
return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
|
||||
},
|
||||
[self] (const MediaResult& aError) {
|
||||
self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
|
||||
return SamplesPromise::CreateAndReject(aError, __func__);
|
||||
});
|
||||
p = p->Then(
|
||||
OwnerThread(),
|
||||
__func__,
|
||||
[self](RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
|
||||
DDLOGEX(
|
||||
self.get(), DDLogCategory::Log, "video_first_demuxed", DDNoValue{});
|
||||
self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
|
||||
return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
|
||||
},
|
||||
[self](const MediaResult& aError) {
|
||||
DDLOGEX(
|
||||
self.get(), DDLogCategory::Log, "video_first_demuxing_error", aError);
|
||||
self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
|
||||
return SamplesPromise::CreateAndReject(aError, __func__);
|
||||
});
|
||||
}
|
||||
|
||||
p->Then(OwnerThread(), __func__, this,
|
||||
|
@ -1808,6 +1944,9 @@ MediaFormatReader::OnVideoDemuxCompleted(
|
|||
aSamples->mSamples[0]->mTrackInfo
|
||||
? aSamples->mSamples[0]->mTrackInfo->GetID()
|
||||
: 0);
|
||||
DDLOG(DDLogCategory::Log,
|
||||
"video_demuxed_samples",
|
||||
uint64_t(aSamples->mSamples.Length()));
|
||||
mVideo.mDemuxRequest.Complete();
|
||||
mVideo.mQueuedSamples.AppendElements(aSamples->mSamples);
|
||||
ScheduleUpdate(TrackInfo::kVideoTrack);
|
||||
|
@ -1854,19 +1993,26 @@ MediaFormatReader::DoDemuxAudio()
|
|||
{
|
||||
using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
|
||||
|
||||
DDLOG(DDLogCategory::Log, "audio_demuxing", DDNoValue{});
|
||||
auto p = mAudio.mTrackDemuxer->GetSamples(1);
|
||||
|
||||
if (mAudio.mFirstDemuxedSampleTime.isNothing()) {
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
p = p->Then(OwnerThread(), __func__,
|
||||
[self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
|
||||
self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
|
||||
return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
|
||||
},
|
||||
[self] (const MediaResult& aError) {
|
||||
self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
|
||||
return SamplesPromise::CreateAndReject(aError, __func__);
|
||||
});
|
||||
p = p->Then(
|
||||
OwnerThread(),
|
||||
__func__,
|
||||
[self](RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
|
||||
DDLOGEX(
|
||||
self.get(), DDLogCategory::Log, "audio_first_demuxed", DDNoValue{});
|
||||
self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
|
||||
return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
|
||||
},
|
||||
[self](const MediaResult& aError) {
|
||||
DDLOGEX(
|
||||
self.get(), DDLogCategory::Log, "audio_first_demuxing_error", aError);
|
||||
self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
|
||||
return SamplesPromise::CreateAndReject(aError, __func__);
|
||||
});
|
||||
}
|
||||
|
||||
p->Then(OwnerThread(), __func__, this,
|
||||
|
@ -1884,6 +2030,9 @@ MediaFormatReader::OnAudioDemuxCompleted(
|
|||
aSamples->mSamples[0]->mTrackInfo
|
||||
? aSamples->mSamples[0]->mTrackInfo->GetID()
|
||||
: 0);
|
||||
DDLOG(DDLogCategory::Log,
|
||||
"audio_demuxed_samples",
|
||||
uint64_t(aSamples->mSamples.Length()));
|
||||
mAudio.mDemuxRequest.Complete();
|
||||
mAudio.mQueuedSamples.AppendElements(aSamples->mSamples);
|
||||
ScheduleUpdate(TrackInfo::kAudioTrack);
|
||||
|
@ -1895,14 +2044,94 @@ MediaFormatReader::NotifyNewOutput(
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
for (auto& sample : aResults) {
|
||||
LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64,
|
||||
TrackTypeToStr(aTrack), sample->mTime.ToMicroseconds(),
|
||||
sample->mDuration.ToMicroseconds());
|
||||
decoder.mOutput.AppendElement(sample);
|
||||
decoder.mNumSamplesOutput++;
|
||||
decoder.mNumOfConsecutiveError = 0;
|
||||
}
|
||||
if (aResults.IsEmpty()) {
|
||||
DDLOG(DDLogCategory::Log,
|
||||
aTrack == TrackInfo::kAudioTrack ? "decoded_audio" : "decoded_video",
|
||||
"no output samples");
|
||||
} else
|
||||
for (auto& sample : aResults) {
|
||||
if (DecoderDoctorLogger::IsDDLoggingEnabled()) {
|
||||
switch (sample->mType) {
|
||||
case MediaData::AUDIO_DATA:
|
||||
DDLOGPR(DDLogCategory::Log,
|
||||
aTrack == TrackInfo::kAudioTrack ? "decoded_audio"
|
||||
: "decoded_got_audio!?",
|
||||
"{\"type\":\"AudioData\", \"offset\":%" PRIi64
|
||||
", \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
|
||||
", \"duration_us\":%" PRIi64 ", \"frames\":%" PRIu32
|
||||
", \"kf\":%s, \"channels\":%" PRIu32 ", \"rate\":%" PRIu32
|
||||
", \"bytes\":%zu}",
|
||||
sample->mOffset,
|
||||
sample->mTime.ToMicroseconds(),
|
||||
sample->mTimecode.ToMicroseconds(),
|
||||
sample->mDuration.ToMicroseconds(),
|
||||
sample->mFrames,
|
||||
sample->mKeyframe ? "true" : "false",
|
||||
sample->As<AudioData>()->mChannels,
|
||||
sample->As<AudioData>()->mRate,
|
||||
sample->As<AudioData>()->mAudioData.Size());
|
||||
break;
|
||||
case MediaData::VIDEO_DATA:
|
||||
DDLOGPR(DDLogCategory::Log,
|
||||
aTrack == TrackInfo::kVideoTrack ? "decoded_video"
|
||||
: "decoded_got_video!?",
|
||||
"{\"type\":\"VideoData\", \"offset\":%" PRIi64
|
||||
", \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
|
||||
", \"duration_us\":%" PRIi64 ", \"frames\":%" PRIu32
|
||||
", \"kf\":%s, \"size\":[%" PRIi32 ",%" PRIi32 "]}",
|
||||
sample->mOffset,
|
||||
sample->mTime.ToMicroseconds(),
|
||||
sample->mTimecode.ToMicroseconds(),
|
||||
sample->mDuration.ToMicroseconds(),
|
||||
sample->mFrames,
|
||||
sample->mKeyframe ? "true" : "false",
|
||||
sample->As<VideoData>()->mDisplay.width,
|
||||
sample->As<VideoData>()->mDisplay.height);
|
||||
break;
|
||||
case MediaData::RAW_DATA:
|
||||
DDLOGPR(DDLogCategory::Log,
|
||||
aTrack == TrackInfo::kAudioTrack
|
||||
? "decoded_audio"
|
||||
: aTrack == TrackInfo::kVideoTrack ? "decoded_video"
|
||||
: "decoded_?",
|
||||
"{\"type\":\"RawData\", \"offset\":%" PRIi64
|
||||
" \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
|
||||
", \"duration_us\":%" PRIi64 ", \"frames\":%" PRIu32
|
||||
", \"kf\":%s}",
|
||||
sample->mOffset,
|
||||
sample->mTime.ToMicroseconds(),
|
||||
sample->mTimecode.ToMicroseconds(),
|
||||
sample->mDuration.ToMicroseconds(),
|
||||
sample->mFrames,
|
||||
sample->mKeyframe ? "true" : "false");
|
||||
break;
|
||||
case MediaData::NULL_DATA:
|
||||
DDLOGPR(DDLogCategory::Log,
|
||||
aTrack == TrackInfo::kAudioTrack
|
||||
? "decoded_audio"
|
||||
: aTrack == TrackInfo::kVideoTrack ? "decoded_video"
|
||||
: "decoded_?",
|
||||
"{\"type\":\"NullData\", \"offset\":%" PRIi64
|
||||
" \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
|
||||
", \"duration_us\":%" PRIi64 ", \"frames\":%" PRIu32
|
||||
", \"kf\":%s}",
|
||||
sample->mOffset,
|
||||
sample->mTime.ToMicroseconds(),
|
||||
sample->mTimecode.ToMicroseconds(),
|
||||
sample->mDuration.ToMicroseconds(),
|
||||
sample->mFrames,
|
||||
sample->mKeyframe ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64,
|
||||
TrackTypeToStr(aTrack),
|
||||
sample->mTime.ToMicroseconds(),
|
||||
sample->mDuration.ToMicroseconds());
|
||||
decoder.mOutput.AppendElement(sample);
|
||||
decoder.mNumSamplesOutput++;
|
||||
decoder.mNumOfConsecutiveError = 0;
|
||||
}
|
||||
LOG("Done processing new %s samples", TrackTypeToStr(aTrack));
|
||||
|
||||
if (!aResults.IsEmpty()) {
|
||||
|
@ -2104,7 +2333,7 @@ MediaFormatReader::RequestDemuxSamples(TrackType aTrack)
|
|||
if (decoder.mDemuxEOS) {
|
||||
// Nothing left to demux.
|
||||
// We do not want to attempt to demux while in waiting for data mode
|
||||
// as it would retrigger an unecessary drain.
|
||||
// as it would retrigger an unnecessary drain.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2124,6 +2353,21 @@ MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
|
|||
auto& decoder = GetDecoderData(aTrack);
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
decoder.mFlushed = false;
|
||||
DDLOGPR(DDLogCategory::Log,
|
||||
aTrack == TrackInfo::kAudioTrack
|
||||
? "decode_audio"
|
||||
: aTrack == TrackInfo::kVideoTrack ? "decode_video" : "decode_?",
|
||||
"{\"type\":\"MediaRawData\", \"offset\":%" PRIi64
|
||||
", \"bytes\":%zu, \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
|
||||
", \"duration_us\":%" PRIi64 ", \"frames\":%" PRIu32 "%s%s}",
|
||||
aSample->mOffset,
|
||||
aSample->Size(),
|
||||
aSample->mTime.ToMicroseconds(),
|
||||
aSample->mTimecode.ToMicroseconds(),
|
||||
aSample->mDuration.ToMicroseconds(),
|
||||
aSample->mFrames,
|
||||
aSample->mKeyframe ? " kf" : "",
|
||||
aSample->mEOS ? " eos" : "");
|
||||
decoder.mDecoder->Decode(aSample)
|
||||
->Then(mTaskQueue, __func__,
|
||||
[self, aTrack, &decoder]
|
||||
|
@ -2255,39 +2499,50 @@ MediaFormatReader::InternalSeek(TrackType aTrack,
|
|||
decoder.Flush();
|
||||
decoder.ResetDemuxer();
|
||||
decoder.mTimeThreshold = Some(aTarget);
|
||||
DDLOG(DDLogCategory::Log, "seeking", DDNoValue{});
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, aTrack] (TimeUnit aTime) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
MOZ_ASSERT(
|
||||
decoder.mTimeThreshold,
|
||||
"Seek promise must be disconnected when timethreshold is reset");
|
||||
decoder.mTimeThreshold.ref().mHasSeeked = true;
|
||||
self->SetVideoDecodeThreshold();
|
||||
self->ScheduleUpdate(aTrack);
|
||||
},
|
||||
[self, aTrack] (const MediaResult& aError) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
self->NotifyWaitingForData(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyEndOfStream(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
decoder.mTimeThreshold.reset();
|
||||
break;
|
||||
default:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyError(aTrack, aError);
|
||||
break;
|
||||
}
|
||||
})
|
||||
->Then(
|
||||
OwnerThread(),
|
||||
__func__,
|
||||
[self, aTrack](TimeUnit aTime) {
|
||||
DDLOGEX(self.get(), DDLogCategory::Log, "seeked", DDNoValue{});
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
MOZ_ASSERT(
|
||||
decoder.mTimeThreshold,
|
||||
"Seek promise must be disconnected when timethreshold is reset");
|
||||
decoder.mTimeThreshold.ref().mHasSeeked = true;
|
||||
self->SetVideoDecodeThreshold();
|
||||
self->ScheduleUpdate(aTrack);
|
||||
},
|
||||
[self, aTrack](const MediaResult& aError) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
DDLOGEX(
|
||||
self.get(), DDLogCategory::Log, "seeking_interrupted", aError);
|
||||
self->NotifyWaitingForData(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
DDLOGEX(
|
||||
self.get(), DDLogCategory::Log, "seeking_interrupted", aError);
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyEndOfStream(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
DDLOGEX(
|
||||
self.get(), DDLogCategory::Log, "seeking_interrupted", aError);
|
||||
decoder.mTimeThreshold.reset();
|
||||
break;
|
||||
default:
|
||||
DDLOGEX(self.get(), DDLogCategory::Log, "seeking_error", aError);
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyError(aTrack, aError);
|
||||
break;
|
||||
}
|
||||
})
|
||||
->Track(decoder.mSeekRequest);
|
||||
}
|
||||
|
||||
|
@ -2312,12 +2567,14 @@ MediaFormatReader::DrainDecoder(TrackType aTrack)
|
|||
|
||||
decoder.mDrainState = DrainState::Draining;
|
||||
|
||||
DDLOG(DDLogCategory::Log, "draining", DDNoValue{});
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
decoder.mDecoder->Drain()
|
||||
->Then(mTaskQueue, __func__,
|
||||
[self, aTrack, &decoder]
|
||||
(const MediaDataDecoder::DecodedData& aResults) {
|
||||
decoder.mDrainRequest.Complete();
|
||||
DDLOGEX(self.get(), DDLogCategory::Log, "drained", DDNoValue{});
|
||||
if (aResults.IsEmpty()) {
|
||||
decoder.mDrainState = DrainState::DrainCompleted;
|
||||
} else {
|
||||
|
@ -2329,6 +2586,7 @@ MediaFormatReader::DrainDecoder(TrackType aTrack)
|
|||
},
|
||||
[self, aTrack, &decoder](const MediaResult& aError) {
|
||||
decoder.mDrainRequest.Complete();
|
||||
DDLOGEX(self.get(), DDLogCategory::Log, "draining_error", aError);
|
||||
self->NotifyError(aTrack, aError);
|
||||
})
|
||||
->Track(decoder.mDrainRequest);
|
||||
|
@ -2523,6 +2781,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
decoder.mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER;
|
||||
if (!needsNewDecoder &&
|
||||
++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
|
||||
DDLOG(DDLogCategory::Log, "too_many_decode_errors", decoder.mError.ref());
|
||||
NotifyError(aTrack, decoder.mError.ref());
|
||||
return;
|
||||
}
|
||||
|
@ -2552,6 +2811,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
} else if (aTrack == TrackType::kAudioTrack) {
|
||||
decoder.Flush();
|
||||
} else {
|
||||
DDLOG(DDLogCategory::Log, "no_keyframe", NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
// We can't recover from this error.
|
||||
NotifyError(aTrack, NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
}
|
||||
|
@ -2820,6 +3080,8 @@ MediaFormatReader::OnVideoSkipCompleted(uint32_t aSkipped)
|
|||
LOG("Skipping succeeded, skipped %u frames", aSkipped);
|
||||
mSkipRequest.Complete();
|
||||
|
||||
DDLOG(DDLogCategory::Log, "video_skipped", DDNoValue());
|
||||
|
||||
VideoSkipReset(aSkipped);
|
||||
|
||||
ScheduleUpdate(TrackInfo::kVideoTrack);
|
||||
|
@ -2836,6 +3098,8 @@ MediaFormatReader::OnVideoSkipFailed(
|
|||
switch (aFailure.mFailure.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
DDLOG(
|
||||
DDLogCategory::Log, "video_skipping_interruption", aFailure.mFailure);
|
||||
// Some frames may have been output by the decoder since we initiated the
|
||||
// videoskip process and we know they would be late.
|
||||
DropDecodedSamples(TrackInfo::kVideoTrack);
|
||||
|
@ -2844,11 +3108,14 @@ MediaFormatReader::OnVideoSkipFailed(
|
|||
ScheduleUpdate(TrackInfo::kVideoTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
DDLOG(
|
||||
DDLogCategory::Log, "video_skipping_interruption", aFailure.mFailure);
|
||||
if (mVideo.HasPromise()) {
|
||||
mVideo.RejectPromise(aFailure.mFailure, __func__);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DDLOG(DDLogCategory::Log, "video_skipping_error", aFailure.mFailure);
|
||||
NotifyError(TrackType::kVideoTrack, aFailure.mFailure);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -87,7 +87,10 @@ struct MOZ_STACK_CLASS MediaFormatReaderInit
|
|||
MediaDecoderOwnerID mMediaDecoderOwnerID = nullptr;
|
||||
};
|
||||
|
||||
DDLoggedTypeDeclName(MediaFormatReader);
|
||||
|
||||
class MediaFormatReader final
|
||||
: public DecoderDoctorLifeLogger<MediaFormatReader>
|
||||
{
|
||||
static const bool IsExclusive = true;
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
|
@ -383,6 +386,14 @@ private:
|
|||
, mLastStreamSourceID(UINT32_MAX)
|
||||
, mIsNullDecode(false)
|
||||
{
|
||||
DecoderDoctorLogger::LogConstruction("MediaFormatReader::DecoderData",
|
||||
this);
|
||||
}
|
||||
|
||||
~DecoderData()
|
||||
{
|
||||
DecoderDoctorLogger::LogDestruction("MediaFormatReader::DecoderData",
|
||||
this);
|
||||
}
|
||||
|
||||
MediaFormatReader* mOwner;
|
||||
|
@ -617,6 +628,17 @@ private:
|
|||
: DecoderData(aOwner, aType, aNumOfMaxError)
|
||||
, mHasPromise(false)
|
||||
{
|
||||
DecoderDoctorLogger::LogConstructionAndBase(
|
||||
"MediaFormatReader::DecoderDataWithPromise",
|
||||
this,
|
||||
"MediaFormatReader::DecoderData",
|
||||
static_cast<const MediaFormatReader::DecoderData*>(this));
|
||||
}
|
||||
|
||||
~DecoderDataWithPromise()
|
||||
{
|
||||
DecoderDoctorLogger::LogDestruction(
|
||||
"MediaFormatReader::DecoderDataWithPromise", this);
|
||||
}
|
||||
|
||||
bool HasPromise() const override
|
||||
|
|
|
@ -1721,8 +1721,6 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId,
|
|||
MediaManager* manager = MediaManager::GetIfExists();
|
||||
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
|
||||
realBackend = manager->GetBackend(aWindowId);
|
||||
// We need to listen to this event even JS didn't listen to it.
|
||||
realBackend->AddDeviceChangeCallback(manager);
|
||||
}
|
||||
|
||||
auto result = MakeUnique<SourceSet>();
|
||||
|
@ -2025,6 +2023,9 @@ int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
|
|||
MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
|
||||
MediaManager* manager = MediaManager::GetIfExists();
|
||||
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
|
||||
// this is needed in case persistent permission is given but no gUM()
|
||||
// or enumeration() has created the real backend yet
|
||||
manager->GetBackend(0);
|
||||
if (fakeDeviceChangeEventOn)
|
||||
manager->GetBackend(0)->SetFakeDeviceChangeEvents();
|
||||
}));
|
||||
|
@ -2916,6 +2917,7 @@ MediaManager::GetBackend(uint64_t aWindowId)
|
|||
#else
|
||||
mBackend = new MediaEngineDefault();
|
||||
#endif
|
||||
mBackend->AddDeviceChangeCallback(this);
|
||||
}
|
||||
return mBackend;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,8 @@ using mozilla::media::TimeUnit;
|
|||
mozilla::LazyLogModule gMediaResourceIndexLog("MediaResourceIndex");
|
||||
// Debug logging macro with object pointer and class name.
|
||||
#define ILOG(msg, ...) \
|
||||
MOZ_LOG(gMediaResourceIndexLog, \
|
||||
mozilla::LogLevel::Debug, \
|
||||
("%p " msg, this, ##__VA_ARGS__))
|
||||
DDMOZ_LOG( \
|
||||
gMediaResourceIndexLog, mozilla::LogLevel::Debug, msg, ##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -57,6 +56,7 @@ MediaResourceIndex::MediaResourceIndex(MediaResource* aResource)
|
|||
, mCachedBytes(0)
|
||||
, mCachedBlock(MakeUnique<char[]>(mCacheBlockSize))
|
||||
{
|
||||
DDLINKCHILD("resource", aResource);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#if !defined(MediaResource_h_)
|
||||
#define MediaResource_h_
|
||||
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "Intervals.h"
|
||||
#include "MediaData.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
@ -22,6 +23,8 @@ namespace mozilla {
|
|||
typedef media::Interval<int64_t> MediaByteRange;
|
||||
typedef media::IntervalSet<int64_t> MediaByteRangeSet;
|
||||
|
||||
DDLoggedTypeDeclName(MediaResource);
|
||||
|
||||
/**
|
||||
* Provides a thread-safe, seek/read interface to resources
|
||||
* loaded from a URI. Uses MediaCache to cache data received over
|
||||
|
@ -45,7 +48,7 @@ typedef media::IntervalSet<int64_t> MediaByteRangeSet;
|
|||
* For cross-process blob URL, CloneableWithRangeMediaResource is used.
|
||||
* MediaResource::Create automatically chooses the best implementation class.
|
||||
*/
|
||||
class MediaResource
|
||||
class MediaResource : public DecoderDoctorLifeLogger<MediaResource>
|
||||
{
|
||||
public:
|
||||
// Our refcounting is threadsafe, and when our refcount drops to zero
|
||||
|
@ -147,6 +150,8 @@ private:
|
|||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
DDLoggedTypeDeclName(MediaResourceIndex);
|
||||
|
||||
/*
|
||||
* MediaResourceIndex provides a way to access MediaResource objects.
|
||||
* Read, Seek and Tell must only be called on non-main threads.
|
||||
|
@ -154,7 +159,7 @@ private:
|
|||
* example. You must ensure that no threads are calling these methods once
|
||||
* the MediaResource has been Closed.
|
||||
*/
|
||||
class MediaResourceIndex
|
||||
class MediaResourceIndex : public DecoderDoctorLifeLogger<MediaResourceIndex>
|
||||
{
|
||||
public:
|
||||
explicit MediaResourceIndex(MediaResource* aResource);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef MediaResourceCallback_h_
|
||||
#define MediaResourceCallback_h_
|
||||
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "nsError.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "MediaResult.h"
|
||||
|
@ -17,6 +18,8 @@ class AbstractThread;
|
|||
class MediaDecoderOwner;
|
||||
class MediaResource;
|
||||
|
||||
DDLoggedTypeDeclName(MediaResourceCallback);
|
||||
|
||||
/**
|
||||
* A callback used by MediaResource (sub-classes like FileMediaResource,
|
||||
* RtspMediaResource, and ChannelMediaResource) to notify various events.
|
||||
|
@ -26,7 +29,9 @@ class MediaResource;
|
|||
* gtests for the readers without using a mock MediaResource when you don't
|
||||
* care about the events notified by the MediaResource.
|
||||
*/
|
||||
class MediaResourceCallback {
|
||||
class MediaResourceCallback
|
||||
: public DecoderDoctorLifeLogger<MediaResourceCallback>
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaResourceCallback);
|
||||
|
||||
|
|
|
@ -9,14 +9,24 @@
|
|||
namespace mozilla {
|
||||
|
||||
const char* const kDDLogCategoryShortStrings[kDDLogCategoryCount] = {
|
||||
"con", "dcn", "des", "lnk", "ulk", "prp", "evt", "api", "log"
|
||||
"con", "dcn", "des", "lnk", "ulk", "prp", "evt",
|
||||
"api", "log", "mze", "mzw", "mzi", "mzd", "mzv"
|
||||
};
|
||||
const char* const kDDLogCategoryLongStrings[kDDLogCategoryCount] = {
|
||||
"Construction", "Derived Construction",
|
||||
"Destruction", "Link",
|
||||
"Unlink", "Property",
|
||||
"Event", "API",
|
||||
"Log"
|
||||
"Construction",
|
||||
"Derived Construction",
|
||||
"Destruction",
|
||||
"Link",
|
||||
"Unlink",
|
||||
"Property",
|
||||
"Event",
|
||||
"API",
|
||||
"Log",
|
||||
"MozLog-Error",
|
||||
"MozLog-Warning",
|
||||
"MozLog-Info",
|
||||
"MozLog-Debug",
|
||||
"MozLog-Verbose"
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -23,7 +23,12 @@ MOZ_DEFINE_ENUM_CLASS(DDLogCategory,
|
|||
Property,
|
||||
Event,
|
||||
API,
|
||||
Log));
|
||||
Log,
|
||||
MozLogError,
|
||||
MozLogWarning,
|
||||
MozLogInfo,
|
||||
MozLogDebug,
|
||||
MozLogVerbose));
|
||||
|
||||
// Corresponding short strings, used as JSON property names when logs are
|
||||
// retrieved.
|
||||
|
|
|
@ -305,6 +305,9 @@ size_t
|
|||
DDMediaLogs::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t size = aMallocSizeOf(this) +
|
||||
// This will usually be called after processing, so negligible
|
||||
// external data should still be present in the queue.
|
||||
mMessagesQueue.ShallowSizeOfExcludingThis(aMallocSizeOf) +
|
||||
mLifetimes.SizeOfExcludingThis(aMallocSizeOf) +
|
||||
mMediaLogs.ShallowSizeOfExcludingThis(aMallocSizeOf) +
|
||||
mObjectLinks.ShallowSizeOfExcludingThis(aMallocSizeOf) +
|
||||
|
@ -676,7 +679,8 @@ DDMediaLogs::ProcessLog()
|
|||
ProcessBuffer();
|
||||
FulfillPromises();
|
||||
CleanUpLogs();
|
||||
DDL_INFO("DDMediaLog size: %zu", SizeOfIncludingThis(moz_malloc_size_of));
|
||||
DDL_INFO("ProcessLog() completed - DDMediaLog size: %zu",
|
||||
SizeOfIncludingThis(moz_malloc_size_of));
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -693,6 +697,8 @@ DDMediaLogs::DispatchProcessLog(const MutexAutoLock& aProofOfLock)
|
|||
nsresult
|
||||
DDMediaLogs::DispatchProcessLog()
|
||||
{
|
||||
DDL_INFO("DispatchProcessLog() - Yet-unprocessed message buffers: %d",
|
||||
mMessagesQueue.LiveBuffersStats().mCount);
|
||||
MutexAutoLock lock(mMutex);
|
||||
return DispatchProcessLog(lock);
|
||||
}
|
||||
|
|
|
@ -14,13 +14,23 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
/* static */ Atomic<DecoderDoctorLogger::LogState>
|
||||
/* static */ Atomic<DecoderDoctorLogger::LogState, ReleaseAcquire>
|
||||
DecoderDoctorLogger::sLogState{ DecoderDoctorLogger::scDisabled };
|
||||
|
||||
/* static */ const char* DecoderDoctorLogger::sShutdownReason = nullptr;
|
||||
|
||||
static DDMediaLogs* sMediaLogs;
|
||||
|
||||
/* static */ void
|
||||
DecoderDoctorLogger::Init()
|
||||
{
|
||||
MOZ_ASSERT(static_cast<LogState>(sLogState) == scDisabled);
|
||||
if (MOZ_LOG_TEST(sDecoderDoctorLoggerLog, LogLevel::Error) ||
|
||||
MOZ_LOG_TEST(sDecoderDoctorLoggerEndLog, LogLevel::Error)) {
|
||||
EnableLogging();
|
||||
}
|
||||
}
|
||||
|
||||
// First DDLogShutdowner sets sLogState to scShutdown, to prevent further
|
||||
// logging.
|
||||
struct DDLogShutdowner
|
||||
|
|
|
@ -37,6 +37,10 @@ namespace mozilla {
|
|||
class DecoderDoctorLogger
|
||||
{
|
||||
public:
|
||||
// Called by nsLayoutStatics::Initialize() before any other media work.
|
||||
// Pre-enables logging if MOZ_LOG requires DDLogger.
|
||||
static void Init();
|
||||
|
||||
// Is logging currently enabled? This is tested anyway in all public `Log...`
|
||||
// functions, but it may be used to prevent logging-only work in clients.
|
||||
static inline bool IsDDLoggingEnabled()
|
||||
|
@ -123,6 +127,19 @@ public:
|
|||
DDLoggedTypeTraits<Subject>::Name(), aSubject, aCategory, aLabel, aValue);
|
||||
}
|
||||
|
||||
static void EagerLogPrintf(const char* aSubjectTypeName,
|
||||
const void* aSubjectPointer,
|
||||
DDLogCategory aCategory,
|
||||
const char* aLabel,
|
||||
const char* aString)
|
||||
{
|
||||
Log(aSubjectTypeName,
|
||||
aSubjectPointer,
|
||||
aCategory,
|
||||
aLabel,
|
||||
DDLogValue{ nsCString{ aString } });
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static void EagerLogPrintf(const char* aSubjectTypeName,
|
||||
const void* aSubjectPointer,
|
||||
|
@ -139,6 +156,19 @@ public:
|
|||
nsCString{ nsPrintfCString(aFormat, Forward<Args>(aArgs)...) } });
|
||||
}
|
||||
|
||||
template<typename Subject>
|
||||
static void EagerLogPrintf(const Subject* aSubject,
|
||||
DDLogCategory aCategory,
|
||||
const char* aLabel,
|
||||
const char* aString)
|
||||
{
|
||||
EagerLogPrintf(DDLoggedTypeTraits<Subject>::Name(),
|
||||
aSubject,
|
||||
aCategory,
|
||||
aLabel,
|
||||
aString);
|
||||
}
|
||||
|
||||
template<typename Subject, typename... Args>
|
||||
static void EagerLogPrintf(const Subject* aSubject,
|
||||
DDLogCategory aCategory,
|
||||
|
@ -154,6 +184,69 @@ public:
|
|||
Forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
static void MozLogPrintf(const char* aSubjectTypeName,
|
||||
const void* aSubjectPointer,
|
||||
const LogModule* aLogModule,
|
||||
LogLevel aLogLevel,
|
||||
const char* aString)
|
||||
{
|
||||
Log(aSubjectTypeName,
|
||||
aSubjectPointer,
|
||||
CategoryForMozLogLevel(aLogLevel),
|
||||
aLogModule->Name(), // LogModule name as label.
|
||||
DDLogValue{ nsCString{ aString } });
|
||||
MOZ_LOG(aLogModule,
|
||||
aLogLevel,
|
||||
("%s[%p] %s", aSubjectTypeName, aSubjectPointer, aString));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static void MozLogPrintf(const char* aSubjectTypeName,
|
||||
const void* aSubjectPointer,
|
||||
const LogModule* aLogModule,
|
||||
LogLevel aLogLevel,
|
||||
const char* aFormat,
|
||||
Args&&... aArgs)
|
||||
{
|
||||
nsCString printed = nsPrintfCString(aFormat, Forward<Args>(aArgs)...);
|
||||
Log(aSubjectTypeName,
|
||||
aSubjectPointer,
|
||||
CategoryForMozLogLevel(aLogLevel),
|
||||
aLogModule->Name(), // LogModule name as label.
|
||||
DDLogValue{ printed });
|
||||
MOZ_LOG(aLogModule,
|
||||
aLogLevel,
|
||||
("%s[%p] %s", aSubjectTypeName, aSubjectPointer, printed.get()));
|
||||
}
|
||||
|
||||
template<typename Subject>
|
||||
static void MozLogPrintf(const Subject* aSubject,
|
||||
const LogModule* aLogModule,
|
||||
LogLevel aLogLevel,
|
||||
const char* aString)
|
||||
{
|
||||
MozLogPrintf(DDLoggedTypeTraits<Subject>::Name(),
|
||||
aSubject,
|
||||
aLogModule,
|
||||
aLogLevel,
|
||||
aString);
|
||||
}
|
||||
|
||||
template<typename Subject, typename... Args>
|
||||
static void MozLogPrintf(const Subject* aSubject,
|
||||
const LogModule* aLogModule,
|
||||
LogLevel aLogLevel,
|
||||
const char* aFormat,
|
||||
Args&&... aArgs)
|
||||
{
|
||||
MozLogPrintf(DDLoggedTypeTraits<Subject>::Name(),
|
||||
aSubject,
|
||||
aLogModule,
|
||||
aLogLevel,
|
||||
aFormat,
|
||||
Forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
// Special logging functions. Consider using DecoderDoctorLifeLogger to
|
||||
// automatically capture constructions & destructions.
|
||||
|
||||
|
@ -335,6 +428,29 @@ private:
|
|||
const char* aLabel,
|
||||
DDLogValue&& aValue);
|
||||
|
||||
static void Log(const char* aSubjectTypeName,
|
||||
const void* aSubjectPointer,
|
||||
const LogModule* aLogModule,
|
||||
LogLevel aLogLevel,
|
||||
DDLogValue&& aValue);
|
||||
|
||||
static DDLogCategory CategoryForMozLogLevel(LogLevel aLevel)
|
||||
{
|
||||
switch (aLevel) {
|
||||
default:
|
||||
case LogLevel::Error:
|
||||
return DDLogCategory::MozLogError;
|
||||
case LogLevel::Warning:
|
||||
return DDLogCategory::MozLogWarning;
|
||||
case LogLevel::Info:
|
||||
return DDLogCategory::MozLogInfo;
|
||||
case LogLevel::Debug:
|
||||
return DDLogCategory::MozLogDebug;
|
||||
case LogLevel::Verbose:
|
||||
return DDLogCategory::MozLogVerbose;
|
||||
}
|
||||
}
|
||||
|
||||
using LogState = int;
|
||||
// Currently disabled, may be enabled on request.
|
||||
static constexpr LogState scDisabled = 0;
|
||||
|
@ -346,7 +462,9 @@ private:
|
|||
// Shutdown, cannot be re-enabled.
|
||||
static constexpr LogState scShutdown = 3;
|
||||
// Current state.
|
||||
static Atomic<LogState> sLogState;
|
||||
// "ReleaseAcquire" because when changing to scEnabled, the just-created
|
||||
// sMediaLogs must be accessible to consumers that see scEnabled.
|
||||
static Atomic<LogState, ReleaseAcquire> sLogState;
|
||||
|
||||
// If non-null, reason for an abnormal shutdown.
|
||||
static const char* sShutdownReason;
|
||||
|
@ -400,7 +518,7 @@ public:
|
|||
// Do a printf format check in DEBUG, with the downside that side-effects (from
|
||||
// evaluating the arguments) may happen twice! Who would do that anyway?
|
||||
static void inline MOZ_FORMAT_PRINTF(1, 2) DDLOGPRCheck(const char*, ...) {}
|
||||
#define DDLOGPR_CHECK(_fmt, ...) DDLOGPRCheck(_fmt, __VA_ARGS__)
|
||||
#define DDLOGPR_CHECK(_fmt, ...) DDLOGPRCheck(_fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DDLOGPR_CHECK(_fmt, ...)
|
||||
#endif
|
||||
|
@ -409,9 +527,9 @@ static void inline MOZ_FORMAT_PRINTF(1, 2) DDLOGPRCheck(const char*, ...) {}
|
|||
#define DDLOGPR(_category, _label, _format, ...) \
|
||||
do { \
|
||||
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
||||
DDLOGPR_CHECK(_format, __VA_ARGS__); \
|
||||
DDLOGPR_CHECK(_format, ##__VA_ARGS__); \
|
||||
DecoderDoctorLogger::EagerLogPrintf( \
|
||||
this, _category, _label, _format, __VA_ARGS__); \
|
||||
this, _category, _label, _format, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
@ -431,6 +549,33 @@ static void inline MOZ_FORMAT_PRINTF(1, 2) DDLOGPRCheck(const char*, ...) {}
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
// Log a printf'd string to DDLogger and/or MOZ_LOG, with an EXplicit `this`.
|
||||
// Don't even call MOZ_LOG on Android non-release/beta; See Logging.h.
|
||||
#if !defined(ANDROID) || !defined(RELEASE_OR_BETA)
|
||||
#define DDMOZ_LOGEX(_this, _logModule, _logLevel, _format, ...) \
|
||||
do { \
|
||||
if (DecoderDoctorLogger::IsDDLoggingEnabled() || \
|
||||
MOZ_LOG_TEST(_logModule, _logLevel)) { \
|
||||
DDLOGPR_CHECK(_format, ##__VA_ARGS__); \
|
||||
DecoderDoctorLogger::MozLogPrintf( \
|
||||
_this, _logModule, _logLevel, _format, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define DDMOZ_LOGEX(_this, _logModule, _logLevel, _format, ...) \
|
||||
do { \
|
||||
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
||||
DDLOGPR_CHECK(_format, ##__VA_ARGS__); \
|
||||
DecoderDoctorLogger::MozLogPrintf( \
|
||||
_this, _logModule, _logLevel, _format, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
// Log a printf'd string to DDLogger and/or MOZ_LOG.
|
||||
#define DDMOZ_LOG(_logModule, _logLevel, _format, ...) \
|
||||
DDMOZ_LOGEX(this, _logModule, _logLevel, _format, ##__VA_ARGS__)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DecoderDoctorLogger_h_
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define mozilla_MultiWriterQueue_h_
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "prthread.h"
|
||||
|
@ -253,6 +254,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Size of all buffers (used, or recyclable), excluding external data.
|
||||
size_t ShallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return mAllocatedBuffersStats.Count() * sizeof(Buffer);
|
||||
}
|
||||
|
||||
struct CountAndWatermark
|
||||
{
|
||||
int mCount;
|
||||
|
@ -300,7 +307,10 @@ private:
|
|||
T mT;
|
||||
// mValid should be atomically changed to true *after* mT has been written,
|
||||
// so that the reader can only see valid data.
|
||||
Atomic<bool> mValid{ false };
|
||||
// ReleaseAcquire, because when set to `true`, we want the just-written mT
|
||||
// to be visible to the thread reading this `true`; and when set to `false`,
|
||||
// we want the previous reads to have completed.
|
||||
Atomic<bool, ReleaseAcquire> mValid{ false };
|
||||
};
|
||||
|
||||
// Buffer contains a sequence of BufferedElements starting at a specific
|
||||
|
@ -447,7 +457,11 @@ private:
|
|||
// Index of the next element to write. Modified when an element index is
|
||||
// claimed for a push. If the last element of a buffer is claimed, that push
|
||||
// will be responsible for adding a new head buffer.
|
||||
Atomic<Index::ValueType> mNextElementToWrite{ 0 };
|
||||
// Relaxed, because there is no synchronization based on this variable, each
|
||||
// thread just needs to get a different value, and will then write different
|
||||
// things (which themselves have some atomic validation before they may be
|
||||
// read elsewhere, independent of this `mNextElementToWrite`.)
|
||||
Atomic<Index::ValueType, Relaxed> mNextElementToWrite{ 0 };
|
||||
|
||||
// Index that a live recent buffer reaches. If a push claims a lesser-or-
|
||||
// equal number, the corresponding buffer is guaranteed to still be alive:
|
||||
|
@ -456,15 +470,21 @@ private:
|
|||
// including the one that just claimed a position within it.
|
||||
// Also, the push that claims this exact number is responsible for adding the
|
||||
// next buffer and updating this value accordingly.
|
||||
Atomic<Index::ValueType> mBuffersCoverAtLeastUpTo;
|
||||
// ReleaseAcquire, because when set to a certain value, the just-created
|
||||
// buffer covering the new range must be visible to readers.
|
||||
Atomic<Index::ValueType, ReleaseAcquire> mBuffersCoverAtLeastUpTo;
|
||||
|
||||
// Pointer to the most recent buffer. Never null.
|
||||
// This is the most recent of a deque of yet-unread buffers.
|
||||
// Only modified when adding a new head buffer.
|
||||
Atomic<Buffer*> mMostRecentBuffer;
|
||||
// ReleaseAcquire, because when modified, the just-created new buffer must be
|
||||
// visible to readers.
|
||||
Atomic<Buffer*, ReleaseAcquire> mMostRecentBuffer;
|
||||
|
||||
// Stack of reusable buffers.
|
||||
Atomic<Buffer*> mReusableBuffers;
|
||||
// ReleaseAcquire, because when modified, the just-added buffer must be
|
||||
// visible to readers.
|
||||
Atomic<Buffer*, ReleaseAcquire> mReusableBuffers;
|
||||
|
||||
// Template-provided locking mechanism to protect PopAll()-only member
|
||||
// variables below.
|
||||
|
@ -487,6 +507,8 @@ private:
|
|||
{
|
||||
}
|
||||
|
||||
int Count() const { return int(mCount); }
|
||||
|
||||
CountAndWatermark Get() const
|
||||
{
|
||||
return CountAndWatermark{ int(mCount), int(mWatermark) };
|
||||
|
@ -518,8 +540,10 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
Atomic<int> mCount;
|
||||
Atomic<int> mWatermark;
|
||||
// Relaxed, as these are just gathering stats, so consistency is not
|
||||
// critical.
|
||||
Atomic<int, Relaxed> mCount;
|
||||
Atomic<int, Relaxed> mWatermark;
|
||||
};
|
||||
// All buffers in the mMostRecentBuffer deque.
|
||||
AtomicCountAndWatermark mLiveBuffersStats;
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
struct JSContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class MediaKeySession;
|
||||
} // namespace dom
|
||||
DDLoggedTypeName(dom::MediaKeySession);
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferViewOrArrayBuffer;
|
||||
|
@ -36,7 +42,9 @@ ToCString(MediaKeySessionType aType);
|
|||
nsString
|
||||
ToString(MediaKeySessionType aType);
|
||||
|
||||
class MediaKeySession final : public DOMEventTargetHelper
|
||||
class MediaKeySession final
|
||||
: public DOMEventTargetHelper
|
||||
, public DecoderDoctorLifeLogger<MediaKeySession>
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
|
|
@ -498,6 +498,7 @@ MediaKeys::CreateSession(JSContext* aCx,
|
|||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
DDLINKCHILD("session", session.get());
|
||||
|
||||
// Add session to the set of sessions awaiting their sessionId being ready.
|
||||
mPendingSessions.Put(session->Token(), session);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef mozilla_dom_mediakeys_h__
|
||||
#define mozilla_dom_mediakeys_h__
|
||||
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsISupports.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
@ -26,6 +27,11 @@ namespace mozilla {
|
|||
|
||||
class CDMProxy;
|
||||
|
||||
namespace dom {
|
||||
class MediaKeys;
|
||||
} // namespace dom
|
||||
DDLoggedTypeName(dom::MediaKeys);
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferViewOrArrayBuffer;
|
||||
|
@ -41,9 +47,11 @@ typedef uint32_t PromiseId;
|
|||
|
||||
// This class is used on the main thread only.
|
||||
// Note: its addref/release is not (and can't be) thread safe!
|
||||
class MediaKeys final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public SupportsWeakPtr<MediaKeys>
|
||||
class MediaKeys final
|
||||
: public nsISupports
|
||||
, public nsWrapperCache
|
||||
, public SupportsWeakPtr<MediaKeys>
|
||||
, public DecoderDoctorLifeLogger<MediaKeys>
|
||||
{
|
||||
~MediaKeys();
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
#include "TimeUnits.h"
|
||||
|
||||
extern mozilla::LazyLogModule gMediaDemuxerLog;
|
||||
#define LOG(msg, ...) \
|
||||
MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("FlacDemuxer " msg, ##__VA_ARGS__))
|
||||
#define LOGV(msg, ...) \
|
||||
MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, ("FlacDemuxer " msg, ##__VA_ARGS__))
|
||||
#define LOG(msg, ...) \
|
||||
DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
|
||||
#define LOGV(msg, ...) \
|
||||
DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
|
||||
|
||||
using namespace mozilla::media;
|
||||
|
||||
|
@ -559,13 +559,18 @@ private:
|
|||
|
||||
// FlacDemuxer
|
||||
|
||||
FlacDemuxer::FlacDemuxer(MediaResource* aSource) : mSource(aSource) { }
|
||||
FlacDemuxer::FlacDemuxer(MediaResource* aSource)
|
||||
: mSource(aSource)
|
||||
{
|
||||
DDLINKCHILD("source", aSource);
|
||||
}
|
||||
|
||||
bool
|
||||
FlacDemuxer::InitInternal()
|
||||
{
|
||||
if (!mTrackDemuxer) {
|
||||
mTrackDemuxer = new FlacTrackDemuxer(mSource);
|
||||
DDLINKCHILD("track demuxer", mTrackDemuxer.get());
|
||||
}
|
||||
return mTrackDemuxer->Init();
|
||||
}
|
||||
|
@ -612,6 +617,7 @@ FlacTrackDemuxer::FlacTrackDemuxer(MediaResource* aSource)
|
|||
, mParser(new flac::FrameParser())
|
||||
, mTotalFrameLen(0)
|
||||
{
|
||||
DDLINKCHILD("source", aSource);
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,12 @@ class FrameParser;
|
|||
}
|
||||
class FlacTrackDemuxer;
|
||||
|
||||
DDLoggedTypeDeclNameAndBase(FlacDemuxer, MediaDataDemuxer);
|
||||
DDLoggedTypeNameAndBase(FlacTrackDemuxer, MediaTrackDemuxer);
|
||||
|
||||
class FlacDemuxer : public MediaDataDemuxer
|
||||
class FlacDemuxer
|
||||
: public MediaDataDemuxer
|
||||
, public DecoderDoctorLifeLogger<FlacDemuxer>
|
||||
{
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
|
@ -40,7 +44,9 @@ private:
|
|||
RefPtr<FlacTrackDemuxer> mTrackDemuxer;
|
||||
};
|
||||
|
||||
class FlacTrackDemuxer : public MediaTrackDemuxer
|
||||
class FlacTrackDemuxer
|
||||
: public MediaTrackDemuxer
|
||||
, public DecoderDoctorLifeLogger<FlacTrackDemuxer>
|
||||
{
|
||||
public:
|
||||
explicit FlacTrackDemuxer(MediaResource* aSource);
|
||||
|
|
|
@ -9,10 +9,13 @@
|
|||
#include "nsTArray.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
namespace mozilla {
|
||||
|
||||
class MockMediaResource : public MediaResource
|
||||
DDLoggedTypeDeclNameAndBase(MockMediaResource, MediaResource);
|
||||
|
||||
class MockMediaResource
|
||||
: public MediaResource
|
||||
, public DecoderDoctorLifeLogger<MockMediaResource>
|
||||
{
|
||||
public:
|
||||
explicit MockMediaResource(const char* aFileName);
|
||||
|
|
|
@ -10,12 +10,21 @@
|
|||
#include "mozilla/ArrayUtils.h"
|
||||
#include "MockMediaResource.h"
|
||||
|
||||
class MockMP3MediaResource;
|
||||
class MockMP3StreamMediaResource;
|
||||
namespace mozilla {
|
||||
DDLoggedTypeNameAndBase(::MockMP3MediaResource, MockMediaResource);
|
||||
DDLoggedTypeNameAndBase(::MockMP3StreamMediaResource, MockMP3MediaResource);
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
using media::TimeUnit;
|
||||
|
||||
|
||||
// Regular MP3 file mock resource.
|
||||
class MockMP3MediaResource : public MockMediaResource {
|
||||
class MockMP3MediaResource
|
||||
: public MockMediaResource
|
||||
, public DecoderDoctorLifeLogger<MockMP3MediaResource>
|
||||
{
|
||||
public:
|
||||
explicit MockMP3MediaResource(const char* aFileName)
|
||||
: MockMediaResource(aFileName)
|
||||
|
@ -26,7 +35,10 @@ protected:
|
|||
};
|
||||
|
||||
// MP3 stream mock resource.
|
||||
class MockMP3StreamMediaResource : public MockMP3MediaResource {
|
||||
class MockMP3StreamMediaResource
|
||||
: public MockMP3MediaResource
|
||||
, public DecoderDoctorLifeLogger<MockMP3StreamMediaResource>
|
||||
{
|
||||
public:
|
||||
explicit MockMP3StreamMediaResource(const char* aFileName)
|
||||
: MockMP3MediaResource(aFileName)
|
||||
|
|
|
@ -12,11 +12,18 @@
|
|||
#include "MP4Metadata.h"
|
||||
#include "MoofParser.h"
|
||||
|
||||
class TestStream;
|
||||
namespace mozilla {
|
||||
DDLoggedTypeNameAndBase(::TestStream, ByteStream);
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static const uint32_t E = MP4Metadata::NumberTracksError();
|
||||
|
||||
class TestStream : public ByteStream
|
||||
class TestStream
|
||||
: public ByteStream
|
||||
, public DecoderDoctorLifeLogger<TestStream>
|
||||
{
|
||||
public:
|
||||
TestStream(const uint8_t* aBuffer, size_t aSize)
|
||||
|
|
|
@ -25,7 +25,12 @@ class AbstractThread;
|
|||
class MediaResult;
|
||||
class HLSTrackDemuxer;
|
||||
|
||||
class HLSDemuxer final : public MediaDataDemuxer
|
||||
DDLoggedTypeDeclNameAndBase(HLSDemuxer, MediaDataDemuxer);
|
||||
DDLoggedTypeNameAndBase(HLSTrackDemuxer, MediaTrackDemuxer);
|
||||
|
||||
class HLSDemuxer final
|
||||
: public MediaDataDemuxer
|
||||
, public DecoderDoctorLifeLogger<HLSDemuxer>
|
||||
{
|
||||
class HLSDemuxerCallbacksSupport;
|
||||
public:
|
||||
|
@ -68,7 +73,9 @@ private:
|
|||
java::GeckoHLSDemuxerWrapper::GlobalRef mHLSDemuxerWrapper;
|
||||
};
|
||||
|
||||
class HLSTrackDemuxer : public MediaTrackDemuxer
|
||||
class HLSTrackDemuxer
|
||||
: public MediaTrackDemuxer
|
||||
, public DecoderDoctorLifeLogger<HLSTrackDemuxer>
|
||||
{
|
||||
public:
|
||||
HLSTrackDemuxer(HLSDemuxer* aParent,
|
||||
|
|
|
@ -12,6 +12,14 @@
|
|||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class RemoteVideoDecoder;
|
||||
}
|
||||
DDLoggedTypeCustomNameAndBase(dom::RemoteVideoDecoder,
|
||||
RemoteVideoDecoder,
|
||||
MediaDataDecoder);
|
||||
|
||||
namespace dom {
|
||||
|
||||
class VideoDecoderChild;
|
||||
|
@ -21,7 +29,9 @@ class RemoteDecoderModule;
|
|||
// to a 'real' decoder in the GPU process.
|
||||
// All requests get forwarded to a VideoDecoderChild instance that
|
||||
// operates solely on the VideoDecoderManagerChild thread.
|
||||
class RemoteVideoDecoder : public MediaDataDecoder
|
||||
class RemoteVideoDecoder
|
||||
: public MediaDataDecoder
|
||||
, public DecoderDoctorLifeLogger<RemoteVideoDecoder>
|
||||
{
|
||||
public:
|
||||
friend class RemoteDecoderModule;
|
||||
|
|
|
@ -30,8 +30,28 @@ extern mozilla::LogModule* GetMediaSourceSamplesLog();
|
|||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#define MSE_DEBUG(name, arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Debug, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUGV(name, arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Verbose, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUG(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceSamplesLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define MSE_DEBUGV(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceSamplesLog(), \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define MSE_DEBUGVEX(_this, arg, ...) \
|
||||
DDMOZ_LOGEX(_this, \
|
||||
GetMediaSourceSamplesLog(), \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -48,7 +68,7 @@ ContainerParser::~ContainerParser() = default;
|
|||
MediaResult
|
||||
ContainerParser::IsInitSegmentPresent(MediaByteBuffer* aData)
|
||||
{
|
||||
MSE_DEBUG(ContainerParser, "aLength=%zu [%x%x%x%x]",
|
||||
MSE_DEBUG("aLength=%zu [%x%x%x%x]",
|
||||
aData->Length(),
|
||||
aData->Length() > 0 ? (*aData)[0] : 0,
|
||||
aData->Length() > 1 ? (*aData)[1] : 0,
|
||||
|
@ -60,7 +80,7 @@ ContainerParser::IsInitSegmentPresent(MediaByteBuffer* aData)
|
|||
MediaResult
|
||||
ContainerParser::IsMediaSegmentPresent(MediaByteBuffer* aData)
|
||||
{
|
||||
MSE_DEBUG(ContainerParser, "aLength=%zu [%x%x%x%x]",
|
||||
MSE_DEBUG("aLength=%zu [%x%x%x%x]",
|
||||
aData->Length(),
|
||||
aData->Length() > 0 ? (*aData)[0] : 0,
|
||||
aData->Length() > 1 ? (*aData)[1] : 0,
|
||||
|
@ -119,7 +139,11 @@ ContainerParser::MediaSegmentRange()
|
|||
return mCompleteMediaSegmentRange;
|
||||
}
|
||||
|
||||
class WebMContainerParser : public ContainerParser
|
||||
DDLoggedTypeDeclNameAndBase(WebMContainerParser, ContainerParser);
|
||||
|
||||
class WebMContainerParser
|
||||
: public ContainerParser
|
||||
, public DecoderDoctorLifeLogger<WebMContainerParser>
|
||||
{
|
||||
public:
|
||||
explicit WebMContainerParser(const MediaContainerType& aType)
|
||||
|
@ -183,8 +207,7 @@ public:
|
|||
mCompleteMediaSegmentRange =
|
||||
MediaByteRange(mLastMapping.ref().mSyncOffset, mOffset) + mGlobalOffset;
|
||||
mLastMapping.reset();
|
||||
MSE_DEBUG(WebMContainerParser,
|
||||
"New cluster found at start, ending previous one");
|
||||
MSE_DEBUG("New cluster found at start, ending previous one");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
|
@ -194,6 +217,7 @@ public:
|
|||
mOverlappedMapping.Clear();
|
||||
mInitData = new MediaByteBuffer();
|
||||
mResource = new SourceBufferResource();
|
||||
DDLINKCHILD("resource", mResource.get());
|
||||
mCompleteInitSegmentRange = MediaByteRange();
|
||||
mCompleteMediaHeaderRange = MediaByteRange();
|
||||
mCompleteMediaSegmentRange = MediaByteRange();
|
||||
|
@ -225,11 +249,10 @@ public:
|
|||
MediaByteRange(0, mParser.mInitEndOffset) + mGlobalOffset;
|
||||
char* buffer = reinterpret_cast<char*>(mInitData->Elements());
|
||||
mResource->ReadFromCache(buffer, 0, mParser.mInitEndOffset);
|
||||
MSE_DEBUG(WebMContainerParser, "Stashed init of %" PRId64 " bytes.",
|
||||
mParser.mInitEndOffset);
|
||||
MSE_DEBUG("Stashed init of %" PRId64 " bytes.", mParser.mInitEndOffset);
|
||||
mResource = nullptr;
|
||||
} else {
|
||||
MSE_DEBUG(WebMContainerParser, "Incomplete init found.");
|
||||
MSE_DEBUG("Incomplete init found.");
|
||||
}
|
||||
mHasInitData = true;
|
||||
}
|
||||
|
@ -252,7 +275,7 @@ public:
|
|||
|
||||
int32_t completeIdx = endIdx;
|
||||
while (completeIdx >= 0 && mOffset < mapping[completeIdx].mEndOffset) {
|
||||
MSE_DEBUG(WebMContainerParser, "block is incomplete, missing: %" PRId64,
|
||||
MSE_DEBUG("block is incomplete, missing: %" PRId64,
|
||||
mapping[completeIdx].mEndOffset - mOffset);
|
||||
completeIdx -= 1;
|
||||
}
|
||||
|
@ -312,8 +335,7 @@ public:
|
|||
aStart = mapping[0].mTimecode / NS_PER_USEC;
|
||||
aEnd = (mapping[completeIdx].mTimecode + frameDuration) / NS_PER_USEC;
|
||||
|
||||
MSE_DEBUG(WebMContainerParser,
|
||||
"[%" PRId64 ", %" PRId64 "] [fso=%" PRId64 ", leo=%" PRId64
|
||||
MSE_DEBUG("[%" PRId64 ", %" PRId64 "] [fso=%" PRId64 ", leo=%" PRId64
|
||||
", l=%zu processedIdx=%u fs=%" PRId64 "]",
|
||||
aStart,
|
||||
aEnd,
|
||||
|
@ -341,7 +363,11 @@ private:
|
|||
|
||||
#ifdef MOZ_FMP4
|
||||
|
||||
class MP4Stream : public ByteStream
|
||||
DDLoggedTypeDeclNameAndBase(MP4Stream, ByteStream);
|
||||
|
||||
class MP4Stream
|
||||
: public ByteStream
|
||||
, public DecoderDoctorLifeLogger<MP4Stream>
|
||||
{
|
||||
public:
|
||||
explicit MP4Stream(SourceBufferResource* aResource);
|
||||
|
@ -365,6 +391,7 @@ MP4Stream::MP4Stream(SourceBufferResource* aResource)
|
|||
{
|
||||
MOZ_COUNT_CTOR(MP4Stream);
|
||||
MOZ_ASSERT(aResource);
|
||||
DDLINKCHILD("resource", aResource);
|
||||
}
|
||||
|
||||
MP4Stream::~MP4Stream()
|
||||
|
@ -406,7 +433,11 @@ MP4Stream::Length(int64_t* aSize)
|
|||
return true;
|
||||
}
|
||||
|
||||
class MP4ContainerParser : public ContainerParser
|
||||
DDLoggedTypeDeclNameAndBase(MP4ContainerParser, ContainerParser);
|
||||
|
||||
class MP4ContainerParser
|
||||
: public ContainerParser
|
||||
, public DecoderDoctorLifeLogger<MP4ContainerParser>
|
||||
{
|
||||
public:
|
||||
explicit MP4ContainerParser(const MediaContainerType& aType)
|
||||
|
@ -423,7 +454,7 @@ public:
|
|||
if (aData->Length() < 8) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
AtomParser parser(mType, aData, AtomParser::StopAt::eInitSegment);
|
||||
AtomParser parser(*this, aData, AtomParser::StopAt::eInitSegment);
|
||||
if (!parser.IsValid()) {
|
||||
return MediaResult(
|
||||
NS_ERROR_FAILURE,
|
||||
|
@ -437,7 +468,7 @@ public:
|
|||
if (aData->Length() < 8) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
AtomParser parser(mType, aData, AtomParser::StopAt::eMediaSegment);
|
||||
AtomParser parser(*this, aData, AtomParser::StopAt::eMediaSegment);
|
||||
if (!parser.IsValid()) {
|
||||
return MediaResult(
|
||||
NS_ERROR_FAILURE,
|
||||
|
@ -457,16 +488,19 @@ private:
|
|||
eEnd
|
||||
};
|
||||
|
||||
AtomParser(const MediaContainerType& aType, const MediaByteBuffer* aData,
|
||||
AtomParser(const MP4ContainerParser& aParser,
|
||||
const MediaByteBuffer* aData,
|
||||
StopAt aStop = StopAt::eEnd)
|
||||
{
|
||||
mValid = Init(aType, aData, aStop).isOk();
|
||||
mValid = Init(aParser, aData, aStop).isOk();
|
||||
}
|
||||
|
||||
Result<Ok, nsresult> Init(const MediaContainerType& aType, const MediaByteBuffer* aData,
|
||||
StopAt aStop)
|
||||
Result<Ok, nsresult> Init(const MP4ContainerParser& aParser,
|
||||
const MediaByteBuffer* aData,
|
||||
StopAt aStop)
|
||||
{
|
||||
const MediaContainerType mType(aType); // for logging macro.
|
||||
const MediaContainerType mType(
|
||||
aParser.ContainerType()); // for logging macro.
|
||||
BufferReader reader(aData);
|
||||
AtomType initAtom("moov");
|
||||
AtomType mediaAtom("moof");
|
||||
|
@ -490,9 +524,13 @@ private:
|
|||
const uint8_t* typec = reader.Peek(4);
|
||||
MOZ_TRY_VAR(tmp, reader.ReadU32());
|
||||
AtomType type(tmp);
|
||||
MSE_DEBUGV(AtomParser ,"Checking atom:'%c%c%c%c' @ %u",
|
||||
typec[0], typec[1], typec[2], typec[3],
|
||||
(uint32_t)reader.Offset() - 8);
|
||||
MSE_DEBUGVEX(&aParser,
|
||||
"Checking atom:'%c%c%c%c' @ %u",
|
||||
typec[0],
|
||||
typec[1],
|
||||
typec[2],
|
||||
typec[3],
|
||||
(uint32_t)reader.Offset() - 8);
|
||||
if (std::find(std::begin(validBoxes), std::end(validBoxes), type)
|
||||
== std::end(validBoxes)) {
|
||||
// No valid box found, no point continuing.
|
||||
|
@ -575,12 +613,14 @@ public:
|
|||
bool initSegment = NS_SUCCEEDED(IsInitSegmentPresent(aData));
|
||||
if (initSegment) {
|
||||
mResource = new SourceBufferResource();
|
||||
DDLINKCHILD("resource", mResource.get());
|
||||
mStream = new MP4Stream(mResource);
|
||||
// We use a timestampOffset of 0 for ContainerParser, and require
|
||||
// consumers of ParseStartAndEndTimestamps to add their timestamp offset
|
||||
// manually. This allows the ContainerParser to be shared across different
|
||||
// timestampOffsets.
|
||||
mParser = new MoofParser(mStream, 0, /* aIsAudio = */ false);
|
||||
DDLINKCHILD("parser", mParser.get());
|
||||
mInitData = new MediaByteBuffer();
|
||||
mCompleteInitSegmentRange = MediaByteRange();
|
||||
mCompleteMediaHeaderRange = MediaByteRange();
|
||||
|
@ -607,10 +647,9 @@ public:
|
|||
}
|
||||
char* buffer = reinterpret_cast<char*>(mInitData->Elements());
|
||||
mResource->ReadFromCache(buffer, range.mStart, range.Length());
|
||||
MSE_DEBUG(MP4ContainerParser ,"Stashed init of %" PRIu64 " bytes.",
|
||||
range.Length());
|
||||
MSE_DEBUG("Stashed init of %" PRIu64 " bytes.", range.Length());
|
||||
} else {
|
||||
MSE_DEBUG(MP4ContainerParser, "Incomplete init found.");
|
||||
MSE_DEBUG("Incomplete init found.");
|
||||
}
|
||||
mHasInitData = true;
|
||||
}
|
||||
|
@ -638,8 +677,7 @@ public:
|
|||
}
|
||||
aStart = compositionRange.start;
|
||||
aEnd = compositionRange.end;
|
||||
MSE_DEBUG(MP4ContainerParser, "[%" PRId64 ", %" PRId64 "]",
|
||||
aStart, aEnd);
|
||||
MSE_DEBUG("[%" PRId64 ", %" PRId64 "]", aStart, aEnd);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -657,7 +695,11 @@ private:
|
|||
#endif // MOZ_FMP4
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
class ADTSContainerParser : public ContainerParser
|
||||
DDLoggedTypeDeclNameAndBase(ADTSContainerParser, ContainerParser);
|
||||
|
||||
class ADTSContainerParser
|
||||
: public ContainerParser
|
||||
, public DecoderDoctorLifeLogger<ADTSContainerParser>
|
||||
{
|
||||
public:
|
||||
explicit ADTSContainerParser(const MediaContainerType& aType)
|
||||
|
@ -683,23 +725,23 @@ public:
|
|||
|
||||
// ADTS initialization segments are just the packet header.
|
||||
if (aData->Length() < 7) {
|
||||
MSE_DEBUG(ADTSContainerParser, "buffer too short for header.");
|
||||
MSE_DEBUG("buffer too short for header.");
|
||||
return false;
|
||||
}
|
||||
// Check 0xfffx sync word plus layer 0.
|
||||
if (((*aData)[0] != 0xff) || (((*aData)[1] & 0xf6) != 0xf0)) {
|
||||
MSE_DEBUG(ADTSContainerParser, "no syncword.");
|
||||
MSE_DEBUG("no syncword.");
|
||||
return false;
|
||||
}
|
||||
bool have_crc = !((*aData)[1] & 0x01);
|
||||
if (have_crc && aData->Length() < 9) {
|
||||
MSE_DEBUG(ADTSContainerParser, "buffer too short for header with crc.");
|
||||
MSE_DEBUG("buffer too short for header with crc.");
|
||||
return false;
|
||||
}
|
||||
uint8_t frequency_index = ((*aData)[2] & 0x3c) >> 2;
|
||||
MOZ_ASSERT(frequency_index < 16);
|
||||
if (frequency_index == 15) {
|
||||
MSE_DEBUG(ADTSContainerParser, "explicit frequency disallowed.");
|
||||
MSE_DEBUG("explicit frequency disallowed.");
|
||||
return false;
|
||||
}
|
||||
size_t header_length = have_crc ? 9 : 7;
|
||||
|
@ -728,9 +770,10 @@ public:
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
MSE_DEBUGV(ADTSContainerParser, "%llu byte frame %d aac frames%s",
|
||||
(unsigned long long)header.frame_length, (int)header.aac_frames,
|
||||
header.have_crc ? " crc" : "");
|
||||
MSE_DEBUGV("%llu byte frame %d aac frames%s",
|
||||
(unsigned long long)header.frame_length,
|
||||
(int)header.aac_frames,
|
||||
header.have_crc ? " crc" : "");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -779,10 +822,10 @@ public:
|
|||
|
||||
// Check that we have enough data for the frame body.
|
||||
if (aData->Length() < header.frame_length) {
|
||||
MSE_DEBUGV(ADTSContainerParser, "Not enough data for %llu byte frame"
|
||||
" in %llu byte buffer.",
|
||||
(unsigned long long)header.frame_length,
|
||||
(unsigned long long)(aData->Length()));
|
||||
MSE_DEBUGV("Not enough data for %llu byte frame"
|
||||
" in %llu byte buffer.",
|
||||
(unsigned long long)header.frame_length,
|
||||
(unsigned long long)(aData->Length()));
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mCompleteMediaSegmentRange = MediaByteRange(header.header_length,
|
||||
|
@ -792,8 +835,7 @@ public:
|
|||
// media segment.
|
||||
mCompleteMediaHeaderRange = mCompleteMediaSegmentRange;
|
||||
|
||||
MSE_DEBUG(ADTSContainerParser, "[%" PRId64 ", %" PRId64 "]",
|
||||
aStart, aEnd);
|
||||
MSE_DEBUG("[%" PRId64 ", %" PRId64 "]", aStart, aEnd);
|
||||
// We don't update timestamps, regardless.
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
@ -830,5 +872,6 @@ ContainerParser::CreateForMIMEType(const MediaContainerType& aType)
|
|||
|
||||
#undef MSE_DEBUG
|
||||
#undef MSE_DEBUGV
|
||||
#undef MSE_DEBUGVEX
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -17,7 +17,9 @@ namespace mozilla {
|
|||
class MediaByteBuffer;
|
||||
class SourceBufferResource;
|
||||
|
||||
class ContainerParser
|
||||
DDLoggedTypeDeclName(ContainerParser);
|
||||
|
||||
class ContainerParser : public DecoderDoctorLifeLogger<ContainerParser>
|
||||
{
|
||||
public:
|
||||
explicit ContainerParser(const MediaContainerType& aType);
|
||||
|
@ -76,6 +78,8 @@ public:
|
|||
|
||||
static ContainerParser* CreateForMIMEType(const MediaContainerType& aType);
|
||||
|
||||
const MediaContainerType& ContainerType() const { return mType; }
|
||||
|
||||
protected:
|
||||
RefPtr<MediaByteBuffer> mInitData;
|
||||
RefPtr<SourceBufferResource> mResource;
|
||||
|
|
|
@ -56,8 +56,18 @@ mozilla::LogModule* GetMediaSourceAPILog()
|
|||
return sLogModule;
|
||||
}
|
||||
|
||||
#define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUG(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define MSE_API(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceAPILog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
// Arbitrary limit.
|
||||
static const unsigned int MAX_SOURCE_BUFFERS = 16;
|
||||
|
@ -260,6 +270,7 @@ MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
mSourceBuffers->Append(sourceBuffer);
|
||||
DDLINKCHILD("sourcebuffer[]", sourceBuffer.get());
|
||||
MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get());
|
||||
return sourceBuffer.forget();
|
||||
}
|
||||
|
@ -335,6 +346,7 @@ MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv)
|
|||
mActiveSourceBuffers->Remove(sourceBuffer);
|
||||
}
|
||||
mSourceBuffers->Remove(sourceBuffer);
|
||||
DDUNLINKCHILD(sourceBuffer);
|
||||
// TODO: Free all resources associated with sourceBuffer
|
||||
}
|
||||
|
||||
|
@ -390,10 +402,12 @@ MediaSource::IsTypeSupported(const GlobalObject& aOwner, const nsAString& aType)
|
|||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aOwner.GetAsSupports());
|
||||
diagnostics.StoreFormatDiagnostics(window ? window->GetExtantDoc() : nullptr,
|
||||
aType, NS_SUCCEEDED(rv), __func__);
|
||||
#define this nullptr
|
||||
MSE_API("IsTypeSupported(aType=%s)%s ",
|
||||
NS_ConvertUTF16toUTF8(aType).get(), rv == NS_OK ? "OK" : "[not supported]");
|
||||
#undef this // don't ever remove this line !
|
||||
MOZ_LOG(GetMediaSourceAPILog(),
|
||||
mozilla::LogLevel::Debug,
|
||||
("MediaSource::%s: IsTypeSupported(aType=%s) %s",
|
||||
__func__,
|
||||
NS_ConvertUTF16toUTF8(aType).get(),
|
||||
rv == NS_OK ? "OK" : "[not supported]"));
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ class ErrorResult;
|
|||
template <typename T> class AsyncEventRunner;
|
||||
class MediaResult;
|
||||
|
||||
namespace dom {
|
||||
class MediaSource;
|
||||
} // namespace dom
|
||||
DDLoggedTypeName(dom::MediaSource);
|
||||
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
|
@ -44,7 +49,9 @@ template <typename T> class Optional;
|
|||
{ 0x3839d699, 0x22c5, 0x439f, \
|
||||
{ 0x94, 0xca, 0x0e, 0x0b, 0x26, 0xf9, 0xca, 0xbf } }
|
||||
|
||||
class MediaSource final : public DOMEventTargetHelper
|
||||
class MediaSource final
|
||||
: public DOMEventTargetHelper
|
||||
, public DecoderDoctorLifeLogger<MediaSource>
|
||||
{
|
||||
public:
|
||||
/** WebIDL Methods. */
|
||||
|
|
|
@ -18,8 +18,18 @@
|
|||
|
||||
extern mozilla::LogModule* GetMediaSourceLog();
|
||||
|
||||
#define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("MediaSourceDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("MediaSourceDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUG(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define MSE_DEBUGV(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceLog(), \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
using namespace mozilla::media;
|
||||
|
||||
|
@ -184,12 +194,14 @@ MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
|
|||
{
|
||||
MOZ_ASSERT(!mMediaSource && !GetStateMachine() && NS_IsMainThread());
|
||||
mMediaSource = aMediaSource;
|
||||
DDLINKCHILD("mediasource", aMediaSource);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::DetachMediaSource()
|
||||
{
|
||||
MOZ_ASSERT(mMediaSource && NS_IsMainThread());
|
||||
DDUNLINKCHILD(mMediaSource);
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,11 @@ class MediaSource;
|
|||
|
||||
} // namespace dom
|
||||
|
||||
class MediaSourceDecoder : public MediaDecoder
|
||||
DDLoggedTypeDeclNameAndBase(MediaSourceDecoder, MediaDecoder);
|
||||
|
||||
class MediaSourceDecoder
|
||||
: public MediaDecoder
|
||||
, public DecoderDoctorLifeLogger<MediaSourceDecoder>
|
||||
{
|
||||
public:
|
||||
explicit MediaSourceDecoder(MediaDecoderInit& aInit);
|
||||
|
|
|
@ -144,6 +144,7 @@ MediaSourceDemuxer::GetTrackDemuxer(TrackType aType, uint32_t aTrackNumber)
|
|||
}
|
||||
RefPtr<MediaSourceTrackDemuxer> e =
|
||||
new MediaSourceTrackDemuxer(this, aType, manager);
|
||||
DDLINKCHILD("track demuxer", e.get());
|
||||
mDemuxers.AppendElement(e);
|
||||
return e.forget();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,12 @@ class AbstractThread;
|
|||
class MediaResult;
|
||||
class MediaSourceTrackDemuxer;
|
||||
|
||||
class MediaSourceDemuxer : public MediaDataDemuxer
|
||||
DDLoggedTypeDeclNameAndBase(MediaSourceDemuxer, MediaDataDemuxer);
|
||||
DDLoggedTypeNameAndBase(MediaSourceTrackDemuxer, MediaTrackDemuxer);
|
||||
|
||||
class MediaSourceDemuxer
|
||||
: public MediaDataDemuxer
|
||||
, public DecoderDoctorLifeLogger<MediaSourceDemuxer>
|
||||
{
|
||||
public:
|
||||
explicit MediaSourceDemuxer(AbstractThread* aAbstractMainThread);
|
||||
|
@ -87,7 +92,9 @@ private:
|
|||
MediaInfo mInfo;
|
||||
};
|
||||
|
||||
class MediaSourceTrackDemuxer : public MediaTrackDemuxer
|
||||
class MediaSourceTrackDemuxer
|
||||
: public MediaTrackDemuxer
|
||||
, public DecoderDoctorLifeLogger<MediaSourceTrackDemuxer>
|
||||
{
|
||||
public:
|
||||
MediaSourceTrackDemuxer(MediaSourceDemuxer* aParent,
|
||||
|
|
|
@ -35,9 +35,27 @@ class JSObject;
|
|||
extern mozilla::LogModule* GetMediaSourceLog();
|
||||
extern mozilla::LogModule* GetMediaSourceAPILog();
|
||||
|
||||
#define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUG(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define MSE_DEBUGV(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceLog(), \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define MSE_API(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceAPILog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -137,6 +155,7 @@ SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_API("SetAppendWindowStart(aAppendWindowStart=%f)", aAppendWindowStart);
|
||||
DDLOG(DDLogCategory::API, "SetAppendWindowStart", aAppendWindowStart);
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
|
@ -154,6 +173,7 @@ SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_API("SetAppendWindowEnd(aAppendWindowEnd=%f)", aAppendWindowEnd);
|
||||
DDLOG(DDLogCategory::API, "SetAppendWindowEnd", aAppendWindowEnd);
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
|
@ -172,6 +192,7 @@ SourceBuffer::AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_API("AppendBuffer(ArrayBuffer)");
|
||||
aData.ComputeLengthAndData();
|
||||
DDLOG(DDLogCategory::API, "AppendBuffer", aData.Length());
|
||||
AppendData(aData.Data(), aData.Length(), aRv);
|
||||
}
|
||||
|
||||
|
@ -181,6 +202,7 @@ SourceBuffer::AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_API("AppendBuffer(ArrayBufferView)");
|
||||
aData.ComputeLengthAndData();
|
||||
DDLOG(DDLogCategory::API, "AppendBuffer", aData.Length());
|
||||
AppendData(aData.Data(), aData.Length(), aRv);
|
||||
}
|
||||
|
||||
|
@ -190,17 +212,21 @@ SourceBuffer::Abort(ErrorResult& aRv)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_API("Abort()");
|
||||
if (!IsAttached()) {
|
||||
DDLOG(DDLogCategory::API, "Abort", NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
|
||||
DDLOG(DDLogCategory::API, "Abort", NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
if (mPendingRemoval.Exists()) {
|
||||
DDLOG(DDLogCategory::API, "Abort", NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
DDLOG(DDLogCategory::API, "Abort", NS_OK);
|
||||
AbortBufferAppend();
|
||||
ResetParserState();
|
||||
mCurrentAttributes.SetAppendWindowStart(0);
|
||||
|
@ -231,6 +257,8 @@ SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_API("Remove(aStart=%f, aEnd=%f)", aStart, aEnd);
|
||||
DDLOG(DDLogCategory::API, "Remove-from", aStart);
|
||||
DDLOG(DDLogCategory::API, "Remove-until", aEnd);
|
||||
if (!IsAttached()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
|
@ -313,6 +341,7 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource,
|
|||
|
||||
mTrackBuffersManager =
|
||||
new TrackBuffersManager(aMediaSource->GetDecoder(), aType);
|
||||
DDLINKCHILD("track buffers manager", mTrackBuffersManager.get());
|
||||
|
||||
MSE_DEBUG("Create mTrackBuffersManager=%p",
|
||||
mTrackBuffersManager.get());
|
||||
|
@ -429,6 +458,7 @@ SourceBuffer::AppendDataCompletedWithSuccess(const SourceBufferTask::AppendBuffe
|
|||
{
|
||||
MOZ_ASSERT(mUpdating);
|
||||
mPendingAppend.Complete();
|
||||
DDLOG(DDLogCategory::API, "AppendBuffer-completed", NS_OK);
|
||||
|
||||
if (aResult.first()) {
|
||||
if (!mActive) {
|
||||
|
@ -465,6 +495,7 @@ SourceBuffer::AppendDataErrored(const MediaResult& aError)
|
|||
{
|
||||
MOZ_ASSERT(mUpdating);
|
||||
mPendingAppend.Complete();
|
||||
DDLOG(DDLogCategory::API, "AppendBuffer-error", aError);
|
||||
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
|
|
|
@ -37,11 +37,15 @@ class ErrorResult;
|
|||
class MediaByteBuffer;
|
||||
template <typename T> class AsyncEventRunner;
|
||||
|
||||
DDLoggedTypeName(dom::SourceBuffer);
|
||||
|
||||
namespace dom {
|
||||
|
||||
class TimeRanges;
|
||||
|
||||
class SourceBuffer final : public DOMEventTargetHelper
|
||||
class SourceBuffer final
|
||||
: public DOMEventTargetHelper
|
||||
, public DecoderDoctorLifeLogger<SourceBuffer>
|
||||
{
|
||||
public:
|
||||
/** WebIDL Methods. */
|
||||
|
|
|
@ -17,15 +17,17 @@ mozilla::LogModule* GetSourceBufferResourceLog()
|
|||
}
|
||||
|
||||
#define SBR_DEBUG(arg, ...) \
|
||||
MOZ_LOG( \
|
||||
GetSourceBufferResourceLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
("SourceBufferResource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
DDMOZ_LOG(GetSourceBufferResourceLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define SBR_DEBUGV(arg, ...) \
|
||||
MOZ_LOG( \
|
||||
GetSourceBufferResourceLog(), \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
("SourceBufferResource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
DDMOZ_LOG(GetSourceBufferResourceLog(), \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
|
@ -26,8 +26,12 @@ class SourceBuffer;
|
|||
|
||||
} // namespace dom
|
||||
|
||||
DDLoggedTypeDeclNameAndBase(SourceBufferResource, MediaResource);
|
||||
|
||||
// SourceBufferResource is not thread safe.
|
||||
class SourceBufferResource final : public MediaResource
|
||||
class SourceBufferResource final
|
||||
: public MediaResource
|
||||
, public DecoderDoctorLifeLogger<SourceBufferResource>
|
||||
{
|
||||
public:
|
||||
SourceBufferResource();
|
||||
|
|
|
@ -24,15 +24,33 @@
|
|||
|
||||
extern mozilla::LogModule* GetMediaSourceLog();
|
||||
|
||||
#define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("TrackBuffersManager(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("TrackBuffersManager(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUG(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
#define MSE_DEBUGV(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceLog(), \
|
||||
mozilla::LogLevel::Verbose, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
mozilla::LogModule* GetMediaSourceSamplesLog()
|
||||
{
|
||||
static mozilla::LazyLogModule sLogModule("MediaSourceSamples");
|
||||
return sLogModule;
|
||||
}
|
||||
#define SAMPLE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Debug, ("TrackBuffersManager(%p:%s)::%s: " arg, this, mType.OriginalString().Data(), __func__, ##__VA_ARGS__))
|
||||
#define SAMPLE_DEBUG(arg, ...) \
|
||||
DDMOZ_LOG(GetMediaSourceSamplesLog(), \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"(%s)::%s: " arg, \
|
||||
mType.OriginalString().Data(), \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -114,6 +132,7 @@ TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
|
|||
, mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
|
||||
DDLINKCHILD("parser", mParser.get());
|
||||
}
|
||||
|
||||
TrackBuffersManager::~TrackBuffersManager()
|
||||
|
@ -879,6 +898,7 @@ TrackBuffersManager::CreateDemuxerforMIMEType()
|
|||
if (mType.Type() == MEDIAMIMETYPE("video/webm") ||
|
||||
mType.Type() == MEDIAMIMETYPE("audio/webm")) {
|
||||
mInputDemuxer = new WebMDemuxer(mCurrentInputBuffer, true /* IsMediaSource*/ );
|
||||
DDLINKCHILD("demuxer", mInputDemuxer.get());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -886,6 +906,7 @@ TrackBuffersManager::CreateDemuxerforMIMEType()
|
|||
if (mType.Type() == MEDIAMIMETYPE("video/mp4") ||
|
||||
mType.Type() == MEDIAMIMETYPE("audio/mp4")) {
|
||||
mInputDemuxer = new MP4Demuxer(mCurrentInputBuffer);
|
||||
DDLINKCHILD("demuxer", mInputDemuxer.get());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -950,6 +971,7 @@ TrackBuffersManager::OnDemuxerResetDone(const MediaResult& aResult)
|
|||
mVideoTracks.mDemuxer =
|
||||
mInputDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
|
||||
MOZ_ASSERT(mVideoTracks.mDemuxer);
|
||||
DDLINKCHILD("video demuxer", mVideoTracks.mDemuxer.get());
|
||||
}
|
||||
|
||||
uint32_t numAudios = mInputDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
|
||||
|
@ -958,6 +980,7 @@ TrackBuffersManager::OnDemuxerResetDone(const MediaResult& aResult)
|
|||
mAudioTracks.mDemuxer =
|
||||
mInputDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
|
||||
MOZ_ASSERT(mAudioTracks.mDemuxer);
|
||||
DDLINKCHILD("audio demuxer", mAudioTracks.mDemuxer.get());
|
||||
}
|
||||
|
||||
if (mPendingInputBuffer) {
|
||||
|
@ -1043,6 +1066,7 @@ TrackBuffersManager::OnDemuxerInitDone(const MediaResult& aResult)
|
|||
mVideoTracks.mDemuxer =
|
||||
mInputDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
|
||||
MOZ_ASSERT(mVideoTracks.mDemuxer);
|
||||
DDLINKCHILD("video demuxer", mVideoTracks.mDemuxer.get());
|
||||
info.mVideo = *mVideoTracks.mDemuxer->GetInfo()->GetAsVideoInfo();
|
||||
info.mVideo.mTrackId = 2;
|
||||
}
|
||||
|
@ -1053,6 +1077,7 @@ TrackBuffersManager::OnDemuxerInitDone(const MediaResult& aResult)
|
|||
mAudioTracks.mDemuxer =
|
||||
mInputDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
|
||||
MOZ_ASSERT(mAudioTracks.mDemuxer);
|
||||
DDLINKCHILD("audio demuxer", mAudioTracks.mDemuxer.get());
|
||||
info.mAudio = *mAudioTracks.mDemuxer->GetInfo()->GetAsAudioInfo();
|
||||
info.mAudio.mTrackId = 1;
|
||||
}
|
||||
|
@ -2049,7 +2074,11 @@ TrackBuffersManager::RecreateParser(bool aReuseInitData)
|
|||
// as it has parsed the entire InputBuffer provided.
|
||||
// Once the old TrackBuffer/MediaSource implementation is removed
|
||||
// we can optimize this part. TODO
|
||||
if (mParser) {
|
||||
DDUNLINKCHILD(mParser.get());
|
||||
}
|
||||
mParser = ContainerParser::CreateForMIMEType(mType);
|
||||
DDLINKCHILD("parser", mParser.get());
|
||||
if (aReuseInitData && mInitData) {
|
||||
int64_t start, end;
|
||||
mParser->ParseStartAndEndTimestamps(mInitData, start, end);
|
||||
|
|
|
@ -65,7 +65,9 @@ private:
|
|||
nsTArray<RefPtr<SourceBufferTask>> mQueue;
|
||||
};
|
||||
|
||||
class TrackBuffersManager
|
||||
DDLoggedTypeDeclName(TrackBuffersManager);
|
||||
|
||||
class TrackBuffersManager : public DecoderDoctorLifeLogger<TrackBuffersManager>
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffersManager);
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
#include "VideoUtils.h"
|
||||
|
||||
extern mozilla::LazyLogModule gMediaDemuxerLog;
|
||||
#define MP3LOG(msg, ...) \
|
||||
MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("MP3Demuxer " msg, ##__VA_ARGS__))
|
||||
#define MP3LOGV(msg, ...) \
|
||||
MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, ("MP3Demuxer " msg, ##__VA_ARGS__))
|
||||
#define MP3LOG(msg, ...) \
|
||||
DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
|
||||
#define MP3LOGV(msg, ...) \
|
||||
DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
|
||||
|
||||
using mozilla::media::TimeUnit;
|
||||
using mozilla::media::TimeInterval;
|
||||
|
@ -30,13 +30,18 @@ namespace mozilla {
|
|||
|
||||
// MP3Demuxer
|
||||
|
||||
MP3Demuxer::MP3Demuxer(MediaResource* aSource) : mSource(aSource) { }
|
||||
MP3Demuxer::MP3Demuxer(MediaResource* aSource)
|
||||
: mSource(aSource)
|
||||
{
|
||||
DDLINKCHILD("source", aSource);
|
||||
}
|
||||
|
||||
bool
|
||||
MP3Demuxer::InitInternal()
|
||||
{
|
||||
if (!mTrackDemuxer) {
|
||||
mTrackDemuxer = new MP3TrackDemuxer(mSource);
|
||||
DDLINKCHILD("track demuxer", mTrackDemuxer.get());
|
||||
}
|
||||
return mTrackDemuxer->Init();
|
||||
}
|
||||
|
@ -107,6 +112,7 @@ MP3TrackDemuxer::MP3TrackDemuxer(MediaResource* aSource)
|
|||
, mSamplesPerSecond(0)
|
||||
, mChannels(0)
|
||||
{
|
||||
DDLINKCHILD("source", aSource);
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
@ -767,3 +773,6 @@ MP3TrackDemuxer::AverageFrameLength() const
|
|||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#undef MP3LOG
|
||||
#undef MP3LOGV
|
||||
|
|
|
@ -13,7 +13,12 @@ namespace mozilla {
|
|||
|
||||
class MP3TrackDemuxer;
|
||||
|
||||
class MP3Demuxer : public MediaDataDemuxer
|
||||
DDLoggedTypeDeclNameAndBase(MP3Demuxer, MediaDataDemuxer);
|
||||
DDLoggedTypeNameAndBase(MP3TrackDemuxer, MediaTrackDemuxer);
|
||||
|
||||
class MP3Demuxer
|
||||
: public MediaDataDemuxer
|
||||
, public DecoderDoctorLifeLogger<MP3Demuxer>
|
||||
{
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
|
@ -36,7 +41,9 @@ private:
|
|||
|
||||
// The MP3 demuxer used to extract MPEG frames and side information out of
|
||||
// MPEG streams.
|
||||
class MP3TrackDemuxer : public MediaTrackDemuxer
|
||||
class MP3TrackDemuxer
|
||||
: public MediaTrackDemuxer
|
||||
, public DecoderDoctorLifeLogger<MP3TrackDemuxer>
|
||||
{
|
||||
public:
|
||||
// Constructor, expecting a valid media resource.
|
||||
|
|
|
@ -12,7 +12,11 @@
|
|||
namespace mozilla {
|
||||
class MediaByteBuffer;
|
||||
|
||||
class BufferStream : public ByteStream
|
||||
DDLoggedTypeDeclNameAndBase(BufferStream, ByteStream);
|
||||
|
||||
class BufferStream
|
||||
: public ByteStream
|
||||
, public mozilla::DecoderDoctorLifeLogger<BufferStream>
|
||||
{
|
||||
public:
|
||||
/* BufferStream does not take ownership of aData nor does it make a copy.
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
#ifndef STREAM_H_
|
||||
#define STREAM_H_
|
||||
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
namespace mozilla {
|
||||
|
||||
class ByteStream
|
||||
DDLoggedTypeDeclName(ByteStream);
|
||||
|
||||
class ByteStream : public DecoderDoctorLifeLogger<ByteStream>
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ByteStream);
|
||||
|
|
|
@ -29,11 +29,20 @@ mozilla::LogModule* GetDemuxerLog()
|
|||
return gMediaDemuxerLog;
|
||||
}
|
||||
|
||||
#define LOG(arg, ...) MOZ_LOG(gMediaDemuxerLog, mozilla::LogLevel::Debug, ("MP4Demuxer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define LOG(arg, ...) \
|
||||
DDMOZ_LOG(gMediaDemuxerLog, \
|
||||
mozilla::LogLevel::Debug, \
|
||||
"::%s: " arg, \
|
||||
__func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MP4TrackDemuxer : public MediaTrackDemuxer
|
||||
DDLoggedTypeDeclNameAndBase(MP4TrackDemuxer, MediaTrackDemuxer);
|
||||
|
||||
class MP4TrackDemuxer
|
||||
: public MediaTrackDemuxer
|
||||
, public DecoderDoctorLifeLogger<MP4TrackDemuxer>
|
||||
{
|
||||
public:
|
||||
MP4TrackDemuxer(MP4Demuxer* aParent,
|
||||
|
@ -120,6 +129,8 @@ MP4Demuxer::MP4Demuxer(MediaResource* aResource)
|
|||
: mResource(aResource)
|
||||
, mStream(new ResourceStream(aResource))
|
||||
{
|
||||
DDLINKCHILD("resource", aResource);
|
||||
DDLINKCHILD("stream", mStream.get());
|
||||
}
|
||||
|
||||
RefPtr<MP4Demuxer::InitPromise>
|
||||
|
@ -147,6 +158,7 @@ MP4Demuxer::Init()
|
|||
new BufferStream(initData.Ref());
|
||||
|
||||
MP4Metadata metadata{bufferstream};
|
||||
DDLINKCHILD("metadata", &metadata);
|
||||
nsresult rv = metadata.Parse();
|
||||
if (NS_FAILED(rv)) {
|
||||
return InitPromise::CreateAndReject(
|
||||
|
@ -222,8 +234,10 @@ MP4Demuxer::Init()
|
|||
}
|
||||
continue;
|
||||
}
|
||||
mAudioDemuxers.AppendElement(
|
||||
new MP4TrackDemuxer(this, Move(info.Ref()), *indices.Ref().get()));
|
||||
RefPtr<MP4TrackDemuxer> demuxer =
|
||||
new MP4TrackDemuxer(this, Move(info.Ref()), *indices.Ref().get());
|
||||
DDLINKCHILD("audio demuxer", demuxer.get());
|
||||
mAudioDemuxers.AppendElement(Move(demuxer));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,8 +270,10 @@ MP4Demuxer::Init()
|
|||
}
|
||||
continue;
|
||||
}
|
||||
mVideoDemuxers.AppendElement(
|
||||
new MP4TrackDemuxer(this, Move(info.Ref()), *indices.Ref().get()));
|
||||
RefPtr<MP4TrackDemuxer> demuxer =
|
||||
new MP4TrackDemuxer(this, Move(info.Ref()), *indices.Ref().get());
|
||||
DDLINKCHILD("video demuxer", demuxer.get());
|
||||
mVideoDemuxers.AppendElement(Move(demuxer));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,11 @@ namespace mozilla {
|
|||
class MP4TrackDemuxer;
|
||||
class ResourceStream;
|
||||
|
||||
class MP4Demuxer : public MediaDataDemuxer
|
||||
DDLoggedTypeDeclNameAndBase(MP4Demuxer, MediaDataDemuxer);
|
||||
|
||||
class MP4Demuxer
|
||||
: public MediaDataDemuxer
|
||||
, public DecoderDoctorLifeLogger<MP4Demuxer>
|
||||
{
|
||||
public:
|
||||
explicit MP4Demuxer(MediaResource* aResource);
|
||||
|
|
|
@ -103,6 +103,8 @@ MP4Metadata::MP4Metadata(ByteStream* aSource)
|
|||
: mSource(aSource)
|
||||
, mSourceAdaptor(aSource)
|
||||
{
|
||||
DDLINKCHILD("source", aSource);
|
||||
|
||||
Mp4parseIo io = { read_source, &mSourceAdaptor };
|
||||
mParser.reset(mp4parse_new(&io));
|
||||
MOZ_ASSERT(mParser);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
DDLoggedTypeDeclName(MP4Metadata);
|
||||
|
||||
// The memory owner in mIndice.indices is rust mp4 parser, so lifetime of this
|
||||
// class SHOULD NOT longer than rust parser.
|
||||
class IndiceWrapper
|
||||
|
@ -52,7 +54,7 @@ private:
|
|||
CheckedInt<size_t> mOffset;
|
||||
};
|
||||
|
||||
class MP4Metadata
|
||||
class MP4Metadata : public DecoderDoctorLifeLogger<MP4Metadata>
|
||||
{
|
||||
public:
|
||||
explicit MP4Metadata(ByteStream* aSource);
|
||||
|
|
|
@ -111,10 +111,16 @@ MoofParser::FirstCompleteMediaSegment()
|
|||
return MediaByteRange();
|
||||
}
|
||||
|
||||
class BlockingStream : public ByteStream {
|
||||
DDLoggedTypeDeclNameAndBase(BlockingStream, ByteStream);
|
||||
|
||||
class BlockingStream
|
||||
: public ByteStream
|
||||
, public DecoderDoctorLifeLogger<BlockingStream>
|
||||
{
|
||||
public:
|
||||
explicit BlockingStream(ByteStream* aStream) : mStream(aStream)
|
||||
{
|
||||
DDLINKCHILD("stream", aStream);
|
||||
}
|
||||
|
||||
bool ReadAt(int64_t offset, void* data, size_t size, size_t* bytes_read)
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче