author | Bobby Holley <bobbyholley@gmail.com> |
Tue, 09 Jun 2015 12:41:24 -0700 (2015-06-09) | |
changeset 249385 | 645564f3f35f929fda373de5352263dce1c92e2a |
parent 249384 | bc8f5c62dbef51c76a6e3a494840d1546f117fe7 |
child 249386 | 5a1fd02713e2d68389850715a37192c7e498f0e2 |
push id | 61234 |
push user | bobbyholley@gmail.com |
push date | Wed, 17 Jun 2015 16:49:23 +0000 (2015-06-17) |
treeherder | mozilla-inbound@a5eb0b1fcf39 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jww |
bugs | 1172264 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/media/AbstractMediaDecoder.h +++ b/dom/media/AbstractMediaDecoder.h @@ -3,16 +3,17 @@ /* 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 AbstractMediaDecoder_h_ #define AbstractMediaDecoder_h_ #include "mozilla/Attributes.h" +#include "StateMirroring.h" #include "MediaInfo.h" #include "nsISupports.h" #include "nsDataHashtable.h" #include "nsThreadUtils.h" namespace mozilla { @@ -66,18 +67,17 @@ public: virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) = 0; // Increments the parsed, decoded and dropped frame counters by the passed in // counts. // Can be called on any thread. 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<media::NullableTimeUnit>* 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 // tag). virtual void UpdateEstimatedMediaDuration(int64_t aDuration) = 0; // Set the media as being seekable or not. virtual void SetMediaSeekable(bool aMediaSeekable) = 0;
--- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -306,20 +306,21 @@ double MediaDecoder::GetDuration() MOZ_ASSERT(NS_IsMainThread()); if (mInfiniteStream) { return std::numeric_limits<double>::infinity(); } return mDuration; } -int64_t MediaDecoder::GetMediaDuration() +AbstractCanonical<media::NullableTimeUnit>* +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; }
--- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -397,18 +397,17 @@ public: // Add an output stream. All decoder output will be sent to the stream. // The stream is initially blocked. The decoder is responsible for unblocking // it while it is playing back. virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); // 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<media::NullableTimeUnit>* 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 // no headers give a hint of a possible duration (Content-Length, // Content-Duration, and variants), and we cannot seek in the media // stream to determine the duration. // // When the media stream ends, we can know the duration, thus the stream is
--- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -10,16 +10,18 @@ #include "VideoUtils.h" #include "ImageContainer.h" #include "nsPrintfCString.h" #include "mozilla/mozalloc.h" #include <stdint.h> #include <algorithm> +using namespace mozilla::media; + namespace mozilla { // Un-comment to enable logging of seek bisections. //#define SEEK_LOGGING extern PRLogModuleInfo* gMediaDecoderLog; #define DECODER_LOG(x, ...) \ MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("Decoder=%p " x, mDecoder, ##__VA_ARGS__)) @@ -62,25 +64,39 @@ public: 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(!!aBorrowedTaskQueue) , mAudioDiscontinuity(false) , mVideoDiscontinuity(false) { MOZ_COUNT_CTOR(MediaDecoderReader); + MOZ_ASSERT(NS_IsMainThread()); + + // Dispatch initialization that needs to happen on that task queue. + nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderReader::InitializationTask); + mTaskQueue->Dispatch(r.forget()); +} + +void +MediaDecoderReader::InitializationTask() +{ + if (mDecoder->CanonicalDurationOrNull()) { + mDuration.Connect(mDecoder->CanonicalDurationOrNull()); + } } MediaDecoderReader::~MediaDecoderReader() { MOZ_ASSERT(mShutdown); MOZ_ASSERT(!mDecoder); ResetDecode(); MOZ_COUNT_DTOR(MediaDecoderReader); @@ -152,22 +168,22 @@ MediaDecoderReader::SetStartTime(int64_t mStartTime = aStartTime; } media::TimeIntervals MediaDecoderReader::GetBuffered() { NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals()); AutoPinned<MediaResource> stream(mDecoder->GetResource()); - int64_t durationUs = 0; - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - durationUs = mDecoder->GetMediaDuration(); + + if (!mDuration.ReadOnWrongThread().isSome()) { + return TimeIntervals(); } - return GetEstimatedBufferedTimeRanges(stream, durationUs); + + return GetEstimatedBufferedTimeRanges(stream, mDuration.ReadOnWrongThread().ref().ToMicroseconds()); } nsRefPtr<MediaDecoderReader::MetadataPromise> MediaDecoderReader::AsyncReadMetadata() { typedef ReadMetadataFailureReason Reason; MOZ_ASSERT(OnTaskQueue()); @@ -336,16 +352,18 @@ MediaDecoderReader::Shutdown() { MOZ_ASSERT(OnTaskQueue()); mShutdown = true; mBaseAudioPromise.RejectIfExists(END_OF_STREAM, __func__); mBaseVideoPromise.RejectIfExists(END_OF_STREAM, __func__); ReleaseMediaResources(); + mDuration.DisconnectIfConnected(); + nsRefPtr<ShutdownPromise> 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 OnTaskQueue(). if (mTaskQueue && !mTaskQueueIsBorrowed) { // If we own our task queue, shutdown ends when the task queue is done. p = mTaskQueue->BeginShutdown();
--- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -76,16 +76,22 @@ public: typedef MediaPromise<MediaData::Type, WaitForDataRejectValue, /* IsExclusive = */ true> WaitForDataPromise; NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader) // The caller must ensure that Shutdown() is called before aDecoder is // destroyed. 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. virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0; // 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. @@ -313,16 +319,19 @@ protected: AbstractMediaDecoder* mDecoder; // Decode task queue. nsRefPtr<MediaTaskQueue> mTaskQueue; // Stores presentation info required for playback. MediaInfo mInfo; + // Duration, mirrored from the state machine task queue. + Mirror<media::NullableTimeUnit> mDuration; + // Whether we should accept media that we know we can't play // directly, because they have a number of channel higher than // what we support. bool mIgnoreAudioOutputFormat; // The start time of the media, in microseconds. This is the presentation // time of the first frame decoded from the media. This is initialized to -1, // and then set to a value >= by MediaDecoderStateMachine::SetStartTime(),
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1375,26 +1375,16 @@ void MediaDecoderStateMachine::VolumeCha } } bool MediaDecoderStateMachine::IsRealTime() const { return mRealTime; } -int64_t MediaDecoderStateMachine::GetDuration() -{ - AssertCurrentThreadInMonitor(); - if (mDuration.Ref().isNothing() || Duration().IsInfinite()) { - return -1; - } - - return Duration().ToMicroseconds(); -} - void MediaDecoderStateMachine::RecomputeDuration() { MOZ_ASSERT(OnTaskQueue()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); // We dispatch DurationChanged to the MediaDecoder when the duration changes // sometime after initialization, unless it has already been fired by the code // that set the new duration.
--- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -181,20 +181,16 @@ public: NS_NewRunnableMethod(this, &MediaDecoderStateMachine::Shutdown); TaskQueue()->Dispatch(runnable.forget()); } void FinishShutdown(); bool IsRealTime() const; - // Called from the main thread to get the duration. The decoder monitor - // must be obtained before calling this. It is in units of microseconds. - int64_t GetDuration(); - // Functions used by assertions to ensure we're calling things // on the appropriate threads. bool OnDecodeTaskQueue() const; bool OnTaskQueue() const; // Seeks to the decoder to aTarget asynchronously. // Must be called on the state machine thread. nsRefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget);
--- a/dom/media/StateMirroring.h +++ b/dom/media/StateMirroring.h @@ -304,16 +304,19 @@ private: } operator const T&() { MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn()); return mValue; } + // Temporary workaround for naughty code. + const T& ReadOnWrongThread() { return mValue; } + virtual void UpdateValue(const T& aNewValue) override { MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn()); if (mValue != aNewValue) { mValue = aNewValue; WatchTarget::NotifyWatchers(); } } @@ -369,16 +372,17 @@ public: void DisconnectIfConnected() { mImpl->DisconnectIfConnected(); } // Access to the Impl<T>. operator Impl&() { return *mImpl; } Impl* operator&() { return mImpl; } // Access to the T. const T& Ref() const { return *mImpl; } + const T& ReadOnWrongThread() const { return mImpl->ReadOnWrongThread(); } operator const T&() const { return Ref(); } private: nsRefPtr<Impl> mImpl; }; #undef MIRROR_LOG
--- a/dom/media/StateWatching.h +++ b/dom/media/StateWatching.h @@ -3,16 +3,17 @@ /* 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/. */ #if !defined(StateWatching_h_) #define StateWatching_h_ #include "AbstractThread.h" +#include "TaskDispatcher.h" #include "mozilla/UniquePtr.h" #include "mozilla/unused.h" #include "nsISupportsImpl.h" /* * The state-watching machinery automates the process of responding to changes
--- a/dom/media/TaskDispatcher.h +++ b/dom/media/TaskDispatcher.h @@ -11,16 +11,18 @@ #include "mozilla/UniquePtr.h" #include "mozilla/unused.h" #include "nsISupportsImpl.h" #include "nsTArray.h" #include "nsThreadUtils.h" +#include <queue> + namespace mozilla { /* * A classic approach to cross-thread communication is to dispatch asynchronous * runnables to perform updates on other threads. This generally works well, but * there are sometimes reasons why we might want to delay the actual dispatch of * these tasks until a specified moment. At present, this is primarily useful to * ensure that mirrored state gets updated atomically - but there may be other
--- a/dom/media/gstreamer/GStreamerReader.cpp +++ b/dom/media/gstreamer/GStreamerReader.cpp @@ -882,25 +882,19 @@ media::TimeIntervals GStreamerReader::Ge #if GST_VERSION_MAJOR == 0 GstFormat format = GST_FORMAT_TIME; #endif AutoPinned<MediaResource> resource(mDecoder->GetResource()); nsTArray<MediaByteRange> ranges; resource->GetCachedRanges(ranges); - if (resource->IsDataCachedToEndOfResource(0)) { + if (resource->IsDataCachedToEndOfResource(0) && mDuration.ReadOnWrongThread().isSome()) { /* fast path for local or completely cached files */ - gint64 duration = 0; - - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - duration = mDecoder->GetMediaDuration(); - } - + gint64 duration = mDuration.ReadOnWrongThread().ref().ToMicroseconds(); LOG(LogLevel::Debug, "complete range [0, %f] for [0, %li]", (double) duration / GST_MSECOND, GetDataLength()); buffered += media::TimeInterval(media::TimeUnit::FromMicroseconds(0), media::TimeUnit::FromMicroseconds(duration)); return buffered; }
--- a/dom/media/mediasource/SourceBufferDecoder.h +++ b/dom/media/mediasource/SourceBufferDecoder.h @@ -31,17 +31,16 @@ public: NS_DECL_THREADSAFE_ISUPPORTS virtual bool IsMediaSeekable() final override; virtual bool IsShutdown() const final override; virtual bool IsTransportSeekable() final override; virtual bool OnDecodeTaskQueue() const final override; virtual bool OnStateMachineTaskQueue() const final override; - virtual int64_t GetMediaDuration() final override { MOZ_ASSERT_UNREACHABLE(""); return -1; }; virtual layers::ImageContainer* GetImageContainer() final override; virtual MediaDecoderOwner* GetOwner() final override; virtual SourceBufferResource* GetResource() const final override; virtual ReentrantMonitor& GetReentrantMonitor() final override; virtual VideoFrameContainer* GetVideoFrameContainer() final override; virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, MediaDecoderEventVisibility aEventVisibility) final override;
--- a/dom/media/webaudio/BufferDecoder.cpp +++ b/dom/media/webaudio/BufferDecoder.cpp @@ -80,23 +80,16 @@ BufferDecoder::NotifyBytesConsumed(int64 void BufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) { // ignore } -int64_t -BufferDecoder::GetMediaDuration() -{ - // unknown - return -1; -} - void BufferDecoder::UpdateEstimatedMediaDuration(int64_t aDuration) { // ignore } void BufferDecoder::SetMediaSeekable(bool aMediaSeekable)
--- a/dom/media/webaudio/BufferDecoder.h +++ b/dom/media/webaudio/BufferDecoder.h @@ -40,18 +40,16 @@ public: virtual MediaResource* GetResource() const final override; virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) final override; virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) final override; - virtual int64_t GetMediaDuration() final override; - virtual void UpdateEstimatedMediaDuration(int64_t aDuration) final override; virtual void SetMediaSeekable(bool aMediaSeekable) final override; virtual VideoFrameContainer* GetVideoFrameContainer() final override; virtual layers::ImageContainer* GetImageContainer() final override; virtual bool IsTransportSeekable() final override;