From 502674878a12d81bc376116b233ee789c19e2af1 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Wed, 5 May 2021 10:23:10 +0800 Subject: [PATCH 01/18] Revert "Revert recent dom/media related changes. This should hopefully restore stability as 27 March 2021 build." This reverts commit c5b776d07aef8f34823e7f359fe0b488f5891d3d. --- dom/ipc/ContentChild.cpp | 14 + dom/ipc/ContentChild.h | 3 + dom/ipc/ContentParent.cpp | 14 + dom/ipc/ContentParent.h | 3 + dom/ipc/PContent.ipdl | 4 + dom/media/AbstractMediaDecoder.h | 4 +- dom/media/DecodedStream.cpp | 22 +- dom/media/DecodedStream.h | 9 +- dom/media/IdpSandbox.jsm | 2 +- dom/media/MediaDecoder.cpp | 76 +- dom/media/MediaDecoder.h | 36 +- dom/media/MediaDecoderReader.cpp | 71 +- dom/media/MediaDecoderReader.h | 34 +- dom/media/MediaDecoderStateMachine.cpp | 424 ++--- dom/media/MediaDecoderStateMachine.h | 211 +-- dom/media/MediaFormatReader.cpp | 42 +- dom/media/MediaFormatReader.h | 65 +- dom/media/MediaInfo.h | 3 - dom/media/MediaManager.cpp | 1585 +++++++++-------- dom/media/MediaManager.h | 62 +- dom/media/MediaResource.cpp | 52 + dom/media/MediaResource.h | 30 + dom/media/MediaTaskQueue.cpp | 9 +- dom/media/MediaTaskQueue.h | 9 + dom/media/PeerConnection.js | 1 + dom/media/StateMirroring.h | 17 +- dom/media/StateWatching.h | 1 + dom/media/TaskDispatcher.h | 2 + dom/media/TrackUnionStream.cpp | 32 +- dom/media/TrackUnionStream.h | 9 + dom/media/fmp4/MP4Reader.cpp | 28 +- dom/media/fmp4/MP4Reader.h | 4 +- dom/media/gtest/TestMP4Reader.cpp | 3 +- dom/media/mediasource/MediaSourceDecoder.cpp | 2 +- dom/media/mediasource/MediaSourceReader.cpp | 53 +- dom/media/mediasource/MediaSourceReader.h | 8 +- dom/media/mediasource/SourceBufferDecoder.h | 1 - dom/media/mediasource/TrackBuffer.cpp | 20 +- dom/media/nsIDOMNavigatorUserMedia.idl | 3 +- dom/media/omx/MediaCodecReader.cpp | 6 +- dom/media/omx/MediaCodecReader.h | 2 +- dom/media/omx/MediaOmxReader.cpp | 21 +- dom/media/omx/MediaOmxReader.h | 17 +- dom/media/omx/OmxDecoder.h | 2 - dom/media/systemservices/MediaChild.cpp | 138 +- dom/media/systemservices/MediaChild.h | 33 +- dom/media/systemservices/MediaParent.cpp | 215 ++- dom/media/systemservices/MediaParent.h | 35 +- dom/media/systemservices/MediaUtils.h | 389 +++- dom/media/systemservices/PMedia.ipdl | 3 +- .../test/test_streams_individual_pause.html | 9 +- dom/media/tests/mochitest/head.js | 9 +- .../mochitest/identity/.#identityPcTest.js | 1 + .../mochitest/identity/identityPcTest.js | 51 + dom/media/tests/mochitest/identity/idp.js | 76 +- dom/media/tests/mochitest/identity/idp.sjs | 18 + dom/media/tests/mochitest/identity/login.html | 31 + .../tests/mochitest/identity/mochitest.ini | 8 + .../mochitest/identity/test_fingerprints.html | 2 +- .../identity/test_getIdentityAssertion.html | 7 +- .../mochitest/identity/test_idpproxy.html | 6 +- .../mochitest/identity/test_loginNeeded.html | 71 + ...st_peerConnection_asymmetricIsolation.html | 32 + .../test_peerConnection_peerIdentity.html | 62 +- .../mochitest/test_enumerateDevices.html | 41 +- .../test_getUserMedia_constraints.html | 8 - dom/media/webaudio/AudioContext.cpp | 44 + dom/media/webaudio/AudioContext.h | 27 + dom/media/webaudio/BufferDecoder.cpp | 7 - dom/media/webaudio/BufferDecoder.h | 2 - dom/media/webaudio/MediaBufferDecoder.cpp | 14 +- dom/media/webaudio/OscillatorNode.cpp | 11 +- dom/media/webaudio/PeriodicWave.h | 1 - dom/media/webaudio/blink/PeriodicWave.h | 4 + dom/media/webm/WebMReader.cpp | 4 +- dom/media/webm/WebMReader.h | 2 +- dom/media/webrtc/MediaEngine.h | 27 +- .../webrtc/MediaEngineCameraVideoSource.cpp | 141 +- .../webrtc/MediaEngineCameraVideoSource.h | 34 +- dom/media/webrtc/MediaEngineDefault.cpp | 44 +- dom/media/webrtc/MediaEngineDefault.h | 45 +- .../webrtc/MediaEngineGonkVideoSource.cpp | 9 +- dom/media/webrtc/MediaEngineGonkVideoSource.h | 3 +- .../webrtc/MediaEngineTabVideoSource.cpp | 7 +- dom/media/webrtc/MediaEngineTabVideoSource.h | 9 +- dom/media/webrtc/MediaEngineWebRTC.cpp | 35 +- dom/media/webrtc/MediaEngineWebRTC.h | 38 +- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 30 +- dom/media/webrtc/MediaEngineWebRTCVideo.cpp | 34 +- dom/media/webrtc/MediaTrackConstraints.cpp | 126 ++ dom/media/webrtc/MediaTrackConstraints.h | 23 + dom/webidl/MediaStream.webidl | 14 +- dom/webidl/MediaTrackConstraintSet.webidl | 4 +- ipc/glue/BackgroundChildImpl.cpp | 13 - ipc/glue/BackgroundChildImpl.h | 6 - ipc/glue/BackgroundParentImpl.cpp | 13 - ipc/glue/BackgroundParentImpl.h | 6 - ipc/glue/PBackground.ipdl | 3 - 98 files changed, 2929 insertions(+), 2112 deletions(-) create mode 100644 dom/media/tests/mochitest/identity/.#identityPcTest.js create mode 100644 dom/media/tests/mochitest/identity/identityPcTest.js create mode 100644 dom/media/tests/mochitest/identity/idp.sjs create mode 100644 dom/media/tests/mochitest/identity/login.html create mode 100644 dom/media/tests/mochitest/identity/test_loginNeeded.html create mode 100644 dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index dc5d5e55ff..40be61bf84 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -50,6 +50,7 @@ #include "mozilla/plugins/PluginInstanceParent.h" #include "mozilla/plugins/PluginModuleParent.h" #include "mozilla/widget/WidgetMessageUtils.h" +#include "mozilla/media/MediaChild.h" #if defined(MOZ_CONTENT_SANDBOX) #if defined(XP_WIN) @@ -201,6 +202,7 @@ using namespace mozilla::dom::mobileconnection; using namespace mozilla::dom::mobilemessage; using namespace mozilla::dom::telephony; using namespace mozilla::dom::voicemail; +using namespace mozilla::media; using namespace mozilla::embedding; using namespace mozilla::gmp; using namespace mozilla::hal_sandbox; @@ -1704,6 +1706,18 @@ ContentChild::DeallocPVoicemailChild(PVoicemailChild* aActor) return true; } +media::PMediaChild* +ContentChild::AllocPMediaChild() +{ + return media::AllocPMediaChild(); +} + +bool +ContentChild::DeallocPMediaChild(media::PMediaChild *aActor) +{ + return media::DeallocPMediaChild(aActor); +} + PStorageChild* ContentChild::AllocPStorageChild() { diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 2114ed0f6e..489bcf2dbf 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -256,6 +256,9 @@ public: PVoicemailChild* SendPVoicemailConstructor(PVoicemailChild* aActor); virtual bool DeallocPVoicemailChild(PVoicemailChild*) override; + virtual PMediaChild* AllocPMediaChild() override; + virtual bool DeallocPMediaChild(PMediaChild* aActor) override; + virtual PStorageChild* AllocPStorageChild() override; virtual bool DeallocPStorageChild(PStorageChild* aActor) override; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 1949a98ac1..5c38601c4c 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -73,6 +73,7 @@ #include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/layers/SharedBufferManagerParent.h" #include "mozilla/LookAndFeel.h" +#include "mozilla/media/MediaParent.h" #include "mozilla/net/NeckoParent.h" #include "mozilla/plugins/PluginBridge.h" #include "mozilla/Preferences.h" @@ -253,6 +254,7 @@ using namespace mozilla::dom::mobileconnection; using namespace mozilla::dom::mobilemessage; using namespace mozilla::dom::telephony; using namespace mozilla::dom::voicemail; +using namespace mozilla::media; using namespace mozilla::embedding; using namespace mozilla::gmp; using namespace mozilla::hal; @@ -3699,6 +3701,18 @@ ContentParent::DeallocPVoicemailParent(PVoicemailParent* aActor) return true; } +media::PMediaParent* +ContentParent::AllocPMediaParent() +{ + return media::AllocPMediaParent(); +} + +bool +ContentParent::DeallocPMediaParent(media::PMediaParent *aActor) +{ + return media::DeallocPMediaParent(aActor); +} + PStorageParent* ContentParent::AllocPStorageParent() { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 7463093187..66ff4b6fc2 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -633,6 +633,9 @@ private: virtual bool RecvPVoicemailConstructor(PVoicemailParent* aActor) override; virtual bool DeallocPVoicemailParent(PVoicemailParent* aActor) override; + virtual PMediaParent* AllocPMediaParent() override; + virtual bool DeallocPMediaParent(PMediaParent* aActor) override; + virtual bool DeallocPStorageParent(PStorageParent* aActor) override; virtual PBluetoothParent* AllocPBluetoothParent() override; diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 7f7ce89e9a..57f6279c7c 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -24,6 +24,7 @@ include protocol PHal; include protocol PIcc; include protocol PProcessHangMonitor; include protocol PImageBridge; +include protocol PMedia; include protocol PMemoryReportRequest; include protocol PMobileConnection; include protocol PNecko; @@ -434,6 +435,7 @@ prio(normal upto urgent) sync protocol PContent manages PFMRadio; manages PHal; manages PIcc; + manages PMedia; manages PMemoryReportRequest; manages PMobileConnection; manages PNecko; @@ -762,6 +764,8 @@ parent: PVoicemail(); + PMedia(); + PBluetooth(); PFMRadio(); diff --git a/dom/media/AbstractMediaDecoder.h b/dom/media/AbstractMediaDecoder.h index b0c6fe6fcf..b5997468b3 100644 --- a/dom/media/AbstractMediaDecoder.h +++ b/dom/media/AbstractMediaDecoder.h @@ -8,6 +8,7 @@ #define AbstractMediaDecoder_h_ #include "mozilla/Attributes.h" +#include "StateMirroring.h" #include "MediaInfo.h" #include "nsISupports.h" #include "nsDataHashtable.h" @@ -68,8 +69,7 @@ public: virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) = 0; - // Return the duration of the media in microseconds. - virtual int64_t GetMediaDuration() = 0; + virtual AbstractCanonical* CanonicalDurationOrNull() { return nullptr; }; // Sets the duration of the media in microseconds. The MediaDecoder // fires a durationchange event to its owner (e.g., an HTML audio diff --git a/dom/media/DecodedStream.cpp b/dom/media/DecodedStream.cpp index 2c6304f023..3beffaa89b 100644 --- a/dom/media/DecodedStream.cpp +++ b/dom/media/DecodedStream.cpp @@ -69,10 +69,8 @@ private: bool mStreamFinishedOnMainThread; }; -DecodedStreamData::DecodedStreamData(int64_t aInitialTime, - SourceMediaStream* aStream) +DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream) : mAudioFramesWritten(0) - , mInitialTime(aInitialTime) , mNextVideoTime(-1) , mNextAudioTime(-1) , mStreamInitialized(false) @@ -102,9 +100,9 @@ DecodedStreamData::IsFinished() const } int64_t -DecodedStreamData::GetClock() const +DecodedStreamData::GetPosition() const { - return mInitialTime + mListener->GetLastOutputTime(); + return mListener->GetLastOutputTime(); } class OutputStreamListener : public MediaStreamListener { @@ -189,10 +187,10 @@ DecodedStream::GetData() const void DecodedStream::DestroyData() { - MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(NS_IsMainThread()); GetReentrantMonitor().AssertCurrentThreadIn(); - // Avoid the redundant blocking to output stream. + // Avoid the redundant blocking to output stream. if (!mData) { return; } @@ -222,18 +220,18 @@ DecodedStream::DestroyData() } void -DecodedStream::RecreateData(int64_t aInitialTime, MediaStreamGraph* aGraph) +DecodedStream::RecreateData(MediaStreamGraph* aGraph) { - MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(NS_IsMainThread()); GetReentrantMonitor().AssertCurrentThreadIn(); MOZ_ASSERT((aGraph && !mData && OutputStreams().IsEmpty()) || // first time (!aGraph && mData)); // 2nd time and later auto source = aGraph->CreateSourceStream(nullptr); DestroyData(); - mData.reset(new DecodedStreamData(aInitialTime, source)); + mData.reset(new DecodedStreamData(source)); - // Note that the delay between removing ports in DestroyDecodedStream + // Note that the delay between removing ports in DestroyDecodedStream // and adding new ones won't cause a glitch since all graph operations // between main-thread stable states take effect atomically. auto& outputStreams = OutputStreams(); @@ -247,7 +245,7 @@ DecodedStream::RecreateData(int64_t aInitialTime, MediaStreamGraph* aGraph) nsTArray& DecodedStream::OutputStreams() { - GetReentrantMonitor().AssertCurrentThreadIn(); + GetReentrantMonitor().AssertCurrentThreadIn(); return mOutputStreams; } diff --git a/dom/media/DecodedStream.h b/dom/media/DecodedStream.h index 0ccdb29280..b1d7c59d1b 100644 --- a/dom/media/DecodedStream.h +++ b/dom/media/DecodedStream.h @@ -37,19 +37,16 @@ class Image; */ class DecodedStreamData { public: - DecodedStreamData(int64_t aInitialTime, SourceMediaStream* aStream); + explicit DecodedStreamData(SourceMediaStream* aStream); ~DecodedStreamData(); bool IsFinished() const; - int64_t GetClock() const; + int64_t GetPosition() const; /* The following group of fields are protected by the decoder's monitor * and can be read or written on any thread. */ // Count of audio frames written to the stream int64_t mAudioFramesWritten; - // Saved value of aInitialTime. Timestamp of the first audio and/or - // video packet written. - const int64_t mInitialTime; // microseconds // mNextVideoTime is the end timestamp for the last packet sent to the stream. // Therefore video packets starting at or after this time need to be copied // to the output stream. @@ -92,7 +89,7 @@ public: explicit DecodedStream(ReentrantMonitor& aMonitor); DecodedStreamData* GetData() const; void DestroyData(); - void RecreateData(int64_t aInitialTime, MediaStreamGraph* aGraph); + void RecreateData(MediaStreamGraph* aGraph); nsTArray& OutputStreams(); ReentrantMonitor& GetReentrantMonitor() const; void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded); diff --git a/dom/media/IdpSandbox.jsm b/dom/media/IdpSandbox.jsm index 7c638b1003..a3bc58f92f 100644 --- a/dom/media/IdpSandbox.jsm +++ b/dom/media/IdpSandbox.jsm @@ -202,7 +202,7 @@ IdpSandbox.prototype = { wantGlobalProperties: [ 'indexedDB', 'XMLHttpRequest', 'TextEncoder', 'TextDecoder', 'URL', 'URLSearchParams', 'atob', 'btoa', 'Blob', 'crypto', - 'rtcIdentityProvider' + 'rtcIdentityProvider', 'fetch' ] }); let registrar = this.sandbox.rtcIdentityProvider; diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 962fd4e2d9..23dd510066 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -308,25 +308,21 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream, double MediaDecoder::GetDuration() { MOZ_ASSERT(NS_IsMainThread()); - if (mInfiniteStream) { - return std::numeric_limits::infinity(); - } - if (mDuration >= 0) { - return static_cast(mDuration) / static_cast(USECS_PER_S); - } - return std::numeric_limits::quiet_NaN(); + return mDuration; } -int64_t MediaDecoder::GetMediaDuration() +AbstractCanonical* +MediaDecoder::CanonicalDurationOrNull() { - NS_ENSURE_TRUE(GetStateMachine(), -1); - return GetStateMachine()->GetDuration(); + MOZ_ASSERT(mDecoderStateMachine); + return mDecoderStateMachine->CanonicalDuration(); } void MediaDecoder::SetInfinite(bool aInfinite) { MOZ_ASSERT(NS_IsMainThread()); mInfiniteStream = aInfinite; + DurationChanged(); } bool MediaDecoder::IsInfinite() @@ -347,7 +343,8 @@ MediaDecoder::MediaDecoder() : mVolume(AbstractThread::MainThread(), 0.0, "MediaDecoder::mVolume (Canonical)"), mPlaybackRate(AbstractThread::MainThread(), 1.0, "MediaDecoder::mPlaybackRate (Canonical)"), mPreservesPitch(AbstractThread::MainThread(), true, "MediaDecoder::mPreservesPitch (Canonical)"), - mDuration(-1), + mDuration(std::numeric_limits::quiet_NaN()), + mStateMachineDuration(AbstractThread::MainThread(), NullableTimeUnit(), "MediaDecoder::mStateMachineDuration (Mirror)"), mMediaSeekable(true), mSameOriginMedia(false), mReentrantMonitor("media.decoder"), @@ -370,6 +367,7 @@ MediaDecoder::MediaDecoder() : mPausedForPlaybackRateNull(false), mMinimizePreroll(false), mMediaTracksConstructed(false), + mFiredMetadataLoaded(false), mIsDormant(false), mWasEndedWhenEnteredDormant(false), mIsHeuristicDormantSupported( @@ -389,6 +387,9 @@ MediaDecoder::MediaDecoder() : // Initialize watchers. // + // mDuration + mWatchManager.Watch(mStateMachineDuration, &MediaDecoder::DurationChanged); + // readyState mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateReadyState); mWatchManager.Watch(mNextFrameStatus, &MediaDecoder::UpdateReadyState); @@ -647,17 +648,6 @@ void MediaDecoder::MetadataLoaded(nsAutoPtr aInfo, aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->HasAudio(), aInfo->HasVideo()); - { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1; - // Duration has changed so we should recompute playback rate - UpdatePlaybackRate(); - } - - if (mDuration == -1) { - SetInfinite(true); - } - mInfo = aInfo.forget(); ConstructMediaTracks(); @@ -666,6 +656,7 @@ void MediaDecoder::MetadataLoaded(nsAutoPtr aInfo, // our new size. Invalidate(); if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { + mFiredMetadataLoaded = true; mOwner->MetadataLoaded(mInfo, nsAutoPtr(aTags.forget())); } } @@ -866,9 +857,9 @@ double MediaDecoder::ComputePlaybackRate(bool* aReliable) MOZ_ASSERT(NS_IsMainThread() || OnStateMachineTaskQueue() || OnDecodeTaskQueue()); int64_t length = mResource ? mResource->GetLength() : -1; - if (mDuration >= 0 && length >= 0) { + if (!IsNaN(mDuration) && !mozilla::IsInfinite(mDuration) && length >= 0) { *aReliable = true; - return length * static_cast(USECS_PER_S) / mDuration; + return length * mDuration; } return mPlaybackStatistics->GetRateAtLastStop(aReliable); } @@ -1076,24 +1067,38 @@ void MediaDecoder::UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisib } } -void MediaDecoder::DurationChanged(TimeUnit aNewDuration) +void MediaDecoder::DurationChanged() { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - int64_t oldDuration = mDuration; - mDuration = aNewDuration.ToMicroseconds(); + + double oldDuration = mDuration; + if (IsInfinite()) { + mDuration = std::numeric_limits::infinity(); + } else if (mExplicitDuration.Ref().isSome()) { + mDuration = mExplicitDuration.Ref().ref(); + } else if (mStateMachineDuration.Ref().isSome()) { + mDuration = mStateMachineDuration.Ref().ref().ToSeconds(); + } + + if (mDuration == oldDuration || IsNaN(mDuration)) { + return; + } + + DECODER_LOG("Duration changed to %f", mDuration); + // Duration has changed so we should recompute playback rate UpdatePlaybackRate(); - SetInfinite(mDuration == -1); - - if (mOwner && oldDuration != mDuration && !IsInfinite()) { - DECODER_LOG("Duration changed to %lld", mDuration); + // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=28822 for a discussion + // of whether we should fire durationchange on explicit infinity. + if (mOwner && mFiredMetadataLoaded && + (!mozilla::IsInfinite(mDuration) || mExplicitDuration.Ref().isSome())) { mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange")); } - if (CurrentPosition() > aNewDuration.ToMicroseconds()) { - Seek(aNewDuration.ToSeconds(), SeekTarget::Accurate); + if (CurrentPosition() > TimeUnit::FromSeconds(mDuration).ToMicroseconds()) { + Seek(mDuration, SeekTarget::Accurate); } } @@ -1156,8 +1161,7 @@ void MediaDecoder::SetFragmentEndTime(double aTime) { MOZ_ASSERT(NS_IsMainThread()); if (mDecoderStateMachine) { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - mDecoderStateMachine->SetFragmentEndTime(static_cast(aTime * USECS_PER_S)); + mDecoderStateMachine->DispatchSetFragmentEndTime(static_cast(aTime * USECS_PER_S)); } } @@ -1255,9 +1259,11 @@ MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine) mDecoderStateMachine = aStateMachine; if (mDecoderStateMachine) { + mStateMachineDuration.Connect(mDecoderStateMachine->CanonicalDuration()); mNextFrameStatus.Connect(mDecoderStateMachine->CanonicalNextFrameStatus()); mCurrentPosition.Connect(mDecoderStateMachine->CanonicalCurrentPosition()); } else { + mStateMachineDuration.DisconnectIfConnected(); mNextFrameStatus.DisconnectIfConnected(); mCurrentPosition.DisconnectIfConnected(); } diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index 4f08aaf4d9..76beba38eb 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -399,8 +399,7 @@ public: // Return the duration of the video in seconds. virtual double GetDuration(); - // Return the duration of the video in seconds. - int64_t GetMediaDuration() final override; + AbstractCanonical* CanonicalDurationOrNull() override; // A media stream is assumed to be infinite if the metadata doesn't // contain the duration, and range requests are not supported, and @@ -508,10 +507,6 @@ public: // Returns a weak reference to the media decoder owner. MediaDecoderOwner* GetMediaOwner() const; - // Called by the state machine to notify the decoder that the duration - // has changed. - void DurationChanged(media::TimeUnit aNewDuration); - bool OnStateMachineTaskQueue() const override; bool OnDecodeTaskQueue() const override; @@ -874,6 +869,10 @@ protected: // Return true if the decoder has reached the end of playback bool IsEnded() const; + // Called by the state machine to notify the decoder that the duration + // has changed. + void DurationChanged(); + // State-watching manager. WatchManager mWatchManager; @@ -929,10 +928,11 @@ public: AbstractCanonical* CanonicalPreservesPitch() { return &mPreservesPitch; } protected: - // Duration of the media resource. Set to -1 if unknown. - // Set when the metadata is loaded. Accessed on the main thread - // only. - int64_t mDuration; + // Official duration of the media resource as observed by script. + double mDuration; + + // Duration of the media resource according to the state machine. + Mirror mStateMachineDuration; // True if the media is seekable (i.e. supports random access). bool mMediaSeekable; @@ -980,10 +980,19 @@ public: AbstractCanonical* CanonicalEstimatedDuration() { return &mEstimatedDuration; } protected: - // Media duration set explicitly by JS. Currently, this is only ever present for MSE. + // Media duration set explicitly by JS. At present, this is only ever present + // for MSE. Canonical> mExplicitDuration; double ExplicitDuration() { return mExplicitDuration.Ref().ref(); } - void SetExplicitDuration(double aValue) { mExplicitDuration.Set(Some(aValue)); } + void SetExplicitDuration(double aValue) + { + mExplicitDuration.Set(Some(aValue)); + + // We Invoke DurationChanged explicitly, rather than using a watcher, so + // that it takes effect immediately, rather than at the end of the current task. + DurationChanged(); + } + public: AbstractCanonical>* CanonicalExplicitDuration() { return &mExplicitDuration; } protected: @@ -1075,6 +1084,9 @@ protected: // track list, false if all tracks are removed from the track list. bool mMediaTracksConstructed; + // True if we've already fired metadataloaded. + bool mFiredMetadataLoaded; + // Stores media info, including info of audio tracks and video tracks, should // only be accessed from main thread. nsAutoPtr mInfo; diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index f5ba3bdccb..76adfc1531 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -15,6 +15,8 @@ #include #include +using namespace mozilla::media; + namespace mozilla { // Un-comment to enable logging of seek bisections. @@ -60,18 +62,36 @@ public: size_t mSize; }; -MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder) +MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder, + MediaTaskQueue* aBorrowedTaskQueue) : mAudioCompactor(mAudioQueue) , mDecoder(aDecoder) + , mTaskQueue(aBorrowedTaskQueue ? aBorrowedTaskQueue + : new MediaTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK), + /* aSupportsTailDispatch = */ true)) + , mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderReader::mDuration (Mirror)") , mIgnoreAudioOutputFormat(false) , mStartTime(-1) , mHitAudioDecodeError(false) , mShutdown(false) - , mTaskQueueIsBorrowed(false) + , mTaskQueueIsBorrowed(!!aBorrowedTaskQueue) , mAudioDiscontinuity(false) , mVideoDiscontinuity(false) { MOZ_COUNT_CTOR(MediaDecoderReader); + MOZ_ASSERT(NS_IsMainThread()); + + // Dispatch initialization that needs to happen on that task queue. + nsCOMPtr r = NS_NewRunnableMethod(this, &MediaDecoderReader::InitializationTask); + mTaskQueue->Dispatch(r.forget()); +} + +void +MediaDecoderReader::InitializationTask() +{ + if (mDecoder->CanonicalDurationOrNull()) { + mDuration.Connect(mDecoder->CanonicalDurationOrNull()); + } } MediaDecoderReader::~MediaDecoderReader() @@ -153,26 +173,12 @@ MediaDecoderReader::GetBuffered() { NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals()); AutoPinned stream(mDecoder->GetResource()); - int64_t durationUs = 0; - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - durationUs = mDecoder->GetMediaDuration(); - } - return GetEstimatedBufferedTimeRanges(stream, durationUs); -} -int64_t -MediaDecoderReader::ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) -{ - int64_t startTime = std::min(aAudio ? aAudio->mTime : INT64_MAX, - aVideo ? aVideo->mTime : INT64_MAX); - if (startTime == INT64_MAX) { - startTime = 0; + if (!mDuration.Ref().isSome()) { + return TimeIntervals(); } - DECODER_LOG("ComputeStartTime first video frame start %lld", aVideo ? aVideo->mTime : -1); - DECODER_LOG("ComputeStartTime first audio frame start %lld", aAudio ? aAudio->mTime : -1); - NS_ASSERTION(startTime >= 0, "Start time is negative"); - return startTime; + + return GetEstimatedBufferedTimeRanges(stream, mDuration.Ref().ref().ToMicroseconds()); } nsRefPtr @@ -220,7 +226,7 @@ public: NS_METHOD Run() { - MOZ_ASSERT(mReader->GetTaskQueue()->IsCurrentThreadIn()); + MOZ_ASSERT(mReader->OnTaskQueue()); // Make sure ResetDecode hasn't been called in the mean time. if (!mReader->mBaseVideoPromise.IsEmpty()) { @@ -245,7 +251,7 @@ public: NS_METHOD Run() { - MOZ_ASSERT(mReader->GetTaskQueue()->IsCurrentThreadIn()); + MOZ_ASSERT(mReader->OnTaskQueue()); // Make sure ResetDecode hasn't been called in the mean time. if (!mReader->mBaseAudioPromise.IsEmpty()) { @@ -330,23 +336,12 @@ MediaDecoderReader::RequestAudioData() return p; } -MediaTaskQueue* -MediaDecoderReader::EnsureTaskQueue() -{ - if (!mTaskQueue) { - MOZ_ASSERT(!mTaskQueueIsBorrowed); - RefPtr pool(GetMediaThreadPool(MediaThreadType::PLAYBACK)); - MOZ_DIAGNOSTIC_ASSERT(pool); - mTaskQueue = new MediaTaskQueue(pool.forget()); - } - - return mTaskQueue; -} - void MediaDecoderReader::BreakCycles() { - mTaskQueue = nullptr; + // Nothing left to do here these days. We keep this method around so that, if + // we need it, we don't have to make all of the subclass implementations call + // the superclass method again. } nsRefPtr @@ -359,11 +354,13 @@ MediaDecoderReader::Shutdown() mBaseVideoPromise.RejectIfExists(END_OF_STREAM, __func__); ReleaseMediaResources(); + mDuration.DisconnectIfConnected(); + nsRefPtr p; // Spin down the task queue if necessary. We wait until BreakCycles to null // out mTaskQueue, since otherwise any remaining tasks could crash when they - // invoke GetTaskQueue()->IsCurrentThreadIn(). + // invoke OnTaskQueue(). if (mTaskQueue && !mTaskQueueIsBorrowed) { // If we own our task queue, shutdown ends when the task queue is done. p = mTaskQueue->BeginShutdown(); diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index 5052a49c37..96befc0e87 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -79,7 +79,13 @@ public: // The caller must ensure that Shutdown() is called before aDecoder is // destroyed. - explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder); + explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder, MediaTaskQueue* aBorrowedTaskQueue = nullptr); + + // Does any spinup that needs to happen on this task queue. This runs on a + // different thread than Init, and there should not be ordering dependencies + // between the two (even though in practice, Init will always run first right + // now thanks to the tail dispatcher). + void InitializationTask(); // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE // on failure. @@ -107,18 +113,9 @@ public: // thread. virtual nsRefPtr Shutdown(); - MediaTaskQueue* EnsureTaskQueue(); - virtual bool OnTaskQueue() { - return !GetTaskQueue() || GetTaskQueue()->IsCurrentThreadIn(); - } - - void SetBorrowedTaskQueue(MediaTaskQueue* aTaskQueue) - { - MOZ_ASSERT(!mTaskQueue && aTaskQueue); - mTaskQueue = aTaskQueue; - mTaskQueueIsBorrowed = true; + return TaskQueue()->IsCurrentThreadIn(); } // Resets all state related to decoding, emptying all buffers etc. @@ -225,8 +222,6 @@ public: // MediaSourceReader opts out of the start-time-guessing mechanism. virtual bool ForceZeroStartTime() const { return false; } - virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio); - // The MediaDecoderStateMachine uses various heuristics that assume that // raw media data is arriving sequentially from a network channel. This // makes sense in the