diff --git a/CLOBBER b/CLOBBER
index d4cdfaff33d..acdf4b6cff2 100644
--- a/CLOBBER
+++ b/CLOBBER
@@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
-Merge day clobber
\ No newline at end of file
+Bug 1061335 - CLOBBER for Win32 compiler update.
diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml
index feaafbb9346..7f9727d5587 100644
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index 8b4a531b49c..de360725069 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index fa37d5d70e5..47a9ccda3a7 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index ff6b4860911..df46bc13849 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index 8b4a531b49c..de360725069 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml
index 7db74a4d186..40f5a23df76 100644
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml
index 2076adf92a1..842cd0e7b4c 100644
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index e89440c295b..4aec98fd74a 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
- "revision": "291b607f32e6173d8fe225c644cc7397cdf82fa5",
+ "revision": "3e3eb020773e765f4cb7775356ae9c22896db875",
"repo_path": "/integration/gaia-central"
}
diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml
index dc0128dfa92..76a4ed57327 100644
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml
index 51d5693379b..80d1c3c41ad 100644
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/mozconfigs/win32_gecko/debug b/b2g/config/mozconfigs/win32_gecko/debug
index 6751cf655d4..b37b3969d40 100644
--- a/b2g/config/mozconfigs/win32_gecko/debug
+++ b/b2g/config/mozconfigs/win32_gecko/debug
@@ -15,7 +15,7 @@ export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
- . $topsrcdir/build/win32/mozconfig.vs2010-win64
+ . $topsrcdir/build/win32/mozconfig.vs2013-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
diff --git a/b2g/config/mozconfigs/win32_gecko/nightly b/b2g/config/mozconfigs/win32_gecko/nightly
index 271825868b5..670354f8e1e 100644
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -14,7 +14,7 @@ export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
- . $topsrcdir/build/win32/mozconfig.vs2010-win64
+ . $topsrcdir/build/win32/mozconfig.vs2013-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index a5b5ee9fc4e..9ff9daf778a 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml
index 373ecf9cc9b..93c00685ee1 100644
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in
index 18d0aaf3df8..0f6c7970d26 100644
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -115,7 +115,6 @@
#ifdef XP_UNIX
#ifndef XP_MACOSX
@BINPATH@/run-mozilla.sh
-@BINPATH@/mozilla-xremote-client
#endif
#endif
diff --git a/browser/components/nsBrowserContentHandler.js b/browser/components/nsBrowserContentHandler.js
index d504e2e4ad1..20db9e6b287 100644
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -342,86 +342,6 @@ nsBrowserContentHandler.prototype = {
cmdLine.preventDefault = true;
}
- try {
- var remoteCommand = cmdLine.handleFlagWithParam("remote", true);
- }
- catch (e) {
- throw NS_ERROR_ABORT;
- }
-
- if (remoteCommand != null) {
- try {
- var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand);
- var remoteVerb;
- if (a) {
- remoteVerb = a[1].toLowerCase();
- var remoteParams = [];
- var sepIndex = a[2].lastIndexOf(",");
- if (sepIndex == -1)
- remoteParams[0] = a[2];
- else {
- remoteParams[0] = a[2].substring(0, sepIndex);
- remoteParams[1] = a[2].substring(sepIndex + 1);
- }
- }
-
- switch (remoteVerb) {
- case "openurl":
- case "openfile":
- // openURL()
- // openURL(,new-window)
- // openURL(,new-tab)
-
- // First param is the URL, second param (if present) is the "target"
- // (tab, window)
- var url = remoteParams[0];
- var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW;
- if (remoteParams[1]) {
- var targetParam = remoteParams[1].toLowerCase()
- .replace(/^\s*|\s*$/g, "");
- if (targetParam == "new-tab")
- target = nsIBrowserDOMWindow.OPEN_NEWTAB;
- else if (targetParam == "new-window")
- target = nsIBrowserDOMWindow.OPEN_NEWWINDOW;
- else {
- // The "target" param isn't one of our supported values, so
- // assume it's part of a URL that contains commas.
- url += "," + remoteParams[1];
- }
- }
-
- var uri = resolveURIInternal(cmdLine, url);
- handURIToExistingBrowser(uri, target, cmdLine);
- break;
-
- case "xfedocommand":
- // xfeDoCommand(openBrowser)
- if (remoteParams[0].toLowerCase() != "openbrowser")
- throw NS_ERROR_ABORT;
-
- // Passing defaultArgs, so use NO_EXTERNAL_URIS
- openWindow(null, this.chromeURL, "_blank",
- "chrome,dialog=no,all" + this.getFeatures(cmdLine),
- this.defaultArgs, NO_EXTERNAL_URIS);
- break;
-
- default:
- // Somebody sent us a remote command we don't know how to process:
- // just abort.
- throw "Unknown remote command.";
- }
-
- cmdLine.preventDefault = true;
- }
- catch (e) {
- Components.utils.reportError(e);
- // If we had a -remote flag but failed to process it, throw
- // NS_ERROR_ABORT so that the xremote code knows to return a failure
- // back to the handling code.
- throw NS_ERROR_ABORT;
- }
- }
-
var uriparam;
try {
while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
diff --git a/browser/config/mozconfigs/win32/common-opt b/browser/config/mozconfigs/win32/common-opt
index 66a3ccf374e..8aff356a9c5 100644
--- a/browser/config/mozconfigs/win32/common-opt
+++ b/browser/config/mozconfigs/win32/common-opt
@@ -27,7 +27,7 @@ export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
- . $topsrcdir/build/win32/mozconfig.vs2010-win64
+ . $topsrcdir/build/win32/mozconfig.vs2013-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
diff --git a/browser/config/mozconfigs/win32/debug b/browser/config/mozconfigs/win32/debug
index c1a6b1373d3..85cd5f903ab 100644
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -20,7 +20,7 @@ ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
export MOZILLA_OFFICIAL=1
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
- . $topsrcdir/build/win32/mozconfig.vs2010-win64
+ . $topsrcdir/build/win32/mozconfig.vs2013-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
diff --git a/browser/config/mozconfigs/win32/l10n-mozconfig b/browser/config/mozconfigs/win32/l10n-mozconfig
index 4113d990b88..103c78b4821 100644
--- a/browser/config/mozconfigs/win32/l10n-mozconfig
+++ b/browser/config/mozconfigs/win32/l10n-mozconfig
@@ -8,7 +8,7 @@ ac_add_options --with-windows-version=601
export MOZILLA_OFFICIAL=1
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
- . $topsrcdir/build/win32/mozconfig.vs2010-win64
+ . $topsrcdir/build/win32/mozconfig.vs2013-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 79948493b5c..037a7d941f7 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -161,7 +161,6 @@
#ifdef XP_UNIX
#ifndef XP_MACOSX
@BINPATH@/run-mozilla.sh
-@BINPATH@/mozilla-xremote-client
#endif
#endif
diff --git a/config/config.mk b/config/config.mk
index ed85218a61a..2353c7bed3c 100644
--- a/config/config.mk
+++ b/config/config.mk
@@ -675,10 +675,19 @@ ifeq (,$(filter $(OS_TARGET),WINNT Darwin))
CHECK_TEXTREL = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep TEXTREL > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_textrel | We do not want text relocations in libraries and programs' || true
endif
+ifeq ($(MOZ_WIDGET_TOOLKIT),android)
+# While this is very unlikely (libc being added by the compiler at the end
+# of the linker command line), if libmozglue.so ends up after libc.so, all
+# hell breaks loose, so better safe than sorry, and check it's actually the
+# case.
+CHECK_MOZGLUE_ORDER = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep NEEDED | awk '{ libs[$$NF] = ++n } END { if (libs["[libmozglue.so]"] && libs["[libc.so]"] < libs["[libmozglue.so]"]) { print "libmozglue.so must be linked before libc.so"; exit 1 } }'
+endif
+
define CHECK_BINARY
$(call CHECK_STDCXX,$(1))
$(call CHECK_TEXTREL,$(1))
$(call LOCAL_CHECKS,$(1))
+$(call CHECK_MOZGLUE_ORDER,$(1))
endef
# autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
diff --git a/config/external/nss/Makefile.in b/config/external/nss/Makefile.in
index 3aa05a47c06..068a332d6ef 100644
--- a/config/external/nss/Makefile.in
+++ b/config/external/nss/Makefile.in
@@ -330,7 +330,7 @@ nss_def_file := $(srcdir)/nss.def
ifeq (WINNT,$(OS_TARGET))
# Create a .def file based on the various .def files for nss, smime, ssl and
# nssutil.
-nss3.def: $(nss_def_file) $(DEPTH)/db/sqlite3/src/sqlite-processed.def
+nss3.def: $(nss_def_file) $(DEPTH)/db/sqlite3/src/sqlite-processed.def $(NSS_EXTRA_SYMBOLS_FILE)
echo LIBRARY nss3$(DLL_SUFFIX) > $@.tmp
echo EXPORTS >> $@.tmp
grep -v -h -e ^LIBRARY -e ^EXPORTS -e ^\; $^ >> $@.tmp
@@ -340,10 +340,9 @@ ifdef GCC_USE_GNU_LD
sqlite_def_file := $(topsrcdir)/db/sqlite3/src/sqlite.def
nspr_def_file := $(srcdir)/nspr-dummy.def
-nss3.def: $(nss_def_file) $(sqlite_def_file) $(nspr_def_file)
+nss3.def: $(nss_def_file) $(sqlite_def_file) $(nspr_def_file) $(NSS_EXTRA_SYMBOLS_FILE)
@$(call py_action,convert_def_file, \
- $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ \
- $(nss_def_file) $(sqlite_def_file) $(nspr_def_file))
+ $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ $^)
GARBAGE += \
nss3.def \
diff --git a/configure.in b/configure.in
index 59757cfe157..fa6a1bf1dfc 100644
--- a/configure.in
+++ b/configure.in
@@ -7192,9 +7192,7 @@ else
*-android*|*-linuxandroid*)
AC_DEFINE(MOZ_MEMORY_LINUX)
AC_DEFINE(MOZ_MEMORY_ANDROID)
- if test -z "$gonkdir"; then
- _WRAP_MALLOC=1
- else
+ if test -n "$gonkdir"; then
AC_DEFINE(MOZ_MEMORY_GONK)
fi
MOZ_GLUE_LDFLAGS=
@@ -7243,11 +7241,7 @@ dnl our own linker.
if test "$OS_TARGET" = Android; then
WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue"
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
- if test "$MOZ_WIDGET_TOOLKIT" = android; then
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror"
- fi
if test -z "$gonkdir"; then
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise"
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=memccpy,--wrap=memchr,--wrap=memrchr,--wrap=memcmp,--wrap=memcpy,--wrap=memmove,--wrap=memset,--wrap=memmem,--wrap=index,--wrap=strchr,--wrap=strrchr,--wrap=strlen,--wrap=strcmp,--wrap=strcpy,--wrap=strcat,--wrap=strcasecmp,--wrap=strncasecmp,--wrap=strstr,--wrap=strcasestr,--wrap=strtok,--wrap=strtok_r,--wrap=strerror,--wrap=strerror_r,--wrap=strnlen,--wrap=strncat,--wrap=strncmp,--wrap=strncpy,--wrap=strlcat,--wrap=strlcpy,--wrap=strcspn,--wrap=strpbrk,--wrap=strsep,--wrap=strspn,--wrap=strcoll,--wrap=strxfrm"
fi
if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
@@ -7255,39 +7249,6 @@ if test "$OS_TARGET" = Android; then
fi
fi
-dnl ========================================================
-dnl = Use malloc wrapper lib
-dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(wrap-malloc,
-[ --enable-wrap-malloc Wrap malloc calls (gnu linker only)],
- _WRAP_MALLOC=1,
- _WRAP_MALLOC= )
-
-if test -n "$_WRAP_MALLOC"; then
- if test -n "$GNU_CC"; then
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=malloc,--wrap=calloc,--wrap=valloc,--wrap=free,--wrap=realloc,--wrap=memalign"
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=__builtin_new,--wrap=__builtin_vec_new,--wrap=__builtin_delete,--wrap=__builtin_vec_delete"
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=strdup,--wrap=strndup"
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=vasprintf,--wrap=asprintf"
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=posix_memalign,--wrap=malloc_usable_size"
- dnl Wrap operator new and operator delete on Android.
- if test "$OS_TARGET" = "Android"; then
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_Znwj,--wrap=_Znaj,--wrap=_ZdlPv,--wrap=_ZdaPv"
- dnl Wrap the nothrow variants too.
- WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_ZnwjRKSt9nothrow_t,--wrap=_ZnajRKSt9nothrow_t,--wrap=_ZdlPvRKSt9nothrow_t,--wrap=_ZdaPvRKSt9nothrow_t"
- fi
- else
- AC_MSG_ERROR([--enable-wrap-malloc is not supported for non-GNU toolchains])
- fi
-fi
-
-dnl ========================================================
-dnl = Location of malloc wrapper lib
-dnl ========================================================
-MOZ_ARG_WITH_STRING(wrap-malloc,
-[ --with-wrap-malloc=DIR Location of malloc wrapper library],
- WRAP_LDFLAGS="${WRAP_LDFLAGS} $withval")
-
dnl ========================================================
dnl = Use JS Call tracing
dnl ========================================================
@@ -8938,6 +8899,8 @@ if test "$MOZ_DEBUG"; then
fi
AC_SUBST(MOZ_EM_DEBUG)
+AC_SUBST(NSS_EXTRA_SYMBOLS_FILE)
+
if test -n "$COMPILE_ENVIRONMENT"; then
AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
@@ -9136,9 +9099,6 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
fi
if test -n "$MANGLE"; then
MANGLED=
- if test -n "$_WRAP_MALLOC" -a -z "$JEMALLOC_WRAPPER"; then
- JEMALLOC_WRAPPER=__wrap_
- fi
for mangle in ${MANGLE}; do
if test -n "$MANGLED"; then
MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle,$MANGLED"
@@ -9232,11 +9192,6 @@ if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
export WRAP_LDFLAGS
-if test -n "$_WRAP_MALLOC"; then
- # Avoid doubling wrap malloc arguments
- _SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--enable-wrap-malloc *//'`"
-fi
-
if test -n "$MOZ_USING_CCACHE"; then
# Avoid double prepending ccache by omitting --with-ccache in building NSPR.
_SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--with-ccache[[^ ]]*//'`"
diff --git a/content/html/content/public/HTMLMediaElement.h b/content/html/content/public/HTMLMediaElement.h
index 9914bd9410c..5086bbf3ebe 100755
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -285,13 +285,6 @@ public:
void NotifyMediaTrackEnabled(MediaTrack* aTrack);
- /**
- * Called by a DOMMediaStream when it has tracks available.
- * This allows us to setup audio and video outputs after the stream
- * has already reported that playback started, in case they are added late.
- */
- void NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream);
-
virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
/**
@@ -623,7 +616,6 @@ protected:
class MediaLoadListener;
class StreamListener;
- class MediaStreamTracksAvailableCallback;
virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
@@ -1026,9 +1018,6 @@ protected:
nsMediaNetworkState mNetworkState;
nsMediaReadyState mReadyState;
- // Last value passed from codec or stream source to UpdateReadyStateForData.
- NextFrameStatus mLastNextFrameStatus;
-
enum LoadAlgorithmState {
// No load algorithm instance is waiting for a source to be added to the
// media in order to continue loading.
diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp
index 2a409bd1d52..de2a1267f85 100755
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -71,8 +71,6 @@
#include "mozilla/dom/MediaSource.h"
#include "MediaMetadataManager.h"
#include "MediaSourceDecoder.h"
-#include "AudioStreamTrack.h"
-#include "VideoStreamTrack.h"
#include "AudioChannelService.h"
@@ -666,10 +664,7 @@ void HTMLMediaElement::AbortExistingLoads()
mHaveQueuedSelectResource = false;
mSuspendedForPreloadNone = false;
mDownloadSuspendedByCache = false;
- mHasAudio = false;
- mHasVideo = false;
mSourcePointer = nullptr;
- mLastNextFrameStatus = NEXT_FRAME_UNINITIALIZED;
mTags = nullptr;
@@ -903,39 +898,6 @@ void HTMLMediaElement::NotifyMediaTrackEnabled(MediaTrack* aTrack)
}
}
-void HTMLMediaElement::NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream)
-{
- if (!mSrcStream || mSrcStream != aStream) {
- return;
- }
-
- bool oldHasAudio = mHasAudio;
- bool oldHasVideo = mHasVideo;
-
- nsAutoTArray,1> audioTracks;
- aStream->GetAudioTracks(audioTracks);
- nsAutoTArray,1> videoTracks;
- aStream->GetVideoTracks(videoTracks);
-
- mHasAudio = !audioTracks.IsEmpty();
- mHasVideo = !videoTracks.IsEmpty();
-
- if (!oldHasAudio && mHasAudio) {
- GetSrcMediaStream()->AddAudioOutput(this);
- GetSrcMediaStream()->SetAudioOutputVolume(this, float(mMuted ? 0.0 : mVolume));
- }
- if (!oldHasVideo && mHasVideo ) {
- VideoFrameContainer* container = GetVideoFrameContainer();
- if (container) {
- GetSrcMediaStream()->AddVideoOutput(container);
- }
- // mHasVideo changed so make sure the screen wakelock is updated
- NotifyOwnerDocumentActivityChanged();
- }
-
- CheckAutoplayDataReady();
-}
-
void HTMLMediaElement::LoadFromSourceChildren()
{
NS_ASSERTION(mDelayingLoadEvent,
@@ -2025,7 +1987,6 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed& aNo
mCurrentLoadID(0),
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
- mLastNextFrameStatus(NEXT_FRAME_UNINITIALIZED),
mLoadWaitStatus(NOT_WAITING),
mVolume(1.0),
mPreloadAction(PRELOAD_UNDEFINED),
@@ -2854,28 +2815,6 @@ private:
bool mPendingNotifyOutput;
};
-class HTMLMediaElement::MediaStreamTracksAvailableCallback:
- public DOMMediaStream::OnTracksAvailableCallback
-{
-public:
- explicit MediaStreamTracksAvailableCallback(HTMLMediaElement* aElement,
- DOMMediaStream::TrackTypeHints aExpectedTracks = 0):
- DOMMediaStream::OnTracksAvailableCallback(aExpectedTracks),
- mElement(aElement)
- {}
- virtual void NotifyTracksAvailable(DOMMediaStream* aStream)
- {
- NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-
- if (!mElement) {
- return;
- }
- mElement->NotifyMediaStreamTracksAvailable(aStream);
- }
-private:
- HTMLMediaElement* mElement;
-};
-
void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
{
NS_ASSERTION(!mSrcStream && !mSrcStreamListener, "Should have been ended already");
@@ -2897,24 +2836,22 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
if (mPausedForInactiveDocumentOrChannel) {
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
}
-
- mSrcStream->OnTracksAvailable(new MediaStreamTracksAvailableCallback(this, DOMMediaStream::HINT_CONTENTS_AUDIO));
- mSrcStream->OnTracksAvailable(new MediaStreamTracksAvailableCallback(this, DOMMediaStream::HINT_CONTENTS_VIDEO));
-
- MediaInfo mediaInfo;
- mediaInfo.mAudio.mHasAudio = mHasAudio;
- mediaInfo.mVideo.mHasVideo = mHasVideo;
- MetadataLoaded(&mediaInfo, nullptr);
-
- DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
- mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
-
ChangeDelayLoadStatus(false);
+ GetSrcMediaStream()->AddAudioOutput(this);
+ GetSrcMediaStream()->SetAudioOutputVolume(this, float(mMuted ? 0.0 : mVolume));
+ VideoFrameContainer* container = GetVideoFrameContainer();
+ if (container) {
+ GetSrcMediaStream()->AddVideoOutput(container);
+ }
// Note: we must call DisconnectTrackListListeners(...) before dropping
// mSrcStream
mSrcStream->ConstructMediaTracks(AudioTracks(), VideoTracks());
+ ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
+ DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
+ DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
+ ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
AddRemoveSelfReference();
// FirstFrameLoaded() will be called when the stream has current data.
}
@@ -2930,12 +2867,12 @@ void HTMLMediaElement::EndSrcMediaStreamPlayback()
// Kill its reference to this element
mSrcStreamListener->Forget();
mSrcStreamListener = nullptr;
- if (stream && mHasAudio) {
+ if (stream) {
stream->RemoveAudioOutput(this);
}
VideoFrameContainer* container = GetVideoFrameContainer();
if (container) {
- if (stream && mHasVideo) {
+ if (stream) {
stream->RemoveVideoOutput(container);
}
container->ClearCurrentFrame();
@@ -2987,11 +2924,6 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
mVideoFrameContainer->ForgetElement();
mVideoFrameContainer = nullptr;
}
-
- if (IsVideo()) {
- // Update the screen wakelock in case mHasVideo changed
- NotifyOwnerDocumentActivityChanged();
- }
}
void HTMLMediaElement::FirstFrameLoaded()
@@ -2999,7 +2931,6 @@ void HTMLMediaElement::FirstFrameLoaded()
NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
ChangeDelayLoadStatus(false);
- UpdateReadyStateForData(NEXT_FRAME_UNAVAILABLE);
if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
!HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
@@ -3162,18 +3093,10 @@ bool HTMLMediaElement::ShouldCheckAllowOrigin()
void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
{
- mLastNextFrameStatus = aNextFrame;
-
if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
// aNextFrame might have a next frame because the decoder can advance
// on its own thread before MetadataLoaded gets a chance to run.
// The arrival of more data can't change us out of this readyState.
-
- return;
- }
-
- if (!mHasAudio && !mHasVideo) {
- // No tracks available yet, don't advance from HAVE_METADATA
return;
}
@@ -3196,14 +3119,6 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
return;
}
- if (mReadyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && mHasVideo) {
- VideoFrameContainer* container = GetVideoFrameContainer();
- if (container && mMediaSize == nsIntSize(-1,-1)) {
- // No frame has been set yet. Don't advance.
- return;
- }
- }
-
if (aNextFrame != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
if (!mWaitingFired && aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
@@ -3344,15 +3259,14 @@ void HTMLMediaElement::ChangeNetworkState(nsMediaNetworkState aState)
bool HTMLMediaElement::CanActivateAutoplay()
{
- // For stream inputs, we activate autoplay on HAVE_METADATA because
+ // For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
// this element itself might be blocking the stream from making progress by
// being paused.
return !mPausedForInactiveDocumentOrChannel &&
mAutoplaying &&
mPaused &&
((mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
- (mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA)) &&
- (mHasAudio || mHasVideo) &&
+ (mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
mAutoplayEnabled &&
!IsEditable();
@@ -3381,14 +3295,24 @@ void HTMLMediaElement::CheckAutoplayDataReady()
VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer()
{
- if (mVideoFrameContainer)
- return mVideoFrameContainer;
+ // If we have loaded the metadata, and the size of the video is still
+ // (-1, -1), the media has no video. Don't go a create a video frame
+ // container.
+ if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
+ mMediaSize == nsIntSize(-1, -1)) {
+ return nullptr;
+ }
// Only video frames need an image container.
if (!IsVideo()) {
return nullptr;
}
+ mHasVideo = true;
+
+ if (mVideoFrameContainer)
+ return mVideoFrameContainer;
+
mVideoFrameContainer =
new VideoFrameContainer(this, LayerManager::CreateAsynchronousImageContainer());
@@ -3501,7 +3425,6 @@ void HTMLMediaElement::NotifyDecoderPrincipalChanged()
void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
{
mMediaSize = size;
- UpdateReadyStateForData(mLastNextFrameStatus);
}
void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
diff --git a/content/media/MediaDecoderReader.h b/content/media/MediaDecoderReader.h
index afecaf525cc..d88777af1c9 100644
--- a/content/media/MediaDecoderReader.h
+++ b/content/media/MediaDecoderReader.h
@@ -39,6 +39,9 @@ public:
// True if this reader is waiting media resource allocation
virtual bool IsWaitingMediaResources() { return false; }
+ // True if this reader is waiting for a Content Decryption Module to become
+ // available.
+ virtual bool IsWaitingOnCDMResource() { return false; }
// True when this reader need to become dormant state
virtual bool IsDormantNeeded() { return false; }
// Release media resources they should be released in dormant state
diff --git a/content/media/eme/MediaKeys.cpp b/content/media/eme/MediaKeys.cpp
index 9872f5dfa8a..25ec02fc105 100644
--- a/content/media/eme/MediaKeys.cpp
+++ b/content/media/eme/MediaKeys.cpp
@@ -16,9 +16,16 @@
#include "nsContentUtils.h"
#include "nsIScriptObjectPrincipal.h"
#include "mozilla/Preferences.h"
+#include "nsContentTypeParser.h"
+#ifdef MOZ_FMP4
+#include "MP4Decoder.h"
+#endif
#ifdef XP_WIN
#include "mozilla/WindowsVersion.h"
#endif
+#include "nsContentCID.h"
+#include "nsServiceManagerUtils.h"
+#include "mozIGeckoMediaPluginService.h"
namespace mozilla {
@@ -107,15 +114,86 @@ MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, Error
}
static bool
-IsSupportedKeySystem(const nsAString& aKeySystem)
+HaveGMPFor(const nsCString& aKeySystem,
+ const nsCString& aAPI,
+ const nsCString& aTag = EmptyCString())
{
- return aKeySystem.EqualsASCII("org.w3.clearkey") ||
-#ifdef XP_WIN
- (aKeySystem.EqualsASCII("com.adobe.access") &&
- IsVistaOrLater() &&
- Preferences::GetBool("media.eme.adobe-access.enabled", false)) ||
+ nsCOMPtr mps =
+ do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+ if (NS_WARN_IF(!mps)) {
+ return false;
+ }
+
+ nsTArray tags;
+ tags.AppendElement(aKeySystem);
+ if (!aTag.IsEmpty()) {
+ tags.AppendElement(aTag);
+ }
+ // Note: EME plugins need a non-null nodeId here, as they must
+ // not be shared across origins.
+ bool hasPlugin = false;
+ if (NS_FAILED(mps->HasPluginForAPI(aAPI,
+ &tags,
+ &hasPlugin))) {
+ return false;
+ }
+ return hasPlugin;
+}
+
+static bool
+IsPlayableMP4Type(const nsAString& aContentType)
+{
+#ifdef MOZ_FMP4
+ nsContentTypeParser parser(aContentType);
+ nsAutoString mimeType;
+ nsresult rv = parser.GetType(mimeType);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+ nsAutoString codecs;
+ parser.GetParameter("codecs", codecs);
+
+ NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
+ return MP4Decoder::CanHandleMediaType(mimeTypeUTF8, codecs);
+#else
+ return false;
#endif
- false;
+}
+
+bool
+MediaKeys::IsTypeSupported(const nsAString& aKeySystem,
+ const Optional& aInitDataType,
+ const Optional& aContentType)
+{
+ if (aKeySystem.EqualsLiteral("org.w3.clearkey") &&
+ (!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
+ (!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
+ HaveGMPFor(NS_LITERAL_CSTRING("org.w3.clearkey"),
+ NS_LITERAL_CSTRING("eme-decrypt"))) {
+ return true;
+ }
+
+#ifdef XP_WIN
+ // Note: Adobe Access's GMP uses WMF to decode, so anything our MP4Reader
+ // thinks it can play on Windows, the Access GMP should be able to play.
+ if (aKeySystem.EqualsLiteral("com.adobe.access") &&
+ Preferences::GetBool("media.eme.adobe-access.enabled", false) &&
+ IsVistaOrLater() && // Win Vista and later only.
+ (!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
+ (!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
+ HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
+ NS_LITERAL_CSTRING("eme-decrypt")) &&
+ HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
+ NS_LITERAL_CSTRING("decode-video"),
+ NS_LITERAL_CSTRING("h264")) &&
+ HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
+ NS_LITERAL_CSTRING("decode-audio"),
+ NS_LITERAL_CSTRING("aac"))) {
+ return true;
+ }
+#endif
+
+ return false;
}
/* static */
@@ -128,8 +206,16 @@ MediaKeys::IsTypeSupported(const GlobalObject& aGlobal,
{
// TODO: Should really get spec changed to this is async, so we can wait
// for user to consent to running plugin.
- return IsSupportedKeySystem(aKeySystem) ? IsTypeSupportedResult::Maybe
- : IsTypeSupportedResult::_empty;
+ bool supported = IsTypeSupported(aKeySystem, aInitDataType, aContentType);
+
+ EME_LOG("MediaKeys::IsTypeSupported keySystem='%s' initDataType='%s' contentType='%s' supported=%d",
+ NS_ConvertUTF16toUTF8(aKeySystem).get(),
+ (aInitDataType.WasPassed() ? NS_ConvertUTF16toUTF8(aInitDataType.Value()).get() : ""),
+ (aContentType.WasPassed() ? NS_ConvertUTF16toUTF8(aContentType.Value()).get() : ""),
+ supported);
+
+ return supported ? IsTypeSupportedResult::Probably
+ : IsTypeSupportedResult::_empty;
}
already_AddRefed
@@ -242,7 +328,7 @@ MediaKeys::Init(ErrorResult& aRv)
return nullptr;
}
- if (!IsSupportedKeySystem(mKeySystem)) {
+ if (!IsTypeSupported(mKeySystem)) {
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return promise.forget();
}
@@ -271,7 +357,7 @@ MediaKeys::Init(ErrorResult& aRv)
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
return promise.forget();
}
-
+
mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
if (!mPrincipal || !mTopLevelPrincipal) {
diff --git a/content/media/eme/MediaKeys.h b/content/media/eme/MediaKeys.h
index b7bc934d1f1..f651ce5dc73 100644
--- a/content/media/eme/MediaKeys.h
+++ b/content/media/eme/MediaKeys.h
@@ -124,6 +124,10 @@ public:
private:
+ static bool IsTypeSupported(const nsAString& aKeySystem,
+ const Optional& aInitDataType = Optional(),
+ const Optional& aContentType = Optional());
+
bool IsInPrivateBrowsing();
already_AddRefed Init(ErrorResult& aRv);
diff --git a/content/media/fmp4/BlankDecoderModule.cpp b/content/media/fmp4/BlankDecoderModule.cpp
index 25d8b63311e..e8a3419568f 100644
--- a/content/media/fmp4/BlankDecoderModule.cpp
+++ b/content/media/fmp4/BlankDecoderModule.cpp
@@ -109,7 +109,7 @@ public:
// with a U and V plane that are half the size of the Y plane, i.e 8 bit,
// 2x2 subsampled. Have the data pointers of each frame point to the
// first plane, they'll always be zero'd memory anyway.
- uint8_t* frame = new uint8_t[mFrameWidth * mFrameHeight];
+ nsAutoArrayPtr frame(new uint8_t[mFrameWidth * mFrameHeight]);
memset(frame, 0, mFrameWidth * mFrameHeight);
VideoData::YCbCrBuffer buffer;
diff --git a/content/media/fmp4/MP4Reader.h b/content/media/fmp4/MP4Reader.h
index 72d39cf21c9..43f816e5e0e 100644
--- a/content/media/fmp4/MP4Reader.h
+++ b/content/media/fmp4/MP4Reader.h
@@ -92,7 +92,7 @@ private:
bool IsSupportedAudioMimeType(const char* aMimeType);
void NotifyResourcesStatusChanged();
bool IsWaitingOnCodecResource();
- bool IsWaitingOnCDMResource();
+ virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
nsAutoPtr mDemuxer;
nsAutoPtr mPlatform;
diff --git a/content/media/fmp4/PlatformDecoderModule.cpp b/content/media/fmp4/PlatformDecoderModule.cpp
index cd145b5a6ad..bc737ec9f92 100644
--- a/content/media/fmp4/PlatformDecoderModule.cpp
+++ b/content/media/fmp4/PlatformDecoderModule.cpp
@@ -61,6 +61,7 @@ PlatformDecoderModule::Init()
#endif
}
+#ifdef MOZ_EME
class CreateTaskQueueTask : public nsRunnable {
public:
NS_IMETHOD Run() {
@@ -81,7 +82,6 @@ CreateTaskQueue()
return t->mTaskQueue.forget();
}
-#ifdef MOZ_EME
/* static */
PlatformDecoderModule*
PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
diff --git a/content/media/gmp/GMPAudioDecoderParent.cpp b/content/media/gmp/GMPAudioDecoderParent.cpp
index 0e5b4e68894..55b9fde9f8b 100644
--- a/content/media/gmp/GMPAudioDecoderParent.cpp
+++ b/content/media/gmp/GMPAudioDecoderParent.cpp
@@ -31,6 +31,7 @@ namespace gmp {
GMPAudioDecoderParent::GMPAudioDecoderParent(GMPParent* aPlugin)
: mIsOpen(false)
+ , mShuttingDown(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
{
@@ -161,17 +162,19 @@ GMPAudioDecoderParent::Shutdown()
LOGD(("%s: %p", __FUNCTION__, this));
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+ if (mShuttingDown) {
+ return NS_OK;
+ }
+ mShuttingDown = true;
+
// Notify client we're gone! Won't occur after Close()
if (mCallback) {
mCallback->Terminated();
mCallback = nullptr;
}
- if (mIsOpen) {
- // Don't send DecodingComplete if we died
- mIsOpen = false;
- unused << SendDecodingComplete();
- }
+ mIsOpen = false;
+ unused << SendDecodingComplete();
return NS_OK;
}
diff --git a/content/media/gmp/GMPAudioDecoderParent.h b/content/media/gmp/GMPAudioDecoderParent.h
index 0d924cd9c82..00d230884d0 100644
--- a/content/media/gmp/GMPAudioDecoderParent.h
+++ b/content/media/gmp/GMPAudioDecoderParent.h
@@ -53,6 +53,7 @@ private:
virtual bool Recv__delete__() MOZ_OVERRIDE;
bool mIsOpen;
+ bool mShuttingDown;
nsRefPtr mPlugin;
GMPAudioDecoderProxyCallback* mCallback;
};
diff --git a/content/media/gmp/GMPDecryptorParent.cpp b/content/media/gmp/GMPDecryptorParent.cpp
index 07f83152884..41631e6d982 100644
--- a/content/media/gmp/GMPDecryptorParent.cpp
+++ b/content/media/gmp/GMPDecryptorParent.cpp
@@ -13,6 +13,7 @@ namespace gmp {
GMPDecryptorParent::GMPDecryptorParent(GMPParent* aPlugin)
: mIsOpen(false)
+ , mShuttingDown(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
{
@@ -328,16 +329,19 @@ GMPDecryptorParent::Shutdown()
{
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+ if (mShuttingDown) {
+ return;
+ }
+ mShuttingDown = true;
+
// Notify client we're gone! Won't occur after Close()
if (mCallback) {
mCallback->Terminated();
mCallback = nullptr;
}
- if (mIsOpen) {
- mIsOpen = false;
- unused << SendDecryptingComplete();
- }
+ mIsOpen = false;
+ unused << SendDecryptingComplete();
}
// Note: Keep this sync'd up with Shutdown
diff --git a/content/media/gmp/GMPDecryptorParent.h b/content/media/gmp/GMPDecryptorParent.h
index 9c1d166de50..987c17358cb 100644
--- a/content/media/gmp/GMPDecryptorParent.h
+++ b/content/media/gmp/GMPDecryptorParent.h
@@ -106,6 +106,7 @@ private:
virtual bool Recv__delete__() MOZ_OVERRIDE;
bool mIsOpen;
+ bool mShuttingDown;
nsRefPtr mPlugin;
GMPDecryptorProxyCallback* mCallback;
};
diff --git a/content/media/gmp/GMPService.cpp b/content/media/gmp/GMPService.cpp
index ebd2802c51c..b5d476d03fa 100644
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -143,6 +143,7 @@ GeckoMediaPluginService::GeckoMediaPluginService()
: mMutex("GeckoMediaPluginService::mMutex")
, mShuttingDown(false)
, mShuttingDownOnGMPThread(false)
+ , mScannedPluginOnDisk(false)
, mWaitingForPluginsAsyncShutdown(false)
{
MOZ_ASSERT(NS_IsMainThread());
@@ -590,7 +591,7 @@ GeckoMediaPluginService::UnloadPlugins()
MutexAutoLock lock(mMutex);
// Note: CloseActive is async; it will actually finish
// shutting down when all the plugins have unloaded.
- for (uint32_t i = 0; i < mPlugins.Length(); i++) {
+ for (size_t i = 0; i < mPlugins.Length(); i++) {
mPlugins[i]->CloseActive(true);
}
mPlugins.Clear();
@@ -619,7 +620,7 @@ GeckoMediaPluginService::CrashPlugins()
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
MutexAutoLock lock(mMutex);
- for (uint32_t i = 0; i < mPlugins.Length(); i++) {
+ for (size_t i = 0; i < mPlugins.Length(); i++) {
mPlugins[i]->Crash();
}
}
@@ -652,6 +653,8 @@ GeckoMediaPluginService::LoadFromEnvironment()
pos = next + 1;
}
}
+
+ mScannedPluginOnDisk = true;
}
NS_IMETHODIMP
@@ -693,47 +696,88 @@ GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
return NS_OK;
}
+class DummyRunnable : public nsRunnable {
+public:
+ NS_IMETHOD Run() { return NS_OK; }
+};
+
NS_IMETHODIMP
-GeckoMediaPluginService::HasPluginForAPI(const nsACString& aNodeId,
- const nsACString& aAPI,
+GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
nsTArray* aTags,
bool* aResult)
{
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aResult);
- nsCString temp(aAPI);
- GMPParent *parent = SelectPluginForAPI(aNodeId, temp, *aTags, false);
- *aResult = !!parent;
+ const char* env = nullptr;
+ if (!mScannedPluginOnDisk && (env = PR_GetEnv("MOZ_GMP_PATH")) && *env) {
+ // We have a MOZ_GMP_PATH environment variable which may specify the
+ // location of plugins to load, and we haven't yet scanned the disk to
+ // see if there are plugins there. Get the GMP thread, which will
+ // cause an event to be dispatched to which scans for plugins. We
+ // dispatch a sync event to the GMP thread here in order to wait until
+ // after the GMP thread has scanned any paths in MOZ_GMP_PATH.
+ nsCOMPtr thread;
+ nsresult rv = GetThread(getter_AddRefs(thread));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ thread->Dispatch(new DummyRunnable(), NS_DISPATCH_SYNC);
+ MOZ_ASSERT(mScannedPluginOnDisk, "Should have scanned MOZ_GMP_PATH by now");
+ }
+
+ {
+ MutexAutoLock lock(mMutex);
+ nsCString api(aAPI);
+ GMPParent* gmp = FindPluginForAPIFrom(0, api, *aTags, nullptr);
+ *aResult = (gmp != nullptr);
+ }
return NS_OK;
}
+GMPParent*
+GeckoMediaPluginService::FindPluginForAPIFrom(size_t aSearchStartIndex,
+ const nsCString& aAPI,
+ const nsTArray& aTags,
+ size_t* aOutPluginIndex)
+{
+ mMutex.AssertCurrentThreadOwns();
+ for (size_t i = aSearchStartIndex; i < mPlugins.Length(); i++) {
+ GMPParent* gmp = mPlugins[i];
+ bool supportsAllTags = true;
+ for (size_t t = 0; t < aTags.Length(); t++) {
+ const nsCString& tag = aTags.ElementAt(t);
+ if (!gmp->SupportsAPI(aAPI, tag)) {
+ supportsAllTags = false;
+ break;
+ }
+ }
+ if (!supportsAllTags) {
+ continue;
+ }
+ if (aOutPluginIndex) {
+ *aOutPluginIndex = i;
+ }
+ return gmp;
+ }
+ return nullptr;
+}
+
GMPParent*
GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
const nsCString& aAPI,
- const nsTArray& aTags,
- bool aCloneCrossNodeIds)
+ const nsTArray& aTags)
{
- MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossNodeIds,
+ MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread,
"Can't clone GMP plugins on non-GMP threads.");
GMPParent* gmpToClone = nullptr;
{
MutexAutoLock lock(mMutex);
- for (uint32_t i = 0; i < mPlugins.Length(); i++) {
- GMPParent* gmp = mPlugins[i];
- bool supportsAllTags = true;
- for (uint32_t t = 0; t < aTags.Length(); t++) {
- const nsCString& tag = aTags[t];
- if (!gmp->SupportsAPI(aAPI, tag)) {
- supportsAllTags = false;
- break;
- }
- }
- if (!supportsAllTags) {
- continue;
- }
+ size_t index = 0;
+ GMPParent* gmp = nullptr;
+ while ((gmp = FindPluginForAPIFrom(index, aAPI, aTags, &index))) {
if (aNodeId.IsEmpty()) {
if (gmp->CanBeSharedCrossNodeIds()) {
return gmp;
@@ -744,15 +788,17 @@ GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
return gmp;
}
- // This GMP has the correct type but has the wrong origin; hold on to it
+ // This GMP has the correct type but has the wrong nodeId; hold on to it
// in case we need to clone it.
gmpToClone = gmp;
+ // Loop around and try the next plugin; it may be usable from aNodeId.
+ index++;
}
}
// Plugin exists, but we can't use it due to cross-origin separation. Create a
// new one.
- if (aCloneCrossNodeIds && gmpToClone) {
+ if (gmpToClone) {
GMPParent* clone = ClonePlugin(gmpToClone);
if (!aNodeId.IsEmpty()) {
clone->SetNodeId(aNodeId);
@@ -847,7 +893,7 @@ GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)
}
MutexAutoLock lock(mMutex);
- for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
+ for (size_t i = 0; i < mPlugins.Length(); ++i) {
nsCOMPtr pluginpath = mPlugins[i]->GetDirectory();
bool equals;
if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
diff --git a/content/media/gmp/GMPService.h b/content/media/gmp/GMPService.h
index 87504cd87f4..25e5563593e 100644
--- a/content/media/gmp/GMPService.h
+++ b/content/media/gmp/GMPService.h
@@ -19,6 +19,7 @@
#include "nsITimer.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
+#include "mozilla/Atomics.h"
template struct already_AddRefed;
@@ -49,8 +50,11 @@ private:
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
const nsCString& aAPI,
- const nsTArray& aTags,
- bool aCloneCrossNodeIds = true);
+ const nsTArray& aTags);
+ GMPParent* FindPluginForAPIFrom(size_t aSearchStartIndex,
+ const nsCString& aAPI,
+ const nsTArray& aTags,
+ size_t* aOutPluginIndex);
void UnloadPlugins();
void CrashPlugins();
@@ -94,6 +98,10 @@ private:
bool mShuttingDown;
bool mShuttingDownOnGMPThread;
+ // True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
+ // plugins found there into mPlugins.
+ Atomic mScannedPluginOnDisk;
+
template
class MainThreadOnly {
public:
diff --git a/content/media/gmp/GMPVideoDecoderParent.cpp b/content/media/gmp/GMPVideoDecoderParent.cpp
index 9176353af2c..319f78d4228 100644
--- a/content/media/gmp/GMPVideoDecoderParent.cpp
+++ b/content/media/gmp/GMPVideoDecoderParent.cpp
@@ -45,6 +45,7 @@ namespace gmp {
GMPVideoDecoderParent::GMPVideoDecoderParent(GMPParent* aPlugin)
: GMPSharedMemManager(aPlugin)
, mIsOpen(false)
+ , mShuttingDown(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
, mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
@@ -187,6 +188,11 @@ GMPVideoDecoderParent::Shutdown()
LOGD(("%s: %p", __FUNCTION__, this));
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+ if (mShuttingDown) {
+ return NS_OK;
+ }
+ mShuttingDown = true;
+
// Notify client we're gone! Won't occur after Close()
if (mCallback) {
mCallback->Terminated();
@@ -194,11 +200,8 @@ GMPVideoDecoderParent::Shutdown()
}
mVideoHost.DoneWithAPI();
- if (mIsOpen) {
- // Don't send DecodingComplete if we died
- mIsOpen = false;
- unused << SendDecodingComplete();
- }
+ mIsOpen = false;
+ unused << SendDecodingComplete();
return NS_OK;
}
diff --git a/content/media/gmp/GMPVideoDecoderParent.h b/content/media/gmp/GMPVideoDecoderParent.h
index 911d32aa467..36f3b2bc349 100644
--- a/content/media/gmp/GMPVideoDecoderParent.h
+++ b/content/media/gmp/GMPVideoDecoderParent.h
@@ -77,6 +77,7 @@ private:
virtual bool Recv__delete__() MOZ_OVERRIDE;
bool mIsOpen;
+ bool mShuttingDown;
nsRefPtr mPlugin;
GMPVideoDecoderCallbackProxy* mCallback;
GMPVideoHostImpl mVideoHost;
diff --git a/content/media/gmp/GMPVideoEncoderParent.cpp b/content/media/gmp/GMPVideoEncoderParent.cpp
index 69d612cf79d..6f2af86d9d6 100644
--- a/content/media/gmp/GMPVideoEncoderParent.cpp
+++ b/content/media/gmp/GMPVideoEncoderParent.cpp
@@ -52,6 +52,7 @@ namespace gmp {
GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
: GMPSharedMemManager(aPlugin),
mIsOpen(false),
+ mShuttingDown(false),
mPlugin(aPlugin),
mCallback(nullptr),
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
@@ -220,17 +221,20 @@ GMPVideoEncoderParent::Shutdown()
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+ if (mShuttingDown) {
+ return;
+ }
+ mShuttingDown = true;
+
// Notify client we're gone! Won't occur after Close()
if (mCallback) {
mCallback->Terminated();
mCallback = nullptr;
}
mVideoHost.DoneWithAPI();
- if (mIsOpen) {
- // Don't send EncodingComplete if we died
- mIsOpen = false;
- unused << SendEncodingComplete();
- }
+
+ mIsOpen = false;
+ unused << SendEncodingComplete();
}
static void
diff --git a/content/media/gmp/GMPVideoEncoderParent.h b/content/media/gmp/GMPVideoEncoderParent.h
index ca6ddb6cec5..aaec972bf80 100644
--- a/content/media/gmp/GMPVideoEncoderParent.h
+++ b/content/media/gmp/GMPVideoEncoderParent.h
@@ -74,6 +74,7 @@ private:
virtual bool Recv__delete__() MOZ_OVERRIDE;
bool mIsOpen;
+ bool mShuttingDown;
nsRefPtr mPlugin;
GMPVideoEncoderCallbackProxy* mCallback;
GMPVideoHostImpl mVideoHost;
diff --git a/content/media/gmp/mozIGeckoMediaPluginService.idl b/content/media/gmp/mozIGeckoMediaPluginService.idl
index 4efa8078f4e..8d5f72c67dd 100644
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -26,7 +26,7 @@ class GMPVideoHost;
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
-[scriptable, uuid(b350d3b6-00c9-4602-bdfe-84c2be8d1e7a)]
+[scriptable, uuid(657443a4-6b5d-4181-98b0-56997b35bd57)]
interface mozIGeckoMediaPluginService : nsISupports
{
@@ -40,9 +40,7 @@ interface mozIGeckoMediaPluginService : nsISupports
* Callable on any thread
*/
[noscript]
- boolean hasPluginForAPI([optional] in ACString nodeId,
- in ACString api,
- in TagArray tags);
+ boolean hasPluginForAPI(in ACString api, in TagArray tags);
/**
* Get a video decoder that supports the specified tags.
diff --git a/content/media/gtest/TestGMPCrossOrigin.cpp b/content/media/gtest/TestGMPCrossOrigin.cpp
new file mode 100644
index 00000000000..abcd65248a3
--- /dev/null
+++ b/content/media/gtest/TestGMPCrossOrigin.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/StaticPtr.h"
+#include "GMPVideoDecoderProxy.h"
+#include "GMPVideoEncoderProxy.h"
+#include "GMPService.h"
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIFile.h"
+#include "nsISimpleEnumerator.h"
+
+using namespace mozilla;
+using namespace mozilla::gmp;
+
+struct GMPTestRunner
+{
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPTestRunner)
+
+ void DoTest(void (GMPTestRunner::*aTestMethod)());
+ void RunTestGMPTestCodec();
+ void RunTestGMPCrossOrigin();
+
+private:
+ ~GMPTestRunner() { }
+};
+
+void
+GMPTestRunner::RunTestGMPTestCodec()
+{
+ nsRefPtr service =
+ GeckoMediaPluginService::GetGeckoMediaPluginService();
+
+ GMPVideoHost* host = nullptr;
+ GMPVideoDecoderProxy* decoder = nullptr;
+ GMPVideoDecoderProxy* decoder2 = nullptr;
+ GMPVideoEncoderProxy* encoder = nullptr;
+
+ nsTArray tags;
+ tags.AppendElement(NS_LITERAL_CSTRING("h264"));
+
+ service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("o"), &host, &decoder2);
+ service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING(""), &host, &decoder);
+
+ service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING(""), &host, &encoder);
+
+ EXPECT_TRUE(host);
+ EXPECT_TRUE(decoder);
+ EXPECT_TRUE(decoder2);
+ EXPECT_TRUE(encoder);
+
+ if (decoder) decoder->Close();
+ if (decoder2) decoder2->Close();
+ if (encoder) encoder->Close();
+}
+
+void
+GMPTestRunner::RunTestGMPCrossOrigin()
+{
+ nsRefPtr service =
+ GeckoMediaPluginService::GetGeckoMediaPluginService();
+
+ GMPVideoHost* host = nullptr;
+ nsTArray tags;
+ tags.AppendElement(NS_LITERAL_CSTRING("h264"));
+
+ GMPVideoDecoderProxy* decoder1 = nullptr;
+ GMPVideoDecoderProxy* decoder2 = nullptr;
+ GMPVideoEncoderProxy* encoder1 = nullptr;
+ GMPVideoEncoderProxy* encoder2 = nullptr;
+
+ service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder1);
+ service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &decoder2);
+ EXPECT_TRUE(!!decoder1 && !!decoder2 &&
+ decoder1->ParentID() != decoder2->ParentID());
+
+ service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder1);
+ service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &encoder2);
+ EXPECT_TRUE(!!encoder1 && !!encoder2 &&
+ encoder1->ParentID() != encoder2->ParentID());
+
+ if (decoder2) decoder2->Close();
+ if (encoder2) encoder2->Close();
+
+ service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder2);
+ EXPECT_TRUE(!!decoder1 && !!decoder2 &&
+ decoder1->ParentID() == decoder2->ParentID());
+
+ service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder2);
+ EXPECT_TRUE(!!encoder1 && !!encoder2 &&
+ encoder1->ParentID() == encoder2->ParentID());
+
+ if (decoder1) decoder1->Close();
+ if (decoder2) decoder2->Close();
+ if (encoder1) encoder1->Close();
+ if (encoder2) encoder2->Close();
+}
+
+void
+GMPTestRunner::DoTest(void (GMPTestRunner::*aTestMethod)())
+{
+ nsRefPtr service =
+ GeckoMediaPluginService::GetGeckoMediaPluginService();
+ nsCOMPtr thread;
+
+ service->GetThread(getter_AddRefs(thread));
+ thread->Dispatch(NS_NewRunnableMethod(this, aTestMethod), NS_DISPATCH_SYNC);
+}
+
+TEST(GeckoMediaPlugins, GMPTestCodec) {
+ nsRefPtr runner = new GMPTestRunner();
+ runner->DoTest(&GMPTestRunner::RunTestGMPTestCodec);
+}
+
+TEST(GeckoMediaPlugins, GMPCrossOrigin) {
+ nsRefPtr runner = new GMPTestRunner();
+ runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin);
+}
diff --git a/content/media/gtest/moz.build b/content/media/gtest/moz.build
index d043c8e6bb7..0f059178675 100644
--- a/content/media/gtest/moz.build
+++ b/content/media/gtest/moz.build
@@ -6,6 +6,7 @@
UNIFIED_SOURCES += [
'TestAudioCompactor.cpp',
+ 'TestGMPCrossOrigin.cpp',
'TestTrackEncoder.cpp',
'TestVideoSegment.cpp',
'TestWebMBuffered.cpp'
@@ -25,6 +26,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
LOCAL_INCLUDES += [
'/content/media/encoder',
+ '/content/media/gmp',
]
FINAL_LIBRARY = 'xul-gtest'
diff --git a/content/media/mediasource/MediaSourceDecoder.cpp b/content/media/mediasource/MediaSourceDecoder.cpp
index 819e15241d1..237c9cd9860 100644
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -187,4 +187,17 @@ MediaSourceDecoder::PrepareReaderInitialization()
mReader->PrepareInitialization();
}
+#ifdef MOZ_EME
+nsresult
+MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
+{
+ nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = mReader->SetCDMProxy(aProxy);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+#endif
+
} // namespace mozilla
diff --git a/content/media/mediasource/MediaSourceDecoder.h b/content/media/mediasource/MediaSourceDecoder.h
index 6efa09eb5ba..936ad232b5f 100644
--- a/content/media/mediasource/MediaSourceDecoder.h
+++ b/content/media/mediasource/MediaSourceDecoder.h
@@ -63,6 +63,10 @@ public:
// registered TrackBuffers essential for initialization.
void PrepareReaderInitialization();
+#ifdef MOZ_EME
+ virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
+#endif
+
private:
// The owning MediaSource holds a strong reference to this decoder, and
// calls Attach/DetachMediaSource on this decoder to set and clear
diff --git a/content/media/mediasource/MediaSourceReader.cpp b/content/media/mediasource/MediaSourceReader.cpp
index afa5ce2f52a..ab014ef91e6 100644
--- a/content/media/mediasource/MediaSourceReader.cpp
+++ b/content/media/mediasource/MediaSourceReader.cpp
@@ -329,6 +329,9 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType)
MSE_DEBUG("MediaSourceReader(%p)::CreateSubDecoder subdecoder %p subreader %p",
this, decoder.get(), reader.get());
decoder->SetReader(reader);
+#ifdef MOZ_EME
+ decoder->SetCDMProxy(mCDMProxy);
+#endif
return decoder.forget();
}
@@ -515,4 +518,20 @@ MediaSourceReader::IsEnded()
return mEnded;
}
+#ifdef MOZ_EME
+nsresult
+MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)
+{
+ ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+
+ mCDMProxy = aProxy;
+ for (size_t i = 0; i < mTrackBuffers.Length(); i++) {
+ nsresult rv = mTrackBuffers[i]->SetCDMProxy(aProxy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+#endif
+
} // namespace mozilla
diff --git a/content/media/mediasource/MediaSourceReader.h b/content/media/mediasource/MediaSourceReader.h
index f7ca11f842a..8227d8121ed 100644
--- a/content/media/mediasource/MediaSourceReader.h
+++ b/content/media/mediasource/MediaSourceReader.h
@@ -101,6 +101,10 @@ public:
// Return true if the Ended method has been called
bool IsEnded();
+#ifdef MOZ_EME
+ nsresult SetCDMProxy(CDMProxy* aProxy);
+#endif
+
private:
bool SwitchAudioReader(int64_t aTarget);
bool SwitchVideoReader(int64_t aTarget);
@@ -123,6 +127,10 @@ private:
nsRefPtr mAudioTrack;
nsRefPtr mVideoTrack;
+#ifdef MOZ_EME
+ nsRefPtr mCDMProxy;
+#endif
+
// These are read and written on the decode task queue threads.
int64_t mLastAudioTime;
int64_t mLastVideoTime;
diff --git a/content/media/mediasource/SourceBufferDecoder.h b/content/media/mediasource/SourceBufferDecoder.h
index c02336dffa4..b064c2aadde 100644
--- a/content/media/mediasource/SourceBufferDecoder.h
+++ b/content/media/mediasource/SourceBufferDecoder.h
@@ -11,6 +11,9 @@
#include "MediaDecoderReader.h"
#include "SourceBufferResource.h"
#include "mozilla/Attributes.h"
+#ifdef MOZ_EME
+#include "mozilla/CDMProxy.h"
+#endif
#include "mozilla/ReentrantMonitor.h"
namespace mozilla {
@@ -81,6 +84,23 @@ public:
mTaskQueue = aTaskQueue;
}
+#ifdef MOZ_EME
+ virtual nsresult SetCDMProxy(CDMProxy* aProxy)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+ mCDMProxy = aProxy;
+ return NS_OK;
+ }
+
+ virtual CDMProxy* GetCDMProxy() MOZ_OVERRIDE
+ {
+ MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
+ ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+ return mCDMProxy;
+ }
+#endif
+
// Given a time convert it into an approximate byte offset from the
// cached data. Returns -1 if no such value is computable.
int64_t ConvertToByteOffset(double aTime);
@@ -96,6 +116,10 @@ private:
AbstractMediaDecoder* mParentDecoder;
nsRefPtr mReader;
int64_t mMediaDuration;
+
+#ifdef MOZ_EME
+ nsRefPtr mCDMProxy;
+#endif
};
} // namespace mozilla
diff --git a/content/media/mediasource/TrackBuffer.cpp b/content/media/mediasource/TrackBuffer.cpp
index 5dd901a4bff..6f9bc6fcb0c 100644
--- a/content/media/mediasource/TrackBuffer.cpp
+++ b/content/media/mediasource/TrackBuffer.cpp
@@ -237,6 +237,7 @@ TrackBuffer::NewDecoder()
mLastStartTimestamp = 0;
mLastEndTimestamp = 0;
+ decoder->SetTaskQueue(mTaskQueue);
return QueueInitializeDecoder(decoder);
}
@@ -247,7 +248,6 @@ TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
NS_NewRunnableMethodWithArg(this,
&TrackBuffer::InitializeDecoder,
aDecoder);
- aDecoder->SetTaskQueue(mTaskQueue);
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
MSE_DEBUG("MediaSourceReader(%p): Failed to enqueue decoder initialization task", this);
RemoveDecoder(aDecoder);
@@ -272,8 +272,16 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
MediaInfo mi;
nsAutoPtr tags; // TODO: Handle metadata.
nsresult rv = reader->ReadMetadata(&mi, getter_Transfers(tags));
- aDecoder->SetTaskQueue(nullptr);
reader->SetIdle();
+
+ if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) {
+ ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
+ mWaitingDecoders.AppendElement(aDecoder);
+ return;
+ }
+
+ aDecoder->SetTaskQueue(nullptr);
+
if (NS_FAILED(rv) || (!mi.HasVideo() && !mi.HasAudio())) {
// XXX: Need to signal error back to owning SourceBuffer.
MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d",
@@ -415,6 +423,31 @@ TrackBuffer::Decoders()
return mInitializedDecoders;
}
+#ifdef MOZ_EME
+nsresult
+TrackBuffer::SetCDMProxy(CDMProxy* aProxy)
+{
+ ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
+
+ for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
+ nsresult rv = mDecoders[i]->SetCDMProxy(aProxy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ for (uint32_t i = 0; i < mWaitingDecoders.Length(); ++i) {
+ CDMCaps::AutoLock caps(aProxy->Capabilites());
+ caps.CallOnMainThreadWhenCapsAvailable(
+ NS_NewRunnableMethodWithArg(this,
+ &TrackBuffer::QueueInitializeDecoder,
+ mWaitingDecoders[i]));
+ }
+
+ mWaitingDecoders.Clear();
+
+ return NS_OK;
+}
+#endif
+
#if defined(DEBUG)
void
TrackBuffer::Dump(const char* aPath)
diff --git a/content/media/mediasource/TrackBuffer.h b/content/media/mediasource/TrackBuffer.h
index 67ba0f59f81..3510afaa5ff 100644
--- a/content/media/mediasource/TrackBuffer.h
+++ b/content/media/mediasource/TrackBuffer.h
@@ -73,6 +73,10 @@ public:
// TODO: Refactor to a cleaner interface between TrackBuffer and MediaSourceReader.
const nsTArray>& Decoders();
+#ifdef MOZ_EME
+ nsresult SetCDMProxy(CDMProxy* aProxy);
+#endif
+
#if defined(DEBUG)
void Dump(const char* aPath);
#endif
@@ -127,6 +131,10 @@ private:
// Access protected by mParentDecoder's monitor.
nsTArray> mInitializedDecoders;
+ // Decoders which are waiting on a Content Decryption Module to be able to
+ // finish ReadMetadata.
+ nsTArray> mWaitingDecoders;
+
// The decoder that the owning SourceBuffer is currently appending data to.
nsRefPtr mCurrentDecoder;
diff --git a/content/media/test/gizmo-frag-cenc.xml b/content/media/test/gizmo-frag-cenc.xml
new file mode 100644
index 00000000000..9211c1326b7
--- /dev/null
+++ b/content/media/test/gizmo-frag-cenc.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/media/test/gizmo-frag-cenc1.m4s b/content/media/test/gizmo-frag-cenc1.m4s
new file mode 100644
index 00000000000..6e2529377ca
Binary files /dev/null and b/content/media/test/gizmo-frag-cenc1.m4s differ
diff --git a/content/media/test/gizmo-frag-cenc2.m4s b/content/media/test/gizmo-frag-cenc2.m4s
new file mode 100644
index 00000000000..12b4481cd67
Binary files /dev/null and b/content/media/test/gizmo-frag-cenc2.m4s differ
diff --git a/content/media/test/gizmo-frag-cencinit.mp4 b/content/media/test/gizmo-frag-cencinit.mp4
new file mode 100644
index 00000000000..54193b196c3
Binary files /dev/null and b/content/media/test/gizmo-frag-cencinit.mp4 differ
diff --git a/content/media/test/manifest.js b/content/media/test/manifest.js
index c6c29f8bb29..5da55c7bac5 100644
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -640,14 +640,28 @@ var gMetadataTests = [
var gEMETests = [
{
name:"short-cenc.mp4",
- type:"video/mp4",
+ type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
keys: {
// "keyid" : "key"
"7e571d017e571d017e571d017e571d01" : "7e5711117e5711117e5711117e571111",
"7e571d027e571d027e571d027e571d02" : "7e5722227e5722227e5722227e572222",
},
sessionType:"temporary",
+ duration:0.47
},
+ // XXX Bug 1082239
+ //{
+ // name:"gizmo-frag-cencinit.mp4",
+ // fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
+ // type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
+ // keys: {
+ // // "keyid" : "key"
+ // "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+ // "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+ // },
+ // sessionType:"temporary",
+ // duration:2.00,
+ //},
];
function checkMetadata(msg, e, test) {
diff --git a/content/media/test/mochitest.ini b/content/media/test/mochitest.ini
index 38ca7878502..e4d59338cf1 100644
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -140,6 +140,9 @@ support-files =
dirac.ogg^headers^
dynamic_redirect.sjs
dynamic_resource.sjs
+ gizmo-frag-cenc1.m4s
+ gizmo-frag-cenc2.m4s
+ gizmo-frag-cencinit.mp4
file_access_controls.html
fragment_noplay.js
fragment_play.js
@@ -319,7 +322,6 @@ skip-if = buildapp == 'mulet' || os == 'win' # bug 894922
[test_bug686942.html]
[test_bug726904.html]
[test_bug874897.html]
-[test_bug879717.html]
[test_bug883173.html]
[test_bug895091.html]
[test_bug895305.html]
diff --git a/content/media/test/test_bug879717.html b/content/media/test/test_bug879717.html
deleted file mode 100644
index d726f5c99db..00000000000
--- a/content/media/test/test_bug879717.html
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
- Test for bug 879717, check that a video element can be drawn into a canvas directly on 'play' event
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/content/media/test/test_encryptedMediaExtensions.html b/content/media/test/test_encryptedMediaExtensions.html
index 1988815208e..4876c990232 100644
--- a/content/media/test/test_encryptedMediaExtensions.html
+++ b/content/media/test/test_encryptedMediaExtensions.html
@@ -104,46 +104,131 @@ function UpdateSessionFunc(test) {
}
}
+function PlayFragmented(test, elem)
+{
+ var ms = new MediaSource();
+ elem.src = URL.createObjectURL(ms);
+
+ var sb;
+ var curFragment = 0;
+
+ function addNextFragment() {
+ if (curFragment >= test.fragments.length) {
+ ms.endOfStream();
+ elem.play();
+ return;
+ }
+
+ var fragmentFile = test.fragments[curFragment++];
+
+ var req = new XMLHttpRequest();
+ req.open("GET", fragmentFile);
+ req.responseType = "arraybuffer";
+
+ req.addEventListener("load", function() {
+ sb.appendBuffer(new Uint8Array(req.response));
+ });
+
+ info("fetching resource " + fragmentFile);
+ req.send(null);
+ }
+
+ ms.addEventListener("sourceopen", function () {
+ sb = ms.addSourceBuffer(test.type);
+ sb.addEventListener("updateend", addNextFragment);
+
+ addNextFragment();
+ });
+}
+
+function PlayTest(test, elem)
+{
+ if (test.fragments) {
+ PlayFragmented(test, elem);
+ return;
+ }
+
+ // This file isn't fragmented; set the media source normally.
+ elem.src = test.name;
+ elem.play();
+}
+
function startTest(test, token)
{
+ manager.started(test._token);
+
var v = document.createElement("video");
- manager.started(token);
+ var gotEncrypted = false;
+ var gotPlaying = false;
v.addEventListener("encrypted", function(ev) {
- info("got encrypted event");
+ gotEncrypted = true;
+
+ info(token + " got encrypted event");
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
- "MediaKeys should support this keysystem");
+ token + " MediaKeys should support this keysystem");
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
- info("created MediaKeys object ok");
+ info(token + " created MediaKeys object ok");
return v.setMediaKeys(mediaKeys);
}, bail("failed to create MediaKeys object")).then(function() {
- info("set MediaKeys on