Bug 1172264 - Mirror duration from the MDSM to the MediaDecoderReader and remove MDSM::GetDuration. r=jww
authorBobby Holley <bobbyholley@gmail.com>
Tue, 09 Jun 2015 12:41:24 -0700
changeset 249385 645564f3f35f929fda373de5352263dce1c92e2a
parent 249384 bc8f5c62dbef51c76a6e3a494840d1546f117fe7
child 249386 5a1fd02713e2d68389850715a37192c7e498f0e2
push id61234
push userbobbyholley@gmail.com
push dateWed, 17 Jun 2015 16:49:23 +0000
treeherdermozilla-inbound@a5eb0b1fcf39 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjww
bugs1172264
milestone41.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
Bug 1172264 - Mirror duration from the MDSM to the MediaDecoderReader and remove MDSM::GetDuration. r=jww
dom/media/AbstractMediaDecoder.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderReader.cpp
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/StateMirroring.h
dom/media/StateWatching.h
dom/media/TaskDispatcher.h
dom/media/gstreamer/GStreamerReader.cpp
dom/media/mediasource/SourceBufferDecoder.h
dom/media/webaudio/BufferDecoder.cpp
dom/media/webaudio/BufferDecoder.h
--- 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;