Bug 1371202. P1 - plumb the 'loop' attribute into MDSM.
MozReview-Commit-ID: DtsaXmtQw76
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2468,17 +2468,18 @@ nsresult HTMLMediaElement::LoadResource(
if (mMediaSource) {
MediaDecoderInit decoderInit(
this,
mAudioChannel,
mMuted ? 0.0 : mVolume,
mPreservesPitch,
mPlaybackRate,
mPreloadAction == HTMLMediaElement::PRELOAD_METADATA,
- mHasSuspendTaint);
+ mHasSuspendTaint,
+ HasAttr(kNameSpaceID_None, nsGkAtoms::loop));
RefPtr<MediaSourceDecoder> decoder = new MediaSourceDecoder(decoderInit);
if (!mMediaSource->Attach(decoder)) {
// TODO: Handle failure: run "If the media data cannot be fetched at
// all, due to network errors, causing the user agent to give up
// trying to fetch the resource" section of resource fetch algorithm.
decoder->Shutdown();
return NS_ERROR_FAILURE;
@@ -4229,16 +4230,20 @@ HTMLMediaElement::AfterSetAttr(int32_t a
CheckAutoplayDataReady();
}
// This attribute can affect AddRemoveSelfReference
AddRemoveSelfReference();
UpdatePreloadAction();
}
} else if (aName == nsGkAtoms::preload) {
UpdatePreloadAction();
+ } else if (aName == nsGkAtoms::loop) {
+ if (mDecoder) {
+ mDecoder->SetLooping(!!aValue);
+ }
}
}
// Since AfterMaybeChangeAttr may call DoLoad, make sure that it is called
// *after* any possible changes to mSrcMediaSource.
if (aValue) {
AfterMaybeChangeAttr(aNameSpaceID, aName, aNotify);
}
@@ -4602,17 +4607,18 @@ nsresult HTMLMediaElement::InitializeDec
MediaDecoderInit decoderInit(
this,
mAudioChannel,
mMuted ? 0.0 : mVolume,
mPreservesPitch,
mPlaybackRate,
mPreloadAction == HTMLMediaElement::PRELOAD_METADATA,
- mHasSuspendTaint);
+ mHasSuspendTaint,
+ HasAttr(kNameSpaceID_None, nsGkAtoms::loop));
RefPtr<MediaDecoder> decoder = aOriginal->Clone(decoderInit);
if (!decoder)
return NS_ERROR_FAILURE;
LOG(LogLevel::Debug, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
RefPtr<MediaResource> resource =
@@ -4640,17 +4646,18 @@ nsresult HTMLMediaElement::InitializeDec
DecoderDoctorDiagnostics diagnostics;
MediaDecoderInit decoderInit(
this,
mAudioChannel,
mMuted ? 0.0 : mVolume,
mPreservesPitch,
mPlaybackRate,
mPreloadAction == HTMLMediaElement::PRELOAD_METADATA,
- mHasSuspendTaint);
+ mHasSuspendTaint,
+ HasAttr(kNameSpaceID_None, nsGkAtoms::loop));
RefPtr<MediaDecoder> decoder =
DecoderTraits::CreateDecoder(mimeType, decoderInit, &diagnostics);
diagnostics.StoreFormatDiagnostics(OwnerDoc(),
NS_ConvertASCIItoUTF16(mimeType),
decoder != nullptr,
__func__);
if (!decoder) {
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -395,16 +395,17 @@ MediaDecoder::MediaDecoder(MediaDecoderI
, INIT_MIRROR(mBuffered, TimeIntervals())
, INIT_MIRROR(mNextFrameStatus, MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE)
, INIT_MIRROR(mCurrentPosition, TimeUnit::Zero())
, INIT_MIRROR(mStateMachineDuration, NullableTimeUnit())
, INIT_MIRROR(mPlaybackPosition, 0)
, INIT_MIRROR(mIsAudioDataAudible, false)
, INIT_CANONICAL(mVolume, aInit.mVolume)
, INIT_CANONICAL(mPreservesPitch, aInit.mPreservesPitch)
+ , INIT_CANONICAL(mLooping, aInit.mLooping)
, INIT_CANONICAL(mExplicitDuration, Maybe<double>())
, INIT_CANONICAL(mPlayState, PLAY_STATE_LOADING)
, INIT_CANONICAL(mNextState, PLAY_STATE_PAUSED)
, INIT_CANONICAL(mLogicallySeeking, false)
, INIT_CANONICAL(mSameOriginMedia, false)
, INIT_CANONICAL(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE)
, INIT_CANONICAL(mPlaybackBytesPerSecond, 0.0)
, INIT_CANONICAL(mPlaybackRateReliable, true)
@@ -1442,16 +1443,23 @@ MediaDecoder::SetPlaybackRate(double aPl
void
MediaDecoder::SetPreservesPitch(bool aPreservesPitch)
{
MOZ_ASSERT(NS_IsMainThread());
mPreservesPitch = aPreservesPitch;
}
void
+MediaDecoder::SetLooping(bool aLooping)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mLooping = aLooping;
+}
+
+void
MediaDecoder::ConnectMirrors(MediaDecoderStateMachine* aObject)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aObject);
mStateMachineDuration.Connect(aObject->CanonicalDuration());
mBuffered.Connect(aObject->CanonicalBuffered());
mNextFrameStatus.Connect(aObject->CanonicalNextFrameStatus());
mCurrentPosition.Connect(aObject->CanonicalCurrentPosition());
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -61,31 +61,34 @@ struct MediaDecoderInit
{
MediaDecoderOwner* const mOwner;
const dom::AudioChannel mAudioChannel;
const double mVolume;
const bool mPreservesPitch;
const double mPlaybackRate;
const bool mMinimizePreroll;
const bool mHasSuspendTaint;
+ const bool mLooping;
MediaDecoderInit(MediaDecoderOwner* aOwner,
dom::AudioChannel aAudioChannel,
double aVolume,
bool aPreservesPitch,
double aPlaybackRate,
bool aMinimizePreroll,
- bool aHasSuspendTaint)
+ bool aHasSuspendTaint,
+ bool aLooping)
: mOwner(aOwner)
, mAudioChannel(aAudioChannel)
, mVolume(aVolume)
, mPreservesPitch(aPreservesPitch)
, mPlaybackRate(aPlaybackRate)
, mMinimizePreroll(aMinimizePreroll)
, mHasSuspendTaint(aHasSuspendTaint)
+ , mLooping(aLooping)
{
}
};
class MediaDecoder : public AbstractMediaDecoder
{
public:
// Used to register with MediaResource to receive notifications which will
@@ -222,16 +225,17 @@ public:
// Pause video playback.
virtual void Pause();
// Adjust the speed of the playback, optionally with pitch correction,
void SetVolume(double aVolume);
void SetPlaybackRate(double aPlaybackRate);
void SetPreservesPitch(bool aPreservesPitch);
+ void SetLooping(bool aLooping);
bool GetMinimizePreroll() const { return mMinimizePreroll; }
// All MediaStream-related data is protected by mReentrantMonitor.
// We have at most one DecodedStreamData per MediaDecoder. Its stream
// is used as the input for each ProcessedMediaStream created by calls to
// captureStream(UntilEnded). Seeking creates a new source stream, as does
// replaying after the input as ended. In the latter case, the new source is
@@ -761,16 +765,18 @@ protected:
// Used to distinguish whether the audio is producing sound.
Mirror<bool> mIsAudioDataAudible;
// Volume of playback. 0.0 = muted. 1.0 = full volume.
Canonical<double> mVolume;
Canonical<bool> mPreservesPitch;
+ Canonical<bool> mLooping;
+
// Media duration set explicitly by JS. At present, this is only ever present
// for MSE.
Canonical<Maybe<double>> mExplicitDuration;
// Set to one of the valid play states.
// This can only be changed on the main thread while holding the decoder
// monitor. Thus, it can be safely read while holding the decoder monitor
// OR on the main thread.
@@ -806,16 +812,20 @@ protected:
public:
AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override;
AbstractCanonical<double>* CanonicalVolume() { return &mVolume; }
AbstractCanonical<bool>* CanonicalPreservesPitch()
{
return &mPreservesPitch;
}
+ AbstractCanonical<bool>* CanonicalLooping()
+ {
+ return &mLooping;
+ }
AbstractCanonical<Maybe<double>>* CanonicalExplicitDuration()
{
return &mExplicitDuration;
}
AbstractCanonical<PlayState>* CanonicalPlayState() { return &mPlayState; }
AbstractCanonical<PlayState>* CanonicalNextPlayState() { return &mNextState; }
AbstractCanonical<bool>* CanonicalLogicallySeeking()
{
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2668,16 +2668,17 @@ ShutdownState::Enter()
// Disconnect canonicals and mirrors before shutting down our task queue.
master->mBuffered.DisconnectIfConnected();
master->mExplicitDuration.DisconnectIfConnected();
master->mPlayState.DisconnectIfConnected();
master->mNextPlayState.DisconnectIfConnected();
master->mVolume.DisconnectIfConnected();
master->mPreservesPitch.DisconnectIfConnected();
+ master->mLooping.DisconnectIfConnected();
master->mSameOriginMedia.DisconnectIfConnected();
master->mMediaPrincipalHandle.DisconnectIfConnected();
master->mPlaybackBytesPerSecond.DisconnectIfConnected();
master->mPlaybackRateReliable.DisconnectIfConnected();
master->mDecoderPosition.DisconnectIfConnected();
master->mDuration.DisconnectAll();
master->mNextFrameStatus.DisconnectAll();
@@ -2730,16 +2731,17 @@ MediaDecoderStateMachine::MediaDecoderSt
mVideoDecodeMode(VideoDecodeMode::Normal),
mIsMSE(aDecoder->IsMSE()),
INIT_MIRROR(mBuffered, TimeIntervals()),
INIT_MIRROR(mExplicitDuration, Maybe<double>()),
INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
INIT_MIRROR(mNextPlayState, MediaDecoder::PLAY_STATE_PAUSED),
INIT_MIRROR(mVolume, 1.0),
INIT_MIRROR(mPreservesPitch, true),
+ INIT_MIRROR(mLooping, false),
INIT_MIRROR(mSameOriginMedia, false),
INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
INIT_MIRROR(mPlaybackBytesPerSecond, 0.0),
INIT_MIRROR(mPlaybackRateReliable, true),
INIT_MIRROR(mDecoderPosition, 0),
INIT_CANONICAL(mDuration, NullableTimeUnit()),
INIT_CANONICAL(mNextFrameStatus, MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE),
INIT_CANONICAL(mCurrentPosition, TimeUnit::Zero()),
@@ -2776,16 +2778,17 @@ MediaDecoderStateMachine::Initialization
// Connect mirrors.
mBuffered.Connect(mReader->CanonicalBuffered());
mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration());
mPlayState.Connect(aDecoder->CanonicalPlayState());
mNextPlayState.Connect(aDecoder->CanonicalNextPlayState());
mVolume.Connect(aDecoder->CanonicalVolume());
mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
+ mLooping.Connect(aDecoder->CanonicalLooping());
mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
mMediaPrincipalHandle.Connect(aDecoder->CanonicalMediaPrincipalHandle());
mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
// Initialize watchers.
mWatchManager.Watch(mBuffered,
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -697,16 +697,20 @@ private:
Mirror<MediaDecoder::PlayState> mNextPlayState;
// Volume of playback. 0.0 = muted. 1.0 = full volume.
Mirror<double> mVolume;
// Pitch preservation for the playback rate.
Mirror<bool> mPreservesPitch;
+ // Whether to seek back to the start of the media resource
+ // upon reaching the end.
+ Mirror<bool> mLooping;
+
// True if the media is same-origin with the element. Data can only be
// passed to MediaStreams when this is true.
Mirror<bool> mSameOriginMedia;
// An identifier for the principal of the media. Used to track when
// main-thread induced principal changes get reflected on MSG thread.
Mirror<PrincipalHandle> mMediaPrincipalHandle;