mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Backed out 6 changesets (bug 1395922) for failing Media tests test_eme_sample_groups_playback.html and test_eme_sample_groups_playback.html r=backout a=backout
Backed out changeset f856af63682e (bug 1395922) Backed out changeset f59a7e727f39 (bug 1395922) Backed out changeset 9cd31c6a8e2c (bug 1395922) Backed out changeset d46f952f94f8 (bug 1395922) Backed out changeset f786d928b1e0 (bug 1395922) Backed out changeset bacda0f99f71 (bug 1395922)
This commit is contained in:
parent
aaa47364af
commit
6bf19d4921
@ -1486,11 +1486,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncomingMediaKeys)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPlayPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSeekDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSetMediaKeysDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
||||
@ -1517,11 +1515,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncomingMediaKeys)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedVideoStreamTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPlayPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSeekDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSetMediaKeysDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLMediaElement)
|
||||
@ -1716,7 +1712,6 @@ void HTMLMediaElement::ShutdownDecoder()
|
||||
{
|
||||
RemoveMediaElementFromURITable();
|
||||
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
|
||||
mSetCDMRequest.DisconnectIfExists();
|
||||
mWaitingForKeyListener.DisconnectIfExists();
|
||||
if (mMediaSource) {
|
||||
mMediaSource->CompletePendingTransactions();
|
||||
@ -3980,7 +3975,6 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||
mPlaybackRate(1.0),
|
||||
mPreservesPitch(true),
|
||||
mPlayed(new TimeRanges(ToSupports(OwnerDoc()))),
|
||||
mAttachingMediaKey(false),
|
||||
mCurrentPlayRangeStart(-1.0),
|
||||
mLoadedDataFired(false),
|
||||
mAutoplaying(true),
|
||||
@ -7012,180 +7006,6 @@ HTMLMediaElement::ContainsRestrictedContent()
|
||||
return GetMediaKeys() != nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetCDMProxyFailure(const MediaResult& aResult)
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
|
||||
ResetSetMediaKeysTempVariables();
|
||||
|
||||
mSetMediaKeysDOMPromise->MaybeReject(aResult.Code(), aResult.Message());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::RemoveMediaKeys()
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
// 5.2.3 Stop using the CDM instance represented by the mediaKeys attribute
|
||||
// to decrypt media data and remove the association with the media element.
|
||||
mMediaKeys->Unbind();
|
||||
mMediaKeys = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::TryRemoveMediaKeysAssociation()
|
||||
{
|
||||
MOZ_ASSERT(mMediaKeys);
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
// 5.2.1 If the user agent or CDM do not support removing the association,
|
||||
// let this object's attaching media keys value be false and reject promise
|
||||
// with a new DOMException whose name is NotSupportedError.
|
||||
// 5.2.2 If the association cannot currently be removed, let this object's
|
||||
// attaching media keys value be false and reject promise with a new
|
||||
// DOMException whose name is InvalidStateError.
|
||||
if (mDecoder) {
|
||||
RefPtr<HTMLMediaElement> self = this;
|
||||
mDecoder->SetCDMProxy(nullptr)
|
||||
->Then(mAbstractMainThread,
|
||||
__func__,
|
||||
[self]() {
|
||||
self->mSetCDMRequest.Complete();
|
||||
|
||||
self->RemoveMediaKeys();
|
||||
if (self->AttachNewMediaKeys()) {
|
||||
// No incoming MediaKeys object or MediaDecoder is not created yet.
|
||||
self->MakeAssociationWithCDMResolved();
|
||||
}
|
||||
},
|
||||
[self](const MediaResult& aResult) {
|
||||
self->mSetCDMRequest.Complete();
|
||||
// 5.2.4 If the preceding step failed, let this object's attaching media
|
||||
// keys value be false and reject promise with a new DOMException whose
|
||||
// name is the appropriate error name.
|
||||
self->SetCDMProxyFailure(aResult);
|
||||
})
|
||||
->Track(mSetCDMRequest);
|
||||
return false;
|
||||
}
|
||||
|
||||
RemoveMediaKeys();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::DetachExistingMediaKeys()
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
// 5.1 If mediaKeys is not null, CDM instance represented by mediaKeys is
|
||||
// already in use by another media element, and the user agent is unable
|
||||
// to use it with this element, let this object's attaching media keys
|
||||
// value be false and reject promise with a new DOMException whose name
|
||||
// is QuotaExceededError.
|
||||
if (mIncomingMediaKeys && mIncomingMediaKeys->IsBoundToMediaElement()) {
|
||||
SetCDMProxyFailure(MediaResult(
|
||||
NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
|
||||
"MediaKeys object is already bound to another HTMLMediaElement"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5.2 If the mediaKeys attribute is not null, run the following steps:
|
||||
if (mMediaKeys) {
|
||||
return TryRemoveMediaKeysAssociation();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::MakeAssociationWithCDMResolved()
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
|
||||
// 5.4 Set the mediaKeys attribute to mediaKeys.
|
||||
mMediaKeys = mIncomingMediaKeys;
|
||||
// 5.5 Let this object's attaching media keys value be false.
|
||||
ResetSetMediaKeysTempVariables();
|
||||
// 5.6 Resolve promise.
|
||||
mSetMediaKeysDOMPromise->MaybeResolveWithUndefined();
|
||||
mSetMediaKeysDOMPromise = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::TryMakeAssociationWithCDM(CDMProxy* aProxy)
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(aProxy);
|
||||
|
||||
// 5.3.3 Queue a task to run the "Attempt to Resume Playback If Necessary"
|
||||
// algorithm on the media element.
|
||||
// Note: Setting the CDMProxy on the MediaDecoder will unblock playback.
|
||||
if (mDecoder) {
|
||||
// CDMProxy is set asynchronously in MediaFormatReader, once it's done,
|
||||
// HTMLMediaElement should resolve or reject the DOM promise.
|
||||
RefPtr<HTMLMediaElement> self = this;
|
||||
mDecoder->SetCDMProxy(aProxy)
|
||||
->Then(mAbstractMainThread,
|
||||
__func__,
|
||||
[self]() {
|
||||
self->mSetCDMRequest.Complete();
|
||||
self->MakeAssociationWithCDMResolved();
|
||||
},
|
||||
[self](const MediaResult& aResult) {
|
||||
self->mSetCDMRequest.Complete();
|
||||
self->SetCDMProxyFailure(aResult);
|
||||
})
|
||||
->Track(mSetCDMRequest);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::AttachNewMediaKeys()
|
||||
{
|
||||
LOG(LogLevel::Debug,
|
||||
("%s incoming MediaKeys(%p)", __func__, mIncomingMediaKeys.get()));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
|
||||
// 5.3. If mediaKeys is not null, run the following steps:
|
||||
if (mIncomingMediaKeys) {
|
||||
auto cdmProxy = mIncomingMediaKeys->GetCDMProxy();
|
||||
if (!cdmProxy) {
|
||||
SetCDMProxyFailure(MediaResult(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"CDM crashed before binding MediaKeys object to HTMLMediaElement"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5.3.1 Associate the CDM instance represented by mediaKeys with the
|
||||
// media element for decrypting media data.
|
||||
if (NS_FAILED(mIncomingMediaKeys->Bind(this))) {
|
||||
// 5.3.2 If the preceding step failed, run the following steps:
|
||||
|
||||
// 5.3.2.1 Set the mediaKeys attribute to null.
|
||||
mMediaKeys = nullptr;
|
||||
// 5.3.2.2 Let this object's attaching media keys value be false.
|
||||
// 5.3.2.3 Reject promise with a new DOMException whose name is
|
||||
// the appropriate error name.
|
||||
SetCDMProxyFailure(
|
||||
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"Failed to bind MediaKeys object to HTMLMediaElement"));
|
||||
return false;
|
||||
}
|
||||
return TryMakeAssociationWithCDM(cdmProxy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::ResetSetMediaKeysTempVariables()
|
||||
{
|
||||
mAttachingMediaKey = false;
|
||||
mIncomingMediaKeys = nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
ErrorResult& aRv)
|
||||
@ -7217,31 +7037,89 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Note: Our attaching code is synchronous, so we can skip the following steps.
|
||||
|
||||
// 2. If this object's attaching media keys value is true, return a
|
||||
// promise rejected with a new DOMException whose name is InvalidStateError.
|
||||
if (mAttachingMediaKey) {
|
||||
promise->MaybeReject(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING("A MediaKeys object is in attaching operation."));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 3. Let this object's attaching media keys value be true.
|
||||
mAttachingMediaKey = true;
|
||||
mIncomingMediaKeys = aMediaKeys;
|
||||
|
||||
// 4. Let promise be a new promise.
|
||||
mSetMediaKeysDOMPromise = promise;
|
||||
|
||||
// 5. Run the following steps in parallel:
|
||||
|
||||
// 5.1 & 5.2 & 5.3
|
||||
if (!DetachExistingMediaKeys() || !AttachNewMediaKeys()) {
|
||||
// 5.1 If mediaKeys is not null, CDM instance represented by mediaKeys is
|
||||
// already in use by another media element, and the user agent is unable
|
||||
// to use it with this element, let this object's attaching media keys
|
||||
// value be false and reject promise with a new DOMException whose name
|
||||
// is QuotaExceededError.
|
||||
if (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
|
||||
NS_LITERAL_CSTRING("MediaKeys object is already bound to another HTMLMediaElement"));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.4, 5.5, 5.6
|
||||
MakeAssociationWithCDMResolved();
|
||||
// 5.2 If the mediaKeys attribute is not null, run the following steps:
|
||||
if (mMediaKeys) {
|
||||
// 5.2.1 If the user agent or CDM do not support removing the association,
|
||||
// let this object's attaching media keys value be false and reject promise
|
||||
// with a new DOMException whose name is NotSupportedError.
|
||||
|
||||
// 5.2.2 If the association cannot currently be removed, let this object's
|
||||
// attaching media keys value be false and reject promise with a new
|
||||
// DOMException whose name is InvalidStateError.
|
||||
if (mDecoder) {
|
||||
// We don't support swapping out the MediaKeys once we've started to
|
||||
// setup the playback pipeline. Note this also means we don't need to worry
|
||||
// about handling disassociating the MediaKeys from the MediaDecoder.
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING("Can't change MediaKeys on HTMLMediaElement after load has started"));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.2.3 Stop using the CDM instance represented by the mediaKeys attribute
|
||||
// to decrypt media data and remove the association with the media element.
|
||||
mMediaKeys->Unbind();
|
||||
mMediaKeys = nullptr;
|
||||
|
||||
// 5.2.4 If the preceding step failed, let this object's attaching media
|
||||
// keys value be false and reject promise with a new DOMException whose
|
||||
// name is the appropriate error name.
|
||||
}
|
||||
|
||||
// 5.3. If mediaKeys is not null, run the following steps:
|
||||
if (aMediaKeys) {
|
||||
if (!aMediaKeys->GetCDMProxy()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING("CDM crashed before binding MediaKeys object to HTMLMediaElement"));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.3.1 Associate the CDM instance represented by mediaKeys with the
|
||||
// media element for decrypting media data.
|
||||
if (NS_FAILED(aMediaKeys->Bind(this))) {
|
||||
// 5.3.2 If the preceding step failed, run the following steps:
|
||||
// 5.3.2.1 Set the mediaKeys attribute to null.
|
||||
mMediaKeys = nullptr;
|
||||
// 5.3.2.2 Let this object's attaching media keys value be false.
|
||||
// 5.3.2.3 Reject promise with a new DOMException whose name is
|
||||
// the appropriate error name.
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING("Failed to bind MediaKeys object to HTMLMediaElement"));
|
||||
return promise.forget();
|
||||
}
|
||||
// 5.3.3 Queue a task to run the "Attempt to Resume Playback If Necessary"
|
||||
// algorithm on the media element.
|
||||
// Note: Setting the CDMProxy on the MediaDecoder will unblock playback.
|
||||
if (mDecoder) {
|
||||
mDecoder->SetCDMProxy(aMediaKeys->GetCDMProxy());
|
||||
}
|
||||
}
|
||||
|
||||
// 5.4 Set the mediaKeys attribute to mediaKeys.
|
||||
mMediaKeys = aMediaKeys;
|
||||
|
||||
// 5.5 Let this object's attaching media keys value be false.
|
||||
|
||||
// 5.6 Resolve promise.
|
||||
promise->MaybeResolveWithUndefined();
|
||||
|
||||
// 6. Return promise.
|
||||
return promise.forget();
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "MediaEventSource.h"
|
||||
#include "SeekTarget.h"
|
||||
#include "MediaDecoderOwner.h"
|
||||
#include "MediaPromiseDefs.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
@ -1333,15 +1332,6 @@ protected:
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
bool DetachExistingMediaKeys();
|
||||
bool TryRemoveMediaKeysAssociation();
|
||||
void RemoveMediaKeys();
|
||||
bool AttachNewMediaKeys();
|
||||
bool TryMakeAssociationWithCDM(CDMProxy* aProxy);
|
||||
void MakeAssociationWithCDMResolved();
|
||||
void SetCDMProxyFailure(const MediaResult& aResult);
|
||||
void ResetSetMediaKeysTempVariables();
|
||||
|
||||
// The current decoder. Load() has been called on this decoder.
|
||||
// At most one of mDecoder and mSrcStream can be non-null.
|
||||
RefPtr<MediaDecoder> mDecoder;
|
||||
@ -1544,12 +1534,6 @@ protected:
|
||||
|
||||
// Encrypted Media Extension media keys.
|
||||
RefPtr<MediaKeys> mMediaKeys;
|
||||
RefPtr<MediaKeys> mIncomingMediaKeys;
|
||||
// The dom promise is used for HTMLMediaElement::SetMediaKeys.
|
||||
RefPtr<DetailedPromise> mSetMediaKeysDOMPromise;
|
||||
// Used to indicate if the MediaKeys attaching operation is on-going or not.
|
||||
bool mAttachingMediaKey;
|
||||
MozPromiseRequestHolder<SetCDMPromise> mSetCDMRequest;
|
||||
|
||||
// Stores the time at the start of the current 'played' range.
|
||||
double mCurrentPlayRangeStart;
|
||||
|
@ -1423,15 +1423,18 @@ MediaDecoder::CanPlayThrough()
|
||||
return val;
|
||||
}
|
||||
|
||||
RefPtr<SetCDMPromise>
|
||||
void
|
||||
MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return InvokeAsync<RefPtr<CDMProxy>>(mReader->OwnerThread(),
|
||||
mReader.get(),
|
||||
__func__,
|
||||
&MediaFormatReader::SetCDMProxy,
|
||||
aProxy);
|
||||
RefPtr<CDMProxy> proxy = aProxy;
|
||||
RefPtr<MediaFormatReader> reader = mReader;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
||||
"MediaFormatReader::SetCDMProxy",
|
||||
[reader, proxy]() {
|
||||
reader->SetCDMProxy(proxy);
|
||||
});
|
||||
mReader->OwnerThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "MediaDecoderOwner.h"
|
||||
#include "MediaEventSource.h"
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "MediaPromiseDefs.h"
|
||||
#include "MediaResource.h"
|
||||
#include "MediaStatistics.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
@ -356,7 +355,7 @@ private:
|
||||
return mAbstractMainThread;
|
||||
}
|
||||
|
||||
RefPtr<SetCDMPromise> SetCDMProxy(CDMProxy* aProxy);
|
||||
void SetCDMProxy(CDMProxy* aProxy);
|
||||
|
||||
void EnsureTelemetryReported();
|
||||
|
||||
|
@ -1228,10 +1228,6 @@ MediaFormatReader::Shutdown()
|
||||
mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
mSkipRequest.DisconnectIfExists();
|
||||
mSetCDMPromise.RejectIfExists(
|
||||
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"MediaFormatReader is shutting down"),
|
||||
__func__);
|
||||
|
||||
if (mAudio.HasPromise()) {
|
||||
mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
@ -1322,101 +1318,23 @@ MediaFormatReader::Init()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaFormatReader::ResolveSetCDMPromiseIfDone(TrackType aTrack)
|
||||
{
|
||||
// When a CDM proxy is set, MFR would shutdown the existing MediaDataDecoder
|
||||
// and would create new one for specific track in the next Update.
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (mSetCDMPromise.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCDMProxy);
|
||||
if (mSetCDMForTracks.contains(aTrack)) {
|
||||
mSetCDMForTracks -= aTrack;
|
||||
}
|
||||
|
||||
if (mSetCDMForTracks.isEmpty()) {
|
||||
LOGV("%s : Done ", __func__);
|
||||
mSetCDMPromise.Resolve(/* aIgnored = */ true, __func__);
|
||||
ScheduleUpdate(TrackInfo::kAudioTrack);
|
||||
ScheduleUpdate(TrackInfo::kVideoTrack);
|
||||
return true;
|
||||
}
|
||||
LOGV("%s : %s track is ready.", __func__, TrackTypeToStr(aTrack));
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::PrepareToSetCDMForTrack(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("%s : %s", __func__, TrackTypeToStr(aTrack));
|
||||
|
||||
mSetCDMForTracks += aTrack;
|
||||
if (mCDMProxy) {
|
||||
// An old cdm proxy exists, so detaching old cdm proxy by shutting down
|
||||
// MediaDataDecoder.
|
||||
ShutdownDecoder(aTrack);
|
||||
}
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
bool
|
||||
MediaFormatReader::IsDecoderWaitingForCDM(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return IsEncrypted() && mSetCDMForTracks.contains(aTrack) && !mCDMProxy;
|
||||
}
|
||||
|
||||
RefPtr<SetCDMPromise>
|
||||
MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("SetCDMProxy (%p)", aProxy);
|
||||
|
||||
if (mShutdown) {
|
||||
return SetCDMPromise::CreateAndReject(
|
||||
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"MediaFormatReader is shutting down"),
|
||||
__func__);
|
||||
}
|
||||
|
||||
mSetCDMPromise.RejectIfExists(
|
||||
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"Another new CDM proxy is being set."),
|
||||
__func__);
|
||||
|
||||
// Shutdown all decoders as switching CDM proxy indicates that it's
|
||||
// inappropriate for the existing decoders to continue decoding via the old
|
||||
// CDM proxy.
|
||||
if (HasAudio()) {
|
||||
PrepareToSetCDMForTrack(TrackInfo::kAudioTrack);
|
||||
}
|
||||
if (HasVideo()) {
|
||||
PrepareToSetCDMForTrack(TrackInfo::kVideoTrack);
|
||||
}
|
||||
|
||||
mCDMProxy = aProxy;
|
||||
|
||||
if (IsEncrypted() && !mCDMProxy) {
|
||||
// Release old PDMFactory which contains an EMEDecoderModule.
|
||||
mPlatform = nullptr;
|
||||
}
|
||||
|
||||
if (!mInitDone || mSetCDMForTracks.isEmpty() || !mCDMProxy) {
|
||||
// 1) MFR is not initialized yet or
|
||||
// 2) Demuxer is initialized without active audio and video or
|
||||
// 3) A null cdm proxy is set
|
||||
// the promise can be resolved directly.
|
||||
mSetCDMForTracks.clear();
|
||||
return SetCDMPromise::CreateAndResolve(/* aIgnored = */ true, __func__);
|
||||
}
|
||||
|
||||
RefPtr<SetCDMPromise> p = mSetCDMPromise.Ensure(__func__);
|
||||
return p;
|
||||
RefPtr<CDMProxy> proxy = aProxy;
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableFunction("MediaFormatReader::SetCDMProxy", [=]() {
|
||||
MOZ_ASSERT(self->OnTaskQueue());
|
||||
self->mCDMProxy = proxy;
|
||||
if (HasAudio()) {
|
||||
self->ScheduleUpdate(TrackInfo::kAudioTrack);
|
||||
}
|
||||
if (HasVideo()) {
|
||||
self->ScheduleUpdate(TrackInfo::kVideoTrack);
|
||||
}
|
||||
});
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2473,13 +2391,6 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key",
|
||||
TrackTypeToStr(aTrack));
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
|
||||
} else if (IsDecoderWaitingForCDM(aTrack)) {
|
||||
// Rejecting the promise could lead to entering buffering state for MDSM,
|
||||
// once a qualified(with the same key system and sessions created by the
|
||||
// same InitData) new cdm proxy is set, decoding can be resumed.
|
||||
LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for CDM",
|
||||
TrackTypeToStr(aTrack));
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2537,7 +2448,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
|
||||
LOGV("Update(%s) ni=%d no=%d in:%" PRIu64 " out:%" PRIu64
|
||||
" qs=%u decoding:%d flushing:%d desc:%s pending:%u waiting:%d eos:%d "
|
||||
"ds:%d sid:%u waitcdm:%d",
|
||||
"ds:%d sid:%u",
|
||||
TrackTypeToStr(aTrack),
|
||||
needInput,
|
||||
needOutput,
|
||||
@ -2551,10 +2462,9 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
decoder.mWaitingForData,
|
||||
decoder.mDemuxEOS,
|
||||
int32_t(decoder.mDrainState),
|
||||
decoder.mLastStreamSourceID,
|
||||
IsDecoderWaitingForCDM(aTrack));
|
||||
decoder.mLastStreamSourceID);
|
||||
|
||||
if (IsWaitingOnCDMResource() || !ResolveSetCDMPromiseIfDone(aTrack)) {
|
||||
if (IsWaitingOnCDMResource()) {
|
||||
// If the content is encrypted, MFR won't start to create decoder until
|
||||
// CDMProxy is set.
|
||||
return;
|
||||
@ -2564,9 +2474,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
(!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting)) ||
|
||||
(decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
|
||||
// Nothing more we can do at present.
|
||||
LOGV("Still waiting for data or key. data(%d)/key(%d)",
|
||||
decoder.mWaitingForData,
|
||||
decoder.mWaitingForKey);
|
||||
LOGV("Still waiting for data or key.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "MediaDataDemuxer.h"
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "MediaPrefs.h"
|
||||
#include "MediaPromiseDefs.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "PDMFactory.h"
|
||||
#include "SeekTarget.h"
|
||||
@ -92,6 +91,7 @@ class MediaFormatReader final
|
||||
static const bool IsExclusive = true;
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
typedef MozPromise<bool, MediaResult, IsExclusive> NotifyDataArrivedPromise;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaFormatReader)
|
||||
|
||||
public:
|
||||
@ -194,7 +194,7 @@ public:
|
||||
// cases like MSE.
|
||||
bool UseBufferingHeuristics() const { return mTrackDemuxersMayBlock; }
|
||||
|
||||
RefPtr<SetCDMPromise> SetCDMProxy(CDMProxy* aProxy);
|
||||
void SetCDMProxy(CDMProxy* aProxy);
|
||||
|
||||
// Returns a string describing the state of the decoder data.
|
||||
// Used for debugging purposes.
|
||||
@ -792,12 +792,6 @@ private:
|
||||
|
||||
// Used in bug 1393399 for telemetry.
|
||||
const MediaDecoderOwnerID mMediaDecoderOwnerID;
|
||||
|
||||
bool ResolveSetCDMPromiseIfDone(TrackType aTrack);
|
||||
void PrepareToSetCDMForTrack(TrackType aTrack);
|
||||
MozPromiseHolder<SetCDMPromise> mSetCDMPromise;
|
||||
TrackSet mSetCDMForTracks{};
|
||||
bool IsDecoderWaitingForCDM(TrackType aTrack);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -1,19 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef MediaPromiseDefs_h_
|
||||
#define MediaPromiseDefs_h_
|
||||
|
||||
#include "MediaResult.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using SetCDMPromise =
|
||||
MozPromise<bool /* aIgnored */, MediaResult, /* IsExclusive */ true>;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -121,7 +121,6 @@ EXPORTS += [
|
||||
'MediaMetadataManager.h',
|
||||
'MediaMIMETypes.h',
|
||||
'MediaPrefs.h',
|
||||
'MediaPromiseDefs.h',
|
||||
'MediaQueue.h',
|
||||
'MediaRecorder.h',
|
||||
'MediaResource.h',
|
||||
|
@ -1 +0,0 @@
|
||||
Cache-Control: no-store
|
@ -74,8 +74,6 @@ support-files =
|
||||
bipbop-cenc-videoinit.mp4^headers^
|
||||
bipbop-cenc-video-10s.mp4
|
||||
bipbop-cenc-video-10s.mp4^headers^
|
||||
bipbop_225w_175kbps.mp4
|
||||
bipbop_225w_175kbps.mp4^headers^
|
||||
bipbop_225w_175kbps-cenc-audio-key1-1.m4s
|
||||
bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^
|
||||
bipbop_225w_175kbps-cenc-audio-key1-2.m4s
|
||||
@ -760,8 +758,6 @@ skip-if = toolkit == 'android' # bug 1149374
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_detach_media_keys.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_detach_reattach_same_mediakeys_during_playback.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_initDataTypes.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_missing_pssh.html]
|
||||
@ -787,8 +783,6 @@ skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_stream_capture_blocked_case3.html]
|
||||
tags=msg capturestream
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_unsetMediaKeys_then_capture.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_waitingforkey.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_empty_resource.html]
|
||||
|
@ -1,144 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<video id="v" controls></video>
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
var EMEmanifest = [
|
||||
{
|
||||
name:"bipbop 10s",
|
||||
tracks: [
|
||||
{
|
||||
name:"video",
|
||||
type:"video/mp4; codecs=\"avc1.4d4015\"",
|
||||
fragments:[ "bipbop-cenc-video-10s.mp4",
|
||||
]
|
||||
}
|
||||
],
|
||||
keys: {
|
||||
"7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
|
||||
},
|
||||
sessionType:"temporary",
|
||||
sessionCount:1,
|
||||
duration:10.01
|
||||
},
|
||||
];
|
||||
|
||||
function sleep(time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
// To check if playback can be blocked and resumed correctly after
|
||||
// detaching original mediakeys and reattach it back.
|
||||
function startTest(test, token)
|
||||
{
|
||||
manager.started(token);
|
||||
|
||||
var mk_ori;
|
||||
let finish = new EMEPromise;
|
||||
|
||||
let v = document.getElementById("v");
|
||||
let sessions = [];
|
||||
function onSessionCreated(session) {
|
||||
sessions.push(session);
|
||||
}
|
||||
|
||||
function closeSessions() {
|
||||
let p = new EMEPromise;
|
||||
Promise.all(sessions.map(s => s.close()))
|
||||
.then(p.resolve, p.reject);
|
||||
return p.promise;
|
||||
}
|
||||
|
||||
function setMediaKeysToElement(mk, solve, reject) {
|
||||
v.setMediaKeys(mk).then(solve, reject);
|
||||
}
|
||||
|
||||
function ReattachOriMediaKeys() {
|
||||
function onOriMediaKeysSetOK() {
|
||||
ok(true, TimeStamp(token) + " (ENCRYPTED) Set original MediaKeys back OK!");
|
||||
}
|
||||
function onOriMediaKeysSetFailed() {
|
||||
ok(false, " Failed to set original mediakeys back.");
|
||||
}
|
||||
|
||||
function onCanPlayAgain(ev) {
|
||||
Promise.all([closeSessions()])
|
||||
.then(() => {
|
||||
ok(true, " (ENCRYPTED) Playback can be resumed.");
|
||||
manager.finished(token);
|
||||
}, () => {
|
||||
ok(false, TimeStamp(token) + " Sessions are closed incorrectly.");
|
||||
manager.finished(token);
|
||||
});
|
||||
}
|
||||
|
||||
once(v, "canplay", onCanPlayAgain);
|
||||
setMediaKeysToElement(mk_ori, onOriMediaKeysSetOK, onOriMediaKeysSetFailed)
|
||||
}
|
||||
|
||||
function triggerSeek() {
|
||||
v.currentTime = v.duration / 2;
|
||||
}
|
||||
|
||||
function onCanPlay(ev) {
|
||||
function onSetMediaKeysToNullOK() {
|
||||
ok(true, TimeStamp(token) + " Set MediaKeys to null. OK!");
|
||||
|
||||
triggerSeek();
|
||||
|
||||
SimpleTest.requestFlakyTimeout("To reattach mediakeys back again in 5s.");
|
||||
sleep(5000).then(ReattachOriMediaKeys);
|
||||
}
|
||||
function onSetMediaKeysToNullFailed() {
|
||||
ok(false, TimeStamp(token) + " Set MediaKeys to null. FAILED!");
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("To detach mediakeys after receiving 'canplay' event in 2s");
|
||||
sleep(2000).then(() => {
|
||||
setMediaKeysToElement(null, onSetMediaKeysToNullOK, onSetMediaKeysToNullFailed);
|
||||
});
|
||||
}
|
||||
|
||||
once(v, "canplay", onCanPlay);
|
||||
|
||||
var p1 = LoadInitData(v, test, token);
|
||||
var p2 = CreateAndSetMediaKeys(v, test, token);
|
||||
var p3 = LoadTest(test, v, token);
|
||||
Promise.all([p1, p2, p3])
|
||||
.then(values => {
|
||||
let initData = values[0];
|
||||
// stash the mediakeys
|
||||
mk_ori = v.mediaKeys;
|
||||
initData.map(ev => {
|
||||
let session = v.mediaKeys.createSession();
|
||||
onSessionCreated(session);
|
||||
MakeRequest(test, token, ev, session);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
return finish.promise;
|
||||
})
|
||||
.catch(reason => ok(false, reason))
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
manager.runTests(EMEmanifest, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,117 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
// Test that if we can capture a video frame while playing clear content after
|
||||
// removing the MediaKeys object which was used for a previous encrypted content
|
||||
// playback on the same video element
|
||||
function startTest(test, token)
|
||||
{
|
||||
manager.started(token);
|
||||
var sessions = [];
|
||||
function onSessionCreated(session) {
|
||||
sessions.push(session);
|
||||
}
|
||||
|
||||
function closeSessions() {
|
||||
let p = new EMEPromise;
|
||||
Promise.all(sessions.map(s => s.close()))
|
||||
.then(p.resolve, p.reject);
|
||||
return p.promise;
|
||||
}
|
||||
|
||||
let v = document.createElement("video");
|
||||
document.body.appendChild(v);
|
||||
|
||||
let finish = new EMEPromise;
|
||||
|
||||
function onVideoEnded(ev) {
|
||||
ok(true, TimeStamp(token) + " (ENCRYPTED) content playback ended.");
|
||||
v.removeEventListener("ended", onVideoEnded);
|
||||
|
||||
function playClearVideo() {
|
||||
var p1 = once(v, 'ended', (e) => {
|
||||
ok(true, TimeStamp(token) + " (CLEAR) content playback ended.");
|
||||
console.log(" bipbop.mp4 playback ended !!");
|
||||
});
|
||||
var p2 = once(v, 'loadeddata', (e) => {
|
||||
ok(true, TimeStamp(token) + " Receiving event 'loadeddata' for (CLEAR) content.");
|
||||
canvasElem = document.createElement('canvas');
|
||||
document.body.appendChild(canvasElem);
|
||||
ctx2d = canvasElem.getContext('2d');
|
||||
|
||||
var gotTypeError = false;
|
||||
try {
|
||||
ctx2d.drawImage(v, 0, 0);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
gotTypeError = true;
|
||||
}
|
||||
}
|
||||
ok(!gotTypeError, TimeStamp(token) + " Canvas2D context drawImage succeed.")
|
||||
});
|
||||
v.src = 'bipbop_225w_175kbps.mp4';
|
||||
v.play();
|
||||
Promise.all([p1, p2, closeSessions()]).then(() => {
|
||||
manager.finished(token);
|
||||
}, () => {
|
||||
ok(false, TimeStamp(token) + " Something wrong.");
|
||||
manager.finished(token);
|
||||
});
|
||||
}
|
||||
|
||||
Promise.all(sessions.map(s => s.close()))
|
||||
.then(() => {
|
||||
v.setMediaKeys(null)
|
||||
.then(() => {
|
||||
ok(true, TimeStamp(token) + " Setting MediaKeys to null.");
|
||||
playClearVideo();
|
||||
}, () => {
|
||||
ok(false, TimeStamp(token) + " Setting MediaKeys to null.");
|
||||
});;
|
||||
});
|
||||
}
|
||||
|
||||
v.addEventListener("ended", onVideoEnded);
|
||||
|
||||
// Create a MediaKeys object and set to HTMLMediaElement then start the playback.
|
||||
Promise.all([
|
||||
LoadInitData(v, test, token),
|
||||
CreateAndSetMediaKeys(v, test, token),
|
||||
LoadTest(test, v, token)])
|
||||
.then(values => {
|
||||
let initData = values[0];
|
||||
v.play();
|
||||
initData.map(ev => {
|
||||
let session = v.mediaKeys.createSession();
|
||||
onSessionCreated(session);
|
||||
MakeRequest(test, token, ev, session);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
return finish.promise;
|
||||
})
|
||||
.catch(reason => ok(false, reason))
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user