summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/base/nsGlobalWindow.cpp13
-rw-r--r--dom/base/nsGlobalWindow.h2
-rw-r--r--dom/geolocation/nsGeolocation.cpp12
-rw-r--r--dom/indexedDB/ActorsParent.cpp35
-rw-r--r--dom/indexedDB/IDBFactory.cpp18
-rw-r--r--dom/indexedDB/KeyPath.cpp77
-rw-r--r--dom/media/AudioStream.cpp3
-rw-r--r--dom/media/CubebUtils.cpp25
-rw-r--r--dom/media/CubebUtils.h2
-rw-r--r--dom/media/GraphDriver.cpp10
-rw-r--r--dom/media/MediaData.h3
-rw-r--r--dom/media/MediaPrefs.h3
-rw-r--r--dom/media/VideoUtils.cpp37
-rw-r--r--dom/media/VideoUtils.h5
-rw-r--r--dom/media/platforms/agnostic/AOMDecoder.cpp332
-rw-r--r--dom/media/platforms/agnostic/AOMDecoder.h62
-rw-r--r--dom/media/platforms/agnostic/AgnosticDecoderModule.cpp19
-rw-r--r--dom/media/platforms/agnostic/VPXDecoder.cpp53
-rw-r--r--dom/media/platforms/agnostic/VPXDecoder.h12
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp18
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp1
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegLibWrapper.h3
-rw-r--r--dom/media/platforms/ffmpeg/ffvpx/moz.build2
-rw-r--r--dom/media/platforms/moz.build8
-rw-r--r--dom/media/test/bug1377278.webm (renamed from dom/media/test/bug580982.webm)bin215594 -> 215594 bytes
-rw-r--r--dom/media/test/bug1377278.webm^headers^ (renamed from dom/media/test/bug580982.webm^headers^)0
-rw-r--r--dom/media/test/manifest.js4
-rw-r--r--dom/media/test/mochitest.ini4
-rw-r--r--dom/media/webm/WebMDecoder.cpp9
-rw-r--r--dom/media/webm/WebMDemuxer.cpp166
-rw-r--r--dom/media/webm/WebMDemuxer.h18
-rw-r--r--dom/webidl/CommandEvent.webidl6
-rw-r--r--dom/webidl/CompositionEvent.webidl10
-rw-r--r--dom/webidl/CustomEvent.webidl6
-rw-r--r--dom/webidl/DeviceMotionEvent.webidl12
-rw-r--r--dom/webidl/DeviceOrientationEvent.webidl12
-rw-r--r--dom/webidl/DragEvent.webidl30
-rw-r--r--dom/webidl/Event.webidl4
-rw-r--r--dom/webidl/HashChangeEvent.webidl8
-rw-r--r--dom/webidl/KeyEvent.webidl18
-rw-r--r--dom/webidl/MessageEvent.webidl12
-rw-r--r--dom/webidl/MouseEvent.webidl64
-rw-r--r--dom/webidl/MouseScrollEvent.webidl30
-rw-r--r--dom/webidl/MutationEvent.webidl14
-rw-r--r--dom/webidl/ScrollAreaEvent.webidl16
-rw-r--r--dom/webidl/SimpleGestureEvent.webidl36
-rw-r--r--dom/webidl/StorageEvent.webidl14
-rw-r--r--dom/webidl/TimeEvent.webidl4
-rw-r--r--dom/webidl/TouchEvent.webidl22
-rw-r--r--dom/webidl/UIEvent.webidl8
-rw-r--r--dom/webidl/XULCommandEvent.webidl18
-rw-r--r--dom/xbl/nsXBLBinding.cpp3
-rw-r--r--dom/xbl/nsXBLProtoImpl.cpp12
53 files changed, 941 insertions, 374 deletions
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 88cebe42b..86160c77c 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2023,7 +2023,7 @@ nsGlobalWindow::ClearControllers()
}
void
-nsGlobalWindow::FreeInnerObjects()
+nsGlobalWindow::FreeInnerObjects(bool aForDocumentOpen)
{
NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
@@ -2082,8 +2082,10 @@ nsGlobalWindow::FreeInnerObjects()
mDocumentURI = mDoc->GetDocumentURI();
mDocBaseURI = mDoc->GetDocBaseURI();
- while (mDoc->EventHandlingSuppressed()) {
- mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false);
+ if (!aForDocumentOpen) {
+ while (mDoc->EventHandlingSuppressed()) {
+ mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false);
+ }
}
// Note: we don't have to worry about eAnimationsOnly suppressions because
@@ -3000,6 +3002,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
+ bool handleDocumentOpen = false;
+
JS::Rooted<JSObject*> newInnerGlobal(cx);
if (reUseInnerWindow) {
// We're reusing the current inner window.
@@ -3091,6 +3095,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
if (currentInner && currentInner->GetWrapperPreserveColor()) {
if (oldDoc == aDocument) {
+ handleDocumentOpen = true;
// Move the navigator from the old inner window to the new one since
// this is a document.write. This is safe from a same-origin point of
// view because document.write can only be used by the same origin.
@@ -3115,7 +3120,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// Don't free objects on our current inner window if it's going to be
// held in the bfcache.
if (!currentInner->IsFrozen()) {
- currentInner->FreeInnerObjects();
+ currentInner->FreeInnerObjects(handleDocumentOpen);
}
}
diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h
index 467bc6796..80bf33b80 100644
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1380,7 +1380,7 @@ protected:
}
}
- void FreeInnerObjects();
+ void FreeInnerObjects(bool aForDocumentOpen = false);
nsGlobalWindow *CallerInnerWindow();
// Only to be called on an inner window.
diff --git a/dom/geolocation/nsGeolocation.cpp b/dom/geolocation/nsGeolocation.cpp
index 201d4d89a..244018ee8 100644
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -395,18 +395,6 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices)
{
MOZ_ASSERT(aChoices.isUndefined());
- if (mRequester) {
- // Record whether a location callback is fulfilled while the owner window
- // is not visible.
- bool isVisible = false;
- nsCOMPtr<nsPIDOMWindowInner> window = mLocator->GetParentObject();
-
- if (window) {
- nsCOMPtr<nsIDocument> doc = window->GetDoc();
- isVisible = doc && !doc->Hidden();
- }
- }
-
if (mLocator->ClearPendingRequest(this)) {
return NS_OK;
}
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index e6fe9e2a8..58c113058 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -23,6 +23,7 @@
#include "mozilla/AppProcessChecker.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/Casting.h"
+#include "mozilla/CheckedInt.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/ErrorNames.h"
#include "mozilla/LazyIdleThread.h"
@@ -249,8 +250,6 @@ const char kSQLiteJournalSuffix[] = ".sqlite-journal";
const char kSQLiteSHMSuffix[] = ".sqlite-shm";
const char kSQLiteWALSuffix[] = ".sqlite-wal";
-const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
-
const char kPrefFileHandleEnabled[] = "dom.fileHandle.enabled";
#define IDB_PREFIX "indexedDB"
@@ -784,29 +783,25 @@ MakeCompressedIndexDataValues(
MOZ_ASSERT(!keyBuffer.IsEmpty());
- // Don't let |infoLength| overflow.
- if (NS_WARN_IF(UINT32_MAX - keyBuffer.Length() <
- CompressedByteCountForIndexId(info.mIndexId) +
- CompressedByteCountForNumber(keyBufferLength) +
- CompressedByteCountForNumber(sortKeyBufferLength))) {
- IDB_REPORT_INTERNAL_ERR();
- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
- }
-
- const uint32_t infoLength =
- CompressedByteCountForIndexId(info.mIndexId) +
+ const CheckedUint32 infoLength =
+ CheckedUint32(CompressedByteCountForIndexId(info.mIndexId)) +
CompressedByteCountForNumber(keyBufferLength) +
CompressedByteCountForNumber(sortKeyBufferLength) +
keyBufferLength +
sortKeyBufferLength;
+ // Don't let |infoLength| overflow.
+ if (NS_WARN_IF(!infoLength.isValid())) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
// Don't let |blobDataLength| overflow.
- if (NS_WARN_IF(UINT32_MAX - infoLength < blobDataLength)) {
+ if (NS_WARN_IF(UINT32_MAX - infoLength.value() < blobDataLength)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
- blobDataLength += infoLength;
+ blobDataLength += infoLength.value();
}
UniqueFreePtr<uint8_t> blobData(
@@ -21172,16 +21167,6 @@ FactoryOp::CheckPermission(ContentParent* aContentParent,
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
- if (NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
- if (aContentParent) {
- // The DOM in the other process should have kept us from receiving any
- // indexedDB messages so assume that the child is misbehaving.
- aContentParent->KillHard("IndexedDB CheckPermission 1");
- }
-
- return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
- }
-
const ContentPrincipalInfo& contentPrincipalInfo =
principalInfo.get_ContentPrincipalInfo();
if (contentPrincipalInfo.attrs().mPrivateBrowsingId != 0) {
diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp
index 663828978..825d2ac36 100644
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -47,12 +47,6 @@ namespace dom {
using namespace mozilla::dom::quota;
using namespace mozilla::ipc;
-namespace {
-
-const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
-
-} // namespace
-
class IDBFactory::BackgroundCreateCallback final
: public nsIIPCBackgroundChildCreateCallback
{
@@ -130,12 +124,6 @@ IDBFactory::CreateForWindow(nsPIDOMWindowInner* aWindow,
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
- if (!(NS_SUCCEEDED(rv) && nsContentUtils::IsSystemPrincipal(principal)) &&
- NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
- *aFactory = nullptr;
- return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
- }
-
if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) {
NS_WARNING("IndexedDB is not permitted in a third-party window.");
*aFactory = nullptr;
@@ -246,12 +234,6 @@ IDBFactory::CreateForMainThreadJSInternal(
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipalInfo);
- if (aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo &&
- NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
- *aFactory = nullptr;
- return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
- }
-
IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
if (NS_WARN_IF(!mgr)) {
IDB_REPORT_INTERNAL_ERR();
diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp
index dc8d10668..30edd8cd7 100644
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -14,6 +14,7 @@
#include "xpcpublic.h"
#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/IDBObjectStoreBinding.h"
namespace mozilla {
@@ -100,7 +101,6 @@ GetJSValFromKeyPathString(JSContext* aCx,
const char16_t* keyPathChars = token.BeginReading();
const size_t keyPathLen = token.Length();
- bool hasProp;
if (!targetObject) {
// We're still walking the chain of existing objects
// http://w3c.github.io/IndexedDB/#dfn-evaluate-a-key-path-on-a-value
@@ -116,16 +116,77 @@ GetJSValFromKeyPathString(JSContext* aCx,
}
obj = &currentVal.toObject();
- bool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
- &hasProp);
+ // We call JS_GetOwnUCPropertyDescriptor on purpose (as opposed to
+ // JS_GetUCPropertyDescriptor) to avoid searching the prototype chain.
+ JS::Rooted<JS::PropertyDescriptor> desc(aCx);
+ bool ok = JS_GetOwnUCPropertyDescriptor(aCx, obj, keyPathChars,
+ keyPathLen, &desc);
IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
- if (hasProp) {
- // Get if the property exists...
- JS::Rooted<JS::Value> intermediate(aCx);
- bool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &intermediate);
- IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+ JS::Rooted<JS::Value> intermediate(aCx);
+ bool hasProp = false;
+
+ if (desc.object()) {
+ intermediate = desc.value();
+ hasProp = true;
+ } else {
+ // If we get here it means the object doesn't have the property or the
+ // property is available throuch a getter. We don't want to call any
+ // getters to avoid potential re-entrancy.
+ // The blob object is special since its properties are available
+ // only through getters but we still want to support them for key
+ // extraction. So they need to be handled manually.
+ Blob* blob;
+ if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
+ if (token.EqualsLiteral("size")) {
+ ErrorResult rv;
+ uint64_t size = blob->GetSize(rv);
+ MOZ_ALWAYS_TRUE(!rv.Failed());
+
+ intermediate = JS_NumberValue(size);
+ hasProp = true;
+ } else if (token.EqualsLiteral("type")) {
+ nsString type;
+ blob->GetType(type);
+
+ JSString* string =
+ JS_NewUCStringCopyN(aCx, type.get(), type.Length());
+
+ intermediate = JS::StringValue(string);
+ hasProp = true;
+ } else {
+ RefPtr<File> file = blob->ToFile();
+ if (file) {
+ if (token.EqualsLiteral("name")) {
+ nsString name;
+ file->GetName(name);
+
+ JSString* string =
+ JS_NewUCStringCopyN(aCx, name.get(), name.Length());
+
+ intermediate = JS::StringValue(string);
+ hasProp = true;
+ } else if (token.EqualsLiteral("lastModified")) {
+ ErrorResult rv;
+ int64_t lastModifiedDate = file->GetLastModified(rv);
+ MOZ_ALWAYS_TRUE(!rv.Failed());
+
+ intermediate = JS_NumberValue(lastModifiedDate);
+ hasProp = true;
+ } else if (token.EqualsLiteral("lastModifiedDate")) {
+ ErrorResult rv;
+ Date lastModifiedDate = file->GetLastModifiedDate(rv);
+ MOZ_ALWAYS_TRUE(!rv.Failed());
+
+ lastModifiedDate.ToDateObject(aCx, &intermediate);
+ hasProp = true;
+ }
+ }
+ }
+ }
+ }
+ if (hasProp) {
// Treat explicitly undefined as an error.
if (intermediate.isUndefined()) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp
index 896dee407..4b1d82c37 100644
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -345,7 +345,6 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
cubeb* cubebContext = CubebUtils::GetCubebContext();
if (!cubebContext) {
NS_WARNING("Can't get cubeb context!");
- CubebUtils::ReportCubebStreamInitFailure(true);
return NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR;
}
@@ -367,10 +366,8 @@ AudioStream::OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams,
latency_frames,
DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
mCubebStream.reset(stream);
- CubebUtils::ReportCubebBackendUsed();
} else {
NS_WARNING(nsPrintfCString("AudioStream::OpenCubeb() %p failed to init cubeb", this).get());
- CubebUtils::ReportCubebStreamInitFailure(aIsFirst);
return NS_ERROR_FAILURE;
}
diff --git a/dom/media/CubebUtils.cpp b/dom/media/CubebUtils.cpp
index 93792e63b..0f0167d9c 100644
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -239,31 +239,6 @@ cubeb* GetCubebContextUnlocked()
return sCubebContext;
}
-void ReportCubebBackendUsed()
-{
- StaticMutexAutoLock lock(sMutex);
-
- sAudioStreamInitEverSucceeded = true;
-
- bool foundBackend = false;
- for (uint32_t i = 0; i < ArrayLength(AUDIOSTREAM_BACKEND_ID_STR); i++) {
- if (!strcmp(cubeb_get_backend_id(sCubebContext), AUDIOSTREAM_BACKEND_ID_STR[i])) {
- foundBackend = true;
- }
- }
-}
-
-void ReportCubebStreamInitFailure(bool aIsFirst)
-{
- StaticMutexAutoLock lock(sMutex);
- if (!aIsFirst && !sAudioStreamInitEverSucceeded) {
- // This machine has no audio hardware, or it's in really bad shape, don't
- // send this info, since we want CUBEB_BACKEND_INIT_FAILURE_OTHER to detect
- // failures to open multiple streams in a process over time.
- return;
- }
-}
-
uint32_t GetCubebPlaybackLatencyInMilliseconds()
{
StaticMutexAutoLock lock(sMutex);
diff --git a/dom/media/CubebUtils.h b/dom/media/CubebUtils.h
index fa5fc2294..f43492374 100644
--- a/dom/media/CubebUtils.h
+++ b/dom/media/CubebUtils.h
@@ -35,8 +35,6 @@ double GetVolumeScale();
bool GetFirstStream();
cubeb* GetCubebContext();
cubeb* GetCubebContextUnlocked();
-void ReportCubebStreamInitFailure(bool aIsFirstStream);
-void ReportCubebBackendUsed();
uint32_t GetCubebPlaybackLatencyInMilliseconds();
Maybe<uint32_t> GetCubebMSGLatencyInFrames();
bool CubebLatencyPrefSet();
diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp
index 47762c56e..b60dfee9d 100644
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -623,9 +623,6 @@ AudioCallbackDriver::Init()
cubeb* cubebContext = CubebUtils::GetCubebContext();
if (!cubebContext) {
NS_WARNING("Could not get cubeb context.");
- if (!mFromFallback) {
- CubebUtils::ReportCubebStreamInitFailure(true);
- }
return;
}
@@ -710,18 +707,11 @@ AudioCallbackDriver::Init()
NS_WARNING_ASSERTION(
rv == CUBEB_OK,
"Could not set the audio stream volume in GraphDriver.cpp");
- CubebUtils::ReportCubebBackendUsed();
} else {
#ifdef MOZ_WEBRTC
StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex());
#endif
NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
- // Only report failures when we're not coming from a driver that was
- // created itself as a fallback driver because of a previous audio driver
- // failure.
- if (!mFromFallback) {
- CubebUtils::ReportCubebStreamInitFailure(firstStream);
- }
// Fall back to a driver using a normal thread. If needed,
// the graph will try to re-open an audio stream later.
MonitorAutoLock lock(GraphImpl()->GetMonitor());
diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h
index a79aac6ed..905b4c1d9 100644
--- a/dom/media/MediaData.h
+++ b/dom/media/MediaData.h
@@ -14,6 +14,7 @@
#include "nsIMemoryReporter.h"
#include "SharedBuffer.h"
#include "mozilla/RefPtr.h"
+#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsTArray.h"
@@ -631,6 +632,8 @@ public:
{
return sizeof(*this) + mBuffer.ComputedSizeOfExcludingThis();
}
+ // Access the buffer as a Span.
+ operator Span<const uint8_t>() { return MakeSpan(Data(), Size()); }
const CryptoSample& mCrypto;
RefPtr<MediaByteBuffer> mExtraData;
diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h
index b237ecd3d..e67796edd 100644
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -120,6 +120,9 @@ private:
#ifdef MOZ_FFVPX
DECL_MEDIA_PREF("media.ffvpx.enabled", PDMFFVPXEnabled, bool, true);
#endif
+#ifdef MOZ_AV1
+ DECL_MEDIA_PREF("media.av1.enabled", AV1Enabled, bool, false);
+#endif
#ifdef XP_WIN
DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true);
DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false);
diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp
index b1a202c03..c06ba9070 100644
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -207,8 +207,20 @@ already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType)
name = "MediaPlayback";
break;
}
- return SharedThreadPool::
+ RefPtr<SharedThreadPool> pool = SharedThreadPool::
Get(nsDependentCString(name), MediaPrefs::MediaThreadPoolDefaultCount());
+
+ // Ensure a larger stack for platform decoder threads
+ if (aType == MediaThreadType::PLATFORM_DECODER) {
+ const uint32_t minStackSize = 512*1024;
+ uint32_t stackSize;
+ MOZ_ALWAYS_SUCCEEDS(pool->GetThreadStackSize(&stackSize));
+ if (stackSize < minStackSize) {
+ MOZ_ALWAYS_SUCCEEDS(pool->SetThreadStackSize(minStackSize));
+ }
+ }
+
+ return pool.forget();
}
bool
@@ -426,6 +438,16 @@ ParseMIMETypeString(const nsAString& aMIMEType,
return ParseCodecsString(codecsStr, aOutCodecs);
}
+template <int N>
+static bool
+StartsWith(const nsACString& string, const char (&prefix)[N])
+{
+ if (N - 1 > string.Length()) {
+ return false;
+ }
+ return memcmp(string.Data(), prefix, N - 1) == 0;
+}
+
bool
IsH264CodecString(const nsAString& aCodec)
{
@@ -458,15 +480,14 @@ IsVP9CodecString(const nsAString& aCodec)
aCodec.EqualsLiteral("vp9.0");
}
-template <int N>
-static bool
-StartsWith(const nsACString& string, const char (&prefix)[N])
+#ifdef MOZ_AV1
+bool
+IsAV1CodecString(const nsAString& aCodec)
{
- if (N - 1 > string.Length()) {
- return false;
- }
- return memcmp(string.Data(), prefix, N - 1) == 0;
+ return aCodec.EqualsLiteral("av1") ||
+ StartsWith(NS_ConvertUTF16toUTF8(aCodec), "av01");
}
+#endif
UniquePtr<TrackInfo>
CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType)
diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h
index 441b63792..aaf0e9903 100644
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -345,6 +345,11 @@ IsVP8CodecString(const nsAString& aCodec);
bool
IsVP9CodecString(const nsAString& aCodec);
+#ifdef MOZ_AV1
+bool
+IsAV1CodecString(const nsAString& aCodec);
+#endif
+
// Try and create a TrackInfo with a given codec MIME type.
UniquePtr<TrackInfo>
CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType);
diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp
new file mode 100644
index 000000000..b5d21375e
--- /dev/null
+++ b/dom/media/platforms/agnostic/AOMDecoder.cpp
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AOMDecoder.h"
+#include "MediaResult.h"
+#include "TimeUnits.h"
+#include "aom/aomdx.h"
+#include "aom/aom_image.h"
+#include "gfx2DGlue.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/SyncRunnable.h"
+#include "nsError.h"
+#include "prsystem.h"
+
+#include <algorithm>
+
+#undef LOG
+#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("AOMDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
+
+namespace mozilla {
+
+using namespace gfx;
+using namespace layers;
+
+AOMDecoder::AOMDecoder(const CreateDecoderParams& aParams)
+ : mImageContainer(aParams.mImageContainer)
+ , mTaskQueue(aParams.mTaskQueue)
+ , mCallback(aParams.mCallback)
+ , mIsFlushing(false)
+ , mInfo(aParams.VideoConfig())
+{
+ PodZero(&mCodec);
+}
+
+AOMDecoder::~AOMDecoder()
+{
+}
+
+void
+AOMDecoder::Shutdown()
+{
+ aom_codec_destroy(&mCodec);
+}
+
+RefPtr<MediaDataDecoder::InitPromise>
+AOMDecoder::Init()
+{
+ int decode_threads = 2;
+
+ aom_codec_iface_t* dx = aom_codec_av1_dx();
+ if (mInfo.mDisplay.width >= 2048) {
+ decode_threads = 8;
+ }
+ else if (mInfo.mDisplay.width >= 1024) {
+ decode_threads = 4;
+ }
+ decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors());
+
+ aom_codec_dec_cfg_t config;
+ PodZero(&config);
+ config.threads = decode_threads;
+ config.w = config.h = 0; // set after decode
+ config.allow_lowbitdepth = true;
+
+ aom_codec_flags_t flags = 0;
+
+ if (!dx || aom_codec_dec_init(&mCodec, dx, &config, flags)) {
+ return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
+ }
+ return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
+}
+
+void
+AOMDecoder::Flush()
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ mIsFlushing = true;
+ nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
+ // nothing to do for now.
+ });
+ SyncRunnable::DispatchToThread(mTaskQueue, r);
+ mIsFlushing = false;
+}
+
+// Ported from third_party/aom/tools_common.c.
+static aom_codec_err_t
+highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) {
+ int plane;
+ if (dst->d_w != src->d_w || dst->d_h != src->d_h)
+ return AOM_CODEC_INVALID_PARAM;
+ if (dst->x_chroma_shift != src->x_chroma_shift)
+ return AOM_CODEC_INVALID_PARAM;
+ if (dst->y_chroma_shift != src->y_chroma_shift)
+ return AOM_CODEC_INVALID_PARAM;
+ if (dst->fmt != (src->fmt & ~AOM_IMG_FMT_HIGHBITDEPTH))
+ return AOM_CODEC_INVALID_PARAM;
+ if (down_shift < 0)
+ return AOM_CODEC_INVALID_PARAM;
+ switch (dst->fmt) {
+ case AOM_IMG_FMT_I420:
+ case AOM_IMG_FMT_I422:
+ case AOM_IMG_FMT_I444:
+ break;
+ default:
+ return AOM_CODEC_INVALID_PARAM;
+ }
+ switch (src->fmt) {
+ case AOM_IMG_FMT_I42016:
+ case AOM_IMG_FMT_I42216:
+ case AOM_IMG_FMT_I44416:
+ break;
+ default:
+ // We don't support anything that's not 16 bit
+ return AOM_CODEC_UNSUP_BITSTREAM;
+ }
+ for (plane = 0; plane < 3; plane++) {
+ int w = src->d_w;
+ int h = src->d_h;
+ int x, y;
+ if (plane) {
+ w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
+ h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
+ }
+ for (y = 0; y < h; y++) {
+ uint16_t *p_src =
+ (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
+ uint8_t *p_dst =
+ dst->planes[plane] + y * dst->stride[plane];
+ for (x = 0; x < w; x++) *p_dst++ = (*p_src++ >> down_shift) & 0xFF;
+ }
+ }
+ return AOM_CODEC_OK;
+}
+
+// UniquePtr dtor wrapper for aom_image_t.
+struct AomImageFree {
+ void operator()(aom_image_t* img) { aom_img_free(img); }
+};
+
+MediaResult
+AOMDecoder::DoDecode(MediaRawData* aSample)
+{
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
+#if defined(DEBUG)
+ NS_ASSERTION(IsKeyframe(*aSample) == aSample->mKeyframe,
+ "AOM Decode Keyframe error sample->mKeyframe and si.si_kf out of sync");
+#endif
+
+ if (aom_codec_err_t r = aom_codec_decode(&mCodec, aSample->Data(), aSample->Size(), nullptr)) {
+ LOG("AOM Decode error: %s", aom_codec_err_to_string(r));
+ return MediaResult(
+ NS_ERROR_DOM_MEDIA_DECODE_ERR,
+ RESULT_DETAIL("AOM error decoding AV1 sample: %s", aom_codec_err_to_string(r)));
+ }
+
+ aom_codec_iter_t iter = nullptr;
+ aom_image_t *img;
+ UniquePtr<aom_image_t, AomImageFree> img8;
+
+ while ((img = aom_codec_get_frame(&mCodec, &iter))) {
+ // Track whether the underlying buffer is 8 or 16 bits per channel.
+ bool highbd = bool(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH);
+ if (highbd) {
+ // Downsample images with more than 8 bits per channel.
+ aom_img_fmt_t fmt8 = static_cast<aom_img_fmt_t>(img->fmt ^ AOM_IMG_FMT_HIGHBITDEPTH);
+ img8.reset(aom_img_alloc(NULL, fmt8, img->d_w, img->d_h, 16));
+ if (img8 == nullptr) {
+ LOG("Couldn't allocate bitdepth reduction target!");
+ return MediaResult(
+ NS_ERROR_OUT_OF_MEMORY,
+ RESULT_DETAIL("Couldn't allocate conversion buffer for AV1 frame"));
+ }
+ if (aom_codec_err_t r = highbd_img_downshift(img8.get(), img, img->bit_depth - 8)) {
+ return MediaResult(
+ NS_ERROR_DOM_MEDIA_DECODE_ERR,
+ RESULT_DETAIL("Error converting AV1 frame to 8 bits: %s",
+ aom_codec_err_to_string(r)));
+ }
+ // img normally points to storage owned by mCodec, so it is not freed.
+ // To copy out the contents of img8 we can overwrite img with an alias.
+ // Since img is assigned at the start of the while loop and img8 is held
+ // outside that loop, the alias won't outlive the storage it points to.
+ img = img8.get();
+ highbd = false;
+ }
+
+ NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 ||
+ img->fmt == AOM_IMG_FMT_I42016 ||
+ img->fmt == AOM_IMG_FMT_I444 ||
+ img->fmt == AOM_IMG_FMT_I44416,
+ "AV1 image format not I420 or I444");
+
+ // Chroma shifts are rounded down as per the decoding examples in the SDK
+ VideoData::YCbCrBuffer b;
+ b.mPlanes[0].mData = img->planes[0];
+ b.mPlanes[0].mStride = img->stride[0];
+ b.mPlanes[0].mHeight = img->d_h;
+ b.mPlanes[0].mWidth = img->d_w;
+ b.mPlanes[0].mOffset = 0;
+ b.mPlanes[0].mSkip = highbd ? 1 : 0;
+
+ b.mPlanes[1].mData = img->planes[1];
+ b.mPlanes[1].mStride = img->stride[1];
+ b.mPlanes[1].mOffset = 0;
+ b.mPlanes[1].mSkip = highbd ? 1 : 0;
+
+ b.mPlanes[2].mData = img->planes[2];
+ b.mPlanes[2].mStride = img->stride[2];
+ b.mPlanes[2].mOffset = 0;
+ b.mPlanes[2].mSkip = highbd ? 1 : 0;
+
+ if (img->fmt == AOM_IMG_FMT_I420 ||
+ img->fmt == AOM_IMG_FMT_I42016) {
+ b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
+ b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
+
+ b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
+ b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
+ } else if (img->fmt == AOM_IMG_FMT_I444) {
+ b.mPlanes[1].mHeight = img->d_h;
+ b.mPlanes[1].mWidth = img->d_w;
+
+ b.mPlanes[2].mHeight = img->d_h;
+ b.mPlanes[2].mWidth = img->d_w;
+ } else {
+ LOG("AOM Unknown image format");
+ return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
+ RESULT_DETAIL("AOM Unknown image format"));
+ }
+
+ RefPtr<VideoData> v =
+ VideoData::CreateAndCopyData(mInfo,
+ mImageContainer,
+ aSample->mOffset,
+ aSample->mTime,
+ aSample->mDuration,
+ b,
+ aSample->mKeyframe,
+ aSample->mTimecode,
+ mInfo.ScaledImageRect(img->d_w,
+ img->d_h));
+
+ if (!v) {
+ LOG("Image allocation error source %ux%u display %ux%u picture %ux%u",
+ img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height,
+ mInfo.mImage.width, mInfo.mImage.height);
+ return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__);
+ }
+ mCallback->Output(v);
+ }
+ return NS_OK;
+}
+
+void
+AOMDecoder::ProcessDecode(MediaRawData* aSample)
+{
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+ if (mIsFlushing) {
+ return;
+ }
+ MediaResult rv = DoDecode(aSample);
+ if (NS_FAILED(rv)) {
+ mCallback->Error(rv);
+ } else {
+ mCallback->InputExhausted();
+ }
+}
+
+void
+AOMDecoder::Input(MediaRawData* aSample)
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
+ this, &AOMDecoder::ProcessDecode, aSample));
+}
+
+void
+AOMDecoder::ProcessDrain()
+{
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+ mCallback->DrainComplete();
+}
+
+void
+AOMDecoder::Drain()
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ mTaskQueue->Dispatch(NewRunnableMethod(this, &AOMDecoder::ProcessDrain));
+}
+
+/* static */
+bool
+AOMDecoder::IsAV1(const nsACString& aMimeType)
+{
+ return aMimeType.EqualsLiteral("video/webm; codecs=av1") ||
+ aMimeType.EqualsLiteral("video/av1");
+}
+
+/* static */
+bool
+AOMDecoder::IsKeyframe(Span<const uint8_t> aBuffer) {
+ aom_codec_stream_info_t info;
+ PodZero(&info);
+
+ aom_codec_peek_stream_info(aom_codec_av1_dx(),
+ aBuffer.Elements(),
+ aBuffer.Length(),
+ &info);
+
+ return bool(info.is_kf);
+}
+
+/* static */
+nsIntSize
+AOMDecoder::GetFrameSize(Span<const uint8_t> aBuffer) {
+ aom_codec_stream_info_t info;
+ PodZero(&info);
+
+ aom_codec_peek_stream_info(aom_codec_av1_dx(),
+ aBuffer.Elements(),
+ aBuffer.Length(),
+ &info);
+
+ return nsIntSize(info.w, info.h);
+}
+
+} // namespace mozilla
+#undef LOG
diff --git a/dom/media/platforms/agnostic/AOMDecoder.h b/dom/media/platforms/agnostic/AOMDecoder.h
new file mode 100644
index 000000000..ec6b1f95a
--- /dev/null
+++ b/dom/media/platforms/agnostic/AOMDecoder.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(AOMDecoder_h_)
+#define AOMDecoder_h_
+
+#include "PlatformDecoderModule.h"
+#include "mozilla/Span.h"
+
+#include <stdint.h>
+#include "aom/aom_decoder.h"
+
+namespace mozilla {
+
+class AOMDecoder : public MediaDataDecoder
+{
+public:
+ explicit AOMDecoder(const CreateDecoderParams& aParams);
+
+ RefPtr<InitPromise> Init() override;
+ void Input(MediaRawData* aSample) override;
+ void Flush() override;
+ void Drain() override;
+ void Shutdown() override;
+ const char* GetDescriptionName() const override
+ {
+ return "libaom (AV1) video decoder";
+ }
+
+ // Return true if aMimeType is a one of the strings used
+ // by our demuxers to identify AV1 streams.
+ static bool IsAV1(const nsACString& aMimeType);
+
+ // Return true if a sample is a keyframe.
+ static bool IsKeyframe(Span<const uint8_t> aBuffer);
+
+ // Return the frame dimensions for a sample.
+ static nsIntSize GetFrameSize(Span<const uint8_t> aBuffer);
+
+private:
+ ~AOMDecoder();
+ void ProcessDecode(MediaRawData* aSample);
+ MediaResult DoDecode(MediaRawData* aSample);
+ void ProcessDrain();
+
+ const RefPtr<layers::ImageContainer> mImageContainer;
+ const RefPtr<TaskQueue> mTaskQueue;
+ MediaDataDecoderCallback* mCallback;
+ Atomic<bool> mIsFlushing;
+
+ // AOM decoder state
+ aom_codec_ctx_t mCodec;
+
+ const VideoInfo& mInfo;
+};
+
+} // namespace mozilla
+
+#endif // AOMDecoder_h_
diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
index 7bd75b7fe..cf5ed3d22 100644
--- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AgnosticDecoderModule.h"
+#include "MediaPrefs.h"
#include "mozilla/Logging.h"
#include "OpusDecoder.h"
#include "VorbisDecoder.h"
@@ -12,6 +13,10 @@
#include "WAVDecoder.h"
#include "TheoraDecoder.h"
+#ifdef MOZ_AV1
+#include "AOMDecoder.h"
+#endif
+
namespace mozilla {
bool
@@ -24,6 +29,11 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType,
VorbisDataDecoder::IsVorbis(aMimeType) ||
WaveDataDecoder::IsWave(aMimeType) ||
TheoraDecoder::IsTheora(aMimeType);
+#ifdef MOZ_AV1
+ if (MediaPrefs::AV1Enabled()) {
+ supports |= AOMDecoder::IsAV1(aMimeType);
+ }
+#endif
MOZ_LOG(sPDMLog, LogLevel::Debug, ("Agnostic decoder %s requested type",
supports ? "supports" : "rejects"));
return supports;
@@ -36,7 +46,14 @@ AgnosticDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
if (VPXDecoder::IsVPX(aParams.mConfig.mMimeType)) {
m = new VPXDecoder(aParams);
- } else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) {
+ }
+#ifdef MOZ_AV1
+ else if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType) &&
+ MediaPrefs::AV1Enabled()) {
+ m = new AOMDecoder(aParams);
+ }
+#endif
+ else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) {
m = new TheoraDecoder(aParams);
}
diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp
index 77c81b51b..f2f84487f 100644
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -22,7 +22,7 @@ namespace mozilla {
using namespace gfx;
using namespace layers;
-static int MimeTypeToCodec(const nsACString& aMimeType)
+static VPXDecoder::Codec MimeTypeToCodec(const nsACString& aMimeType)
{
if (aMimeType.EqualsLiteral("video/webm; codecs=vp8")) {
return VPXDecoder::Codec::VP8;
@@ -31,7 +31,7 @@ static int MimeTypeToCodec(const nsACString& aMimeType)
} else if (aMimeType.EqualsLiteral("video/vp9")) {
return VPXDecoder::Codec::VP9;
}
- return -1;
+ return VPXDecoder::Codec::Unknown;
}
VPXDecoder::VPXDecoder(const CreateDecoderParams& aParams)
@@ -101,17 +101,10 @@ MediaResult
VPXDecoder::DoDecode(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
#if defined(DEBUG)
- vpx_codec_stream_info_t si;
- PodZero(&si);
- si.sz = sizeof(si);
- if (mCodec == Codec::VP8) {
- vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aSample->Data(), aSample->Size(), &si);
- } else if (mCodec == Codec::VP9) {
- vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aSample->Data(), aSample->Size(), &si);
- }
- NS_ASSERTION(bool(si.is_kf) == aSample->mKeyframe,
- "VPX Decode Keyframe error sample->mKeyframe and si.si_kf out of sync");
+ NS_ASSERTION(IsKeyframe(*aSample, mCodec) == aSample->mKeyframe,
+ "VPX Decode Keyframe error sample->mKeyframe and sample data out of sync");
#endif
if (vpx_codec_err_t r = vpx_codec_decode(&mVPX, aSample->Data(), aSample->Size(), nullptr, 0)) {
@@ -249,5 +242,41 @@ VPXDecoder::IsVP9(const nsACString& aMimeType)
return IsVPX(aMimeType, VPXDecoder::VP9);
}
+/* static */
+bool
+VPXDecoder::IsKeyframe(Span<const uint8_t> aBuffer, Codec aCodec)
+{
+ vpx_codec_stream_info_t si;
+ PodZero(&si);
+ si.sz = sizeof(si);
+
+ if (aCodec == Codec::VP8) {
+ vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aBuffer.Elements(), aBuffer.Length(), &si);
+ return bool(si.is_kf);
+ } else if (aCodec == Codec::VP9) {
+ vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aBuffer.Elements(), aBuffer.Length(), &si);
+ return bool(si.is_kf);
+ }
+
+ return false;
+}
+
+/* static */
+nsIntSize
+VPXDecoder::GetFrameSize(Span<const uint8_t> aBuffer, Codec aCodec)
+{
+ vpx_codec_stream_info_t si;
+ PodZero(&si);
+ si.sz = sizeof(si);
+
+ if (aCodec == Codec::VP8) {
+ vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aBuffer.Elements(), aBuffer.Length(), &si);
+ } else if (aCodec == Codec::VP9) {
+ vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aBuffer.Elements(), aBuffer.Length(), &si);
+ }
+
+ return nsIntSize(si.w, si.h);
+}
+
} // namespace mozilla
#undef LOG
diff --git a/dom/media/platforms/agnostic/VPXDecoder.h b/dom/media/platforms/agnostic/VPXDecoder.h
index d420ec069..4e8d83617 100644
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -7,6 +7,7 @@
#define VPXDecoder_h_
#include "PlatformDecoderModule.h"
+#include "mozilla/Span.h"
#include <stdint.h>
#define VPX_DONT_DEFINE_STDINT_TYPES
@@ -36,7 +37,8 @@ public:
enum Codec: uint8_t {
VP8 = 1 << 0,
- VP9 = 1 << 1
+ VP9 = 1 << 1,
+ Unknown = 1 << 7,
};
// Return true if aMimeType is a one of the strings used by our demuxers to
@@ -46,6 +48,12 @@ public:
static bool IsVP8(const nsACString& aMimeType);
static bool IsVP9(const nsACString& aMimeType);
+ // Return true if a sample is a keyframe for the specified codec.
+ static bool IsKeyframe(Span<const uint8_t> aBuffer, Codec aCodec);
+
+ // Return the frame dimensions for a sample for the specified codec.
+ static nsIntSize GetFrameSize(Span<const uint8_t> aBuffer, Codec aCodec);
+
private:
void ProcessDecode(MediaRawData* aSample);
MediaResult DoDecode(MediaRawData* aSample);
@@ -61,7 +69,7 @@ private:
const VideoInfo& mInfo;
- const int mCodec;
+ const Codec mCodec;
};
} // namespace mozilla
diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
index 8cb5c8578..8655ce25f 100644
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
@@ -69,12 +69,21 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
mCodecContext->extradata_size = mExtraData->Length();
// FFmpeg may use SIMD instructions to access the data which reads the
// data in 32 bytes block. Must ensure we have enough data to read.
+ uint32_t padding_size =
#if LIBAVCODEC_VERSION_MAJOR >= 58
- mExtraData->AppendElements(AV_INPUT_BUFFER_PADDING_SIZE);
+ AV_INPUT_BUFFER_PADDING_SIZE;
#else
- mExtraData->AppendElements(FF_INPUT_BUFFER_PADDING_SIZE);
+ FF_INPUT_BUFFER_PADDING_SIZE;
#endif
- mCodecContext->extradata = mExtraData->Elements();
+ mCodecContext->extradata = static_cast<uint8_t*>(
+ mLib->av_malloc(mExtraData->Length() + padding_size));
+ if (!mCodecContext->extradata) {
+ return MediaResult(NS_ERROR_OUT_OF_MEMORY,
+ RESULT_DETAIL("Couldn't init ffmpeg extradata"));
+ }
+ memcpy(mCodecContext->extradata,
+ mExtraData->Elements(),
+ mExtraData->Length());
} else {
mCodecContext->extradata_size = 0;
}
@@ -165,6 +174,9 @@ FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown()
StaticMutexAutoLock mon(sMonitor);
if (mCodecContext) {
+ if (mCodecContext->extradata) {
+ mLib->av_freep(&mCodecContext->extradata);
+ }
mLib->avcodec_close(mCodecContext);
mLib->av_freep(&mCodecContext);
#if LIBAVCODEC_VERSION_MAJOR >= 55
diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
index 6302882a6..e1c326818 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
@@ -7,6 +7,7 @@
#include "MediaPrefs.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Types.h"
+#include "PlatformDecoderModule.h"
#include "prlink.h"
#define AV_LOG_DEBUG 48
diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
index d6944a1d8..c6c43a4ae 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
@@ -5,6 +5,7 @@
#ifndef __FFmpegLibWrapper_h__
#define __FFmpegLibWrapper_h__
+#include "mozilla/Attributes.h"
#include "mozilla/Types.h"
struct AVCodec;
@@ -91,4 +92,4 @@ private:
} // namespace mozilla
-#endif // FFmpegLibWrapper \ No newline at end of file
+#endif // FFmpegLibWrapper
diff --git a/dom/media/platforms/ffmpeg/ffvpx/moz.build b/dom/media/platforms/ffmpeg/ffvpx/moz.build
index aee58b5b0..c0041a4d4 100644
--- a/dom/media/platforms/ffmpeg/ffvpx/moz.build
+++ b/dom/media/platforms/ffmpeg/ffvpx/moz.build
@@ -20,7 +20,7 @@ SOURCES += [
]
LOCAL_INCLUDES += [
'..',
- '../ffmpeg57/include',
+ '../ffmpeg58/include',
]
if CONFIG['OS_ARCH'] == 'WINNT':
diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build
index 3fb0cc842..be13d31c4 100644
--- a/dom/media/platforms/moz.build
+++ b/dom/media/platforms/moz.build
@@ -55,6 +55,14 @@ if CONFIG['MOZ_FFMPEG']:
'ffmpeg',
]
+if CONFIG['MOZ_AV1']:
+ EXPORTS += [
+ 'agnostic/AOMDecoder.h',
+ ]
+ UNIFIED_SOURCES += [
+ 'agnostic/AOMDecoder.cpp',
+ ]
+
if CONFIG['MOZ_APPLEMEDIA']:
EXPORTS += [
'apple/AppleDecoderModule.h',
diff --git a/dom/media/test/bug580982.webm b/dom/media/test/bug1377278.webm
index 802019f39..802019f39 100644
--- a/dom/media/test/bug580982.webm
+++ b/dom/media/test/bug1377278.webm
Binary files differ
diff --git a/dom/media/test/bug580982.webm^headers^ b/dom/media/test/bug1377278.webm^headers^
index 4030ea1d3..4030ea1d3 100644
--- a/dom/media/test/bug580982.webm^headers^
+++ b/dom/media/test/bug1377278.webm^headers^
diff --git a/dom/media/test/manifest.js b/dom/media/test/manifest.js
index c6d533c1b..7e30cc97d 100644
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -224,6 +224,9 @@ var gPlayTests = [
// Test playback of a webm file
{ name:"seek-short.webm", type:"video/webm", duration:0.23 },
+ // Test playback of a webm file with 'matroska' doctype
+ { name:"bug1377278.webm", type:"video/webm", duration:4.0 },
+
// Test playback of a WebM file with non-zero start time.
{ name:"split.webm", type:"video/webm", duration:1.967 },
@@ -532,7 +535,6 @@ var gErrorTests = [
{ name:"448636.ogv", type:"video/ogg" },
{ name:"bug504843.ogv", type:"video/ogg" },
{ name:"bug501279.ogg", type:"audio/ogg" },
- { name:"bug580982.webm", type:"video/webm" },
{ name:"bug603918.webm", type:"video/webm" },
{ name:"bug604067.webm", type:"video/webm" },
{ name:"bogus.duh", type:"bogus/duh" }
diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini
index ddabf78b6..742ac1b1c 100644
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -382,8 +382,6 @@ support-files =
bug556821.ogv^headers^
bug557094.ogv
bug557094.ogv^headers^
- bug580982.webm
- bug580982.webm^headers^
bug603918.webm
bug603918.webm^headers^
bug604067.webm
@@ -395,6 +393,8 @@ support-files =
bug1301226.wav^headers^
bug1301226-odd.wav
bug1301226-odd.wav^headers^
+ bug1377278.webm
+ bug1377278.webm^headers^
can_play_type_dash.js
can_play_type_ogg.js
can_play_type_wave.js
diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp
index b41de6d40..9575d6e42 100644
--- a/dom/media/webm/WebMDecoder.cpp
+++ b/dom/media/webm/WebMDecoder.cpp
@@ -5,6 +5,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Preferences.h"
+#ifdef MOZ_AV1
+#include "AOMDecoder.h"
+#endif
+#include "MediaPrefs.h"
#include "MediaDecoderStateMachine.h"
#include "WebMDemuxer.h"
#include "WebMDecoder.h"
@@ -65,6 +69,11 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
continue;
}
+#ifdef MOZ_AV1
+ if (MediaPrefs::AV1Enabled() && IsAV1CodecString(codec)) {
+ continue;
+ }
+#endif
// Some unsupported codec.
return false;
}
diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp
index 20ed71581..013da9b2c 100644
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -8,7 +8,11 @@
#include "MediaDecoderStateMachine.h"
#include "AbstractMediaDecoder.h"
#include "MediaResource.h"
+#ifdef MOZ_AV1
+#include "AOMDecoder.h"
+#endif
#include "OpusDecoder.h"
+#include "VPXDecoder.h"
#include "WebMDemuxer.h"
#include "WebMBufferedParser.h"
#include "gfx2DGlue.h"
@@ -24,12 +28,9 @@
#include "mozilla/Sprintf.h"
#include <algorithm>
+#include <numeric>
#include <stdint.h>
-#define VPX_DONT_DEFINE_STDINT_TYPES
-#include "vpx/vp8dx.h"
-#include "vpx/vpx_decoder.h"
-
#define WEBM_DEBUG(arg, ...) MOZ_LOG(gMediaDemuxerLog, mozilla::LogLevel::Debug, ("WebMDemuxer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
extern mozilla::LazyLogModule gMediaDemuxerLog;
@@ -322,6 +323,9 @@ WebMDemuxer::ReadMetadata()
case NESTEGG_CODEC_VP9:
mInfo.mVideo.mMimeType = "video/webm; codecs=vp9";
break;
+ case NESTEGG_CODEC_AV1:
+ mInfo.mVideo.mMimeType = "video/webm; codecs=av1";
+ break;
default:
NS_WARNING("Unknown WebM video codec");
return NS_ERROR_FAILURE;
@@ -549,7 +553,7 @@ WebMDemuxer::GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber) {
return crypto;
}
-bool
+nsresult
WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples)
{
if (mIsMediaSource) {
@@ -557,17 +561,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
EnsureUpToDateIndex();
}
- RefPtr<NesteggPacketHolder> holder(NextPacket(aType));
+ RefPtr<NesteggPacketHolder> holder;
+ nsresult rv = NextPacket(aType, holder);
- if (!holder) {
- return false;
+ if (NS_FAILED(rv)) {
+ return rv;
}
int r = 0;
unsigned int count = 0;
r = nestegg_packet_count(holder->Packet(), &count);
if (r == -1) {
- return false;
+ return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
int64_t tstamp = holder->Timestamp();
int64_t duration = holder->Duration();
@@ -578,7 +583,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
// video frame.
int64_t next_tstamp = INT64_MIN;
if (aType == TrackInfo::kAudioTrack) {
- RefPtr<NesteggPacketHolder> next_holder(NextPacket(aType));
+ RefPtr<NesteggPacketHolder> next_holder;
+ rv = NextPacket(aType, next_holder);
+ if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+ return rv;
+ }
if (next_holder) {
next_tstamp = next_holder->Timestamp();
PushAudioPacket(next_holder);
@@ -593,7 +602,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
}
mLastAudioFrameTime = Some(tstamp);
} else if (aType == TrackInfo::kVideoTrack) {
- RefPtr<NesteggPacketHolder> next_holder(NextPacket(aType));
+ RefPtr<NesteggPacketHolder> next_holder;
+ rv = NextPacket(aType, next_holder);
+ if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+ return rv;
+ }
if (next_holder) {
next_tstamp = next_holder->Timestamp();
PushVideoPacket(next_holder);
@@ -610,7 +623,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
}
if (mIsMediaSource && next_tstamp == INT64_MIN) {
- return false;
+ return NS_ERROR_DOM_MEDIA_END_OF_STREAM;
}
int64_t discardPadding = 0;
@@ -626,7 +639,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
r = nestegg_packet_data(holder->Packet(), i, &data, &length);
if (r == -1) {
WEBM_DEBUG("nestegg_packet_data failed r=%d", r);
- return false;
+ return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
bool isKeyframe = false;
if (aType == TrackInfo::kAudioTrack) {
@@ -636,29 +649,46 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
// Packet is encrypted, can't peek, use packet info
isKeyframe = nestegg_packet_has_keyframe(holder->Packet()) == NESTEGG_PACKET_HAS_KEYFRAME_TRUE;
} else {
- vpx_codec_stream_info_t si;
- PodZero(&si);
- si.sz = sizeof(si);
+ auto sample = MakeSpan(data, length);
switch (mVideoCodec) {
case NESTEGG_CODEC_VP8:
- vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si);
+ isKeyframe = VPXDecoder::IsKeyframe(sample, VPXDecoder::Codec::VP8);
break;
case NESTEGG_CODEC_VP9:
- vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si);
+ isKeyframe = VPXDecoder::IsKeyframe(sample, VPXDecoder::Codec::VP9);
+ break;
+#ifdef MOZ_AV1
+ case NESTEGG_CODEC_AV1:
+ isKeyframe = AOMDecoder::IsKeyframe(sample);
break;
+#endif
+ default:
+ NS_WARNING("Cannot detect keyframes in unknown WebM video codec");
+ return NS_ERROR_FAILURE;
}
- isKeyframe = si.is_kf;
if (isKeyframe) {
- // We only look for resolution changes on keyframes for both VP8 and
- // VP9. Other resolution changes are invalid.
- if (mLastSeenFrameWidth.isSome() && mLastSeenFrameHeight.isSome() &&
- (si.w != mLastSeenFrameWidth.value() ||
- si.h != mLastSeenFrameHeight.value())) {
- mInfo.mVideo.mDisplay = nsIntSize(si.w, si.h);
+ // For both VP8 and VP9, we only look for resolution changes
+ // on keyframes. Other resolution changes are invalid.
+ auto dimensions = nsIntSize(0, 0);
+ switch (mVideoCodec) {
+ case NESTEGG_CODEC_VP8:
+ dimensions = VPXDecoder::GetFrameSize(sample, VPXDecoder::Codec::VP8);
+ break;
+ case NESTEGG_CODEC_VP9:
+ dimensions = VPXDecoder::GetFrameSize(sample, VPXDecoder::Codec::VP9);
+ break;
+#ifdef MOZ_AV1
+ case NESTEGG_CODEC_AV1:
+ dimensions = AOMDecoder::GetFrameSize(sample);
+ break;
+#endif
+ }
+ if (mLastSeenFrameSize.isSome()
+ && (dimensions != mLastSeenFrameSize.value())) {
+ mInfo.mVideo.mDisplay = dimensions;
mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID);
}
- mLastSeenFrameWidth = Some(si.w);
- mLastSeenFrameHeight = Some(si.h);
+ mLastSeenFrameSize = Some(dimensions);
}
}
}
@@ -668,7 +698,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
RefPtr<MediaRawData> sample = new MediaRawData(data, length);
if (length && !sample->Data()) {
// OOM.
- return false;
+ return NS_ERROR_OUT_OF_MEMORY;
}
sample->mTimecode = tstamp;
sample->mTime = tstamp;
@@ -721,11 +751,12 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
}
aSamples->Push(sample);
}
- return true;
+ return NS_OK;
}
-RefPtr<NesteggPacketHolder>
-WebMDemuxer::NextPacket(TrackInfo::TrackType aType)
+nsresult
+WebMDemuxer::NextPacket(TrackInfo::TrackType aType,
+ RefPtr<NesteggPacketHolder>& aPacket)
{
bool isVideo = aType == TrackInfo::kVideoTrack;
@@ -734,56 +765,64 @@ WebMDemuxer::NextPacket(TrackInfo::TrackType aType)
bool hasType = isVideo ? mHasVideo : mHasAudio;
if (!hasType) {
- return nullptr;
+ return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
// The packet queue for the type that we are interested in.
WebMPacketQueue &packets = isVideo ? mVideoPackets : mAudioPackets;
if (packets.GetSize() > 0) {
- return packets.PopFront();
+ aPacket = packets.PopFront();
+ return NS_OK;
}
// Track we are interested in
uint32_t ourTrack = isVideo ? mVideoTrack : mAudioTrack;
do {
- RefPtr<NesteggPacketHolder> holder = DemuxPacket(aType);
+ RefPtr<NesteggPacketHolder> holder;
+ nsresult rv = DemuxPacket(aType, holder);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
if (!holder) {
- return nullptr;
+ return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
if (ourTrack == holder->Track()) {
- return holder;
+ aPacket = holder;
+ return NS_OK;
}
} while (true);
}
-RefPtr<NesteggPacketHolder>
-WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType)
+nsresult
+WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType,
+ RefPtr<NesteggPacketHolder>& aPacket)
{
nestegg_packet* packet;
int r = nestegg_read_packet(Context(aType), &packet);
if (r == 0) {
nestegg_read_reset(Context(aType));
- return nullptr;
+ return NS_ERROR_DOM_MEDIA_END_OF_STREAM;
} else if (r < 0) {
- return nullptr;
+ return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
unsigned int track = 0;
r = nestegg_packet_track(packet, &track);
if (r == -1) {
- return nullptr;
+ return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
int64_t offset = Resource(aType).Tell();
RefPtr<NesteggPacketHolder> holder = new NesteggPacketHolder();
if (!holder->Init(packet, offset, track, false)) {
- return nullptr;
+ return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
- return holder;
+ aPacket = holder;
+ return NS_OK;
}
void
@@ -943,7 +982,14 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime)
media::TimeUnit seekTime = aTime;
mSamples.Reset();
mParent->SeekInternal(mType, aTime);
- mParent->GetNextPacket(mType, &mSamples);
+ nsresult rv = mParent->GetNextPacket(mType, &mSamples);
+ if (NS_FAILED(rv)) {
+ if (rv == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+ // Ignore the error for now, the next GetSample will be rejected with EOS.
+ return SeekPromise::CreateAndResolve(media::TimeUnit(), __func__);
+ }
+ return SeekPromise::CreateAndReject(rv, __func__);
+ }
mNeedKeyframe = true;
// Check what time we actually seeked to.
@@ -956,15 +1002,18 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime)
return SeekPromise::CreateAndResolve(seekTime, __func__);
}
-RefPtr<MediaRawData>
-WebMTrackDemuxer::NextSample()
+nsresult
+WebMTrackDemuxer::NextSample(RefPtr<MediaRawData>& aData)
{
- while (mSamples.GetSize() < 1 && mParent->GetNextPacket(mType, &mSamples)) {
+ nsresult rv;
+ while (mSamples.GetSize() < 1 &&
+ NS_SUCCEEDED((rv = mParent->GetNextPacket(mType, &mSamples)))) {
}
if (mSamples.GetSize()) {
- return mSamples.PopFront();
+ aData = mSamples.PopFront();
+ return NS_OK;
}
- return nullptr;
+ return rv;
}
RefPtr<WebMTrackDemuxer::SamplesPromise>
@@ -973,9 +1022,12 @@ WebMTrackDemuxer::GetSamples(int32_t aNumSamples)
RefPtr<SamplesHolder> samples = new SamplesHolder;
MOZ_ASSERT(aNumSamples);
+ nsresult rv = NS_ERROR_DOM_MEDIA_END_OF_STREAM;
+
while (aNumSamples) {
- RefPtr<MediaRawData> sample(NextSample());
- if (!sample) {
+ RefPtr<MediaRawData> sample;
+ rv = NextSample(sample);
+ if (NS_FAILED(rv)) {
break;
}
if (mNeedKeyframe && !sample->mKeyframe) {
@@ -987,7 +1039,7 @@ WebMTrackDemuxer::GetSamples(int32_t aNumSamples)
}
if (samples->mSamples.IsEmpty()) {
- return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
+ return SamplesPromise::CreateAndReject(rv, __func__);
} else {
UpdateSamples(samples->mSamples);
return SamplesPromise::CreateAndResolve(samples, __func__);
@@ -1022,7 +1074,8 @@ WebMTrackDemuxer::SetNextKeyFrameTime()
}
// Demux and buffer frames until we find a keyframe.
RefPtr<MediaRawData> sample;
- while (!foundKeyframe && (sample = NextSample())) {
+ nsresult rv = NS_OK;
+ while (!foundKeyframe && NS_SUCCEEDED((rv = NextSample(sample)))) {
if (sample->mKeyframe) {
frameTime = sample->mTime;
foundKeyframe = true;
@@ -1104,10 +1157,11 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
uint32_t parsed = 0;
bool found = false;
RefPtr<MediaRawData> sample;
+ nsresult rv = NS_OK;
int64_t sampleTime;
WEBM_DEBUG("TimeThreshold: %f", aTimeThreshold.ToSeconds());
- while (!found && (sample = NextSample())) {
+ while (!found && NS_SUCCEEDED((rv = NextSample(sample)))) {
parsed++;
sampleTime = sample->mTime;
if (sample->mKeyframe && sampleTime >= aTimeThreshold.ToMicroseconds()) {
@@ -1116,7 +1170,9 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
mSamples.PushFront(sample.forget());
}
}
- SetNextKeyFrameTime();
+ if (NS_SUCCEEDED(rv)) {
+ SetNextKeyFrameTime();
+ }
if (found) {
WEBM_DEBUG("next sample: %f (parsed: %d)",
media::TimeUnit::FromMicroseconds(sampleTime).ToSeconds(),
diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h
index 6fff38e7d..36d381e57 100644
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -8,9 +8,13 @@
#include "nsTArray.h"
#include "MediaDataDemuxer.h"
+#include "MediaResource.h"
#include "NesteggPacketHolder.h"
#include "mozilla/Move.h"
+#include <deque>
+#include <stdint.h>
+
typedef struct nestegg nestegg;
namespace mozilla {
@@ -111,7 +115,8 @@ public:
bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
// Demux next WebM packet and append samples to MediaRawDataQueue
- bool GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples);
+ nsresult GetNextPacket(TrackInfo::TrackType aType,
+ MediaRawDataQueue *aSamples);
nsresult Reset(TrackInfo::TrackType aType);
@@ -175,11 +180,13 @@ private:
// Read a packet from the nestegg file. Returns nullptr if all packets for
// the particular track have been read. Pass TrackInfo::kVideoTrack or
// TrackInfo::kVideoTrack to indicate the type of the packet we want to read.
- RefPtr<NesteggPacketHolder> NextPacket(TrackInfo::TrackType aType);
+ nsresult NextPacket(TrackInfo::TrackType aType,
+ RefPtr<NesteggPacketHolder>& aPacket);
// Internal method that demuxes the next packet from the stream. The caller
// is responsible for making sure it doesn't get lost.
- RefPtr<NesteggPacketHolder> DemuxPacket(TrackInfo::TrackType aType);
+ nsresult DemuxPacket(TrackInfo::TrackType aType,
+ RefPtr<NesteggPacketHolder>& aPacket);
// libnestegg audio and video context for webm container.
// Access on reader's thread only.
@@ -237,8 +244,7 @@ private:
int64_t mLastWebMBlockOffset;
const bool mIsMediaSource;
- Maybe<uint32_t> mLastSeenFrameWidth;
- Maybe<uint32_t> mLastSeenFrameHeight;
+ Maybe<nsIntSize> mLastSeenFrameSize;
// This will be populated only if a resolution change occurs, otherwise it
// will be left as null so the original metadata is used
RefPtr<SharedTrackInfo> mSharedVideoTrackInfo;
@@ -276,7 +282,7 @@ private:
~WebMTrackDemuxer();
void UpdateSamples(nsTArray<RefPtr<MediaRawData>>& aSamples);
void SetNextKeyFrameTime();
- RefPtr<MediaRawData> NextSample ();
+ nsresult NextSample(RefPtr<MediaRawData>& aData);
RefPtr<WebMDemuxer> mParent;
TrackInfo::TrackType mType;
UniquePtr<TrackInfo> mInfo;
diff --git a/dom/webidl/CommandEvent.webidl b/dom/webidl/CommandEvent.webidl
index 8c16e856c..9856c77c3 100644
--- a/dom/webidl/CommandEvent.webidl
+++ b/dom/webidl/CommandEvent.webidl
@@ -8,7 +8,7 @@ interface CommandEvent : Event {
readonly attribute DOMString? command;
void initCommandEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- DOMString? command);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional DOMString? command = null);
};
diff --git a/dom/webidl/CompositionEvent.webidl b/dom/webidl/CompositionEvent.webidl
index c293683ce..e4a54d678 100644
--- a/dom/webidl/CompositionEvent.webidl
+++ b/dom/webidl/CompositionEvent.webidl
@@ -25,9 +25,9 @@ interface CompositionEvent : UIEvent
partial interface CompositionEvent
{
void initCompositionEvent(DOMString typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- Window? viewArg,
- DOMString? dataArg,
- DOMString localeArg);
+ optional boolean canBubbleArg = false,
+ optional boolean cancelableArg = false,
+ optional Window? viewArg = null,
+ optional DOMString? dataArg = null,
+ optional DOMString localeArg = "");
};
diff --git a/dom/webidl/CustomEvent.webidl b/dom/webidl/CustomEvent.webidl
index 299a41ec0..1ea5572b7 100644
--- a/dom/webidl/CustomEvent.webidl
+++ b/dom/webidl/CustomEvent.webidl
@@ -19,9 +19,9 @@ interface CustomEvent : Event
// initCustomEvent is a Gecko specific deprecated method.
[Throws]
void initCustomEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- any detail);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional any detail = null);
};
dictionary CustomEventInit : EventInit
diff --git a/dom/webidl/DeviceMotionEvent.webidl b/dom/webidl/DeviceMotionEvent.webidl
index fa4ecf3ca..c26ab080c 100644
--- a/dom/webidl/DeviceMotionEvent.webidl
+++ b/dom/webidl/DeviceMotionEvent.webidl
@@ -48,10 +48,10 @@ dictionary DeviceMotionEventInit : EventInit {
// Mozilla extensions.
partial interface DeviceMotionEvent {
void initDeviceMotionEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- DeviceAccelerationInit acceleration,
- DeviceAccelerationInit accelerationIncludingGravity,
- DeviceRotationRateInit rotationRate,
- double? interval);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional DeviceAccelerationInit acceleration,
+ optional DeviceAccelerationInit accelerationIncludingGravity,
+ optional DeviceRotationRateInit rotationRate,
+ optional double? interval = null);
};
diff --git a/dom/webidl/DeviceOrientationEvent.webidl b/dom/webidl/DeviceOrientationEvent.webidl
index 46194453e..9802b3681 100644
--- a/dom/webidl/DeviceOrientationEvent.webidl
+++ b/dom/webidl/DeviceOrientationEvent.webidl
@@ -14,12 +14,12 @@ interface DeviceOrientationEvent : Event
// initDeviceOrientationEvent is a Gecko specific deprecated method.
void initDeviceOrientationEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- double? alpha,
- double? beta,
- double? gamma,
- boolean absolute);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional double? alpha = null,
+ optional double? beta = null,
+ optional double? gamma = null,
+ optional boolean absolute = false);
};
dictionary DeviceOrientationEventInit : EventInit
diff --git a/dom/webidl/DragEvent.webidl b/dom/webidl/DragEvent.webidl
index 2cc173d5c..806177790 100644
--- a/dom/webidl/DragEvent.webidl
+++ b/dom/webidl/DragEvent.webidl
@@ -10,21 +10,21 @@ interface DragEvent : MouseEvent
readonly attribute DataTransfer? dataTransfer;
void initDragEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- Window? aView,
- long aDetail,
- long aScreenX,
- long aScreenY,
- long aClientX,
- long aClientY,
- boolean aCtrlKey,
- boolean aAltKey,
- boolean aShiftKey,
- boolean aMetaKey,
- unsigned short aButton,
- EventTarget? aRelatedTarget,
- DataTransfer? aDataTransfer);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional Window? aView = null,
+ optional long aDetail = 0,
+ optional long aScreenX = 0,
+ optional long aScreenY = 0,
+ optional long aClientX = 0,
+ optional long aClientY = 0,
+ optional boolean aCtrlKey = false,
+ optional boolean aAltKey = false,
+ optional boolean aShiftKey = false,
+ optional boolean aMetaKey = false,
+ optional unsigned short aButton = 0,
+ optional EventTarget? aRelatedTarget = null,
+ optional DataTransfer? aDataTransfer = null);
};
dictionary DragEventInit : MouseEventInit
diff --git a/dom/webidl/Event.webidl b/dom/webidl/Event.webidl
index 70a0ef513..a5d7da7d4 100644
--- a/dom/webidl/Event.webidl
+++ b/dom/webidl/Event.webidl
@@ -51,7 +51,9 @@ interface Event {
[Pure]
readonly attribute DOMHighResTimeStamp timeStamp;
- void initEvent(DOMString type, boolean bubbles, boolean cancelable);
+ void initEvent(DOMString type,
+ optional boolean bubbles = false,
+ optional boolean cancelable = false);
attribute boolean cancelBubble;
};
diff --git a/dom/webidl/HashChangeEvent.webidl b/dom/webidl/HashChangeEvent.webidl
index 735e8eb28..6e8be455c 100644
--- a/dom/webidl/HashChangeEvent.webidl
+++ b/dom/webidl/HashChangeEvent.webidl
@@ -11,10 +11,10 @@ interface HashChangeEvent : Event
readonly attribute DOMString newURL;
void initHashChangeEvent(DOMString typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- DOMString oldURLArg,
- DOMString newURLArg);
+ optional boolean canBubbleArg = false,
+ optional boolean cancelableArg = false,
+ optional DOMString oldURLArg = "",
+ optional DOMString newURLArg = "");
};
dictionary HashChangeEventInit : EventInit
diff --git a/dom/webidl/KeyEvent.webidl b/dom/webidl/KeyEvent.webidl
index 516632854..abb4b6a34 100644
--- a/dom/webidl/KeyEvent.webidl
+++ b/dom/webidl/KeyEvent.webidl
@@ -225,13 +225,13 @@ interface KeyEvent
const unsigned long DOM_VK_WIN_OEM_CLEAR = 0xFE;
void initKeyEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- Window? view,
- boolean ctrlKey,
- boolean altKey,
- boolean shiftKey,
- boolean metaKey,
- unsigned long keyCode,
- unsigned long charCode);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional Window? view = null,
+ optional boolean ctrlKey = false,
+ optional boolean altKey = false,
+ optional boolean shiftKey = false,
+ optional boolean metaKey = false,
+ optional unsigned long keyCode = 0,
+ optional unsigned long charCode = 0);
};
diff --git a/dom/webidl/MessageEvent.webidl b/dom/webidl/MessageEvent.webidl
index 548f14520..be5022d67 100644
--- a/dom/webidl/MessageEvent.webidl
+++ b/dom/webidl/MessageEvent.webidl
@@ -43,10 +43,14 @@ interface MessageEvent : Event {
[Pure, Cached, Frozen]
readonly attribute sequence<MessagePort> ports;
- void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable,
- any data, DOMString origin, DOMString lastEventId,
- (WindowProxy or MessagePort)? source,
- sequence<MessagePort> ports);
+ void initMessageEvent(DOMString type,
+ optional boolean bubbles = false,
+ optional boolean cancelable = false,
+ optional any data = null,
+ optional DOMString origin = "",
+ optional DOMString lastEventId = "",
+ optional (WindowProxy or MessagePort)? source = null,
+ optional sequence<MessagePort> ports = []);
};
dictionary MessageEventInit : EventInit {
diff --git a/dom/webidl/MouseEvent.webidl b/dom/webidl/MouseEvent.webidl
index d21354801..192519d57 100644
--- a/dom/webidl/MouseEvent.webidl
+++ b/dom/webidl/MouseEvent.webidl
@@ -32,21 +32,21 @@ interface MouseEvent : UIEvent {
readonly attribute long movementY;
// Deprecated in DOM Level 3:
- void initMouseEvent(DOMString typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- Window? viewArg,
- long detailArg,
- long screenXArg,
- long screenYArg,
- long clientXArg,
- long clientYArg,
- boolean ctrlKeyArg,
- boolean altKeyArg,
- boolean shiftKeyArg,
- boolean metaKeyArg,
- short buttonArg,
- EventTarget? relatedTargetArg);
+void initMouseEvent(DOMString typeArg,
+ optional boolean canBubbleArg = false,
+ optional boolean cancelableArg = false,
+ optional Window? viewArg = null,
+ optional long detailArg = 0,
+ optional long screenXArg = 0,
+ optional long screenYArg = 0,
+ optional long clientXArg = 0,
+ optional long clientYArg = 0,
+ optional boolean ctrlKeyArg = false,
+ optional boolean altKeyArg = false,
+ optional boolean shiftKeyArg = false,
+ optional boolean metaKeyArg = false,
+ optional short buttonArg = 0,
+ optional EventTarget? relatedTargetArg = null);
// Introduced in DOM Level 3:
boolean getModifierState(DOMString keyArg);
};
@@ -90,23 +90,23 @@ partial interface MouseEvent
readonly attribute unsigned short mozInputSource;
- void initNSMouseEvent(DOMString typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- Window? viewArg,
- long detailArg,
- long screenXArg,
- long screenYArg,
- long clientXArg,
- long clientYArg,
- boolean ctrlKeyArg,
- boolean altKeyArg,
- boolean shiftKeyArg,
- boolean metaKeyArg,
- short buttonArg,
- EventTarget? relatedTargetArg,
- float pressure,
- unsigned short inputSourceArg);
+ void initNSMouseEvent(DOMString typeArg,
+ optional boolean canBubbleArg = false,
+ optional boolean cancelableArg = false,
+ optional Window? viewArg = null,
+ optional long detailArg = 0,
+ optional long screenXArg = 0,
+ optional long screenYArg = 0,
+ optional long clientXArg = 0,
+ optional long clientYArg = 0,
+ optional boolean ctrlKeyArg = false,
+ optional boolean altKeyArg = false,
+ optional boolean shiftKeyArg = false,
+ optional boolean metaKeyArg = false,
+ optional short buttonArg = 0,
+ optional EventTarget? relatedTargetArg = null,
+ optional float pressure = 0,
+ optional unsigned short inputSourceArg = 0);
[ChromeOnly]
readonly attribute boolean hitCluster; // True when touch occurs in a cluster of links
diff --git a/dom/webidl/MouseScrollEvent.webidl b/dom/webidl/MouseScrollEvent.webidl
index aa9e30fd2..c1e52bd8c 100644
--- a/dom/webidl/MouseScrollEvent.webidl
+++ b/dom/webidl/MouseScrollEvent.webidl
@@ -12,19 +12,19 @@ interface MouseScrollEvent : MouseEvent
readonly attribute long axis;
void initMouseScrollEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- Window? view,
- long detail,
- long screenX,
- long screenY,
- long clientX,
- long clientY,
- boolean ctrlKey,
- boolean altKey,
- boolean shiftKey,
- boolean metaKey,
- unsigned short button,
- EventTarget? relatedTarget,
- long axis);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional Window? view = null,
+ optional long detail = 0,
+ optional long screenX = 0,
+ optional long screenY = 0,
+ optional long clientX = 0,
+ optional long clientY = 0,
+ optional boolean ctrlKey = false,
+ optional boolean altKey = false,
+ optional boolean shiftKey = false,
+ optional boolean metaKey = false,
+ optional short button = 0,
+ optional EventTarget? relatedTarget = null,
+ optional long axis = 0);
};
diff --git a/dom/webidl/MutationEvent.webidl b/dom/webidl/MutationEvent.webidl
index 43c7b1cd0..53625b4f9 100644
--- a/dom/webidl/MutationEvent.webidl
+++ b/dom/webidl/MutationEvent.webidl
@@ -23,11 +23,11 @@ interface MutationEvent : Event
[Throws]
void initMutationEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- Node? relatedNode,
- DOMString prevValue,
- DOMString newValue,
- DOMString attrName,
- unsigned short attrChange);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional Node? relatedNode = null,
+ optional DOMString prevValue = "",
+ optional DOMString newValue = "",
+ optional DOMString attrName = "",
+ optional unsigned short attrChange = 0);
};
diff --git a/dom/webidl/ScrollAreaEvent.webidl b/dom/webidl/ScrollAreaEvent.webidl
index 0f48b4bc8..f24b7c0ad 100644
--- a/dom/webidl/ScrollAreaEvent.webidl
+++ b/dom/webidl/ScrollAreaEvent.webidl
@@ -12,12 +12,12 @@ interface ScrollAreaEvent : UIEvent
readonly attribute float height;
void initScrollAreaEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- Window? view,
- long detail,
- float x,
- float y,
- float width,
- float height);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional Window? view = null,
+ optional long detail = 0,
+ optional float x = 0,
+ optional float y = 0,
+ optional float width = 0,
+ optional float height = 0);
};
diff --git a/dom/webidl/SimpleGestureEvent.webidl b/dom/webidl/SimpleGestureEvent.webidl
index 0829076dd..76d0d20f6 100644
--- a/dom/webidl/SimpleGestureEvent.webidl
+++ b/dom/webidl/SimpleGestureEvent.webidl
@@ -25,22 +25,22 @@ interface SimpleGestureEvent : MouseEvent
readonly attribute unsigned long clickCount;
void initSimpleGestureEvent(DOMString typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- Window? viewArg,
- long detailArg,
- long screenXArg,
- long screenYArg,
- long clientXArg,
- long clientYArg,
- boolean ctrlKeyArg,
- boolean altKeyArg,
- boolean shiftKeyArg,
- boolean metaKeyArg,
- unsigned short buttonArg,
- EventTarget? relatedTargetArg,
- unsigned long allowedDirectionsArg,
- unsigned long directionArg,
- double deltaArg,
- unsigned long clickCount);
+ optional boolean canBubbleArg = false,
+ optional boolean cancelableArg = false,
+ optional Window? viewArg = null,
+ optional long detailArg = 0,
+ optional long screenXArg = 0,
+ optional long screenYArg = 0,
+ optional long clientXArg = 0,
+ optional long clientYArg = 0,
+ optional boolean ctrlKeyArg = false,
+ optional boolean altKeyArg = false,
+ optional boolean shiftKeyArg = false,
+ optional boolean metaKeyArg = false,
+ optional short buttonArg = 0,
+ optional EventTarget? relatedTargetArg = null,
+ optional unsigned long allowedDirectionsArg = 0,
+ optional unsigned long directionArg = 0,
+ optional double deltaArg = 0,
+ optional unsigned long clickCount = 0);
};
diff --git a/dom/webidl/StorageEvent.webidl b/dom/webidl/StorageEvent.webidl
index c3e9605eb..e03f8232c 100644
--- a/dom/webidl/StorageEvent.webidl
+++ b/dom/webidl/StorageEvent.webidl
@@ -21,13 +21,13 @@ interface StorageEvent : Event
// Bug 1016053 - This is not spec compliant.
void initStorageEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- DOMString? key,
- DOMString? oldValue,
- DOMString? newValue,
- DOMString? url,
- Storage? storageArea);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional DOMString? key = null,
+ optional DOMString? oldValue = null,
+ optional DOMString? newValue = null,
+ optional DOMString? url = null,
+ optional Storage? storageArea = null);
};
dictionary StorageEventInit : EventInit
diff --git a/dom/webidl/TimeEvent.webidl b/dom/webidl/TimeEvent.webidl
index 40e7a0beb..8bbe4db53 100644
--- a/dom/webidl/TimeEvent.webidl
+++ b/dom/webidl/TimeEvent.webidl
@@ -15,6 +15,6 @@ interface TimeEvent : Event
readonly attribute long detail;
readonly attribute WindowProxy? view;
void initTimeEvent(DOMString aType,
- Window? aView,
- long aDetail);
+ optional Window? aView = null,
+ optional long aDetail = 0);
};
diff --git a/dom/webidl/TouchEvent.webidl b/dom/webidl/TouchEvent.webidl
index d206fe0fb..fd677787a 100644
--- a/dom/webidl/TouchEvent.webidl
+++ b/dom/webidl/TouchEvent.webidl
@@ -23,15 +23,15 @@ interface TouchEvent : UIEvent {
readonly attribute boolean shiftKey;
void initTouchEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- Window? view,
- long detail,
- boolean ctrlKey,
- boolean altKey,
- boolean shiftKey,
- boolean metaKey,
- TouchList? touches,
- TouchList? targetTouches,
- TouchList? changedTouches);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional Window? view = null,
+ optional long detail = 0,
+ optional boolean ctrlKey = false,
+ optional boolean altKey = false,
+ optional boolean shiftKey = false,
+ optional boolean metaKey = false,
+ optional TouchList? touches = null,
+ optional TouchList? targetTouches = null,
+ optional TouchList? changedTouches = null);
};
diff --git a/dom/webidl/UIEvent.webidl b/dom/webidl/UIEvent.webidl
index 9cc1d0cdf..5be6a443a 100644
--- a/dom/webidl/UIEvent.webidl
+++ b/dom/webidl/UIEvent.webidl
@@ -16,10 +16,10 @@ interface UIEvent : Event
readonly attribute WindowProxy? view;
readonly attribute long detail;
void initUIEvent(DOMString aType,
- boolean aCanBubble,
- boolean aCancelable,
- Window? aView,
- long aDetail);
+ optional boolean aCanBubble = false,
+ optional boolean aCancelable = false,
+ optional Window? aView = null,
+ optional long aDetail = 0);
};
// Additional DOM0 properties.
diff --git a/dom/webidl/XULCommandEvent.webidl b/dom/webidl/XULCommandEvent.webidl
index 9c024edc1..72dc3802e 100644
--- a/dom/webidl/XULCommandEvent.webidl
+++ b/dom/webidl/XULCommandEvent.webidl
@@ -15,13 +15,13 @@ interface XULCommandEvent : UIEvent
readonly attribute Event? sourceEvent;
void initCommandEvent(DOMString type,
- boolean canBubble,
- boolean cancelable,
- Window? view,
- long detail,
- boolean ctrlKey,
- boolean altKey,
- boolean shiftKey,
- boolean metaKey,
- Event? sourceEvent);
+ optional boolean canBubble = false,
+ optional boolean cancelable = false,
+ optional Window? view = null,
+ optional long detail = 0,
+ optional boolean ctrlKey = false,
+ optional boolean altKey = false,
+ optional boolean shiftKey = false,
+ optional boolean metaKey = false,
+ optional Event? sourceEvent = null);
};
diff --git a/dom/xbl/nsXBLBinding.cpp b/dom/xbl/nsXBLBinding.cpp
index d9a2aacc5..b8174f6c2 100644
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -1049,7 +1049,8 @@ nsXBLBinding::DoInitJSClass(JSContext *cx,
// to create and define it.
JS::Rooted<JSObject*> proto(cx);
JS::Rooted<JS::PropertyDescriptor> desc(cx);
- if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), &desc)) {
+ if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(),
+ aClassName.Length(), &desc)) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aNew = !desc.object();
diff --git a/dom/xbl/nsXBLProtoImpl.cpp b/dom/xbl/nsXBLProtoImpl.cpp
index 4db9cabf0..5efcb71e0 100644
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -100,11 +100,15 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
// end up with a different content prototype, but we'll already have a property
// holder called |foo| in the XBL scope. Check for that to avoid wasteful and
// weird property holder duplication.
- const char16_t* className = aPrototypeBinding->ClassName().get();
+ const nsString& className = aPrototypeBinding->ClassName();
+ const char16_t* classNameChars = className.get();
+ const size_t classNameLen = className.Length();
+
JS::Rooted<JSObject*> propertyHolder(cx);
JS::Rooted<JS::PropertyDescriptor> existingHolder(cx);
if (scopeObject != globalObject &&
- !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, className, &existingHolder)) {
+ !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, classNameChars,
+ classNameLen, &existingHolder)) {
return NS_ERROR_FAILURE;
}
bool propertyHolderIsNew = !existingHolder.object() || !existingHolder.value().isObject();
@@ -119,8 +123,8 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
// Define it as a property on the scopeObject, using the same name used on
// the content side.
- bool ok = JS_DefineUCProperty(cx, scopeObject, className, -1, propertyHolder,
- JSPROP_PERMANENT | JSPROP_READONLY,
+ bool ok = JS_DefineUCProperty(cx, scopeObject, classNameChars, classNameLen,
+ propertyHolder, JSPROP_PERMANENT | JSPROP_READONLY,
JS_STUBGETTER, JS_STUBSETTER);
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
} else {