Merge mozilla-central to inbound. r=merge a=merge on a CLOSED TREE

This commit is contained in:
Bogdan Tara 2017-12-07 13:02:03 +02:00
Родитель 89531e8dc3 cbd802ee7d
Коммит 8e9610529d
285 изменённых файлов: 4170 добавлений и 1452 удалений

144
.vscode/tasks.json поставляемый
Просмотреть файл

@ -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"
}
}
]

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

@ -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)

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