Merge m-c to b2g-inbound
|
@ -90,6 +90,26 @@ struct GroupPos
|
|||
int32_t setSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* An index type. Assert if out of range value was attempted to be used.
|
||||
*/
|
||||
class index_t
|
||||
{
|
||||
public:
|
||||
index_t(int32_t aVal) : mVal(aVal) {}
|
||||
|
||||
operator uint32_t() const
|
||||
{
|
||||
MOZ_ASSERT(mVal >= 0, "Attempt to use wrong index!");
|
||||
return mVal;
|
||||
}
|
||||
|
||||
bool IsValid() const { return mVal >= 0; }
|
||||
|
||||
private:
|
||||
int32_t mVal;
|
||||
};
|
||||
|
||||
typedef nsRefPtrHashtable<nsPtrHashKey<const void>, Accessible>
|
||||
AccessibleHashtable;
|
||||
|
||||
|
|
|
@ -21,15 +21,17 @@ namespace a11y {
|
|||
inline bool
|
||||
HyperTextAccessible::IsValidOffset(int32_t aOffset)
|
||||
{
|
||||
return ConvertMagicOffset(aOffset) <= CharacterCount();
|
||||
index_t offset = ConvertMagicOffset(aOffset);
|
||||
return offset.IsValid() && offset <= CharacterCount();
|
||||
}
|
||||
|
||||
inline bool
|
||||
HyperTextAccessible::IsValidRange(int32_t aStartOffset, int32_t aEndOffset)
|
||||
{
|
||||
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
return ConvertMagicOffset(aStartOffset) <= endOffset &&
|
||||
endOffset <= CharacterCount();
|
||||
index_t startOffset = ConvertMagicOffset(aStartOffset);
|
||||
index_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
return startOffset.IsValid() && endOffset.IsValid() &&
|
||||
startOffset <= endOffset && endOffset <= CharacterCount();
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -110,7 +112,7 @@ HyperTextAccessible::PasteText(int32_t aPosition)
|
|||
}
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
inline index_t
|
||||
HyperTextAccessible::ConvertMagicOffset(int32_t aOffset) const
|
||||
{
|
||||
if (aOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT)
|
||||
|
@ -119,7 +121,7 @@ HyperTextAccessible::ConvertMagicOffset(int32_t aOffset) const
|
|||
if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
|
||||
return CaretOffset();
|
||||
|
||||
return aOffset < 0 ? std::numeric_limits<uint32_t>::max() : aOffset;
|
||||
return aOffset;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
|
|
|
@ -191,8 +191,13 @@ HyperTextAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOffset,
|
|||
{
|
||||
aText.Truncate();
|
||||
|
||||
uint32_t startOffset = ConvertMagicOffset(aStartOffset);
|
||||
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
index_t startOffset = ConvertMagicOffset(aStartOffset);
|
||||
index_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
if (!startOffset.IsValid() || !endOffset.IsValid() ||
|
||||
startOffset > endOffset || endOffset > CharacterCount()) {
|
||||
NS_ERROR("Wrong in offset");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t startChildIdx = GetChildIndexAtOffset(startOffset);
|
||||
if (startChildIdx == -1)
|
||||
|
@ -608,9 +613,9 @@ HyperTextAccessible::TextBeforeOffset(int32_t aOffset,
|
|||
*aStartOffset = *aEndOffset = 0;
|
||||
aText.Truncate();
|
||||
|
||||
uint32_t convertedOffset = ConvertMagicOffset(aOffset);
|
||||
if (convertedOffset == std::numeric_limits<uint32_t>::max()) {
|
||||
NS_ERROR("Wrong given offset!");
|
||||
index_t convertedOffset = ConvertMagicOffset(aOffset);
|
||||
if (!convertedOffset.IsValid() || convertedOffset > CharacterCount()) {
|
||||
NS_ERROR("Wrong in offset!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -744,9 +749,9 @@ HyperTextAccessible::TextAfterOffset(int32_t aOffset,
|
|||
*aStartOffset = *aEndOffset = 0;
|
||||
aText.Truncate();
|
||||
|
||||
uint32_t convertedOffset = ConvertMagicOffset(aOffset);
|
||||
if (convertedOffset == std::numeric_limits<uint32_t>::max()) {
|
||||
NS_ERROR("Wrong given offset!");
|
||||
index_t convertedOffset = ConvertMagicOffset(aOffset);
|
||||
if (!convertedOffset.IsValid() || convertedOffset > CharacterCount()) {
|
||||
NS_ERROR("Wrong in offset!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -814,10 +819,15 @@ HyperTextAccessible::TextAttributes(bool aIncludeDefAttrs, int32_t aOffset,
|
|||
// the attribute range itself can only stay the same or get smaller.
|
||||
|
||||
*aStartOffset = *aEndOffset = 0;
|
||||
index_t offset = ConvertMagicOffset(aOffset);
|
||||
if (!offset.IsValid() || offset > CharacterCount()) {
|
||||
NS_ERROR("Wrong in offset!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPersistentProperties> attributes =
|
||||
do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
|
||||
|
||||
uint32_t offset = ConvertMagicOffset(aOffset);
|
||||
Accessible* accAtOffset = GetChildAtOffset(offset);
|
||||
if (!accAtOffset) {
|
||||
// Offset 0 is correct offset when accessible has empty text. Include
|
||||
|
@ -1029,11 +1039,14 @@ nsIntRect
|
|||
HyperTextAccessible::TextBounds(int32_t aStartOffset, int32_t aEndOffset,
|
||||
uint32_t aCoordType)
|
||||
{
|
||||
uint32_t startOffset = ConvertMagicOffset(aStartOffset);
|
||||
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
NS_ASSERTION(startOffset < endOffset &&
|
||||
endOffset != std::numeric_limits<uint32_t>::max(),
|
||||
"Wrong bad in!");
|
||||
index_t startOffset = ConvertMagicOffset(aStartOffset);
|
||||
index_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
if (!startOffset.IsValid() || !endOffset.IsValid() ||
|
||||
startOffset > endOffset || endOffset > CharacterCount()) {
|
||||
NS_ERROR("Wrong in offset");
|
||||
return nsIntRect();
|
||||
}
|
||||
|
||||
|
||||
int32_t childIdx = GetChildIndexAtOffset(startOffset);
|
||||
if (childIdx == -1)
|
||||
|
@ -1417,8 +1430,13 @@ HyperTextAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
|
|||
int32_t aStartOffset,
|
||||
int32_t aEndOffset)
|
||||
{
|
||||
uint32_t startOffset = ConvertMagicOffset(aStartOffset);
|
||||
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
index_t startOffset = ConvertMagicOffset(aStartOffset);
|
||||
index_t endOffset = ConvertMagicOffset(aEndOffset);
|
||||
if (!startOffset.IsValid() || !endOffset.IsValid() ||
|
||||
startOffset > endOffset || endOffset > CharacterCount()) {
|
||||
NS_ERROR("Wrong in offset");
|
||||
return false;
|
||||
}
|
||||
|
||||
dom::Selection* domSel = DOMSelection();
|
||||
if (!domSel)
|
||||
|
@ -1879,7 +1897,7 @@ HyperTextAccessible::GetSpellTextAttr(nsINode* aNode,
|
|||
if (rangeCount <= 0)
|
||||
return;
|
||||
|
||||
int32_t startOffset = 0, endOffset = 0;
|
||||
uint32_t startOffset = 0, endOffset = 0;
|
||||
for (int32_t idx = 0; idx < rangeCount; idx++) {
|
||||
nsRange* range = domSel->GetRangeAt(idx);
|
||||
if (range->Collapsed())
|
||||
|
|
|
@ -296,7 +296,11 @@ public:
|
|||
* system.
|
||||
*/
|
||||
nsIntRect CharBounds(int32_t aOffset, uint32_t aCoordType)
|
||||
{ return TextBounds(aOffset, aOffset + 1, aCoordType); }
|
||||
{
|
||||
int32_t endOffset = aOffset == static_cast<int32_t>(CharacterCount()) ?
|
||||
aOffset : aOffset + 1;
|
||||
return TextBounds(aOffset, endOffset, aCoordType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/set caret offset, if no caret then -1.
|
||||
|
@ -421,7 +425,7 @@ protected:
|
|||
/**
|
||||
* Transform magic offset into text offset.
|
||||
*/
|
||||
uint32_t ConvertMagicOffset(int32_t aOffset) const;
|
||||
index_t ConvertMagicOffset(int32_t aOffset) const;
|
||||
|
||||
/**
|
||||
* Adjust an offset the caret stays at to get a text by line boundary.
|
||||
|
|
|
@ -301,6 +301,7 @@ pref("dom.ipc.tabs.disabled", false);
|
|||
pref("layers.acceleration.disabled", false);
|
||||
pref("layers.offmainthreadcomposition.async-animations", true);
|
||||
pref("layers.async-video.enabled", true);
|
||||
pref("layers.async-video-oop.enabled",true);
|
||||
pref("layers.async-pan-zoom.enabled", true);
|
||||
pref("gfx.content.azure.backends", "cairo");
|
||||
#endif
|
||||
|
|
|
@ -51,7 +51,6 @@ MOZ_EXTENSION_MANAGER=1
|
|||
|
||||
MOZ_TIME_MANAGER=1
|
||||
|
||||
MOZ_B2G_CERTDATA=1
|
||||
MOZ_PAY=1
|
||||
MOZ_TOOLKIT_SEARCH=
|
||||
MOZ_PLACES=
|
||||
|
|
|
@ -811,11 +811,7 @@ pref("plugin.state.f5 sam inspection host plugin", 2);
|
|||
// display door hanger if flash not installed
|
||||
pref("plugins.notifyMissingFlash", true);
|
||||
|
||||
#ifdef XP_WIN
|
||||
pref("browser.preferences.instantApply", false);
|
||||
#else
|
||||
pref("browser.preferences.instantApply", true);
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
pref("browser.preferences.animateFadeIn", true);
|
||||
#else
|
||||
|
@ -823,7 +819,7 @@ pref("browser.preferences.animateFadeIn", false);
|
|||
#endif
|
||||
|
||||
// Toggles between the two Preferences implementations, pop-up window and in-content
|
||||
pref("browser.preferences.inContent", false);
|
||||
pref("browser.preferences.inContent", true);
|
||||
|
||||
pref("browser.download.show_plugins_in_list", true);
|
||||
pref("browser.download.hide_plugins_without_extensions", true);
|
||||
|
|
|
@ -99,10 +99,9 @@ function test_multiple_windows() {
|
|||
ok(notification2, "2nd window has a global notification box.");
|
||||
|
||||
let policy;
|
||||
|
||||
let displayCount = 0;
|
||||
let prefPaneClosed = false;
|
||||
let childWindowClosed = false;
|
||||
let prefWindowClosed = false;
|
||||
let mutationObserversRemoved = false;
|
||||
|
||||
function onAlertDisplayed() {
|
||||
displayCount++;
|
||||
|
@ -116,24 +115,26 @@ function test_multiple_windows() {
|
|||
// We register two independent observers and we need both to clean up
|
||||
// properly. This handles gating for test completion.
|
||||
function maybeFinish() {
|
||||
if (!prefPaneClosed) {
|
||||
if (!prefWindowClosed) {
|
||||
dump("Not finishing test yet because pref pane isn't closed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!childWindowClosed) {
|
||||
dump("Not finishing test yet because child window isn't closed.\n");
|
||||
if (!mutationObserversRemoved) {
|
||||
dump("Not finishing test yet because mutation observers haven't been removed yet.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
window2.close();
|
||||
|
||||
dump("Finishing multiple window test.\n");
|
||||
rootLogger.removeAppender(dumpAppender);
|
||||
delete dumpAppender;
|
||||
delete rootLogger;
|
||||
finish();
|
||||
}
|
||||
|
||||
let closeCount = 0;
|
||||
|
||||
function onAlertClose() {
|
||||
closeCount++;
|
||||
|
||||
|
@ -151,8 +152,7 @@ function test_multiple_windows() {
|
|||
is(notification1.allNotifications.length, 0, "No notifications remain on main window.");
|
||||
is(notification2.allNotifications.length, 0, "No notifications remain on 2nd window.");
|
||||
|
||||
window2.close();
|
||||
childWindowClosed = true;
|
||||
mutationObserversRemoved = true;
|
||||
maybeFinish();
|
||||
}
|
||||
|
||||
|
@ -170,11 +170,11 @@ function test_multiple_windows() {
|
|||
Services.obs.addObserver(function observer(prefWin, topic, data) {
|
||||
Services.obs.removeObserver(observer, "advanced-pane-loaded");
|
||||
|
||||
ok(true, "Pref pane opened on info bar button press.");
|
||||
ok(true, "Advanced preferences opened on info bar button press.");
|
||||
executeSoon(function soon() {
|
||||
dump("Closing pref pane.\n");
|
||||
dump("Closing preferences.\n");
|
||||
prefWin.close();
|
||||
prefPaneClosed = true;
|
||||
prefWindowClosed = true;
|
||||
maybeFinish();
|
||||
});
|
||||
}, "advanced-pane-loaded", false);
|
||||
|
|
|
@ -38,6 +38,11 @@ function checkPreferences(prefsWin) {
|
|||
}
|
||||
|
||||
function test() {
|
||||
if (Services.prefs.getBoolPref("browser.preferences.inContent")) {
|
||||
// Bug 881576 - ensure this works with inContent prefs.
|
||||
todo(false, "Bug 881576 - this test needs to be updated for inContent prefs");
|
||||
return;
|
||||
}
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
|
@ -50,10 +55,6 @@ function test() {
|
|||
// window to open - which we track either via a window watcher (for
|
||||
// the window-based prefs) or via an "Initialized" event (for
|
||||
// in-content prefs.)
|
||||
if (Services.prefs.getBoolPref("browser.preferences.inContent")) {
|
||||
// Bug 881576 - ensure this works with inContent prefs.
|
||||
todo(false, "Bug 881576 - this test needs to be updated for inContent prefs");
|
||||
} else {
|
||||
Services.ww.registerNotification(function wwobserver(aSubject, aTopic, aData) {
|
||||
if (aTopic != "domwindowopened")
|
||||
return;
|
||||
|
@ -61,7 +62,6 @@ function test() {
|
|||
checkPreferences(aSubject);
|
||||
});
|
||||
PopupNotifications.panel.firstElementChild.button.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
Services.prefs.setIntPref("offline-apps.quota.warn", 1);
|
||||
|
|
|
@ -505,10 +505,13 @@ function openPreferences(paneID, extraArgs)
|
|||
}
|
||||
|
||||
if (newLoad) {
|
||||
browser.addEventListener("load", function onload() {
|
||||
browser.removeEventListener("load", onload, true);
|
||||
Services.obs.addObserver(function advancedPaneLoadedObs(prefWin, topic, data) {
|
||||
if (prefWin != browser.contentWindow) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(advancedPaneLoadedObs, "advanced-pane-loaded");
|
||||
switchToPane();
|
||||
}, true);
|
||||
}, "advanced-pane-loaded", false);
|
||||
} else {
|
||||
switchToPane();
|
||||
}
|
||||
|
|
|
@ -772,15 +772,16 @@ let CustomizableUIInternal = {
|
|||
continue;
|
||||
}
|
||||
|
||||
let container = areaNode.customizationTarget;
|
||||
let widgetNode = window.document.getElementById(aWidgetId);
|
||||
if (!widgetNode) {
|
||||
if (widgetNode && isOverflowable) {
|
||||
container = areaNode.overflowable.getContainerFor(widgetNode);
|
||||
}
|
||||
|
||||
if (!widgetNode || !container.contains(widgetNode)) {
|
||||
INFO("Widget not found, unable to remove");
|
||||
continue;
|
||||
}
|
||||
let container = areaNode.customizationTarget;
|
||||
if (isOverflowable) {
|
||||
container = areaNode.overflowable.getContainerFor(widgetNode);
|
||||
}
|
||||
|
||||
this.notifyListeners("onWidgetBeforeDOMChange", widgetNode, null, container, true);
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ skip-if = os == "linux"
|
|||
[browser_993322_widget_notoolbar.js]
|
||||
[browser_995164_registerArea_during_customize_mode.js]
|
||||
[browser_996364_registerArea_different_properties.js]
|
||||
[browser_996635_remove_non_widgets.js]
|
||||
[browser_1003588_no_specials_in_panel.js]
|
||||
[browser_1008559_anchor_undo_restore.js]
|
||||
[browser_bootstrapped_custom_toolbar.js]
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// NB: This is testing what happens if something that /isn't/ a customizable
|
||||
// widget gets used in CustomizableUI APIs. Don't use this as an example of
|
||||
// what should happen in a "normal" case or how you should use the API.
|
||||
function test() {
|
||||
// First create a button that isn't customizable, and add it in the nav-bar,
|
||||
// but not in the customizable part of it (the customization target) but
|
||||
// next to the main (hamburger) menu button.
|
||||
const buttonID = "Test-non-widget-non-removable-button";
|
||||
let btn = document.createElement("toolbarbutton");
|
||||
btn.id = buttonID;
|
||||
btn.label = "Hi";
|
||||
btn.setAttribute("style", "width: 20px; height: 20px; background-color: red");
|
||||
document.getElementById("nav-bar").appendChild(btn);
|
||||
registerCleanupFunction(function() {
|
||||
btn.remove();
|
||||
});
|
||||
|
||||
// Now try to add this non-customizable button to the tabstrip. This will
|
||||
// update the internal bookkeeping (ie placements) information, but shouldn't
|
||||
// move the node.
|
||||
CustomizableUI.addWidgetToArea(buttonID, CustomizableUI.AREA_TABSTRIP);
|
||||
let placement = CustomizableUI.getPlacementOfWidget(buttonID);
|
||||
// Check our bookkeeping
|
||||
ok(placement, "Button should be placed");
|
||||
is(placement && placement.area, CustomizableUI.AREA_TABSTRIP, "Should be placed on tabstrip.");
|
||||
// Check we didn't move the node.
|
||||
is(btn.parentNode && btn.parentNode.id, "nav-bar", "Actual button should still be on navbar.");
|
||||
|
||||
// Now remove the node again. This should remove the bookkeeping, but again
|
||||
// not affect the actual node.
|
||||
CustomizableUI.removeWidgetFromArea(buttonID);
|
||||
placement = CustomizableUI.getPlacementOfWidget(buttonID);
|
||||
// Check our bookkeeping:
|
||||
ok(!placement, "Button should no longer have a placement.");
|
||||
// Check our node.
|
||||
is(btn.parentNode && btn.parentNode.id, "nav-bar", "Actual button should still be on navbar.");
|
||||
}
|
||||
|
|
@ -71,6 +71,9 @@ var gAdvancedPane = {
|
|||
#endif
|
||||
this.updateActualCacheSize();
|
||||
this.updateActualAppCacheSize();
|
||||
|
||||
// Notify observers that the UI is now ready
|
||||
Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,7 @@ function selectCategory(name) {
|
|||
let categories = document.getElementById("categories");
|
||||
let item = categories.querySelector(".category[value=" + name + "]");
|
||||
categories.selectedItem = item;
|
||||
gotoPref(name);
|
||||
}
|
||||
|
||||
function gotoPref(page) {
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -19,6 +19,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -17,6 +17,10 @@ function init() {
|
|||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
|
|
|
@ -27,6 +27,12 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.breakpoint {
|
||||
background-image: url("chrome://browser/skin/devtools/editor-breakpoint@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.breakpoint[adding] {
|
||||
transition: transform .25s;
|
||||
}
|
||||
|
@ -35,12 +41,26 @@
|
|||
background-image: url("chrome://browser/skin/devtools/editor-debug-location.png");
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.debugLocation {
|
||||
background-image: url("chrome://browser/skin/devtools/editor-debug-location@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.breakpoint.debugLocation {
|
||||
background-image:
|
||||
url("chrome://browser/skin/devtools/editor-debug-location.png"),
|
||||
url("chrome://browser/skin/devtools/editor-breakpoint.png");
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.breakpoint.debugLocation {
|
||||
background-image:
|
||||
url("chrome://browser/skin/devtools/editor-debug-location@2x.png"),
|
||||
url("chrome://browser/skin/devtools/editor-breakpoint@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
cursor: text;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,3 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include ../../shared/devtools/debugger.inc.css
|
||||
|
||||
.devtools-sidebar-tabs > tabs > tab {
|
||||
min-height: 24px !important;
|
||||
}
|
||||
|
|
|
@ -217,6 +217,7 @@ browser.jar:
|
|||
skin/classic/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
|
||||
skin/classic/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
|
||||
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
|
||||
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
|
||||
skin/classic/browser/devtools/breadcrumbs-divider@2x.png (../shared/devtools/images/breadcrumbs-divider@2x.png)
|
||||
skin/classic/browser/devtools/breadcrumbs-scrollbutton.png (../shared/devtools/images/breadcrumbs-scrollbutton.png)
|
||||
skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
|
||||
|
@ -245,15 +246,24 @@ browser.jar:
|
|||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
skin/classic/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
|
||||
skin/classic/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
|
||||
skin/classic/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
|
||||
skin/classic/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
|
||||
skin/classic/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
|
||||
skin/classic/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
|
||||
skin/classic/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
|
||||
skin/classic/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
|
||||
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
skin/classic/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
|
||||
skin/classic/browser/devtools/responsive-se-resizer.png (../shared/devtools/images/responsive-se-resizer.png)
|
||||
|
@ -266,7 +276,8 @@ browser.jar:
|
|||
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
|
||||
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
|
||||
skin/classic/browser/devtools/inspector.css (devtools/inspector.css)
|
||||
skin/classic/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
|
||||
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
|
||||
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
|
||||
skin/classic/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
|
||||
skin/classic/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
|
||||
skin/classic/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)
|
||||
|
|
|
@ -333,7 +333,9 @@ browser.jar:
|
|||
skin/classic/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
|
||||
skin/classic/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
|
||||
skin/classic/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
|
||||
skin/classic/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
|
||||
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
|
||||
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
|
||||
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
skin/classic/browser/devtools/webconsole.png (../shared/devtools/images/webconsole.png)
|
||||
|
@ -366,15 +368,24 @@ browser.jar:
|
|||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
skin/classic/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
|
||||
skin/classic/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
|
||||
skin/classic/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
|
||||
skin/classic/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
|
||||
skin/classic/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
|
||||
skin/classic/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
|
||||
skin/classic/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
|
||||
skin/classic/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
skin/classic/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
|
||||
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
|
||||
|
@ -387,7 +398,8 @@ browser.jar:
|
|||
skin/classic/browser/devtools/dock-bottom@2x.png (../shared/devtools/images/dock-bottom@2x.png)
|
||||
skin/classic/browser/devtools/dock-side@2x.png (../shared/devtools/images/dock-side@2x.png)
|
||||
* skin/classic/browser/devtools/inspector.css (devtools/inspector.css)
|
||||
skin/classic/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
|
||||
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
|
||||
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
|
||||
skin/classic/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
|
||||
skin/classic/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
|
||||
skin/classic/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)
|
||||
|
|
|
@ -35,8 +35,7 @@
|
|||
min-width: 30px;
|
||||
min-height: 28px;
|
||||
margin: 0;
|
||||
list-style-image: url(profiler-stopwatch.png);
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
list-style-image: url(profiler-stopwatch.svg);
|
||||
}
|
||||
|
||||
#empty-notice > button .button-text {
|
||||
|
@ -74,12 +73,11 @@
|
|||
}
|
||||
|
||||
#record-snapshot {
|
||||
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.png");
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.svg");
|
||||
}
|
||||
|
||||
#record-snapshot[checked] {
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch-checked.svg");
|
||||
}
|
||||
|
||||
/* Snapshots items */
|
||||
|
|
|
@ -61,6 +61,12 @@
|
|||
list-style-image: url(debugger-blackbox.png);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#black-box {
|
||||
list-style-image: url(debugger-blackbox@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#pretty-print {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -69,6 +75,12 @@
|
|||
list-style-image: url(debugger-toggleBreakpoints.png);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#toggle-breakpoints {
|
||||
list-style-image: url(debugger-toggleBreakpoints@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#sources-toolbar .devtools-toolbarbutton:not([label]) {
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
}
|
||||
|
@ -77,6 +89,16 @@
|
|||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#sources-toolbar .devtools-toolbarbutton:not([label]) {
|
||||
-moz-image-region: rect(0px,32px,32px,0px);
|
||||
}
|
||||
|
||||
#sources-toolbar .devtools-toolbarbutton:not([label])[checked] {
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
}
|
||||
|
||||
#sources .black-boxed {
|
||||
color: rgba(128,128,128,0.4);
|
||||
}
|
||||
|
@ -93,7 +115,6 @@
|
|||
|
||||
#black-boxed-message,
|
||||
#source-progress-container {
|
||||
background: url(background-noise-toolbar.png);
|
||||
/* Prevent the container deck from aquiring the size from this message. */
|
||||
min-width: 1px;
|
||||
min-height: 1px;
|
||||
|
@ -184,6 +205,17 @@
|
|||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#trace {
|
||||
list-style-image: url(tracer-icon@2x.png);
|
||||
-moz-image-region: rect(0px,32px,32px,0px);
|
||||
}
|
||||
|
||||
#trace[checked] {
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
}
|
||||
|
||||
#clear-tracer {
|
||||
/* Make this button as narrow as the text inside it. */
|
||||
min-width: 1px;
|
||||
|
@ -280,13 +312,21 @@
|
|||
}
|
||||
|
||||
.dbg-expression-arrow {
|
||||
background: url(commandline-icon.png);
|
||||
background-image: url(commandline-icon.png);
|
||||
background-position: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 32px 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.dbg-expression-arrow {
|
||||
background-image: url(commandline-icon@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.dbg-expression-input {
|
||||
color: inherit;
|
||||
}
|
||||
|
@ -542,10 +582,16 @@
|
|||
/* Toolbar controls */
|
||||
|
||||
.devtools-sidebar-tabs > tabs > tab {
|
||||
min-height: 1em !important;
|
||||
min-height: 24px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
#debugger-toolbar .devtools-toolbarbutton:not([label]) > .toolbarbutton-icon,
|
||||
#sources-toolbar .devtools-toolbarbutton:not([label]) > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#resume {
|
||||
list-style-image: url(debugger-pause.png);
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
|
@ -558,6 +604,18 @@
|
|||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#resume {
|
||||
list-style-image: url(debugger-pause@2x.png);
|
||||
-moz-image-region: rect(0px,32px,32px,0px);
|
||||
}
|
||||
|
||||
#resume[checked] {
|
||||
list-style-image: url(debugger-play@2x.png);
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
}
|
||||
|
||||
#resume ~ toolbarbutton {
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
|
@ -578,6 +636,20 @@
|
|||
list-style-image: url(debugger-step-out.png);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#step-over {
|
||||
list-style-image: url(debugger-step-over@2x.png);
|
||||
}
|
||||
|
||||
#step-in {
|
||||
list-style-image: url(debugger-step-in@2x.png);
|
||||
}
|
||||
|
||||
#step-out {
|
||||
list-style-image: url(debugger-step-out@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#instruments-pane-toggle {
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
|
@ -590,10 +662,25 @@
|
|||
list-style-image: url(debugger-expand.png);
|
||||
}
|
||||
|
||||
#instruments-pane-toggle:active {
|
||||
#instruments-pane-toggle:hover {
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#instruments-pane-toggle {
|
||||
list-style-image: url(debugger-collapse@2x.png);
|
||||
-moz-image-region: rect(0px,32px,32px,0px);
|
||||
}
|
||||
|
||||
#instruments-pane-toggle[pane-collapsed] {
|
||||
list-style-image: url(debugger-expand@2x.png);
|
||||
}
|
||||
|
||||
#instruments-pane-toggle:hover {
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Horizontal vs. vertical layout */
|
||||
|
||||
#vertical-layout-panes-container {
|
||||
|
|
После Ширина: | Высота: | Размер: 988 B |
После Ширина: | Высота: | Размер: 338 B |
После Ширина: | Высота: | Размер: 350 B |
После Ширина: | Высота: | Размер: 189 B |
После Ширина: | Высота: | Размер: 494 B |
После Ширина: | Высота: | Размер: 355 B |
После Ширина: | Высота: | Размер: 339 B |
После Ширина: | Высота: | Размер: 472 B |
После Ширина: | Высота: | Размер: 1.6 KiB |
Двоичные данные
browser/themes/shared/devtools/images/editor-breakpoint.png
До Ширина: | Высота: | Размер: 577 B После Ширина: | Высота: | Размер: 430 B |
После Ширина: | Высота: | Размер: 773 B |
Двоичные данные
browser/themes/shared/devtools/images/editor-debug-location.png
До Ширина: | Высота: | Размер: 308 B После Ширина: | Высота: | Размер: 266 B |
После Ширина: | Высота: | Размер: 462 B |
Двоичные данные
browser/themes/shared/devtools/images/option-icon.png
До Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -0,0 +1,14 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 16 16">
|
||||
<g fill="#3BACE5" fill-rule="evenodd">
|
||||
<path d="m8,1c-3.9,0-7,3.1-7,7s3.1,7 7,7c3.9,0 7-3.1 7-7s-3.1-7-7-7zm-.1,12c-2.8,0-5-2.2-5-5 0-2.8 2.2-5 5-5s5,2.2 5,5c0,2.8-2.2,5-5,5z"/>
|
||||
<path d="m8,6.9c.6,0 1.1,.5 1.1,1.1 0,.6-.5,1.1-1.1,1.1-.6,0-1.1-.5-1.1-1.1 0-.6 .5-1.1 1.1-1.1z"/>
|
||||
<path d="m11.3,4.6l-3.9,2.5 1.5,1.4 2.4-3.9z"/>
|
||||
<path opacity=".4" d="m4.6,10c.7,1.2 2,2 3.4,2 1.5,0 2.7-.8 3.4-2h-6.8z"/>
|
||||
<g opacity=".3">
|
||||
<path d="m7.1,5.1l-.6-1.3-.9,.4 .7,1.3c.2-.1 .5-.3 .8-.4z"/>
|
||||
<path d="m9.8,5.6l.7-1.4-.9-.4-.7,1.3c.3,.2 .6,.3 .9,.5z"/>
|
||||
<path d="m10.8,7c.1,.3 .2,.7 .2,1h2v-1h-2.2z"/>
|
||||
<path d="m5,8c0-.3 .1-.7 .2-1h-2.2l-.1,1h2.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 814 B |
Двоичные данные
browser/themes/shared/devtools/images/profiler-stopwatch.png
До Ширина: | Высота: | Размер: 754 B |
|
@ -0,0 +1,14 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 16 16">
|
||||
<g fill="#edf0f1" fill-rule="evenodd">
|
||||
<path d="m8,1c-3.9,0-7,3.1-7,7s3.1,7 7,7c3.9,0 7-3.1 7-7s-3.1-7-7-7zm-.1,12c-2.8,0-5-2.2-5-5 0-2.8 2.2-5 5-5s5,2.2 5,5c0,2.8-2.2,5-5,5z"/>
|
||||
<path d="m8,6.9c.6,0 1.1,.5 1.1,1.1 0,.6-.5,1.1-1.1,1.1-.6,0-1.1-.5-1.1-1.1 0-.6 .5-1.1 1.1-1.1z"/>
|
||||
<path d="m11.3,4.6l-3.9,2.5 1.5,1.4 2.4-3.9z"/>
|
||||
<path opacity=".4" d="m4.6,10c.7,1.2 2,2 3.4,2 1.5,0 2.7-.8 3.4-2h-6.8z"/>
|
||||
<g opacity=".3">
|
||||
<path d="m7.1,5.1l-.6-1.3-.9,.4 .7,1.3c.2-.1 .5-.3 .8-.4z"/>
|
||||
<path d="m9.8,5.6l.7-1.4-.9-.4-.7,1.3c.3,.2 .6,.3 .9,.5z"/>
|
||||
<path d="m10.8,7c.1,.3 .2,.7 .2,1h2v-1h-2.2z"/>
|
||||
<path d="m5,8c0-.3 .1-.7 .2-1h-2.2l-.1,1h2.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 814 B |
|
@ -21,8 +21,7 @@
|
|||
min-width: 30px;
|
||||
min-height: 28px;
|
||||
margin: 0;
|
||||
list-style-image: url(profiler-stopwatch.png);
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
list-style-image: url(profiler-stopwatch.svg);
|
||||
}
|
||||
|
||||
#requests-menu-perf-notice-button .button-text {
|
||||
|
@ -613,8 +612,7 @@ label.requests-menu-status-code {
|
|||
background: none;
|
||||
box-shadow: none;
|
||||
border-color: transparent;
|
||||
list-style-image: url(profiler-stopwatch.png);
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
list-style-image: url(profiler-stopwatch.svg);
|
||||
-moz-padding-end: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
@ -70,10 +70,9 @@
|
|||
}
|
||||
|
||||
#profiler-start {
|
||||
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.png");
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.svg");
|
||||
}
|
||||
|
||||
#profiler-start[checked] {
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch-checked.svg");
|
||||
}
|
|
@ -792,7 +792,9 @@
|
|||
.theme-light .command-button-invertable[checked=true]:not(:active) > image,
|
||||
.theme-light .devtools-tab[icon-invertable][selected] > image,
|
||||
.theme-light .devtools-tab[icon-invertable][highlighted] > image,
|
||||
.theme-light #resume[checked] > image {
|
||||
.theme-light #resume[checked] > image,
|
||||
.theme-light #record-snapshot[checked] > image,
|
||||
.theme-light #profiler-start[checked] > image {
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,15 +3,3 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include ../../shared/devtools/debugger.inc.css
|
||||
|
||||
.devtools-sidebar-tabs > tabs > tab {
|
||||
min-height: 22px !important;
|
||||
}
|
||||
|
||||
#instruments-pane-toggle:hover {
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
#instruments-pane-toggle:hover:active {
|
||||
-moz-image-region: rect(0px,48px,16px,32px);
|
||||
}
|
||||
|
|
|
@ -249,7 +249,9 @@ browser.jar:
|
|||
skin/classic/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
|
||||
skin/classic/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
|
||||
skin/classic/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
|
||||
skin/classic/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
|
||||
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
|
||||
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
|
||||
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
skin/classic/browser/devtools/webconsole.png (../shared/devtools/images/webconsole.png)
|
||||
|
@ -282,15 +284,24 @@ browser.jar:
|
|||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
skin/classic/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
|
||||
skin/classic/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
|
||||
skin/classic/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
|
||||
skin/classic/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
|
||||
skin/classic/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
|
||||
skin/classic/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
|
||||
skin/classic/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
|
||||
skin/classic/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
|
||||
skin/classic/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
skin/classic/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
|
||||
skin/classic/browser/devtools/responsive-se-resizer.png (../shared/devtools/images/responsive-se-resizer.png)
|
||||
|
@ -303,7 +314,8 @@ browser.jar:
|
|||
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
|
||||
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
|
||||
skin/classic/browser/devtools/inspector.css (devtools/inspector.css)
|
||||
skin/classic/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
|
||||
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
|
||||
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
|
||||
skin/classic/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
|
||||
skin/classic/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
|
||||
skin/classic/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)
|
||||
|
@ -624,7 +636,9 @@ browser.jar:
|
|||
skin/classic/aero/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
|
||||
skin/classic/aero/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
|
||||
skin/classic/aero/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
|
||||
skin/classic/aero/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
|
||||
skin/classic/aero/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
|
||||
skin/classic/aero/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
|
||||
* skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
skin/classic/aero/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
skin/classic/aero/browser/devtools/webconsole.png (../shared/devtools/images/webconsole.png)
|
||||
|
@ -656,15 +670,24 @@ browser.jar:
|
|||
skin/classic/aero/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/aero/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/aero/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/aero/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
|
||||
skin/classic/aero/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
|
||||
skin/classic/aero/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
|
||||
skin/classic/aero/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
|
||||
skin/classic/aero/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
|
||||
skin/classic/aero/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
|
||||
skin/classic/aero/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/aero/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
|
||||
skin/classic/aero/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/aero/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/aero/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/aero/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
skin/classic/aero/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
|
||||
skin/classic/aero/browser/devtools/responsive-se-resizer.png (../shared/devtools/images/responsive-se-resizer.png)
|
||||
|
@ -677,7 +700,8 @@ browser.jar:
|
|||
skin/classic/aero/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
|
||||
skin/classic/aero/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
|
||||
skin/classic/aero/browser/devtools/inspector.css (devtools/inspector.css)
|
||||
skin/classic/aero/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
|
||||
skin/classic/aero/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
|
||||
skin/classic/aero/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
|
||||
skin/classic/aero/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
|
||||
skin/classic/aero/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
|
||||
skin/classic/aero/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)
|
||||
|
|
|
@ -10,8 +10,9 @@ interface nsIURI;
|
|||
interface nsIChannel;
|
||||
interface nsIDocShell;
|
||||
interface nsIDomainPolicy;
|
||||
interface nsILoadContext;
|
||||
|
||||
[scriptable, uuid(2565769a-eaec-47a1-a076-605f5294d286)]
|
||||
[scriptable, uuid(9875f4b2-f9cd-41d1-a461-fe14956823ac)]
|
||||
interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
||||
{
|
||||
/**
|
||||
|
@ -122,6 +123,14 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
|||
in unsigned long appId,
|
||||
in boolean inMozBrowser);
|
||||
|
||||
/**
|
||||
* Returns a principal that has the appId and inMozBrowser of the load
|
||||
* context.
|
||||
* @param loadContext to get appId/inMozBrowser from.
|
||||
*/
|
||||
nsIPrincipal getLoadContextCodebasePrincipal(in nsIURI uri,
|
||||
in nsILoadContext loadContext);
|
||||
|
||||
/**
|
||||
* Returns a principal that has the appId and inMozBrowser of the docshell
|
||||
* inside a mozbrowser frame.
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "js/OldDebugAPI.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "XPCWrapper.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIScriptContext.h"
|
||||
|
@ -295,11 +296,12 @@ nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
|
|||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
NS_QueryNotificationCallbacks(aChannel, docShell);
|
||||
|
||||
if (docShell) {
|
||||
return GetDocShellCodebasePrincipal(uri, docShell, aPrincipal);
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(aChannel, loadContext);
|
||||
|
||||
if (loadContext) {
|
||||
return GetLoadContextCodebasePrincipal(uri, loadContext, aPrincipal);
|
||||
}
|
||||
|
||||
return GetCodebasePrincipalInternal(uri, UNKNOWN_APP_ID,
|
||||
|
@ -969,6 +971,22 @@ nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
|
|||
return GetCodebasePrincipalInternal(aURI, aAppId, aInMozBrowser, aPrincipal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::
|
||||
GetLoadContextCodebasePrincipal(nsIURI* aURI,
|
||||
nsILoadContext* aLoadContext,
|
||||
nsIPrincipal** aPrincipal)
|
||||
{
|
||||
uint32_t appId;
|
||||
aLoadContext->GetAppId(&appId);
|
||||
bool isInBrowserElement;
|
||||
aLoadContext->GetIsInBrowserElement(&isInBrowserElement);
|
||||
return GetCodebasePrincipalInternal(aURI,
|
||||
appId,
|
||||
isInBrowserElement,
|
||||
aPrincipal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
|
||||
nsIDocShell* aDocShell,
|
||||
|
|
|
@ -7522,15 +7522,6 @@ if test -n "$MOZ_B2G_CAMERA"; then
|
|||
fi
|
||||
AC_SUBST(MOZ_B2G_CAMERA)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support B2G-specific changes to the NSS
|
||||
dnl = certificate trust database.
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_B2G_CERTDATA"; then
|
||||
AC_DEFINE(MOZ_B2G_CERTDATA)
|
||||
fi
|
||||
AC_SUBST(MOZ_B2G_CERTDATA)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for Payment API
|
||||
dnl ========================================================
|
||||
|
|
|
@ -175,4 +175,8 @@
|
|||
#define THIRDPARTYUTIL_CID \
|
||||
{0x08c6cc8b, 0xcfb0, 0x421d, {0xb1, 0xf7, 0x68, 0x3f, 0xf2, 0x98, 0x96, 0x81}}
|
||||
|
||||
// {7B121F7E-EBE4-43AB-9410-DC9087A1DBA6}
|
||||
#define GECKO_MEDIA_PLUGIN_SERVICE_CID \
|
||||
{0x7B121F7E, 0xEBE4, 0x43AB, {0x94, 0x10, 0xDC, 0x90, 0x87, 0xA1, 0xDB, 0xA6}}
|
||||
|
||||
#endif /* nsContentCID_h__ */
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsIObserver.h"
|
||||
|
@ -2337,20 +2338,20 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
|||
nsIScriptSecurityManager *securityManager =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
if (securityManager) {
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
nsCOMPtr<nsILoadContext> loadContext(mDocumentContainer);
|
||||
|
||||
if (!docShell && aLoadGroup) {
|
||||
if (!loadContext && aLoadGroup) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> cbs;
|
||||
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
|
||||
docShell = do_GetInterface(cbs);
|
||||
loadContext = do_GetInterface(cbs);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(docShell,
|
||||
"must be in a docshell or pass in an explicit principal");
|
||||
MOZ_ASSERT(loadContext,
|
||||
"must have a load context or pass in an explicit principal");
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = securityManager->
|
||||
GetDocShellCodebasePrincipal(mDocumentURI, docShell,
|
||||
GetLoadContextCodebasePrincipal(mDocumentURI, loadContext,
|
||||
getter_AddRefs(principal));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
SetPrincipal(principal);
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -86,10 +87,8 @@ public:
|
|||
|
||||
~nsScriptLoadRequest()
|
||||
{
|
||||
if (mScriptTextBuf) {
|
||||
js_free(mScriptTextBuf);
|
||||
}
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
|
@ -433,7 +432,7 @@ ParseTypeAttribute(const nsAString& aType, JSVersion* aVersion)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
|
||||
{
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
|
@ -540,6 +539,43 @@ CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
AccumulateJavaScriptVersionTelemetry(nsIScriptElement* aElement,
|
||||
JSVersion aVersion)
|
||||
{
|
||||
uint32_t minorVersion;
|
||||
switch (aVersion) {
|
||||
case JSVERSION_DEFAULT: minorVersion = 5; break;
|
||||
case JSVERSION_1_6: minorVersion = 6; break;
|
||||
case JSVERSION_1_7: minorVersion = 7; break;
|
||||
case JSVERSION_1_8: minorVersion = 8; break;
|
||||
default: MOZ_ASSERT_UNREACHABLE("Unexpected JSVersion");
|
||||
case JSVERSION_UNKNOWN: minorVersion = 0; break;
|
||||
}
|
||||
|
||||
// Only report SpiderMonkey's nonstandard JS versions: 1.6, 1.7, and 1.8.
|
||||
if (minorVersion < 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
|
||||
if (!scriptURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only care about web content, not chrome or add-on JS versions.
|
||||
bool chrome = false;
|
||||
scriptURI->SchemeIs("chrome", &chrome);
|
||||
if (!chrome) {
|
||||
scriptURI->SchemeIs("resource", &chrome);
|
||||
}
|
||||
if (chrome) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::JS_MINOR_VERSION, minorVersion);
|
||||
}
|
||||
|
||||
bool
|
||||
nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
{
|
||||
|
@ -568,6 +604,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
aElement->GetScriptType(type);
|
||||
if (!type.IsEmpty()) {
|
||||
NS_ENSURE_TRUE(ParseTypeAttribute(type, &version), false);
|
||||
AccumulateJavaScriptVersionTelemetry(aElement, version);
|
||||
} else {
|
||||
// no 'type=' element
|
||||
// "language" is a deprecated attribute of HTML, so we check it only for
|
||||
|
|
|
@ -2,7 +2,14 @@ dump('loaded child cpow test\n');
|
|||
|
||||
content.document.title = "Hello, Kitty";
|
||||
|
||||
var done_count = 0;
|
||||
var is_remote;
|
||||
|
||||
(function start() {
|
||||
[is_remote] = sendSyncMessage("cpows:is_remote");
|
||||
parent_test();
|
||||
dom_test();
|
||||
xray_test();
|
||||
sync_test();
|
||||
async_test();
|
||||
rpc_test();
|
||||
|
@ -10,7 +17,12 @@ content.document.title = "Hello, Kitty";
|
|||
// The sync-ness of this call is important, because otherwise
|
||||
// we tear down the child's document while we are
|
||||
// still in the async test in the parent.
|
||||
// This test races with itself to be the final test.
|
||||
lifetime_test(function() {
|
||||
done_count++;
|
||||
if (done_count == 2)
|
||||
sendSyncMessage("cpows:done", {});
|
||||
});
|
||||
}
|
||||
)();
|
||||
|
||||
|
@ -56,6 +68,44 @@ function make_json()
|
|||
return { check: "ok" };
|
||||
}
|
||||
|
||||
function parent_test()
|
||||
{
|
||||
function f(check_func) {
|
||||
let result = check_func(10);
|
||||
ok(result == 20, "calling function in parent worked");
|
||||
return result;
|
||||
}
|
||||
|
||||
addMessageListener("cpows:from_parent", (msg) => {
|
||||
let obj = msg.objects.obj;
|
||||
ok(obj.a == 1, "correct value from parent");
|
||||
done_count++;
|
||||
if (done_count == 2)
|
||||
sendSyncMessage("cpows:done", {});
|
||||
});
|
||||
sendSyncMessage("cpows:parent_test", {}, {func: f});
|
||||
}
|
||||
|
||||
function dom_test()
|
||||
{
|
||||
let element = content.document.createElement("div");
|
||||
element.id = "it_works";
|
||||
content.document.body.appendChild(element);
|
||||
|
||||
sendAsyncMessage("cpows:dom_test", {}, {element: element});
|
||||
Components.utils.schedulePreciseGC(function() {
|
||||
sendSyncMessage("cpows:dom_test_after_gc");
|
||||
});
|
||||
}
|
||||
|
||||
function xray_test()
|
||||
{
|
||||
let element = content.document.createElement("div");
|
||||
element.wrappedJSObject.foo = "hello";
|
||||
|
||||
sendSyncMessage("cpows:xray_test", {}, {element: element});
|
||||
}
|
||||
|
||||
function sync_test()
|
||||
{
|
||||
dump('beginning cpow sync test\n');
|
||||
|
@ -106,3 +156,28 @@ function nested_sync_test()
|
|||
make_json(),
|
||||
rpc_obj);
|
||||
}
|
||||
|
||||
function lifetime_test(finish)
|
||||
{
|
||||
if (!is_remote) {
|
||||
// Only run this test when running out-of-process. Otherwise it
|
||||
// will fail, since local CPOWs don't follow the same ownership
|
||||
// rules.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
dump("beginning lifetime test\n");
|
||||
var obj = {"will_die": {"f": 1}};
|
||||
let [result] = sendSyncMessage("cpows:lifetime_test_1", {}, {obj: obj});
|
||||
ok(result == 10, "got sync result");
|
||||
ok(obj.wont_die.f == 2, "got reverse CPOW");
|
||||
obj.will_die = null;
|
||||
Components.utils.schedulePreciseGC(function() {
|
||||
addMessageListener("cpows:lifetime_test_3", (msg) => {
|
||||
ok(obj.wont_die.f == 2, "reverse CPOW still works");
|
||||
finish();
|
||||
});
|
||||
sendSyncMessage("cpows:lifetime_test_2");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,11 +13,20 @@
|
|||
var test_state = "remote";
|
||||
var test_node = null;
|
||||
var reentered = false;
|
||||
var savedMM = null;
|
||||
|
||||
function info(message) {
|
||||
return opener.wrappedJSObject.info(message);
|
||||
}
|
||||
|
||||
function ok(condition, message) {
|
||||
return opener.wrappedJSObject.ok(condition, message);
|
||||
}
|
||||
|
||||
function is(v1, v2, message) {
|
||||
return opener.wrappedJSObject.is(v1, v2, message);
|
||||
}
|
||||
|
||||
// Make sure that an error in this file actually causes the test to fail.
|
||||
window.onerror = function (msg, url, line) {
|
||||
ok(false, "Error while executing: \n" + msg + "\n" + url + ":" + line);
|
||||
|
@ -145,13 +154,72 @@
|
|||
finish();
|
||||
}
|
||||
|
||||
function recvParentTest(message) {
|
||||
let func = message.objects.func;
|
||||
let result = func(n => 2*n);
|
||||
ok(result == 20, "result == 20");
|
||||
let obj = {a:1};
|
||||
savedMM.sendAsyncMessage("cpows:from_parent", {}, {obj: obj});
|
||||
}
|
||||
|
||||
let savedElement = null;
|
||||
function recvDomTest(message) {
|
||||
savedElement = message.objects.element;
|
||||
}
|
||||
|
||||
function recvDomTestAfterGC(message) {
|
||||
let id;
|
||||
try {
|
||||
id = savedElement.id;
|
||||
} catch (e) {
|
||||
ok(false, "Got exception using DOM element");
|
||||
}
|
||||
is(id, "it_works", "DOM element has expected ID");
|
||||
}
|
||||
|
||||
function recvXrayTest(message) {
|
||||
let element = message.objects.element;
|
||||
is(element.foo, undefined, "DOM element does not expose content properties");
|
||||
}
|
||||
|
||||
let savedWilldieObj;
|
||||
let wontDie = {f:2};
|
||||
function recvLifetimeTest1(message) {
|
||||
let obj = message.objects.obj;
|
||||
savedWilldieObj = obj.will_die;
|
||||
ok(savedWilldieObj.f == 1, "limited-lifetime CPOW works at first");
|
||||
obj.wont_die = wontDie;
|
||||
obj = null;
|
||||
return 10;
|
||||
}
|
||||
function recvLifetimeTest2(message) {
|
||||
let threw = false;
|
||||
try {
|
||||
savedWilldieObj.f;
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
ok(threw, "limited-lifetime CPOW stopped working");
|
||||
wontDie = null;
|
||||
Components.utils.schedulePreciseGC(function() {
|
||||
savedMM.sendAsyncMessage("cpows:lifetime_test_3");
|
||||
});
|
||||
}
|
||||
|
||||
function run_tests(type) {
|
||||
info("Running tests: " + type);
|
||||
var node = document.getElementById('cpowbrowser_' + type);
|
||||
|
||||
test_state = type;
|
||||
test_node = node;
|
||||
|
||||
function recvIsRemote(message) {
|
||||
return type == "remote";
|
||||
}
|
||||
|
||||
var mm = node.messageManager;
|
||||
savedMM = mm;
|
||||
mm.addMessageListener("cpows:is_remote", recvIsRemote);
|
||||
mm.addMessageListener("cpows:async", recvAsyncMessage);
|
||||
mm.addMessageListener("cpows:sync", recvSyncMessage);
|
||||
mm.addMessageListener("cpows:rpc", recvRpcMessage);
|
||||
|
@ -161,6 +229,12 @@
|
|||
mm.addMessageListener("cpows:reenter_sync", recvReenterSyncMessage);
|
||||
mm.addMessageListener("cpows:done", recvDoneMessage);
|
||||
mm.addMessageListener("cpows:fail", recvFailMessage);
|
||||
mm.addMessageListener("cpows:parent_test", recvParentTest);
|
||||
mm.addMessageListener("cpows:dom_test", recvDomTest);
|
||||
mm.addMessageListener("cpows:dom_test_after_gc", recvDomTestAfterGC);
|
||||
mm.addMessageListener("cpows:xray_test", recvXrayTest);
|
||||
mm.addMessageListener("cpows:lifetime_test_1", recvLifetimeTest1);
|
||||
mm.addMessageListener("cpows:lifetime_test_2", recvLifetimeTest2);
|
||||
mm.loadFrameScript("chrome://mochitests/content/chrome/content/base/test/chrome/cpows_child.js", true);
|
||||
}
|
||||
|
||||
|
|
|
@ -5196,6 +5196,8 @@ HTMLInputElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart,
|
|||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown mode!");
|
||||
}
|
||||
|
||||
Optional<nsAString> direction;
|
||||
|
|
|
@ -985,6 +985,8 @@ HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
|
|||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown mode!");
|
||||
}
|
||||
|
||||
Optional<nsAString> direction;
|
||||
|
|
|
@ -77,6 +77,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
|
|||
return;
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("MediaStream %p will finish", aStream));
|
||||
aStream->mFinished = true;
|
||||
aStream->mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
// Force at least one more iteration of the control loop, since we rely
|
||||
// on UpdateCurrentTime to notify our listeners once the stream end
|
||||
// has been reached.
|
||||
|
@ -206,8 +207,10 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
|||
aStream->mUpdateTracks.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
if (!aStream->mFinished) {
|
||||
aStream->mBuffer.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime);
|
||||
}
|
||||
}
|
||||
if (aStream->mBuffer.GetEnd() > 0) {
|
||||
aStream->mHasCurrentData = true;
|
||||
}
|
||||
|
@ -2409,6 +2412,7 @@ void
|
|||
SourceMediaStream::AdvanceKnownTracksTime(StreamTime aKnownTime)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(aKnownTime >= mUpdateKnownTracksTime);
|
||||
mUpdateKnownTracksTime = aKnownTime;
|
||||
if (!mDestroyed) {
|
||||
GraphImpl()->EnsureNextIteration();
|
||||
|
|
|
@ -737,8 +737,7 @@ public:
|
|||
/**
|
||||
* Indicate that this stream should enter the "finished" state. All tracks
|
||||
* must have been ended via EndTrack. The finish time of the stream is
|
||||
* when all tracks have ended and when latest time sent to
|
||||
* AdvanceKnownTracksTime() has been reached.
|
||||
* when all tracks have ended.
|
||||
*/
|
||||
void FinishWithLockHeld();
|
||||
void Finish()
|
||||
|
|
|
@ -49,6 +49,10 @@ StreamBuffer::GetEnd() const
|
|||
StreamTime
|
||||
StreamBuffer::GetAllTracksEnd() const
|
||||
{
|
||||
if (mTracksKnownTime < STREAM_TIME_MAX) {
|
||||
// A track might be added.
|
||||
return STREAM_TIME_MAX;
|
||||
}
|
||||
StreamTime t = 0;
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
|
@ -57,11 +61,6 @@ StreamBuffer::GetAllTracksEnd() const
|
|||
}
|
||||
t = std::max(t, track->GetEndTimeRoundDown());
|
||||
}
|
||||
if (t > mTracksKnownTime) {
|
||||
// It can't be later then mTracksKnownTime, since a track might be added
|
||||
// after that.
|
||||
return STREAM_TIME_MAX;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,8 +106,9 @@ public:
|
|||
// all our tracks have actually finished and been removed from our map,
|
||||
// so we're finished now.
|
||||
FinishOnGraphThread();
|
||||
}
|
||||
} else {
|
||||
mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime(aTo));
|
||||
}
|
||||
if (allHaveCurrentData) {
|
||||
// We can make progress if we're not blocked
|
||||
mHasCurrentData = true;
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPChild.h"
|
||||
#include "GMPVideoDecoderChild.h"
|
||||
#include "GMPVideoEncoderChild.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include <stdlib.h>
|
||||
#include "gmp-video-decode.h"
|
||||
#include "gmp-video-encode.h"
|
||||
#include "GMPPlatform.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPChild::GMPChild()
|
||||
: mLib(nullptr)
|
||||
, mGetAPIFunc(nullptr)
|
||||
, mGMPMessageLoop(MessageLoop::current())
|
||||
{
|
||||
}
|
||||
|
||||
GMPChild::~GMPChild()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::Init(const std::string& aPluginPath,
|
||||
base::ProcessHandle aParentProcessHandle,
|
||||
MessageLoop* aIOLoop,
|
||||
IPC::Channel* aChannel)
|
||||
{
|
||||
return LoadPluginLibrary(aPluginPath) &&
|
||||
Open(aChannel, aParentProcessHandle, aIOLoop);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
|
||||
{
|
||||
nsDependentCString pluginPath(aPluginPath.c_str());
|
||||
|
||||
nsCOMPtr<nsIFile> libFile;
|
||||
nsresult rv = NS_NewNativeLocalFile(pluginPath, true, getter_AddRefs(libFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString leafName;
|
||||
if (NS_FAILED(libFile->GetLeafName(leafName))) {
|
||||
return false;
|
||||
}
|
||||
nsAutoString baseName(Substring(leafName, 4, leafName.Length() - 1));
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".dylib");
|
||||
#elif defined(OS_POSIX)
|
||||
nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".so");
|
||||
#elif defined(XP_WIN)
|
||||
nsAutoString binaryName = baseName + NS_LITERAL_STRING(".dll");
|
||||
#else
|
||||
#error not defined
|
||||
#endif
|
||||
libFile->AppendRelativePath(binaryName);
|
||||
|
||||
nsAutoCString nativePath;
|
||||
libFile->GetNativePath(nativePath);
|
||||
mLib = PR_LoadLibrary(nativePath.get());
|
||||
if (!mLib) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
|
||||
if (!initFunc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto platformAPI = new GMPPlatformAPI();
|
||||
InitPlatformAPI(*platformAPI);
|
||||
|
||||
if (initFunc(platformAPI) != GMPNoErr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
|
||||
if (!mGetAPIFunc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MessageLoop*
|
||||
GMPChild::GMPMessageLoop()
|
||||
{
|
||||
return mGMPMessageLoop;
|
||||
}
|
||||
|
||||
void
|
||||
GMPChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
if (mLib) {
|
||||
GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(PR_FindFunctionSymbol(mLib, "GMPShutdown"));
|
||||
if (shutdownFunc) {
|
||||
shutdownFunc();
|
||||
}
|
||||
}
|
||||
|
||||
if (AbnormalShutdown == aWhy) {
|
||||
NS_WARNING("Abnormal shutdown of GMP process!");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
XRE_ShutdownChildProcess();
|
||||
}
|
||||
|
||||
void
|
||||
GMPChild::ProcessingError(Result aWhat)
|
||||
{
|
||||
switch (aWhat) {
|
||||
case MsgDropped:
|
||||
_exit(0); // Don't trigger a crash report.
|
||||
case MsgNotKnown:
|
||||
MOZ_CRASH("aborting because of MsgNotKnown");
|
||||
case MsgNotAllowed:
|
||||
MOZ_CRASH("aborting because of MsgNotAllowed");
|
||||
case MsgPayloadError:
|
||||
MOZ_CRASH("aborting because of MsgPayloadError");
|
||||
case MsgProcessingError:
|
||||
MOZ_CRASH("aborting because of MsgProcessingError");
|
||||
case MsgRouteError:
|
||||
MOZ_CRASH("aborting because of MsgRouteError");
|
||||
case MsgValueError:
|
||||
MOZ_CRASH("aborting because of MsgValueError");
|
||||
default:
|
||||
MOZ_CRASH("not reached");
|
||||
}
|
||||
}
|
||||
|
||||
PGMPVideoDecoderChild*
|
||||
GMPChild::AllocPGMPVideoDecoderChild()
|
||||
{
|
||||
return new GMPVideoDecoderChild(this);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PGMPVideoEncoderChild*
|
||||
GMPChild::AllocPGMPVideoEncoderChild()
|
||||
{
|
||||
return new GMPVideoEncoderChild(this);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor)
|
||||
{
|
||||
auto vdc = static_cast<GMPVideoDecoderChild*>(aActor);
|
||||
|
||||
void* vd = nullptr;
|
||||
GMPErr err = mGetAPIFunc("decode-video", &vdc->Host(), &vd);
|
||||
if (err != GMPNoErr || !vd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vdc->Init(static_cast<GMPVideoDecoder*>(vd));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor)
|
||||
{
|
||||
auto vec = static_cast<GMPVideoEncoderChild*>(aActor);
|
||||
|
||||
void* ve = nullptr;
|
||||
GMPErr err = mGetAPIFunc("encode-video", &vec->Host(), &ve);
|
||||
if (err != GMPNoErr || !ve) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vec->Init(static_cast<GMPVideoEncoder*>(ve));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPChild_h_
|
||||
#define GMPChild_h_
|
||||
|
||||
#include "mozilla/gmp/PGMPChild.h"
|
||||
#include "gmp-entrypoints.h"
|
||||
#include "prlink.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPChild : public PGMPChild
|
||||
{
|
||||
public:
|
||||
GMPChild();
|
||||
virtual ~GMPChild();
|
||||
|
||||
bool Init(const std::string& aPluginPath,
|
||||
base::ProcessHandle aParentProcessHandle,
|
||||
MessageLoop* aIOLoop,
|
||||
IPC::Channel* aChannel);
|
||||
bool LoadPluginLibrary(const std::string& aPluginPath);
|
||||
MessageLoop* GMPMessageLoop();
|
||||
|
||||
private:
|
||||
virtual PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild() MOZ_OVERRIDE;
|
||||
virtual bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) MOZ_OVERRIDE;
|
||||
virtual PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() MOZ_OVERRIDE;
|
||||
virtual bool DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor) MOZ_OVERRIDE;
|
||||
virtual bool RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor) MOZ_OVERRIDE;
|
||||
virtual bool RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) MOZ_OVERRIDE;
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
virtual void ProcessingError(Result aWhat) MOZ_OVERRIDE;
|
||||
|
||||
PRLibrary* mLib;
|
||||
GMPGetAPIFunc mGetAPIFunc;
|
||||
MessageLoop* mGMPMessageLoop;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPChild_h_
|
|
@ -0,0 +1,329 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPMessageUtils_h_
|
||||
#define GMPMessageUtils_h_
|
||||
|
||||
#include "gmp-video-codec.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodecComplexity>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecComplexity,
|
||||
kGMPComplexityNormal,
|
||||
kGMPComplexityInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVP8ResilienceMode>
|
||||
: public ContiguousEnumSerializer<GMPVP8ResilienceMode,
|
||||
kResilienceOff,
|
||||
kResilienceInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodecType>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecType,
|
||||
kGMPVideoCodecVP8,
|
||||
kGMPVideoCodecInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodecMode>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecMode,
|
||||
kGMPRealtimeVideo,
|
||||
kGMPCodecModeInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodecVP8>
|
||||
{
|
||||
typedef GMPVideoCodecVP8 paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mPictureLossIndicationOn);
|
||||
WriteParam(aMsg, aParam.mFeedbackModeOn);
|
||||
WriteParam(aMsg, aParam.mComplexity);
|
||||
WriteParam(aMsg, aParam.mResilience);
|
||||
WriteParam(aMsg, aParam.mNumberOfTemporalLayers);
|
||||
WriteParam(aMsg, aParam.mDenoisingOn);
|
||||
WriteParam(aMsg, aParam.mErrorConcealmentOn);
|
||||
WriteParam(aMsg, aParam.mAutomaticResizeOn);
|
||||
WriteParam(aMsg, aParam.mFrameDroppingOn);
|
||||
WriteParam(aMsg, aParam.mKeyFrameInterval);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &(aResult->mPictureLossIndicationOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mFeedbackModeOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mComplexity)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mResilience)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mNumberOfTemporalLayers)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mDenoisingOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mErrorConcealmentOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mAutomaticResizeOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mFrameDroppingOn)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mKeyFrameInterval))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%d, %d, %d, %d, %u, %d, %d, %d, %d, %d]",
|
||||
aParam.mPictureLossIndicationOn,
|
||||
aParam.mFeedbackModeOn,
|
||||
aParam.mComplexity,
|
||||
aParam.mResilience,
|
||||
aParam.mNumberOfTemporalLayers,
|
||||
aParam.mDenoisingOn,
|
||||
aParam.mErrorConcealmentOn,
|
||||
aParam.mAutomaticResizeOn,
|
||||
aParam.mFrameDroppingOn,
|
||||
aParam.mKeyFrameInterval));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPSimulcastStream>
|
||||
{
|
||||
typedef GMPSimulcastStream paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mWidth);
|
||||
WriteParam(aMsg, aParam.mHeight);
|
||||
WriteParam(aMsg, aParam.mNumberOfTemporalLayers);
|
||||
WriteParam(aMsg, aParam.mMaxBitrate);
|
||||
WriteParam(aMsg, aParam.mTargetBitrate);
|
||||
WriteParam(aMsg, aParam.mMinBitrate);
|
||||
WriteParam(aMsg, aParam.mQPMax);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &(aResult->mWidth)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mHeight)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mNumberOfTemporalLayers)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mMaxBitrate)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mTargetBitrate)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mMinBitrate)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mQPMax))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%u, %u, %u, %u, %u, %u, %u]", aParam.mWidth, aParam.mHeight,
|
||||
aParam.mNumberOfTemporalLayers, aParam.mMaxBitrate,
|
||||
aParam.mTargetBitrate, aParam.mMinBitrate, aParam.mQPMax));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodec>
|
||||
{
|
||||
typedef GMPVideoCodec paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCodecType);
|
||||
WriteParam(aMsg, nsAutoCString(aParam.mPLName));
|
||||
WriteParam(aMsg, aParam.mPLType);
|
||||
WriteParam(aMsg, aParam.mWidth);
|
||||
WriteParam(aMsg, aParam.mHeight);
|
||||
WriteParam(aMsg, aParam.mStartBitrate);
|
||||
WriteParam(aMsg, aParam.mMaxBitrate);
|
||||
WriteParam(aMsg, aParam.mMinBitrate);
|
||||
WriteParam(aMsg, aParam.mMaxFramerate);
|
||||
if (aParam.mCodecType == kGMPVideoCodecVP8) {
|
||||
WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Serializing unknown codec type!");
|
||||
}
|
||||
WriteParam(aMsg, aParam.mQPMax);
|
||||
WriteParam(aMsg, aParam.mNumberOfSimulcastStreams);
|
||||
for (uint32_t i = 0; i < aParam.mNumberOfSimulcastStreams; i++) {
|
||||
WriteParam(aMsg, aParam.mSimulcastStream[i]);
|
||||
}
|
||||
WriteParam(aMsg, aParam.mMode);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString plName;
|
||||
if (!ReadParam(aMsg, aIter, &plName) ||
|
||||
plName.Length() > kGMPPayloadNameSize - 1) {
|
||||
return false;
|
||||
}
|
||||
memcpy(aResult->mPLName, plName.get(), plName.Length());
|
||||
memset(aResult->mPLName + plName.Length(), 0, kGMPPayloadNameSize - plName.Length());
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mPLType)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mWidth)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mHeight)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mStartBitrate)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMaxBitrate)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMinBitrate)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMaxFramerate))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aResult->mCodecType == kGMPVideoCodecVP8) {
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(false, "De-serializing unknown codec type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mQPMax)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mNumberOfSimulcastStreams))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aResult->mNumberOfSimulcastStreams > kGMPMaxSimulcastStreams) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aResult->mNumberOfSimulcastStreams; i++) {
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mSimulcastStream[i]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mMode))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
const char* codecName = nullptr;
|
||||
if (aParam.mCodecType == kGMPVideoCodecVP8) {
|
||||
codecName = "VP8";
|
||||
}
|
||||
aLog->append(StringPrintf(L"[%s, %u, %u]",
|
||||
codecName,
|
||||
aParam.mWidth,
|
||||
aParam.mHeight));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPCodecSpecificInfoVP8>
|
||||
{
|
||||
typedef GMPCodecSpecificInfoVP8 paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mHasReceivedSLI);
|
||||
WriteParam(aMsg, aParam.mPictureIdSLI);
|
||||
WriteParam(aMsg, aParam.mHasReceivedRPSI);
|
||||
WriteParam(aMsg, aParam.mPictureIdRPSI);
|
||||
WriteParam(aMsg, aParam.mPictureId);
|
||||
WriteParam(aMsg, aParam.mNonReference);
|
||||
WriteParam(aMsg, aParam.mSimulcastIdx);
|
||||
WriteParam(aMsg, aParam.mTemporalIdx);
|
||||
WriteParam(aMsg, aParam.mLayerSync);
|
||||
WriteParam(aMsg, aParam.mTL0PicIdx);
|
||||
WriteParam(aMsg, aParam.mKeyIdx);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &(aResult->mHasReceivedSLI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mPictureIdSLI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mHasReceivedRPSI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mPictureIdRPSI)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mPictureId)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mNonReference)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mSimulcastIdx)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mTemporalIdx)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mLayerSync)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mTL0PicIdx)) &&
|
||||
ReadParam(aMsg, aIter, &(aResult->mKeyIdx))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%d, %u, %d, %u, %d, %d, %u, %u, %d, %d, %d]",
|
||||
aParam.mHasReceivedSLI,
|
||||
aParam.mPictureIdSLI,
|
||||
aParam.mHasReceivedRPSI,
|
||||
aParam.mPictureIdRPSI,
|
||||
aParam.mPictureId,
|
||||
aParam.mNonReference,
|
||||
aParam.mSimulcastIdx,
|
||||
aParam.mTemporalIdx,
|
||||
aParam.mLayerSync,
|
||||
aParam.mTL0PicIdx,
|
||||
aParam.mKeyIdx));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPCodecSpecificInfo>
|
||||
{
|
||||
typedef GMPCodecSpecificInfo paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCodecType);
|
||||
if (aParam.mCodecType == kGMPVideoCodecVP8) {
|
||||
WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Serializing unknown codec type!");
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aResult->mCodecType == kGMPVideoCodecVP8) {
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(false, "De-serializing unknown codec type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
const char* codecName = nullptr;
|
||||
if (aParam.mCodecType == kGMPVideoCodecVP8) {
|
||||
codecName = "VP8";
|
||||
}
|
||||
aLog->append(StringPrintf(L"[%s]", codecName));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // GMPMessageUtils_h_
|
|
@ -0,0 +1,424 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPParent.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsILineInputStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPParent::GMPParent()
|
||||
: mState(GMPStateNotLoaded)
|
||||
, mProcess(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
GMPParent::~GMPParent()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPParent::Init(nsIFile* aPluginDir)
|
||||
{
|
||||
MOZ_ASSERT(aPluginDir);
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
mDirectory = aPluginDir;
|
||||
|
||||
nsAutoString leafname;
|
||||
nsresult rv = aPluginDir->GetLeafName(leafname);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(leafname.Length() > 4);
|
||||
mName = Substring(leafname, 4);
|
||||
|
||||
return ReadGMPMetaData();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPParent::LoadProcess()
|
||||
{
|
||||
MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mState == GMPStateLoaded) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString path;
|
||||
if (NS_FAILED(mDirectory->GetNativePath(path))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mProcess = new GMPProcessParent(path.get());
|
||||
if (!mProcess->Launch(30 * 1000)) {
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool opened = Open(mProcess->GetChannel(), mProcess->GetChildProcessHandle());
|
||||
if (!opened) {
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mState = GMPStateLoaded;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GMPParent::MaybeUnloadProcess()
|
||||
{
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mVideoDecoders.Length() == 0 &&
|
||||
mVideoEncoders.Length() == 0) {
|
||||
UnloadProcess();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPParent::UnloadProcess()
|
||||
{
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mState == GMPStateNotLoaded) {
|
||||
MOZ_ASSERT(mVideoDecoders.IsEmpty() && mVideoEncoders.IsEmpty());
|
||||
return;
|
||||
}
|
||||
|
||||
mState = GMPStateNotLoaded;
|
||||
|
||||
// Invalidate and remove any remaining API objects.
|
||||
for (uint32_t i = mVideoDecoders.Length(); i > 0; i--) {
|
||||
mVideoDecoders[i - 1]->DecodingComplete();
|
||||
}
|
||||
|
||||
// Invalidate and remove any remaining API objects.
|
||||
for (uint32_t i = mVideoEncoders.Length(); i > 0; i--) {
|
||||
mVideoEncoders[i - 1]->EncodingComplete();
|
||||
}
|
||||
|
||||
Close();
|
||||
if (mProcess) {
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder)
|
||||
{
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
MOZ_ALWAYS_TRUE(mVideoDecoders.RemoveElement(aDecoder));
|
||||
|
||||
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
|
||||
// until after this has completed.
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::MaybeUnloadProcess);
|
||||
NS_DispatchToCurrentThread(event);
|
||||
}
|
||||
|
||||
void
|
||||
GMPParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder)
|
||||
{
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
MOZ_ALWAYS_TRUE(mVideoEncoders.RemoveElement(aEncoder));
|
||||
|
||||
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
|
||||
// until after this has completed.
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::MaybeUnloadProcess);
|
||||
NS_DispatchToCurrentThread(event);
|
||||
}
|
||||
|
||||
GMPState
|
||||
GMPParent::State() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsIThread*
|
||||
GMPParent::GMPThread()
|
||||
{
|
||||
if (!mGMPThread) {
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
MOZ_ASSERT(mps);
|
||||
if (!mps) {
|
||||
return nullptr;
|
||||
}
|
||||
mps->GetThread(getter_AddRefs(mGMPThread));
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
}
|
||||
|
||||
return mGMPThread;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
GMPParent::SupportsAPI(const nsCString& aAPI, const nsCString& aTag)
|
||||
{
|
||||
for (uint32_t i = 0; i < mCapabilities.Length(); i++) {
|
||||
if (!mCapabilities[i]->mAPIName.Equals(aAPI)) {
|
||||
continue;
|
||||
}
|
||||
nsTArray<nsCString>& tags = mCapabilities[i]->mAPITags;
|
||||
for (uint32_t j = 0; j < tags.Length(); j++) {
|
||||
if (tags[j].Equals(aTag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPParent::EnsureProcessLoaded()
|
||||
{
|
||||
if (mState == GMPStateLoaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult rv = LoadProcess();
|
||||
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD)
|
||||
{
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!EnsureProcessLoaded()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PGMPVideoDecoderParent* pvdp = SendPGMPVideoDecoderConstructor();
|
||||
if (!pvdp) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsRefPtr<GMPVideoDecoderParent> vdp = static_cast<GMPVideoDecoderParent*>(pvdp);
|
||||
mVideoDecoders.AppendElement(vdp);
|
||||
vdp.forget(aGMPVD);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPParent::GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE)
|
||||
{
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!EnsureProcessLoaded()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PGMPVideoEncoderParent* pvep = SendPGMPVideoEncoderConstructor();
|
||||
if (!pvep) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsRefPtr<GMPVideoEncoderParent> vep = static_cast<GMPVideoEncoderParent*>(pvep);
|
||||
mVideoEncoders.AppendElement(vep);
|
||||
vep.forget(aGMPVE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GMPParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
UnloadProcess();
|
||||
}
|
||||
|
||||
PGMPVideoDecoderParent*
|
||||
GMPParent::AllocPGMPVideoDecoderParent()
|
||||
{
|
||||
GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);
|
||||
NS_ADDREF(vdp);
|
||||
return vdp;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPParent::DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor)
|
||||
{
|
||||
GMPVideoDecoderParent* vdp = static_cast<GMPVideoDecoderParent*>(aActor);
|
||||
NS_RELEASE(vdp);
|
||||
return true;
|
||||
}
|
||||
|
||||
PGMPVideoEncoderParent*
|
||||
GMPParent::AllocPGMPVideoEncoderParent()
|
||||
{
|
||||
GMPVideoEncoderParent* vep = new GMPVideoEncoderParent(this);
|
||||
NS_ADDREF(vep);
|
||||
return vep;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPParent::DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor)
|
||||
{
|
||||
GMPVideoEncoderParent* vep = static_cast<GMPVideoEncoderParent*>(aActor);
|
||||
NS_RELEASE(vep);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ParseNextRecord(nsILineInputStream* aLineInputStream,
|
||||
const nsCString& aPrefix,
|
||||
nsCString& aResult,
|
||||
bool& aMoreLines)
|
||||
{
|
||||
nsAutoCString record;
|
||||
nsresult rv = aLineInputStream->ReadLine(record, &aMoreLines);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (record.Length() <= aPrefix.Length() ||
|
||||
!Substring(record, 0, aPrefix.Length()).Equals(aPrefix)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aResult = Substring(record, aPrefix.Length());
|
||||
aResult.Trim("\b\t\r\n ");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPParent::ReadGMPMetaData()
|
||||
{
|
||||
MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
|
||||
MOZ_ASSERT(!mName.IsEmpty(), "Plugin mName cannot be empty!");
|
||||
|
||||
nsCOMPtr<nsIFile> infoFile;
|
||||
nsresult rv = mDirectory->Clone(getter_AddRefs(infoFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
infoFile->AppendRelativePath(mName + NS_LITERAL_STRING(".info"));
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), infoFile);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(inputStream, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCString value;
|
||||
bool moreLines = false;
|
||||
|
||||
// 'Name:' record
|
||||
nsCString prefix = NS_LITERAL_CSTRING("Name:");
|
||||
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (value.IsEmpty()) {
|
||||
// Not OK for name to be empty. Must have one non-whitespace character.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mDisplayName = value;
|
||||
|
||||
// 'Description:' record
|
||||
if (!moreLines) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
prefix = NS_LITERAL_CSTRING("Description:");
|
||||
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
mDescription = value;
|
||||
|
||||
// 'Version:' record
|
||||
if (!moreLines) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
prefix = NS_LITERAL_CSTRING("Version:");
|
||||
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
mVersion = value;
|
||||
|
||||
// 'Capability:' record
|
||||
if (!moreLines) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
prefix = NS_LITERAL_CSTRING("APIs:");
|
||||
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
nsCCharSeparatedTokenizer apiTokens(value, ',');
|
||||
while (apiTokens.hasMoreTokens()) {
|
||||
nsAutoCString api(apiTokens.nextToken());
|
||||
api.StripWhitespace();
|
||||
if (api.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t tagsStart = api.FindChar('[');
|
||||
if (tagsStart == 0) {
|
||||
// Not allowed to be the first character.
|
||||
// API name must be at least one character.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto cap = new GMPCapability();
|
||||
if (tagsStart == -1) {
|
||||
// No tags.
|
||||
cap->mAPIName.Assign(api);
|
||||
} else {
|
||||
auto tagsEnd = api.FindChar(']');
|
||||
if (tagsEnd == -1 || tagsEnd < tagsStart) {
|
||||
// Invalid syntax, skip whole capability.
|
||||
delete cap;
|
||||
continue;
|
||||
}
|
||||
|
||||
cap->mAPIName.Assign(Substring(api, 0, tagsStart));
|
||||
|
||||
if ((tagsEnd - tagsStart) > 1) {
|
||||
const nsDependentCSubstring ts(Substring(api, tagsStart + 1, tagsEnd - tagsStart - 1));
|
||||
nsCCharSeparatedTokenizer tagTokens(ts, ':');
|
||||
while (tagTokens.hasMoreTokens()) {
|
||||
const nsDependentCSubstring tag(tagTokens.nextToken());
|
||||
cap->mAPITags.AppendElement(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mCapabilities.AppendElement(cap);
|
||||
}
|
||||
|
||||
if (mCapabilities.IsEmpty()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPParent_h_
|
||||
#define GMPParent_h_
|
||||
|
||||
#include "GMPProcessParent.h"
|
||||
#include "GMPVideoDecoderParent.h"
|
||||
#include "GMPVideoEncoderParent.h"
|
||||
#include "mozilla/gmp/PGMPParent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nscore.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsILineInputStream;
|
||||
class nsIThread;
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPCapability
|
||||
{
|
||||
public:
|
||||
nsCString mAPIName;
|
||||
nsTArray<nsCString> mAPITags;
|
||||
};
|
||||
|
||||
enum GMPState {
|
||||
GMPStateNotLoaded,
|
||||
GMPStateLoaded
|
||||
};
|
||||
|
||||
class GMPParent MOZ_FINAL : public PGMPParent
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GMPParent)
|
||||
|
||||
GMPParent();
|
||||
|
||||
nsresult Init(nsIFile* aPluginDir);
|
||||
nsresult LoadProcess();
|
||||
void MaybeUnloadProcess();
|
||||
void UnloadProcess();
|
||||
bool SupportsAPI(const nsCString& aAPI, const nsCString& aTag);
|
||||
nsresult GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD);
|
||||
void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
|
||||
nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
|
||||
void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
|
||||
GMPState State() const;
|
||||
#ifdef DEBUG
|
||||
nsIThread* GMPThread();
|
||||
#endif
|
||||
|
||||
private:
|
||||
~GMPParent();
|
||||
bool EnsureProcessLoaded();
|
||||
nsresult ReadGMPMetaData();
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
virtual PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() MOZ_OVERRIDE;
|
||||
virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) MOZ_OVERRIDE;
|
||||
virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() MOZ_OVERRIDE;
|
||||
virtual bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) MOZ_OVERRIDE;
|
||||
|
||||
GMPState mState;
|
||||
nsCOMPtr<nsIFile> mDirectory; // plugin directory on disk
|
||||
nsString mName; // base name of plugin on disk, UTF-16 because used for paths
|
||||
nsCString mDisplayName; // name of plugin displayed to users
|
||||
nsCString mDescription; // description of plugin for display to users
|
||||
nsCString mVersion;
|
||||
nsTArray<nsAutoPtr<GMPCapability>> mCapabilities;
|
||||
GMPProcessParent* mProcess;
|
||||
|
||||
nsTArray<nsRefPtr<GMPVideoDecoderParent>> mVideoDecoders;
|
||||
nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIThread> mGMPThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPParent_h_
|
|
@ -0,0 +1,216 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPPlatform.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
static MessageLoop* sMainLoop = nullptr;
|
||||
|
||||
// We just need a refcounted wrapper for GMPTask objects.
|
||||
class Runnable MOZ_FINAL
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Runnable)
|
||||
|
||||
Runnable(GMPTask* aTask)
|
||||
: mTask(aTask)
|
||||
{
|
||||
MOZ_ASSERT(mTask);
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
mTask->Run();
|
||||
mTask = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
~Runnable()
|
||||
{
|
||||
}
|
||||
|
||||
nsAutoPtr<GMPTask> mTask;
|
||||
};
|
||||
|
||||
class SyncRunnable MOZ_FINAL
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SyncRunnable)
|
||||
|
||||
SyncRunnable(GMPTask* aTask, MessageLoop* aMessageLoop)
|
||||
: mDone(false)
|
||||
, mTask(aTask)
|
||||
, mMessageLoop(aMessageLoop)
|
||||
, mMonitor("GMPSyncRunnable")
|
||||
{
|
||||
MOZ_ASSERT(mTask);
|
||||
MOZ_ASSERT(mMessageLoop);
|
||||
}
|
||||
|
||||
void Post()
|
||||
{
|
||||
// We assert here for two reasons.
|
||||
// 1) Nobody should be blocking the main thread.
|
||||
// 2) This prevents deadlocks when doing sync calls to main which if the
|
||||
// main thread tries to do a sync call back to the calling thread.
|
||||
MOZ_ASSERT(MessageLoop::current() != sMainLoop);
|
||||
|
||||
mMessageLoop->PostTask(FROM_HERE, NewRunnableMethod(this, &SyncRunnable::Run));
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (!mDone) {
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
mTask->Run();
|
||||
mTask = nullptr;
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mDone = true;
|
||||
lock.Notify();
|
||||
}
|
||||
|
||||
private:
|
||||
~SyncRunnable()
|
||||
{
|
||||
}
|
||||
|
||||
bool mDone;
|
||||
nsAutoPtr<GMPTask> mTask;
|
||||
MessageLoop* mMessageLoop;
|
||||
Monitor mMonitor;
|
||||
};
|
||||
|
||||
GMPErr
|
||||
CreateThread(GMPThread** aThread)
|
||||
{
|
||||
if (!aThread) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
*aThread = new GMPThreadImpl();
|
||||
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPErr
|
||||
RunOnMainThread(GMPTask* aTask)
|
||||
{
|
||||
if (!aTask || !sMainLoop) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
nsRefPtr<Runnable> r = new Runnable(aTask);
|
||||
|
||||
sMainLoop->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run));
|
||||
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPErr
|
||||
SyncRunOnMainThread(GMPTask* aTask)
|
||||
{
|
||||
if (!aTask || !sMainLoop || sMainLoop == MessageLoop::current()) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
nsRefPtr<SyncRunnable> r = new SyncRunnable(aTask, sMainLoop);
|
||||
|
||||
r->Post();
|
||||
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPErr
|
||||
CreateMutex(GMPMutex** aMutex)
|
||||
{
|
||||
if (!aMutex) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
*aMutex = new GMPMutexImpl();
|
||||
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
|
||||
{
|
||||
if (!sMainLoop) {
|
||||
sMainLoop = MessageLoop::current();
|
||||
}
|
||||
|
||||
aPlatformAPI.version = 0;
|
||||
aPlatformAPI.createthread = &CreateThread;
|
||||
aPlatformAPI.runonmainthread = &RunOnMainThread;
|
||||
aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
|
||||
aPlatformAPI.createmutex = &CreateMutex;
|
||||
}
|
||||
|
||||
GMPThreadImpl::GMPThreadImpl()
|
||||
: mMutex("GMPThreadImpl"),
|
||||
mThread("GMPThread")
|
||||
{
|
||||
}
|
||||
|
||||
GMPThreadImpl::~GMPThreadImpl()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GMPThreadImpl::Post(GMPTask* aTask)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mThread.IsRunning()) {
|
||||
bool started = mThread.Start();
|
||||
if (!started) {
|
||||
NS_WARNING("Unable to start GMPThread!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Runnable> r = new Runnable(aTask);
|
||||
|
||||
mThread.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run));
|
||||
}
|
||||
|
||||
void
|
||||
GMPThreadImpl::Join()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mThread.IsRunning()) {
|
||||
mThread.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
GMPMutexImpl::GMPMutexImpl()
|
||||
: mMutex("gmp-mutex")
|
||||
{
|
||||
}
|
||||
|
||||
GMPMutexImpl::~GMPMutexImpl()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GMPMutexImpl::Acquire()
|
||||
{
|
||||
mMutex.Lock();
|
||||
}
|
||||
|
||||
void
|
||||
GMPMutexImpl::Release()
|
||||
{
|
||||
mMutex.Unlock();
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPPlatform_h_
|
||||
#define GMPPlatform_h_
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "gmp-platform.h"
|
||||
#include "base/thread.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI);
|
||||
|
||||
class GMPThreadImpl : public GMPThread
|
||||
{
|
||||
public:
|
||||
GMPThreadImpl();
|
||||
virtual ~GMPThreadImpl();
|
||||
|
||||
// GMPThread
|
||||
virtual void Post(GMPTask* aTask) MOZ_OVERRIDE;
|
||||
virtual void Join() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
Mutex mMutex;
|
||||
base::Thread mThread;
|
||||
};
|
||||
|
||||
class GMPMutexImpl : public GMPMutex
|
||||
{
|
||||
public:
|
||||
GMPMutexImpl();
|
||||
virtual ~GMPMutexImpl();
|
||||
|
||||
// GMPMutex
|
||||
virtual void Acquire() MOZ_OVERRIDE;
|
||||
virtual void Release() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
Mutex mMutex;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPPlatform_h_
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPProcessChild.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/string_util.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "mozilla/ipc/IOThreadChild.h"
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
|
||||
using mozilla::ipc::IOThreadChild;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPProcessChild::GMPProcessChild(ProcessHandle parentHandle)
|
||||
: ProcessChild(parentHandle)
|
||||
{
|
||||
}
|
||||
|
||||
GMPProcessChild::~GMPProcessChild()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
GMPProcessChild::Init()
|
||||
{
|
||||
std::string pluginFilename;
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// NB: need to be very careful in ensuring that the first arg
|
||||
// (after the binary name) here is indeed the plugin module path.
|
||||
// Keep in sync with dom/plugins/PluginModuleParent.
|
||||
std::vector<std::string> values = CommandLine::ForCurrentProcess()->argv();
|
||||
NS_ABORT_IF_FALSE(values.size() >= 2, "not enough args");
|
||||
pluginFilename = values[1];
|
||||
#elif defined(OS_WIN)
|
||||
std::vector<std::wstring> values = CommandLine::ForCurrentProcess()->GetLooseValues();
|
||||
NS_ABORT_IF_FALSE(values.size() >= 1, "not enough loose args");
|
||||
pluginFilename = WideToUTF8(values[0]);
|
||||
#else
|
||||
#error Not implemented
|
||||
#endif
|
||||
|
||||
BackgroundHangMonitor::Startup();
|
||||
|
||||
return mPlugin.Init(pluginFilename,
|
||||
ParentHandle(),
|
||||
IOThreadChild::message_loop(),
|
||||
IOThreadChild::channel());
|
||||
}
|
||||
|
||||
void
|
||||
GMPProcessChild::CleanUp()
|
||||
{
|
||||
BackgroundHangMonitor::Shutdown();
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPProcessChild_h_
|
||||
#define GMPProcessChild_h_
|
||||
|
||||
#include "mozilla/ipc/ProcessChild.h"
|
||||
#include "GMPChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPProcessChild MOZ_FINAL : public mozilla::ipc::ProcessChild {
|
||||
protected:
|
||||
typedef mozilla::ipc::ProcessChild ProcessChild;
|
||||
|
||||
public:
|
||||
GMPProcessChild(ProcessHandle parentHandle);
|
||||
~GMPProcessChild();
|
||||
|
||||
virtual bool Init() MOZ_OVERRIDE;
|
||||
virtual void CleanUp() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
GMPChild mPlugin;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GMPProcessChild);
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPProcessChild_h_
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: sw=4 ts=4 et :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPProcessParent.h"
|
||||
|
||||
#include "base/string_util.h"
|
||||
#include "base/process_util.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
using mozilla::gmp::GMPProcessParent;
|
||||
using mozilla::ipc::GeckoChildProcessHost;
|
||||
using base::ProcessArchitecture;
|
||||
|
||||
template<>
|
||||
struct RunnableMethodTraits<GMPProcessParent>
|
||||
{
|
||||
static void RetainCallee(GMPProcessParent* obj) { }
|
||||
static void ReleaseCallee(GMPProcessParent* obj) { }
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPProcessParent::GMPProcessParent(const std::string& aGMPPath)
|
||||
: GeckoChildProcessHost(GeckoProcessType_GMPlugin),
|
||||
mGMPPath(aGMPPath)
|
||||
{
|
||||
}
|
||||
|
||||
GMPProcessParent::~GMPProcessParent()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
GMPProcessParent::Launch(int32_t aTimeoutMs)
|
||||
{
|
||||
vector<string> args;
|
||||
args.push_back(mGMPPath);
|
||||
return SyncLaunch(args, aTimeoutMs, base::GetCurrentProcessArchitecture());
|
||||
}
|
||||
|
||||
void
|
||||
GMPProcessParent::Delete()
|
||||
{
|
||||
MessageLoop* currentLoop = MessageLoop::current();
|
||||
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
|
||||
|
||||
if (currentLoop == ioLoop) {
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
ioLoop->PostTask(FROM_HERE, NewRunnableMethod(this, &GMPProcessParent::Delete));
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: sw=4 ts=4 et :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPProcessParent_h
|
||||
#define GMPProcessParent_h 1
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/file_path.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/waitable_event.h"
|
||||
#include "chrome/common/child_process_host.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPProcessParent MOZ_FINAL : public mozilla::ipc::GeckoChildProcessHost
|
||||
{
|
||||
public:
|
||||
GMPProcessParent(const std::string& aGMPPath);
|
||||
~GMPProcessParent();
|
||||
|
||||
// Synchronously launch the plugin process. If the process fails to launch
|
||||
// after timeoutMs, this method will return false.
|
||||
bool Launch(int32_t aTimeoutMs);
|
||||
|
||||
void Delete();
|
||||
|
||||
virtual bool CanShutdown() MOZ_OVERRIDE { return true; }
|
||||
const std::string& GetPluginFilePath() { return mGMPPath; }
|
||||
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetShutDownEvent;
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetChannel;
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetChildProcessHandle;
|
||||
|
||||
private:
|
||||
std::string mGMPPath;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GMPProcessParent);
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ifndef GMPProcessParent_h
|
|
@ -0,0 +1,485 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPService.h"
|
||||
#include "GMPParent.h"
|
||||
#include "GMPVideoDecoderParent.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "GeckoChildProcessHost.h"
|
||||
#if defined(XP_WIN)
|
||||
#include "nsIWindowsRegKey.h"
|
||||
#endif
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsXPCOMPrivate.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
static StaticRefPtr<GeckoMediaPluginService> sSingletonService;
|
||||
|
||||
class GMPServiceCreateHelper MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> mService;
|
||||
|
||||
public:
|
||||
static already_AddRefed<GeckoMediaPluginService>
|
||||
GetOrCreate()
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> service;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
service = GetOrCreateOnMainThread();
|
||||
} else {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
MOZ_ASSERT(mainThread);
|
||||
|
||||
nsRefPtr<GMPServiceCreateHelper> createHelper = new GMPServiceCreateHelper();
|
||||
|
||||
mozilla::SyncRunnable::DispatchToThread(mainThread, createHelper, true);
|
||||
|
||||
service = createHelper->mService.forget();
|
||||
}
|
||||
|
||||
return service.forget();
|
||||
}
|
||||
|
||||
private:
|
||||
GMPServiceCreateHelper()
|
||||
{
|
||||
}
|
||||
|
||||
~GMPServiceCreateHelper()
|
||||
{
|
||||
MOZ_ASSERT(!mService);
|
||||
}
|
||||
|
||||
static already_AddRefed<GeckoMediaPluginService>
|
||||
GetOrCreateOnMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<GeckoMediaPluginService> service = sSingletonService.get();
|
||||
if (!service) {
|
||||
service = new GeckoMediaPluginService();
|
||||
service->Init();
|
||||
|
||||
sSingletonService = service;
|
||||
ClearOnShutdown(&sSingletonService);
|
||||
}
|
||||
|
||||
return service.forget();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mService = GetOrCreateOnMainThread();
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
already_AddRefed<GeckoMediaPluginService>
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService()
|
||||
{
|
||||
return GMPServiceCreateHelper::GetOrCreate();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(GeckoMediaPluginService, mozIGeckoMediaPluginService, nsIObserver)
|
||||
|
||||
GeckoMediaPluginService::GeckoMediaPluginService()
|
||||
: mMutex("GeckoMediaPluginService::mMutex")
|
||||
, mShuttingDown(false)
|
||||
, mShuttingDownOnGMPThread(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
GeckoMediaPluginService::~GeckoMediaPluginService()
|
||||
{
|
||||
MOZ_ASSERT(mPlugins.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Cache user directory while we're on the main thread. We do this because
|
||||
// if we try to use "~" in a path during plugin lookup on a non-main thread,
|
||||
// the nsIFile code will try to resolve it using NS_GetSpecialDirectory, which
|
||||
// doesn't work on non-main threads.
|
||||
nsCOMPtr<nsIFile> homeDir;
|
||||
NS_GetSpecialDirectory(NS_OS_HOME_DIR, getter_AddRefs(homeDir));
|
||||
if (homeDir) {
|
||||
homeDir->GetPath(mHomePath);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
|
||||
MOZ_ASSERT(obsService);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aSomeData)
|
||||
{
|
||||
if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
|
||||
nsCOMPtr<nsIThread> gmpThread;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(!mShuttingDown);
|
||||
mShuttingDown = true;
|
||||
gmpThread = mGMPThread;
|
||||
}
|
||||
|
||||
if (gmpThread) {
|
||||
gmpThread->Dispatch(NS_NewRunnableMethod(this, &GeckoMediaPluginService::UnloadPlugins),
|
||||
NS_DISPATCH_SYNC);
|
||||
} else {
|
||||
MOZ_ASSERT(mPlugins.IsEmpty());
|
||||
}
|
||||
} else if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
|
||||
nsCOMPtr<nsIThread> gmpThread;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(mShuttingDown);
|
||||
mGMPThread.swap(gmpThread);
|
||||
}
|
||||
|
||||
if (gmpThread) {
|
||||
gmpThread->Shutdown();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetThread(nsIThread** aThread)
|
||||
{
|
||||
MOZ_ASSERT(aThread);
|
||||
|
||||
// This can be called from any thread.
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mGMPThread) {
|
||||
// Don't allow the thread to be created after shutdown has started.
|
||||
if (mShuttingDown) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = NS_NewNamedThread("GMPThread", getter_AddRefs(mGMPThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ADDREF(mGMPThread);
|
||||
*aThread = mGMPThread;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoDecoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoDecoder** aGMPVD)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
if (mShuttingDownOnGMPThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("decode-video"),
|
||||
NS_LITERAL_CSTRING("vp8"));
|
||||
if (!gmp) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GMPVideoDecoderParent* gmpVDP;
|
||||
nsresult rv = gmp->GetGMPVideoDecoder(&gmpVDP);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aGMPVD = gmpVDP;
|
||||
*aOutVideoHost = &gmpVDP->Host();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoEncoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoEncoder** aGMPVE)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
if (mShuttingDownOnGMPThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("encode-video"),
|
||||
NS_LITERAL_CSTRING("vp8"));
|
||||
if (!gmp) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GMPVideoEncoderParent* gmpVEP;
|
||||
nsresult rv = gmp->GetGMPVideoEncoder(&gmpVEP);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aGMPVE = gmpVEP;
|
||||
*aOutVideoHost = &gmpVEP->Host();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::UnloadPlugins()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
MOZ_ASSERT(!mShuttingDownOnGMPThread);
|
||||
mShuttingDownOnGMPThread = true;
|
||||
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
||||
mPlugins[i]->UnloadProcess();
|
||||
}
|
||||
mPlugins.Clear();
|
||||
}
|
||||
|
||||
GMPParent*
|
||||
GeckoMediaPluginService::SelectPluginForAPI(const nsCString& aAPI,
|
||||
const nsCString& aTag)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
GMPParent* gmp = SelectPluginFromListForAPI(aAPI, aTag);
|
||||
if (gmp) {
|
||||
return gmp;
|
||||
}
|
||||
|
||||
RefreshPluginList();
|
||||
|
||||
return SelectPluginFromListForAPI(aAPI, aTag);
|
||||
}
|
||||
|
||||
GMPParent*
|
||||
GeckoMediaPluginService::SelectPluginFromListForAPI(const nsCString& aAPI,
|
||||
const nsCString& aTag)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
||||
GMPParent* gmp = mPlugins[i];
|
||||
if (gmp->SupportsAPI(aAPI, aTag)) {
|
||||
return gmp;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GeckoMediaPluginService::GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>> &aDirs)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
nsCOMPtr<nsIFile> searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
|
||||
MOZ_ASSERT(!mHomePath.IsEmpty());
|
||||
nsresult rv = searchDir->InitWithPath(mHomePath + NS_LITERAL_STRING("/Library/Internet Plug-Ins/"));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
aDirs.AppendElement(searchDir);
|
||||
searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
|
||||
rv = searchDir->InitWithPath(NS_LITERAL_STRING("/Library/Internet Plug-Ins/"));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
aDirs.AppendElement(searchDir);
|
||||
#elif defined(OS_POSIX)
|
||||
nsCOMPtr<nsIFile> searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
|
||||
nsresult rv = searchDir->InitWithPath(NS_LITERAL_STRING("/usr/lib/mozilla/plugins/"));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
aDirs.AppendElement(searchDir);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
static nsresult
|
||||
GetPossiblePluginsForRegRoot(uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs)
|
||||
{
|
||||
nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
|
||||
if (!regKey) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = regKey->Open(aKey,
|
||||
NS_LITERAL_STRING("Software\\MozillaPlugins"),
|
||||
nsIWindowsRegKey::ACCESS_READ);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t childCount = 0;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(regKey->GetChildCount(&childCount)));
|
||||
for (uint32_t index = 0; index < childCount; index++) {
|
||||
nsAutoString childName;
|
||||
rv = regKey->GetChildName(index, childName);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWindowsRegKey> childKey;
|
||||
rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE,
|
||||
getter_AddRefs(childKey));
|
||||
if (NS_FAILED(rv) || !childKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString path;
|
||||
rv = childKey->ReadStringValue(NS_LITERAL_STRING("Path"), path);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
if (NS_SUCCEEDED(NS_NewLocalFile(path, true, getter_AddRefs(localFile))) &&
|
||||
localFile) {
|
||||
bool isFileThere = false;
|
||||
if (NS_SUCCEEDED(localFile->Exists(&isFileThere)) && isFileThere) {
|
||||
aDirs.AppendElement(localFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
regKey->Close();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
GeckoMediaPluginService::GetPossiblePlugins(nsTArray<nsCOMPtr<nsIFile>>& aDirs)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// The ROOT_KEY_CURRENT_USER entry typically fails to open, causing this call to
|
||||
// fail. Don't check any return values because if we find nothing we don't care.
|
||||
GetPossiblePluginsForRegRoot(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, aDirs);
|
||||
GetPossiblePluginsForRegRoot(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, aDirs);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GeckoMediaPluginService::SearchDirectory(nsIFile* aSearchDir)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
MOZ_ASSERT(aSearchDir);
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
nsresult rv = aSearchDir->GetDirectoryEntries(getter_AddRefs(iter));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool hasMore;
|
||||
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
rv = iter->GetNext(getter_AddRefs(supports));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
ProcessPossiblePlugin(dirEntry);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::ProcessPossiblePlugin(nsIFile* aDir)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
MOZ_ASSERT(aDir);
|
||||
|
||||
bool isDirectory = false;
|
||||
nsresult rv = aDir->IsDirectory(&isDirectory);
|
||||
if (NS_FAILED(rv) || !isDirectory) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString leafName;
|
||||
rv = aDir->GetLeafName(leafName);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(prefix, "gmp-");
|
||||
if (leafName.Length() <= prefix.Length() ||
|
||||
!Substring(leafName, 0, prefix.Length()).Equals(prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = new GMPParent();
|
||||
rv = gmp->Init(aDir);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPlugins.AppendElement(gmp);
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::RefreshPluginList()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
for (uint32_t iPlusOne = mPlugins.Length(); iPlusOne > 0; iPlusOne--) {
|
||||
if (mPlugins[iPlusOne - 1]->State() == GMPStateNotLoaded) {
|
||||
mPlugins.RemoveElementAt(iPlusOne - 1);
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<nsCOMPtr<nsIFile>> searchDirs;
|
||||
nsresult rv = GetDirectoriesToSearch(searchDirs);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < searchDirs.Length(); i++) {
|
||||
SearchDirectory(searchDirs[i]);
|
||||
}
|
||||
|
||||
nsTArray<nsCOMPtr<nsIFile>> possiblePlugins;
|
||||
rv = GetPossiblePlugins(possiblePlugins);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < possiblePlugins.Length(); i++) {
|
||||
ProcessPossiblePlugin(possiblePlugins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPService_h_
|
||||
#define GMPService_h_
|
||||
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIThread.h"
|
||||
|
||||
class nsIFile;
|
||||
template <class> class already_AddRefed;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPParent;
|
||||
|
||||
class GeckoMediaPluginService MOZ_FINAL : public mozIGeckoMediaPluginService
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
|
||||
|
||||
GeckoMediaPluginService();
|
||||
void Init();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZIGECKOMEDIAPLUGINSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
private:
|
||||
~GeckoMediaPluginService();
|
||||
|
||||
GMPParent* SelectPluginFromListForAPI(const nsCString& aAPI, const nsCString& aTag);
|
||||
GMPParent* SelectPluginForAPI(const nsCString& aAPI, const nsCString& aTag);
|
||||
void UnloadPlugins();
|
||||
|
||||
void RefreshPluginList();
|
||||
void ProcessPossiblePlugin(nsIFile* aDir);
|
||||
nsresult SearchDirectory(nsIFile* aSearchDir);
|
||||
nsresult GetPossiblePlugins(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
|
||||
nsresult GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
|
||||
|
||||
nsTArray<nsRefPtr<GMPParent>> mPlugins;
|
||||
Mutex mMutex; // Protects mGMPThread and mShuttingDown
|
||||
nsCOMPtr<nsIThread> mGMPThread;
|
||||
bool mShuttingDown;
|
||||
bool mShuttingDownOnGMPThread;
|
||||
nsString mHomePath;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPService_h_
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPSharedMemManager_h_
|
||||
#define GMPSharedMemManager_h_
|
||||
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) = 0;
|
||||
virtual bool MgrDeallocShmem(ipc::Shmem& aMem) = 0;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPSharedMemManager_h_
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
struct GMPVideoEncodedFrameData
|
||||
{
|
||||
int64_t mCaptureTime_ms;
|
||||
uint32_t mEncodedWidth;
|
||||
uint32_t mEncodedHeight;
|
||||
uint32_t mTimeStamp;
|
||||
uint32_t mFrameType;
|
||||
uint32_t mSize;
|
||||
Shmem mBuffer;
|
||||
bool mCompleteFrame;
|
||||
};
|
||||
|
||||
struct GMPPlaneData
|
||||
{
|
||||
int32_t mSize;
|
||||
int32_t mStride;
|
||||
Shmem mBuffer;
|
||||
};
|
||||
|
||||
struct GMPVideoi420FrameData
|
||||
{
|
||||
GMPPlaneData mYPlane;
|
||||
GMPPlaneData mUPlane;
|
||||
GMPPlaneData mVPlane;
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
uint32_t mTimestamp;
|
||||
int64_t mRenderTime_ms;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoDecoderChild.h"
|
||||
#include "GMPVideoi420FrameImpl.h"
|
||||
#include "GMPChild.h"
|
||||
#include <stdio.h>
|
||||
#include "mozilla/unused.h"
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPVideoDecoderChild::GMPVideoDecoderChild(GMPChild* aPlugin)
|
||||
: mPlugin(aPlugin),
|
||||
mVideoDecoder(nullptr),
|
||||
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
}
|
||||
|
||||
GMPVideoDecoderChild::~GMPVideoDecoderChild()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderChild::Init(GMPVideoDecoder* aDecoder)
|
||||
{
|
||||
MOZ_ASSERT(aDecoder, "Cannot initialize video decoder child without a video decoder!");
|
||||
mVideoDecoder = aDecoder;
|
||||
}
|
||||
|
||||
GMPVideoHostImpl&
|
||||
GMPVideoDecoderChild::Host()
|
||||
{
|
||||
return mVideoHost;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderChild::Decoded(GMPVideoi420Frame* aDecodedFrame)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
if (!aDecodedFrame) {
|
||||
MOZ_CRASH("Not given a decoded frame!");
|
||||
}
|
||||
|
||||
auto df = static_cast<GMPVideoi420FrameImpl*>(aDecodedFrame);
|
||||
|
||||
GMPVideoi420FrameData frameData;
|
||||
df->InitFrameData(frameData);
|
||||
SendDecoded(frameData);
|
||||
|
||||
aDecodedFrame->Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderChild::ReceivedDecodedReferenceFrame(const uint64_t aPictureId)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
SendReceivedDecodedReferenceFrame(aPictureId);
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderChild::ReceivedDecodedFrame(const uint64_t aPictureId)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
SendReceivedDecodedFrame(aPictureId);
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderChild::InputDataExhausted()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
SendInputDataExhausted();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::MgrDeallocShmem(Shmem& aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
const int32_t& aCoreCount)
|
||||
{
|
||||
if (!mVideoDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoDecoder->InitDecode(aCodecSettings, this, aCoreCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
|
||||
const bool& aMissingFrames,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const int64_t& aRenderTimeMs)
|
||||
{
|
||||
if (!mVideoDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto f = new GMPVideoEncodedFrameImpl(aInputFrame, &mVideoHost);
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoDecoder->Decode(f, aMissingFrames, aCodecSpecificInfo, aRenderTimeMs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvReset()
|
||||
{
|
||||
if (!mVideoDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoDecoder->Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvDrain()
|
||||
{
|
||||
if (!mVideoDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoDecoder->Drain();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderChild::RecvDecodingComplete()
|
||||
{
|
||||
if (mVideoDecoder) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoDecoder->DecodingComplete();
|
||||
mVideoDecoder = nullptr;
|
||||
}
|
||||
|
||||
mVideoHost.DoneWithAPI();
|
||||
|
||||
mPlugin = nullptr;
|
||||
|
||||
unused << Send__delete__(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPVideoDecoderChild_h_
|
||||
#define GMPVideoDecoderChild_h_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "mozilla/gmp/PGMPVideoDecoderChild.h"
|
||||
#include "gmp-video-decode.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "GMPVideoHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPChild;
|
||||
|
||||
class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
|
||||
public GMPDecoderCallback,
|
||||
public GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
GMPVideoDecoderChild(GMPChild* aPlugin);
|
||||
virtual ~GMPVideoDecoderChild();
|
||||
|
||||
void Init(GMPVideoDecoder* aDecoder);
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPDecoderCallback
|
||||
virtual void Decoded(GMPVideoi420Frame* decodedFrame) MOZ_OVERRIDE;
|
||||
virtual void ReceivedDecodedReferenceFrame(const uint64_t pictureId) MOZ_OVERRIDE;
|
||||
virtual void ReceivedDecodedFrame(const uint64_t pictureId) MOZ_OVERRIDE;
|
||||
virtual void InputDataExhausted() MOZ_OVERRIDE;
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// PGMPVideoDecoderChild
|
||||
virtual bool RecvInitDecode(const GMPVideoCodec& codecSettings,
|
||||
const int32_t& coreCount) MOZ_OVERRIDE;
|
||||
virtual bool RecvDecode(const GMPVideoEncodedFrameData& inputFrame,
|
||||
const bool& missingFrames,
|
||||
const GMPCodecSpecificInfo& codecSpecificInfo,
|
||||
const int64_t& renderTimeMs) MOZ_OVERRIDE;
|
||||
virtual bool RecvReset() MOZ_OVERRIDE;
|
||||
virtual bool RecvDrain() MOZ_OVERRIDE;
|
||||
virtual bool RecvDecodingComplete() MOZ_OVERRIDE;
|
||||
|
||||
GMPChild* mPlugin;
|
||||
GMPVideoDecoder* mVideoDecoder;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoDecoderChild_h_
|
|
@ -0,0 +1,256 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoDecoderParent.h"
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
#include "GMPVideoi420FrameImpl.h"
|
||||
#include "GMPParent.h"
|
||||
#include <stdio.h>
|
||||
#include "mozilla/unused.h"
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<GMPVideoEncodedFrame> : public nsPointerRefTraits<GMPVideoEncodedFrame>
|
||||
{
|
||||
public:
|
||||
static void Release(GMPVideoEncodedFrame* aFrame) { aFrame->Destroy(); }
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPVideoDecoderParent::GMPVideoDecoderParent(GMPParent* aPlugin)
|
||||
: mCanSendMessages(true)
|
||||
, mPlugin(aPlugin)
|
||||
, mCallback(nullptr)
|
||||
, mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
}
|
||||
|
||||
GMPVideoDecoderParent::~GMPVideoDecoderParent()
|
||||
{
|
||||
}
|
||||
|
||||
GMPVideoHostImpl&
|
||||
GMPVideoDecoderParent::Host()
|
||||
{
|
||||
return mVideoHost;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::MgrDeallocShmem(Shmem& aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoDecoderParent::InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPDecoderCallback* aCallback,
|
||||
int32_t aCoreCount)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!aCallback) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
mCallback = aCallback;
|
||||
|
||||
if (!SendInitDecode(aCodecSettings, aCoreCount)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoDecoderParent::Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs)
|
||||
{
|
||||
nsAutoRef<GMPVideoEncodedFrame> autoDestroy(aInputFrame);
|
||||
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
auto inputFrameImpl = static_cast<GMPVideoEncodedFrameImpl*>(aInputFrame);
|
||||
|
||||
GMPVideoEncodedFrameData frameData;
|
||||
inputFrameImpl->RelinquishFrameData(frameData);
|
||||
|
||||
if (!SendDecode(frameData,
|
||||
aMissingFrames,
|
||||
aCodecSpecificInfo,
|
||||
aRenderTimeMs)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoDecoderParent::Reset()
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendReset()) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoDecoderParent::Drain()
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendDrain()) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
|
||||
void
|
||||
GMPVideoDecoderParent::DecodingComplete()
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video decoder!");
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
mCanSendMessages = false;
|
||||
|
||||
mCallback = nullptr;
|
||||
|
||||
mVideoHost.DoneWithAPI();
|
||||
|
||||
unused << SendDecodingComplete();
|
||||
}
|
||||
|
||||
// Note: Keep this sync'd up with DecodingComplete
|
||||
void
|
||||
GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
if (mPlugin) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mPlugin->VideoDecoderDestroyed(this);
|
||||
mPlugin = nullptr;
|
||||
}
|
||||
mCanSendMessages = false;
|
||||
mCallback = nullptr;
|
||||
mVideoHost.ActorDestroyed();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame)
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto f = new GMPVideoi420FrameImpl(aDecodedFrame, &mVideoHost);
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->Decoded(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId)
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->ReceivedDecodedReferenceFrame(aPictureId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvReceivedDecodedFrame(const uint64_t& aPictureId)
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->ReceivedDecodedFrame(aPictureId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::RecvInputDataExhausted()
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->InputDataExhausted();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoDecoderParent::Recv__delete__()
|
||||
{
|
||||
if (mPlugin) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mPlugin->VideoDecoderDestroyed(this);
|
||||
mPlugin = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPVideoDecoderParent_h_
|
||||
#define GMPVideoDecoderParent_h_
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "gmp-video-decode.h"
|
||||
#include "mozilla/gmp/PGMPVideoDecoderParent.h"
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "GMPVideoHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPParent;
|
||||
|
||||
class GMPVideoDecoderParent MOZ_FINAL : public GMPVideoDecoder
|
||||
, public PGMPVideoDecoderParent
|
||||
, public GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GMPVideoDecoderParent)
|
||||
|
||||
GMPVideoDecoderParent(GMPParent *aPlugin);
|
||||
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoDecoder
|
||||
virtual GMPVideoErr InitDecode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPDecoderCallback* aCallback,
|
||||
int32_t aCoreCount) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Decode(GMPVideoEncodedFrame* aInputFrame,
|
||||
bool aMissingFrames,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs = -1) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Reset() MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Drain() MOZ_OVERRIDE;
|
||||
virtual void DecodingComplete() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
~GMPVideoDecoderParent();
|
||||
|
||||
// PGMPVideoDecoderParent
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
virtual bool RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame) MOZ_OVERRIDE;
|
||||
virtual bool RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
|
||||
virtual bool RecvReceivedDecodedFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
|
||||
virtual bool RecvInputDataExhausted() MOZ_OVERRIDE;
|
||||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mCanSendMessages;
|
||||
GMPParent* mPlugin;
|
||||
GMPDecoderCallback* mCallback;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoDecoderParent_h_
|
|
@ -0,0 +1,286 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost)
|
||||
: mEncodedWidth(0),
|
||||
mEncodedHeight(0),
|
||||
mTimeStamp(0),
|
||||
mCaptureTime_ms(0),
|
||||
mFrameType(kGMPDeltaFrame),
|
||||
mSize(0),
|
||||
mCompleteFrame(false),
|
||||
mHost(aHost)
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
aHost->EncodedFrameCreated(this);
|
||||
}
|
||||
|
||||
GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData,
|
||||
GMPVideoHostImpl* aHost)
|
||||
: mEncodedWidth(aFrameData.mEncodedWidth()),
|
||||
mEncodedHeight(aFrameData.mEncodedHeight()),
|
||||
mTimeStamp(aFrameData.mTimeStamp()),
|
||||
mCaptureTime_ms(aFrameData.mCaptureTime_ms()),
|
||||
mFrameType(static_cast<GMPVideoFrameType>(aFrameData.mFrameType())),
|
||||
mSize(aFrameData.mSize()),
|
||||
mCompleteFrame(aFrameData.mCompleteFrame()),
|
||||
mHost(aHost),
|
||||
mBuffer(aFrameData.mBuffer())
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
aHost->EncodedFrameCreated(this);
|
||||
}
|
||||
|
||||
GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
|
||||
{
|
||||
DestroyBuffer();
|
||||
if (mHost) {
|
||||
mHost->EncodedFrameDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
GMPVideoFrameFormat
|
||||
GMPVideoEncodedFrameImpl::GetFrameFormat()
|
||||
{
|
||||
return kGMPEncodedVideoFrame;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::DoneWithAPI()
|
||||
{
|
||||
DestroyBuffer();
|
||||
|
||||
// Do this after destroying the buffer because destruction
|
||||
// involves deallocation, which requires a host.
|
||||
mHost = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::ActorDestroyed()
|
||||
{
|
||||
// Simply clear out Shmem reference, do not attempt to
|
||||
// properly free it. It has already been freed.
|
||||
mBuffer = ipc::Shmem();
|
||||
// No more host.
|
||||
mHost = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncodedFrameImpl::RelinquishFrameData(GMPVideoEncodedFrameData& aFrameData)
|
||||
{
|
||||
aFrameData.mEncodedWidth() = mEncodedWidth;
|
||||
aFrameData.mEncodedHeight() = mEncodedHeight;
|
||||
aFrameData.mTimeStamp() = mTimeStamp;
|
||||
aFrameData.mCaptureTime_ms() = mCaptureTime_ms;
|
||||
aFrameData.mFrameType() = mFrameType;
|
||||
aFrameData.mSize() = mSize;
|
||||
aFrameData.mCompleteFrame() = mCompleteFrame;
|
||||
aFrameData.mBuffer() = mBuffer;
|
||||
|
||||
// This method is called right before Shmem is sent to another process.
|
||||
// We need to effectively zero out our member copy so that we don't
|
||||
// try to delete Shmem we don't own later.
|
||||
mBuffer = ipc::Shmem();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::DestroyBuffer()
|
||||
{
|
||||
if (mHost && mBuffer.IsWritable()) {
|
||||
mHost->SharedMemMgr()->MgrDeallocShmem(mBuffer);
|
||||
}
|
||||
mBuffer = ipc::Shmem();
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoEncodedFrameImpl::CreateEmptyFrame(uint32_t aSize)
|
||||
{
|
||||
DestroyBuffer();
|
||||
|
||||
if (aSize != 0) {
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(aSize, ipc::SharedMemory::TYPE_BASIC, &mBuffer) ||
|
||||
!Buffer()) {
|
||||
return GMPVideoAllocErr;
|
||||
}
|
||||
}
|
||||
|
||||
mSize = aSize;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoEncodedFrameImpl::CopyFrame(const GMPVideoEncodedFrame& aFrame)
|
||||
{
|
||||
auto& f = static_cast<const GMPVideoEncodedFrameImpl&>(aFrame);
|
||||
|
||||
if (f.mSize != 0) {
|
||||
GMPVideoErr err = CreateEmptyFrame(f.mSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
memcpy(Buffer(), f.Buffer(), f.mSize);
|
||||
}
|
||||
mEncodedWidth = f.mEncodedWidth;
|
||||
mEncodedHeight = f.mEncodedHeight;
|
||||
mTimeStamp = f.mTimeStamp;
|
||||
mCaptureTime_ms = f.mCaptureTime_ms;
|
||||
mFrameType = f.mFrameType;
|
||||
mSize = f.mSize;
|
||||
mCompleteFrame = f.mCompleteFrame;
|
||||
// Don't copy host, that should have been set properly on object creation via host.
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetEncodedWidth(uint32_t aEncodedWidth)
|
||||
{
|
||||
mEncodedWidth = aEncodedWidth;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPVideoEncodedFrameImpl::EncodedWidth()
|
||||
{
|
||||
return mEncodedWidth;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetEncodedHeight(uint32_t aEncodedHeight)
|
||||
{
|
||||
mEncodedHeight = aEncodedHeight;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPVideoEncodedFrameImpl::EncodedHeight()
|
||||
{
|
||||
return mEncodedHeight;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetTimeStamp(uint32_t aTimeStamp)
|
||||
{
|
||||
mTimeStamp = aTimeStamp;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPVideoEncodedFrameImpl::TimeStamp()
|
||||
{
|
||||
return mTimeStamp;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetCaptureTime(int64_t aCaptureTime)
|
||||
{
|
||||
mCaptureTime_ms = aCaptureTime;
|
||||
}
|
||||
|
||||
int64_t
|
||||
GMPVideoEncodedFrameImpl::CaptureTime()
|
||||
{
|
||||
return mCaptureTime_ms;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetFrameType(GMPVideoFrameType aFrameType)
|
||||
{
|
||||
mFrameType = aFrameType;
|
||||
}
|
||||
|
||||
GMPVideoFrameType
|
||||
GMPVideoEncodedFrameImpl::FrameType()
|
||||
{
|
||||
return mFrameType;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetAllocatedSize(uint32_t aNewSize)
|
||||
{
|
||||
if (aNewSize <= AllocatedSize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
ipc::Shmem new_mem;
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(aNewSize, ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
|
||||
!new_mem.get<uint8_t>()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBuffer.IsReadable()) {
|
||||
memcpy(new_mem.get<uint8_t>(), Buffer(), mSize);
|
||||
}
|
||||
|
||||
DestroyBuffer();
|
||||
|
||||
mBuffer = new_mem;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPVideoEncodedFrameImpl::AllocatedSize()
|
||||
{
|
||||
if (mBuffer.IsWritable()) {
|
||||
return mBuffer.Size<uint8_t>();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetSize(uint32_t aSize)
|
||||
{
|
||||
mSize = aSize;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPVideoEncodedFrameImpl::Size()
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::SetCompleteFrame(bool aCompleteFrame)
|
||||
{
|
||||
mCompleteFrame = aCompleteFrame;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncodedFrameImpl::CompleteFrame()
|
||||
{
|
||||
return mCompleteFrame;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
GMPVideoEncodedFrameImpl::Buffer() const
|
||||
{
|
||||
return mBuffer.get<uint8_t>();
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
GMPVideoEncodedFrameImpl::Buffer()
|
||||
{
|
||||
return mBuffer.get<uint8_t>();
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncodedFrameImpl::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* Copyright (c) 2014, Mozilla Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GMPVideoEncodedFrameImpl_h_
|
||||
#define GMPVideoEncodedFrameImpl_h_
|
||||
|
||||
#include "gmp-video-errors.h"
|
||||
#include "gmp-video-frame.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPVideoHostImpl;
|
||||
class GMPVideoEncodedFrameData;
|
||||
|
||||
class GMPVideoEncodedFrameImpl: public GMPVideoEncodedFrame
|
||||
{
|
||||
friend struct IPC::ParamTraits<mozilla::gmp::GMPVideoEncodedFrameImpl>;
|
||||
public:
|
||||
GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost);
|
||||
GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData, GMPVideoHostImpl* aHost);
|
||||
virtual ~GMPVideoEncodedFrameImpl();
|
||||
|
||||
// This is called during a normal destroy sequence, which is
|
||||
// when a consumer is finished or during XPCOM shutdown.
|
||||
void DoneWithAPI();
|
||||
// Does not attempt to release Shmem, as the Shmem has already been released.
|
||||
void ActorDestroyed();
|
||||
|
||||
bool RelinquishFrameData(GMPVideoEncodedFrameData& aFrameData);
|
||||
|
||||
// GMPVideoFrame
|
||||
virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
|
||||
virtual void Destroy() MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoEncodedFrame
|
||||
virtual GMPVideoErr CreateEmptyFrame(uint32_t aSize) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CopyFrame(const GMPVideoEncodedFrame& aFrame) MOZ_OVERRIDE;
|
||||
virtual void SetEncodedWidth(uint32_t aEncodedWidth) MOZ_OVERRIDE;
|
||||
virtual uint32_t EncodedWidth() MOZ_OVERRIDE;
|
||||
virtual void SetEncodedHeight(uint32_t aEncodedHeight) MOZ_OVERRIDE;
|
||||
virtual uint32_t EncodedHeight() MOZ_OVERRIDE;
|
||||
virtual void SetTimeStamp(uint32_t aTimeStamp) MOZ_OVERRIDE;
|
||||
virtual uint32_t TimeStamp() MOZ_OVERRIDE;
|
||||
virtual void SetCaptureTime(int64_t aCaptureTime) MOZ_OVERRIDE;
|
||||
virtual int64_t CaptureTime() MOZ_OVERRIDE;
|
||||
virtual void SetFrameType(GMPVideoFrameType aFrameType) MOZ_OVERRIDE;
|
||||
virtual GMPVideoFrameType FrameType() MOZ_OVERRIDE;
|
||||
virtual void SetAllocatedSize(uint32_t aNewSize) MOZ_OVERRIDE;
|
||||
virtual uint32_t AllocatedSize() MOZ_OVERRIDE;
|
||||
virtual void SetSize(uint32_t aSize) MOZ_OVERRIDE;
|
||||
virtual uint32_t Size() MOZ_OVERRIDE;
|
||||
virtual void SetCompleteFrame(bool aCompleteFrame) MOZ_OVERRIDE;
|
||||
virtual bool CompleteFrame() MOZ_OVERRIDE;
|
||||
virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
|
||||
virtual uint8_t* Buffer() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
void DestroyBuffer();
|
||||
|
||||
uint32_t mEncodedWidth;
|
||||
uint32_t mEncodedHeight;
|
||||
uint32_t mTimeStamp;
|
||||
int64_t mCaptureTime_ms;
|
||||
GMPVideoFrameType mFrameType;
|
||||
uint32_t mSize;
|
||||
bool mCompleteFrame;
|
||||
GMPVideoHostImpl* mHost;
|
||||
ipc::Shmem mBuffer;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoEncodedFrameImpl_h_
|
|
@ -0,0 +1,173 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoEncoderChild.h"
|
||||
#include "GMPChild.h"
|
||||
#include <stdio.h>
|
||||
#include "mozilla/unused.h"
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
#include "GMPVideoi420FrameImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPVideoEncoderChild::GMPVideoEncoderChild(GMPChild* aPlugin)
|
||||
: mPlugin(aPlugin),
|
||||
mVideoEncoder(nullptr),
|
||||
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
}
|
||||
|
||||
GMPVideoEncoderChild::~GMPVideoEncoderChild()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncoderChild::Init(GMPVideoEncoder* aEncoder)
|
||||
{
|
||||
MOZ_ASSERT(aEncoder, "Cannot initialize video encoder child without a video encoder!");
|
||||
mVideoEncoder = aEncoder;
|
||||
}
|
||||
|
||||
GMPVideoHostImpl&
|
||||
GMPVideoEncoderChild::Host()
|
||||
{
|
||||
return mVideoHost;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoEncoderChild::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
auto ef = static_cast<GMPVideoEncodedFrameImpl*>(aEncodedFrame);
|
||||
|
||||
GMPVideoEncodedFrameData frameData;
|
||||
ef->RelinquishFrameData(frameData);
|
||||
|
||||
SendEncoded(frameData, aCodecSpecificInfo);
|
||||
|
||||
aEncodedFrame->Destroy();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::MgrDeallocShmem(Shmem& aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
const int32_t& aNumberOfCores,
|
||||
const uint32_t& aMaxPayloadSize)
|
||||
{
|
||||
if (!mVideoEncoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->InitEncode(aCodecSettings, this, aNumberOfCores, aMaxPayloadSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvEncode(const GMPVideoi420FrameData& aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const InfallibleTArray<int>& aFrameTypes)
|
||||
{
|
||||
if (!mVideoEncoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto f = new GMPVideoi420FrameImpl(aInputFrame, &mVideoHost);
|
||||
|
||||
std::vector<GMPVideoFrameType> frameTypes(aFrameTypes.Length());
|
||||
for (uint32_t i = 0; i < aFrameTypes.Length(); i++) {
|
||||
frameTypes[i] = static_cast<GMPVideoFrameType>(aFrameTypes[i]);
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->Encode(f, aCodecSpecificInfo, frameTypes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvSetChannelParameters(const uint32_t& aPacketLoss,
|
||||
const uint32_t& aRTT)
|
||||
{
|
||||
if (!mVideoEncoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->SetChannelParameters(aPacketLoss, aRTT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvSetRates(const uint32_t& aNewBitRate,
|
||||
const uint32_t& aFrameRate)
|
||||
{
|
||||
if (!mVideoEncoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->SetRates(aNewBitRate, aFrameRate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvSetPeriodicKeyFrames(const bool& aEnable)
|
||||
{
|
||||
if (!mVideoEncoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->SetPeriodicKeyFrames(aEnable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderChild::RecvEncodingComplete()
|
||||
{
|
||||
if (!mVideoEncoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mVideoEncoder->EncodingComplete();
|
||||
|
||||
mVideoHost.DoneWithAPI();
|
||||
|
||||
mPlugin = nullptr;
|
||||
|
||||
unused << Send__delete__(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPVideoEncoderChild_h_
|
||||
#define GMPVideoEncoderChild_h_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "mozilla/gmp/PGMPVideoEncoderChild.h"
|
||||
#include "gmp-video-encode.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "GMPVideoHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPChild;
|
||||
|
||||
class GMPVideoEncoderChild : public PGMPVideoEncoderChild,
|
||||
public GMPEncoderCallback,
|
||||
public GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
GMPVideoEncoderChild(GMPChild* aPlugin);
|
||||
virtual ~GMPVideoEncoderChild();
|
||||
|
||||
void Init(GMPVideoEncoder* aEncoder);
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPEncoderCallback
|
||||
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// PGMPVideoEncoderChild
|
||||
virtual bool RecvInitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
const int32_t& aNumberOfCores,
|
||||
const uint32_t& aMaxPayloadSize) MOZ_OVERRIDE;
|
||||
virtual bool RecvEncode(const GMPVideoi420FrameData& aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const InfallibleTArray<int>& aFrameTypes) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetChannelParameters(const uint32_t& aPacketLoss,
|
||||
const uint32_t& aRTT) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetRates(const uint32_t& aNewBitRate,
|
||||
const uint32_t& aFrameRate) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetPeriodicKeyFrames(const bool& aEnable) MOZ_OVERRIDE;
|
||||
virtual bool RecvEncodingComplete() MOZ_OVERRIDE;
|
||||
|
||||
GMPChild* mPlugin;
|
||||
GMPVideoEncoder* mVideoEncoder;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoEncoderChild_h_
|
|
@ -0,0 +1,242 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoEncoderParent.h"
|
||||
#include "GMPVideoi420FrameImpl.h"
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
#include <stdio.h>
|
||||
#include "mozilla/unused.h"
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "GMPParent.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<GMPVideoi420Frame> : public nsPointerRefTraits<GMPVideoi420Frame>
|
||||
{
|
||||
public:
|
||||
static void Release(GMPVideoi420Frame* aFrame) { aFrame->Destroy(); }
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
|
||||
: mCanSendMessages(true),
|
||||
mPlugin(aPlugin),
|
||||
mCallback(nullptr),
|
||||
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
}
|
||||
|
||||
GMPVideoEncoderParent::~GMPVideoEncoderParent()
|
||||
{
|
||||
}
|
||||
|
||||
GMPVideoHostImpl&
|
||||
GMPVideoEncoderParent::Host()
|
||||
{
|
||||
return mVideoHost;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return AllocShmem(aSize, aType, aMem);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::MgrDeallocShmem(Shmem& aMem)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
return DeallocShmem(aMem);
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoEncoderParent::InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPEncoderCallback* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!aCallback) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
mCallback = aCallback;
|
||||
|
||||
if (!SendInitEncode(aCodecSettings, aNumberOfCores, aMaxPayloadSize)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoEncoderParent::Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const std::vector<GMPVideoFrameType>& aFrameTypes)
|
||||
{
|
||||
nsAutoRef<GMPVideoi420Frame> frameRef(aInputFrame);
|
||||
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
auto inputFrameImpl = static_cast<GMPVideoi420FrameImpl*>(aInputFrame);
|
||||
|
||||
GMPVideoi420FrameData frameData;
|
||||
inputFrameImpl->InitFrameData(frameData);
|
||||
|
||||
InfallibleTArray<int> frameTypes;
|
||||
frameTypes.SetCapacity(aFrameTypes.size());
|
||||
for (std::vector<int>::size_type i = 0; i != aFrameTypes.size(); i++) {
|
||||
frameTypes.AppendElement(static_cast<int>(aFrameTypes[i]));
|
||||
}
|
||||
|
||||
if (!SendEncode(frameData,
|
||||
aCodecSpecificInfo,
|
||||
frameTypes)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoEncoderParent::SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendSetChannelParameters(aPacketLoss, aRTT)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoEncoderParent::SetRates(uint32_t aNewBitRate, uint32_t aFrameRate)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendSetRates(aNewBitRate, aFrameRate)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoEncoderParent::SetPeriodicKeyFrames(bool aEnable)
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendSetPeriodicKeyFrames(aEnable)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
|
||||
void
|
||||
GMPVideoEncoderParent::EncodingComplete()
|
||||
{
|
||||
if (!mCanSendMessages) {
|
||||
NS_WARNING("Trying to use an invalid GMP video encoder!");
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
mCanSendMessages = false;
|
||||
|
||||
mCallback = nullptr;
|
||||
|
||||
mVideoHost.DoneWithAPI();
|
||||
|
||||
unused << SendEncodingComplete();
|
||||
}
|
||||
|
||||
// Note: Keep this sync'd up with DecodingComplete
|
||||
void
|
||||
GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
if (mPlugin) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mPlugin->VideoEncoderDestroyed(this);
|
||||
mPlugin = nullptr;
|
||||
}
|
||||
mCanSendMessages = false;
|
||||
mCallback = nullptr;
|
||||
mVideoHost.ActorDestroyed();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo)
|
||||
{
|
||||
if (!mCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto f = new GMPVideoEncodedFrameImpl(aEncodedFrame, &mVideoHost);
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->Encoded(f, aCodecSpecificInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoEncoderParent::Recv__delete__()
|
||||
{
|
||||
if (mPlugin) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mPlugin->VideoEncoderDestroyed(this);
|
||||
mPlugin = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPVideoEncoderParent_h_
|
||||
#define GMPVideoEncoderParent_h_
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "gmp-video-encode.h"
|
||||
#include "mozilla/gmp/PGMPVideoEncoderParent.h"
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "GMPVideoHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPParent;
|
||||
|
||||
class GMPVideoEncoderParent : public GMPVideoEncoder,
|
||||
public PGMPVideoEncoderParent,
|
||||
public GMPSharedMemManager
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GMPVideoEncoderParent)
|
||||
|
||||
GMPVideoEncoderParent(GMPParent *aPlugin);
|
||||
|
||||
GMPVideoHostImpl& Host();
|
||||
|
||||
// GMPSharedMemManager
|
||||
virtual bool MgrAllocShmem(size_t aSize,
|
||||
ipc::Shmem::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aMem) MOZ_OVERRIDE;
|
||||
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoEncoder
|
||||
virtual GMPVideoErr InitEncode(const GMPVideoCodec& aCodecSettings,
|
||||
GMPEncoderCallback* aCallback,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Encode(GMPVideoi420Frame* aInputFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo,
|
||||
const std::vector<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) MOZ_OVERRIDE;
|
||||
virtual void EncodingComplete() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
virtual ~GMPVideoEncoderParent();
|
||||
|
||||
// PGMPVideoEncoderParent
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
virtual bool RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
|
||||
const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
|
||||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mCanSendMessages;
|
||||
GMPParent* mPlugin;
|
||||
GMPEncoderCallback* mCallback;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoEncoderParent_h_
|
|
@ -0,0 +1,127 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoHost.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "GMPVideoi420FrameImpl.h"
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPVideoHostImpl::GMPVideoHostImpl(GMPSharedMemManager* aSharedMemMgr)
|
||||
: mSharedMemMgr(aSharedMemMgr)
|
||||
{
|
||||
}
|
||||
|
||||
GMPVideoHostImpl::~GMPVideoHostImpl()
|
||||
{
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoHostImpl::CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame)
|
||||
{
|
||||
if (!mSharedMemMgr) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
if (!aFrame) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
*aFrame = nullptr;
|
||||
|
||||
switch (aFormat) {
|
||||
case kGMPI420VideoFrame:
|
||||
*aFrame = new GMPVideoi420FrameImpl(this);
|
||||
return GMPVideoNoErr;
|
||||
case kGMPEncodedVideoFrame:
|
||||
*aFrame = new GMPVideoEncodedFrameImpl(this);
|
||||
return GMPVideoNoErr;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown frame format!");
|
||||
}
|
||||
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoHostImpl::CreatePlane(GMPPlane** aPlane)
|
||||
{
|
||||
if (!mSharedMemMgr) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
if (!aPlane) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
*aPlane = nullptr;
|
||||
|
||||
auto p = new GMPPlaneImpl(this);
|
||||
|
||||
*aPlane = p;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPSharedMemManager*
|
||||
GMPVideoHostImpl::SharedMemMgr()
|
||||
{
|
||||
return mSharedMemMgr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoHostImpl::DoneWithAPI()
|
||||
{
|
||||
for (uint32_t i = mPlanes.Length(); i > 0; i--) {
|
||||
mPlanes[i - 1]->DoneWithAPI();
|
||||
mPlanes.RemoveElementAt(i - 1);
|
||||
}
|
||||
for (uint32_t i = mEncodedFrames.Length(); i > 0; i--) {
|
||||
mEncodedFrames[i - 1]->DoneWithAPI();
|
||||
mEncodedFrames.RemoveElementAt(i - 1);
|
||||
}
|
||||
mSharedMemMgr = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoHostImpl::ActorDestroyed()
|
||||
{
|
||||
for (uint32_t i = mPlanes.Length(); i > 0; i--) {
|
||||
mPlanes[i - 1]->ActorDestroyed();
|
||||
mPlanes.RemoveElementAt(i - 1);
|
||||
}
|
||||
for (uint32_t i = mEncodedFrames.Length(); i > 0; i--) {
|
||||
mEncodedFrames[i - 1]->ActorDestroyed();
|
||||
mEncodedFrames.RemoveElementAt(i - 1);
|
||||
}
|
||||
mSharedMemMgr = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoHostImpl::PlaneCreated(GMPPlaneImpl* aPlane)
|
||||
{
|
||||
mPlanes.AppendElement(aPlane);
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoHostImpl::PlaneDestroyed(GMPPlaneImpl* aPlane)
|
||||
{
|
||||
MOZ_ALWAYS_TRUE(mPlanes.RemoveElement(aPlane));
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoHostImpl::EncodedFrameCreated(GMPVideoEncodedFrameImpl* aEncodedFrame)
|
||||
{
|
||||
mEncodedFrames.AppendElement(aEncodedFrame);
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoHostImpl::EncodedFrameDestroyed(GMPVideoEncodedFrameImpl* aFrame)
|
||||
{
|
||||
MOZ_ALWAYS_TRUE(mEncodedFrames.RemoveElement(aFrame));
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPVideoHost_h_
|
||||
#define GMPVideoHost_h_
|
||||
|
||||
#include "gmp-video-host.h"
|
||||
#include "gmp-video-plane.h"
|
||||
#include "gmp-video-frame.h"
|
||||
#include "gmp-video-host.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPSharedMemManager;
|
||||
class GMPPlaneImpl;
|
||||
class GMPVideoEncodedFrameImpl;
|
||||
|
||||
class GMPVideoHostImpl : public GMPVideoHost
|
||||
{
|
||||
public:
|
||||
GMPVideoHostImpl(GMPSharedMemManager* aSharedMemMgr);
|
||||
virtual ~GMPVideoHostImpl();
|
||||
|
||||
// Used for shared memory allocation and deallocation.
|
||||
GMPSharedMemManager* SharedMemMgr();
|
||||
void DoneWithAPI();
|
||||
void ActorDestroyed();
|
||||
void PlaneCreated(GMPPlaneImpl* aPlane);
|
||||
void PlaneDestroyed(GMPPlaneImpl* aPlane);
|
||||
void EncodedFrameCreated(GMPVideoEncodedFrameImpl* aEncodedFrame);
|
||||
void EncodedFrameDestroyed(GMPVideoEncodedFrameImpl* aFrame);
|
||||
|
||||
// GMPVideoHost
|
||||
virtual GMPVideoErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CreatePlane(GMPPlane** aPlane) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// All shared memory allocations have to be made by an IPDL actor.
|
||||
// This is a reference to the owning actor. If this reference is
|
||||
// null then the actor has died and all allocations must fail.
|
||||
GMPSharedMemManager* mSharedMemMgr;
|
||||
|
||||
// We track all of these things because they need to handle further
|
||||
// allocations through us and we need to notify them when they
|
||||
// can't use us any more.
|
||||
nsTArray<GMPPlaneImpl*> mPlanes;
|
||||
nsTArray<GMPVideoEncodedFrameImpl*> mEncodedFrames;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoHost_h_
|
|
@ -0,0 +1,224 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoPlaneImpl.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPPlaneImpl::GMPPlaneImpl(GMPVideoHostImpl* aHost)
|
||||
: mSize(0),
|
||||
mStride(0),
|
||||
mHost(aHost)
|
||||
{
|
||||
MOZ_ASSERT(mHost);
|
||||
mHost->PlaneCreated(this);
|
||||
}
|
||||
|
||||
GMPPlaneImpl::GMPPlaneImpl(const GMPPlaneData& aPlaneData, GMPVideoHostImpl* aHost)
|
||||
: mBuffer(aPlaneData.mBuffer()),
|
||||
mSize(aPlaneData.mSize()),
|
||||
mStride(aPlaneData.mStride()),
|
||||
mHost(aHost)
|
||||
{
|
||||
MOZ_ASSERT(mHost);
|
||||
mHost->PlaneCreated(this);
|
||||
}
|
||||
|
||||
GMPPlaneImpl::~GMPPlaneImpl()
|
||||
{
|
||||
DestroyBuffer();
|
||||
if (mHost) {
|
||||
mHost->PlaneDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPPlaneImpl::DoneWithAPI()
|
||||
{
|
||||
DestroyBuffer();
|
||||
|
||||
// Do this after destroying the buffer because destruction
|
||||
// involves deallocation, which requires a host.
|
||||
mHost = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPPlaneImpl::ActorDestroyed()
|
||||
{
|
||||
// Simply clear out Shmem reference, do not attempt to
|
||||
// properly free it. It has already been freed.
|
||||
mBuffer = ipc::Shmem();
|
||||
// No more host.
|
||||
mHost = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPPlaneImpl::InitPlaneData(GMPPlaneData& aPlaneData)
|
||||
{
|
||||
aPlaneData.mBuffer() = mBuffer;
|
||||
aPlaneData.mSize() = mSize;
|
||||
aPlaneData.mStride() = mStride;
|
||||
|
||||
// This method is called right before Shmem is sent to another process.
|
||||
// We need to effectively zero out our member copy so that we don't
|
||||
// try to delete memory we don't own later.
|
||||
mBuffer = ipc::Shmem();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPPlaneImpl::MaybeResize(int32_t aNewSize) {
|
||||
if (aNewSize <= AllocatedSize()) {
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
if (!mHost) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
ipc::Shmem new_mem;
|
||||
if (!mHost->SharedMemMgr()->MgrAllocShmem(aNewSize, ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
|
||||
!new_mem.get<uint8_t>()) {
|
||||
return GMPVideoAllocErr;
|
||||
}
|
||||
|
||||
if (mBuffer.IsReadable()) {
|
||||
memcpy(new_mem.get<uint8_t>(), Buffer(), mSize);
|
||||
}
|
||||
|
||||
DestroyBuffer();
|
||||
|
||||
mBuffer = new_mem;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPPlaneImpl::DestroyBuffer()
|
||||
{
|
||||
if (mHost && mBuffer.IsWritable()) {
|
||||
mHost->SharedMemMgr()->MgrDeallocShmem(mBuffer);
|
||||
}
|
||||
mBuffer = ipc::Shmem();
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPPlaneImpl::CreateEmptyPlane(int32_t aAllocatedSize, int32_t aStride, int32_t aPlaneSize)
|
||||
{
|
||||
if (aAllocatedSize < 1 || aStride < 1 || aPlaneSize < 1) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
GMPVideoErr err = MaybeResize(aAllocatedSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mSize = aPlaneSize;
|
||||
mStride = aStride;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPPlaneImpl::Copy(const GMPPlane& aPlane)
|
||||
{
|
||||
auto& planeimpl = static_cast<const GMPPlaneImpl&>(aPlane);
|
||||
|
||||
GMPVideoErr err = MaybeResize(planeimpl.mSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (planeimpl.Buffer() && planeimpl.mSize > 0) {
|
||||
memcpy(Buffer(), planeimpl.Buffer(), mSize);
|
||||
}
|
||||
|
||||
mSize = planeimpl.mSize;
|
||||
mStride = planeimpl.mStride;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPPlaneImpl::Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer)
|
||||
{
|
||||
GMPVideoErr err = MaybeResize(aSize);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (aBuffer && aSize > 0) {
|
||||
memcpy(Buffer(), aBuffer, aSize);
|
||||
}
|
||||
|
||||
mSize = aSize;
|
||||
mStride = aStride;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPPlaneImpl::Swap(GMPPlane& aPlane)
|
||||
{
|
||||
auto& planeimpl = static_cast<GMPPlaneImpl&>(aPlane);
|
||||
|
||||
std::swap(mStride, planeimpl.mStride);
|
||||
std::swap(mSize, planeimpl.mSize);
|
||||
std::swap(mBuffer, planeimpl.mBuffer);
|
||||
}
|
||||
|
||||
int32_t
|
||||
GMPPlaneImpl::AllocatedSize() const
|
||||
{
|
||||
if (mBuffer.IsWritable()) {
|
||||
return mBuffer.Size<uint8_t>();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
GMPPlaneImpl::ResetSize()
|
||||
{
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPPlaneImpl::IsZeroSize() const
|
||||
{
|
||||
return (mSize == 0);
|
||||
}
|
||||
|
||||
int32_t
|
||||
GMPPlaneImpl::Stride() const
|
||||
{
|
||||
return mStride;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
GMPPlaneImpl::Buffer() const
|
||||
{
|
||||
return mBuffer.get<uint8_t>();
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
GMPPlaneImpl::Buffer()
|
||||
{
|
||||
return mBuffer.get<uint8_t>();
|
||||
}
|
||||
|
||||
void
|
||||
GMPPlaneImpl::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPVideoPlaneImpl_h_
|
||||
#define GMPVideoPlaneImpl_h_
|
||||
|
||||
#include "gmp-video-plane.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPVideoHostImpl;
|
||||
class GMPPlaneData;
|
||||
|
||||
class GMPPlaneImpl : public GMPPlane
|
||||
{
|
||||
friend struct IPC::ParamTraits<mozilla::gmp::GMPPlaneImpl>;
|
||||
public:
|
||||
GMPPlaneImpl(GMPVideoHostImpl* aHost);
|
||||
GMPPlaneImpl(const GMPPlaneData& aPlaneData, GMPVideoHostImpl* aHost);
|
||||
virtual ~GMPPlaneImpl();
|
||||
|
||||
// This is called during a normal destroy sequence, which is
|
||||
// when a consumer is finished or during XPCOM shutdown.
|
||||
void DoneWithAPI();
|
||||
// This is called when something has gone wrong - specicifically,
|
||||
// a child process has crashed. Does not attempt to release Shmem,
|
||||
// as the Shmem has already been released.
|
||||
void ActorDestroyed();
|
||||
|
||||
bool InitPlaneData(GMPPlaneData& aPlaneData);
|
||||
|
||||
// GMPPlane
|
||||
virtual GMPVideoErr CreateEmptyPlane(int32_t aAllocatedSize,
|
||||
int32_t aStride,
|
||||
int32_t aPlaneSize) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Copy(const GMPPlane& aPlane) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr Copy(int32_t aSize,
|
||||
int32_t aStride,
|
||||
const uint8_t* aBuffer) MOZ_OVERRIDE;
|
||||
virtual void Swap(GMPPlane& aPlane) MOZ_OVERRIDE;
|
||||
virtual int32_t AllocatedSize() const MOZ_OVERRIDE;
|
||||
virtual void ResetSize() MOZ_OVERRIDE;
|
||||
virtual bool IsZeroSize() const MOZ_OVERRIDE;
|
||||
virtual int32_t Stride() const MOZ_OVERRIDE;
|
||||
virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
|
||||
virtual uint8_t* Buffer() MOZ_OVERRIDE;
|
||||
virtual void Destroy() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
GMPVideoErr MaybeResize(int32_t aNewSize);
|
||||
void DestroyBuffer();
|
||||
|
||||
ipc::Shmem mBuffer;
|
||||
int32_t mSize;
|
||||
int32_t mStride;
|
||||
GMPVideoHostImpl* mHost;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoPlaneImpl_h_
|
|
@ -0,0 +1,337 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPVideoi420FrameImpl.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost)
|
||||
: mYPlane(aHost),
|
||||
mUPlane(aHost),
|
||||
mVPlane(aHost),
|
||||
mWidth(0),
|
||||
mHeight(0),
|
||||
mTimestamp(0),
|
||||
mRenderTime_ms(0)
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
}
|
||||
|
||||
GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData,
|
||||
GMPVideoHostImpl* aHost)
|
||||
: mYPlane(aFrameData.mYPlane(), aHost),
|
||||
mUPlane(aFrameData.mUPlane(), aHost),
|
||||
mVPlane(aFrameData.mVPlane(), aHost),
|
||||
mWidth(aFrameData.mWidth()),
|
||||
mHeight(aFrameData.mHeight()),
|
||||
mTimestamp(aFrameData.mTimestamp()),
|
||||
mRenderTime_ms(aFrameData.mRenderTime_ms())
|
||||
{
|
||||
MOZ_ASSERT(aHost);
|
||||
}
|
||||
|
||||
GMPVideoi420FrameImpl::~GMPVideoi420FrameImpl()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData)
|
||||
{
|
||||
mYPlane.InitPlaneData(aFrameData.mYPlane());
|
||||
mUPlane.InitPlaneData(aFrameData.mUPlane());
|
||||
mVPlane.InitPlaneData(aFrameData.mVPlane());
|
||||
aFrameData.mWidth() = mWidth;
|
||||
aFrameData.mHeight() = mHeight;
|
||||
aFrameData.mTimestamp() = mTimestamp;
|
||||
aFrameData.mRenderTime_ms() = mRenderTime_ms;
|
||||
return true;
|
||||
}
|
||||
|
||||
GMPVideoFrameFormat
|
||||
GMPVideoi420FrameImpl::GetFrameFormat()
|
||||
{
|
||||
return kGMPI420VideoFrame;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoi420FrameImpl::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
|
||||
{
|
||||
int32_t half_width = (aWidth + 1) / 2;
|
||||
if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth ||
|
||||
aStride_u < half_width ||
|
||||
aStride_v < half_width) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const GMPPlaneImpl*
|
||||
GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) const {
|
||||
switch (aType) {
|
||||
case kGMPYPlane:
|
||||
return &mYPlane;
|
||||
case kGMPUPlane:
|
||||
return &mUPlane;
|
||||
case kGMPVPlane:
|
||||
return &mVPlane;
|
||||
default:
|
||||
MOZ_CRASH("Unknown plane type!");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GMPPlaneImpl*
|
||||
GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) {
|
||||
switch (aType) {
|
||||
case kGMPYPlane :
|
||||
return &mYPlane;
|
||||
case kGMPUPlane :
|
||||
return &mUPlane;
|
||||
case kGMPVPlane :
|
||||
return &mVPlane;
|
||||
default:
|
||||
MOZ_CRASH("Unknown plane type!");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
|
||||
{
|
||||
if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
int32_t size_y = aStride_y * aHeight;
|
||||
int32_t half_height = (aHeight + 1) / 2;
|
||||
int32_t size_u = aStride_u * half_height;
|
||||
int32_t size_v = aStride_v * half_height;
|
||||
|
||||
GMPVideoErr err = mYPlane.CreateEmptyPlane(size_y, aStride_y, size_y);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mUPlane.CreateEmptyPlane(size_u, aStride_u, size_u);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mVPlane.CreateEmptyPlane(size_v, aStride_v, size_v);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
mTimestamp = 0;
|
||||
mRenderTime_ms = 0;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoi420FrameImpl::CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
int32_t aSize_u, const uint8_t* aBuffer_u,
|
||||
int32_t aSize_v, const uint8_t* aBuffer_v,
|
||||
int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
|
||||
{
|
||||
MOZ_ASSERT(aBuffer_y);
|
||||
MOZ_ASSERT(aBuffer_u);
|
||||
MOZ_ASSERT(aBuffer_v);
|
||||
|
||||
if (aSize_y < 1 || aSize_u < 1 || aSize_v < 1) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
|
||||
GMPVideoErr err = mYPlane.Copy(aSize_y, aStride_y, aBuffer_y);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mUPlane.Copy(aSize_u, aStride_u, aBuffer_u);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
err = mVPlane.Copy(aSize_v, aStride_v, aBuffer_v);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame)
|
||||
{
|
||||
auto& f = static_cast<const GMPVideoi420FrameImpl&>(aFrame);
|
||||
|
||||
GMPVideoErr err = mYPlane.Copy(f.mYPlane);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mUPlane.Copy(f.mUPlane);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mVPlane.Copy(f.mVPlane);
|
||||
if (err != GMPVideoNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
mWidth = f.mWidth;
|
||||
mHeight = f.mHeight;
|
||||
mTimestamp = f.mTimestamp;
|
||||
mRenderTime_ms = f.mRenderTime_ms;
|
||||
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame)
|
||||
{
|
||||
auto f = static_cast<GMPVideoi420FrameImpl*>(aFrame);
|
||||
mYPlane.Swap(f->mYPlane);
|
||||
mUPlane.Swap(f->mUPlane);
|
||||
mVPlane.Swap(f->mVPlane);
|
||||
std::swap(mWidth, f->mWidth);
|
||||
std::swap(mHeight, f->mHeight);
|
||||
std::swap(mTimestamp, f->mTimestamp);
|
||||
std::swap(mRenderTime_ms, f->mRenderTime_ms);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType)
|
||||
{
|
||||
GMPPlane* p = GetPlane(aType);
|
||||
if (p) {
|
||||
return p->Buffer();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) const
|
||||
{
|
||||
const GMPPlane* p = GetPlane(aType);
|
||||
if (p) {
|
||||
return p->Buffer();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
GMPVideoi420FrameImpl::AllocatedSize(GMPPlaneType aType) const
|
||||
{
|
||||
const GMPPlane* p = GetPlane(aType);
|
||||
if (p) {
|
||||
return p->AllocatedSize();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t
|
||||
GMPVideoi420FrameImpl::Stride(GMPPlaneType aType) const
|
||||
{
|
||||
const GMPPlane* p = GetPlane(aType);
|
||||
if (p) {
|
||||
return p->Stride();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoi420FrameImpl::SetWidth(int32_t aWidth)
|
||||
{
|
||||
if (!CheckDimensions(aWidth, mHeight,
|
||||
mYPlane.Stride(), mUPlane.Stride(),
|
||||
mVPlane.Stride())) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
mWidth = aWidth;
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
GMPVideoErr
|
||||
GMPVideoi420FrameImpl::SetHeight(int32_t aHeight)
|
||||
{
|
||||
if (!CheckDimensions(mWidth, aHeight,
|
||||
mYPlane.Stride(), mUPlane.Stride(),
|
||||
mVPlane.Stride())) {
|
||||
return GMPVideoGenericErr;
|
||||
}
|
||||
mHeight = aHeight;
|
||||
return GMPVideoNoErr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
GMPVideoi420FrameImpl::Width() const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
int32_t
|
||||
GMPVideoi420FrameImpl::Height() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoi420FrameImpl::SetTimestamp(uint32_t aTimestamp)
|
||||
{
|
||||
mTimestamp = aTimestamp;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPVideoi420FrameImpl::Timestamp() const
|
||||
{
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoi420FrameImpl::SetRenderTime_ms(int64_t aRenderTime_ms)
|
||||
{
|
||||
mRenderTime_ms = aRenderTime_ms;
|
||||
}
|
||||
|
||||
int64_t
|
||||
GMPVideoi420FrameImpl::RenderTime_ms() const
|
||||
{
|
||||
return mRenderTime_ms;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPVideoi420FrameImpl::IsZeroSize() const
|
||||
{
|
||||
return (mYPlane.IsZeroSize() && mUPlane.IsZeroSize() && mVPlane.IsZeroSize());
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoi420FrameImpl::ResetSize()
|
||||
{
|
||||
mYPlane.ResetSize();
|
||||
mUPlane.ResetSize();
|
||||
mVPlane.ResetSize();
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPVideoi420FrameImpl_h_
|
||||
#define GMPVideoi420FrameImpl_h_
|
||||
|
||||
#include "gmp-video-frame-i420.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "GMPVideoPlaneImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPVideoi420FrameData;
|
||||
|
||||
class GMPVideoi420FrameImpl : public GMPVideoi420Frame
|
||||
{
|
||||
friend struct IPC::ParamTraits<mozilla::gmp::GMPVideoi420FrameImpl>;
|
||||
public:
|
||||
GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost);
|
||||
GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData, GMPVideoHostImpl* aHost);
|
||||
virtual ~GMPVideoi420FrameImpl();
|
||||
|
||||
bool InitFrameData(GMPVideoi420FrameData& aFrameData);
|
||||
const GMPPlaneImpl* GetPlane(GMPPlaneType aType) const;
|
||||
GMPPlaneImpl* GetPlane(GMPPlaneType aType);
|
||||
|
||||
// GMPVideoFrame
|
||||
virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
|
||||
virtual void Destroy() MOZ_OVERRIDE;
|
||||
|
||||
// GMPVideoi420Frame
|
||||
virtual GMPVideoErr CreateEmptyFrame(int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aStride_y,
|
||||
int32_t aStride_u,
|
||||
int32_t aStride_v) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
|
||||
int32_t aSize_u, const uint8_t* aBuffer_u,
|
||||
int32_t aSize_v, const uint8_t* aBuffer_v,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aStride_y,
|
||||
int32_t aStride_u,
|
||||
int32_t aStride_v) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr CopyFrame(const GMPVideoi420Frame& aFrame) MOZ_OVERRIDE;
|
||||
virtual void SwapFrame(GMPVideoi420Frame* aFrame) MOZ_OVERRIDE;
|
||||
virtual uint8_t* Buffer(GMPPlaneType aType) MOZ_OVERRIDE;
|
||||
virtual const uint8_t* Buffer(GMPPlaneType aType) const MOZ_OVERRIDE;
|
||||
virtual int32_t AllocatedSize(GMPPlaneType aType) const MOZ_OVERRIDE;
|
||||
virtual int32_t Stride(GMPPlaneType aType) const MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetWidth(int32_t aWidth) MOZ_OVERRIDE;
|
||||
virtual GMPVideoErr SetHeight(int32_t aHeight) MOZ_OVERRIDE;
|
||||
virtual int32_t Width() const MOZ_OVERRIDE;
|
||||
virtual int32_t Height() const MOZ_OVERRIDE;
|
||||
virtual void SetTimestamp(uint32_t aTimestamp) MOZ_OVERRIDE;
|
||||
virtual uint32_t Timestamp() const MOZ_OVERRIDE;
|
||||
virtual void SetRenderTime_ms(int64_t aRenderTime_ms) MOZ_OVERRIDE;
|
||||
virtual int64_t RenderTime_ms() const MOZ_OVERRIDE;
|
||||
virtual bool IsZeroSize() const MOZ_OVERRIDE;
|
||||
virtual void ResetSize() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
bool CheckDimensions(int32_t aWidth, int32_t aHeight,
|
||||
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v);
|
||||
|
||||
GMPPlaneImpl mYPlane;
|
||||
GMPPlaneImpl mUPlane;
|
||||
GMPPlaneImpl mVPlane;
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
uint32_t mTimestamp;
|
||||
int64_t mRenderTime_ms;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPVideoi420FrameImpl_h_
|