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