Bug 1160695 - Track "metadata duration" separately and mirror it to MediaDecoderReader. r=jww
authorBobby Holley <bobbyholley@gmail.com>
Sat, 30 May 2015 21:18:12 -0700
changeset 247616 cd83b74ed1e69dfd31080274fa3846d92e8d430e
parent 247615 149efc9c88cc2af250789bfb9711f6c4c9597323
child 247617 74cda113cc8860176ab6eefb0a58af9e2a6653a7
push id60756
push userbobbyholley@gmail.com
push dateMon, 08 Jun 2015 16:23:28 +0000
treeherdermozilla-inbound@636412252449 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjww
bugs1160695
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 1160695 - Track "metadata duration" separately and mirror it to MediaDecoderReader. r=jww
dom/media/AbstractMediaDecoder.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaFormatReader.cpp
dom/media/MediaInfo.h
dom/media/android/AndroidMediaReader.cpp
dom/media/apple/AppleMP3Reader.cpp
dom/media/directshow/DirectShowReader.cpp
dom/media/fmp4/MP4Reader.cpp
dom/media/gstreamer/GStreamerReader.cpp
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/SourceBufferDecoder.cpp
dom/media/mediasource/SourceBufferDecoder.h
dom/media/mediasource/TrackBuffer.cpp
dom/media/ogg/OggReader.cpp
dom/media/omx/MediaCodecReader.cpp
dom/media/omx/MediaOmxReader.cpp
dom/media/raw/RawReader.cpp
dom/media/wave/WaveReader.cpp
dom/media/webaudio/BufferDecoder.cpp
dom/media/webaudio/BufferDecoder.h
dom/media/webm/WebMReader.cpp
dom/media/wmf/WMFReader.cpp
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -69,19 +69,16 @@ public:
   // 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;
 
-  // Set the duration of the media in microseconds.
-  virtual void SetMediaDuration(int64_t aDuration) = 0;
-
   // 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;
 
@@ -95,19 +92,16 @@ public:
   virtual bool IsMediaSeekable() = 0;
 
   virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, MediaDecoderEventVisibility aEventVisibility) = 0;
   virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) = 0;
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, MediaDecoderEventVisibility aEventVisibility) = 0;
 
   virtual void RemoveMediaTracks() = 0;
 
-  // Set the media end time in microseconds
-  virtual void SetMediaEndTime(int64_t aTime) = 0;
-
   // May be called by the reader to notify this decoder that the metadata from
   // the media file has been read. Call on the decode thread only.
   virtual void OnReadMetadataCompleted() = 0;
 
   // Returns the owner of this media decoder. The owner should only be used
   // on the main thread.
   virtual MediaDecoderOwner* GetOwner() = 0;
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1101,22 +1101,16 @@ void MediaDecoder::SetNetworkDuration(Ti
     mDuration = static_cast<int64_t>(NS_round(aDuration * static_cast<double>(USECS_PER_S)));
   }
 
   // Duration has changed so we should recompute playback rate
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   UpdatePlaybackRate();
 }
 
-void MediaDecoder::SetMediaDuration(int64_t aDuration)
-{
-  NS_ENSURE_TRUE_VOID(GetStateMachine());
-  GetStateMachine()->SetDuration(aDuration);
-}
-
 void MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
 {
   if (mPlayState <= PLAY_STATE_LOADING) {
     return;
   }
   NS_ENSURE_TRUE_VOID(GetStateMachine());
   GetStateMachine()->UpdateEstimatedDuration(aDuration);
 }
@@ -1162,22 +1156,16 @@ void MediaDecoder::SetFragmentEndTime(do
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mDecoderStateMachine) {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     mDecoderStateMachine->SetFragmentEndTime(static_cast<int64_t>(aTime * USECS_PER_S));
   }
 }
 
-void MediaDecoder::SetMediaEndTime(int64_t aTime)
-{
-  NS_ENSURE_TRUE_VOID(GetStateMachine());
-  GetStateMachine()->SetMediaEndTime(aTime);
-}
-
 void MediaDecoder::Suspend()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mResource) {
     mResource->Suspend(true);
   }
 }
 
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -457,19 +457,16 @@ public:
   virtual bool IsEndedOrShutdown() const;
 
   // Set the duration of the media resource in units of seconds.
   // This is called via a channel listener if it can pick up the duration
   // from a content header. Must be called from the main thread only.
   void SetNetworkDuration(media::TimeUnit aDuration);
   media::NullableTimeUnit NetworkDuration() { return mNetworkDuration; }
 
-  // Sets the initial duration of the media. Called while the media metadata
-  // is being read and the decode is being setup.
-  void SetMediaDuration(int64_t aDuration) override;
   // Updates the media duration. This is called while the media is being
   // played, calls before the media has reached loaded metadata are ignored.
   // The duration is assumed to be an estimate, and so a degree of
   // instability is expected; if the incoming duration is not significantly
   // different from the existing duration, the change request is ignored.
   // If the incoming duration is significantly different, the duration is
   // changed, this causes a durationchanged event to fire to the media
   // element.
@@ -487,19 +484,16 @@ public:
 
   // Return the time ranges that can be seeked into.
   virtual media::TimeIntervals GetSeekable();
 
   // Set the end time of the media resource. When playback reaches
   // this point the media pauses. aTime is in seconds.
   virtual void SetFragmentEndTime(double aTime);
 
-  // Set the end time of the media. aTime is in microseconds.
-  void SetMediaEndTime(int64_t aTime) final override;
-
   // Invalidate the frame.
   void Invalidate();
   void InvalidateWithFlags(uint32_t aFlags);
 
   // Suspend any media downloads that are in progress. Called by the
   // media element when it is sent to the bfcache, or when we need
   // to throttle the download. Call on the main thread only. This can
   // be called multiple times, there's an internal "suspend count".
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1455,19 +1455,23 @@ private:
   double mSeekTarget;
 };
 
 void MediaDecoderStateMachine::RecomputeDuration()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
-  // XXXbholley - This will do something more sensible in upcoming patches. This
-  // would be incorrect if we ever sent spurious state mirroring updates.
-  if (mNetworkDuration.Ref().isSome()) {
+  if (mInfo.mMetadataDuration.isSome()) {
+    SetDuration(mInfo.mMetadataDuration.ref().ToMicroseconds());
+  } else if (mInfo.mMetadataEndTime.isSome() && mStartTime >= 0) {
+    SetDuration((mInfo.mMetadataEndTime.ref() - TimeUnit::FromMicroseconds(mStartTime)).ToMicroseconds());
+  } else if (mNetworkDuration.Ref().isSome()) {
+    // XXXbholley - This will do something more sensible in upcoming patches. This
+    // would be incorrect if we ever sent spurious state mirroring updates.
     SetDuration(mNetworkDuration.Ref().ref().ToMicroseconds());
   }
 }
 
 void MediaDecoderStateMachine::SetDuration(int64_t aDuration)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
@@ -1513,24 +1517,16 @@ void MediaDecoderStateMachine::UpdateEst
       mozilla::Abs(aDuration - duration) > ESTIMATED_DURATION_FUZZ_FACTOR_USECS) {
     SetDuration(aDuration);
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethod(mDecoder, &MediaDecoder::DurationChanged);
     AbstractThread::MainThread()->Dispatch(event.forget());
   }
 }
 
-void MediaDecoderStateMachine::SetMediaEndTime(int64_t aEndTime)
-{
-  MOZ_ASSERT(OnDecodeTaskQueue());
-  AssertCurrentThreadInMonitor();
-
-  mEndTime = aEndTime;
-}
-
 void MediaDecoderStateMachine::SetFragmentEndTime(int64_t aEndTime)
 {
   AssertCurrentThreadInMonitor();
 
   mFragmentEndTime = aEndTime < 0 ? aEndTime : aEndTime + mStartTime;
 }
 
 bool MediaDecoderStateMachine::IsDormantNeeded()
@@ -2228,26 +2224,29 @@ MediaDecoderStateMachine::OnMetadataRead
   MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mMetadataRequest.Complete();
 
   mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
   mInfo = aMetadata->mInfo;
   mMetadataTags = aMetadata->mTags.forget();
 
+  if (mInfo.mMetadataDuration.isSome() || mInfo.mMetadataEndTime.isSome()) {
+    RecomputeDuration();
+  }
+
   if (HasVideo()) {
     DECODER_LOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
                 mReader->IsAsync(),
                 mReader->VideoIsHardwareAccelerated(),
                 GetAmpleVideoFrames());
   }
 
   mDecoder->StartProgressUpdates();
   mGotDurationFromMetaData = (GetDuration() != -1) || mDurationSet;
-
   if (mGotDurationFromMetaData) {
     // We have all the information required: duration and size
     // Inform the element that we've loaded the metadata.
     EnqueueLoadedMetadataEvent();
   }
 
   if (mReader->IsWaitingOnCDMResource()) {
     // Metadata parsing was successful but we're still waiting for CDM caps
@@ -3234,16 +3233,18 @@ void MediaDecoderStateMachine::SetStartT
   mReader->SetStartTime(mStartTime);
 
   // Set the audio start time to be start of media. If this lies before the
   // first actual audio frame we have, we'll inject silence during playback
   // to ensure the audio starts at the correct time.
   mAudioStartTime = mStartTime;
   mStreamStartTime = mStartTime;
   DECODER_LOG("Set media start time to %lld", mStartTime);
+
+  RecomputeDuration();
 }
 
 void MediaDecoderStateMachine::UpdateNextFrameStatus()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   MediaDecoderOwner::NextFrameStatus status;
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -201,21 +201,16 @@ public:
   // Called from the main thread to set the duration of the media resource
   // if it is able to be obtained via HTTP headers. Called from the
   // state machine thread to set the duration if it is obtained from the
   // media metadata. The decoder monitor must be obtained before calling this.
   // aDuration is in microseconds.
   // A value of INT64_MAX will be treated as infinity.
   void SetDuration(int64_t aDuration);
 
-  // Called while decoding metadata to set the end time of the media
-  // resource. The decoder monitor must be obtained before calling this.
-  // aEndTime is in microseconds.
-  void SetMediaEndTime(int64_t aEndTime);
-
   // Called from main thread to update the duration with an estimated value.
   // The duration is only changed if its significantly different than the
   // the current duration, as the incoming duration is an estimate and so
   // often is unstable as more data is read and the estimate is updated.
   // Can result in a durationchangeevent. aDuration is in microseconds.
   void UpdateEstimatedDuration(int64_t aDuration);
 
   // Functions used by assertions to ensure we're calling things
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -19,16 +19,18 @@
 #include "VideoUtils.h"
 
 #include <algorithm>
 
 #ifdef MOZ_EME
 #include "mozilla/CDMProxy.h"
 #endif
 
+using namespace mozilla::media;
+
 using mozilla::layers::Image;
 using mozilla::layers::LayerManager;
 using mozilla::layers::LayersBackend;
 
 PRLogModuleInfo* GetFormatDecoderLog() {
   static PRLogModuleInfo* log = nullptr;
   if (!log) {
     log = PR_NewLogModule("MediaFormatReader");
@@ -327,18 +329,17 @@ MediaFormatReader::OnDemuxerInitDone(nsr
     mInfo.mCrypto = *crypto;
   }
 
   int64_t videoDuration = HasVideo() ? mInfo.mVideo.mDuration : 0;
   int64_t audioDuration = HasAudio() ? mInfo.mAudio.mDuration : 0;
 
   int64_t duration = std::max(videoDuration, audioDuration);
   if (duration != -1) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(duration);
+    mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(duration));
   }
 
   mSeekable = mDemuxer->IsSeekable();
 
   // Create demuxer object for main thread.
   mMainThreadDemuxer = mDemuxer->Clone();
   if (!mMainThreadDemuxer) {
     mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -10,16 +10,17 @@
 #include "nsRect.h"
 #include "nsRefPtr.h"
 #include "nsSize.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "ImageTypes.h"
 #include "MediaData.h"
 #include "StreamBuffer.h" // for TrackID
+#include "TimeUnits.h"
 
 namespace mozilla {
 
 class AudioInfo;
 class VideoInfo;
 class TextInfo;
 
 class TrackInfo {
@@ -343,14 +344,22 @@ public:
   {
     return HasVideo() || HasAudio();
   }
 
   // TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks.
   VideoInfo mVideo;
   AudioInfo mAudio;
 
+  // If the metadata includes a duration, we store it here.
+  media::NullableTimeUnit mMetadataDuration;
+
+  // The Ogg reader tries to kinda-sorta compute the duration by seeking to the
+  // end and determining the timestamp of the last frame. This isn't useful as
+  // a duration until we know the start time, so we need to track it separately.
+  media::NullableTimeUnit mMetadataEndTime;
+
   EncryptionInfo mCrypto;
 };
 
 } // namespace mozilla
 
 #endif // MediaInfo_h
--- a/dom/media/android/AndroidMediaReader.cpp
+++ b/dom/media/android/AndroidMediaReader.cpp
@@ -13,16 +13,17 @@
 #include "MediaDecoderStateMachine.h"
 #include "ImageContainer.h"
 #include "AbstractMediaDecoder.h"
 #include "gfx2DGlue.h"
 
 namespace mozilla {
 
 using namespace mozilla::gfx;
+using namespace mozilla::media;
 
 typedef mozilla::layers::Image Image;
 typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
 
 AndroidMediaReader::AndroidMediaReader(AbstractMediaDecoder *aDecoder,
                                        const nsACString& aContentType) :
   MediaDecoderReader(aDecoder),
   mType(aContentType),
@@ -50,18 +51,17 @@ nsresult AndroidMediaReader::ReadMetadat
       return NS_ERROR_FAILURE;
     }
   }
 
   // Set the total duration (the max of the audio and video track).
   int64_t durationUs;
   mPlugin->GetDuration(mPlugin, &durationUs);
   if (durationUs) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(durationUs);
+    mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(durationUs));
   }
 
   if (mPlugin->HasVideo(mPlugin)) {
     int32_t width, height;
     mPlugin->GetVideoParameters(mPlugin, &width, &height);
     nsIntRect pictureRect(0, 0, width, height);
 
     // Validate the container-reported frame and pictureRect sizes. This ensures
--- a/dom/media/apple/AppleMP3Reader.cpp
+++ b/dom/media/apple/AppleMP3Reader.cpp
@@ -14,16 +14,18 @@
 // Maximum number of audio frames we will accept from the audio decoder in one
 // go.  Carefully select this to work well with both the mp3 1152 max frames
 // per block and power-of-2 allocation sizes.  Since we must pre-allocate the
 // buffer we cannot use AudioCompactor without paying for an additional
 // allocation and copy.  Therefore, choosing a value that divides exactly into
 // 1152 is most memory efficient.
 #define MAX_AUDIO_FRAMES 128
 
+using namespace mozilla::media;
+
 namespace mozilla {
 
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define LOGE(...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Error, (__VA_ARGS__))
 #define LOGW(...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Warning, (__VA_ARGS__))
 #define LOGD(...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 #define PROPERTY_ID_FORMAT "%c%c%c%c"
@@ -408,21 +410,21 @@ AppleMP3Reader::ReadMetadata(MediaInfo* 
     return NS_ERROR_FAILURE;
   }
 
   if (mStreamReady) {
     aInfo->mAudio.mRate = mAudioSampleRate;
     aInfo->mAudio.mChannels = mAudioChannels;
   }
 
-  {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDuration = mMP3FrameParser.GetDuration();
-    mDecoder->SetMediaDuration(mDuration);
-  }
+  // This special snowflake reader doesn't seem to set *aInfo = mInfo like all
+  // the others. Yuck.
+  mDuration = mMP3FrameParser.GetDuration();
+  mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(mDuration));
+  aInfo->mMetadataDuration.emplace(TimeUnit::FromMicroseconds(mDuration));
 
   return NS_OK;
 }
 
 
 void
 AppleMP3Reader::AudioMetadataCallback(AudioFileStreamID aFileStream,
                                       AudioFileStreamPropertyID aPropertyID,
--- a/dom/media/directshow/DirectShowReader.cpp
+++ b/dom/media/directshow/DirectShowReader.cpp
@@ -9,16 +9,18 @@
 #include "mozilla/RefPtr.h"
 #include "DirectShowUtils.h"
 #include "AudioSinkFilter.h"
 #include "SourceFilter.h"
 #include "SampleSink.h"
 #include "MediaResource.h"
 #include "VideoUtils.h"
 
+using namespace mozilla::media;
+
 namespace mozilla {
 
 
 PRLogModuleInfo*
 GetDirectShowLog() {
   static PRLogModuleInfo* log = nullptr;
   if (!log) {
     log = PR_NewLogModule("DirectShowDecoder");
@@ -189,40 +191,39 @@ DirectShowReader::ReadMetadata(MediaInfo
   mAudioSinkFilter->GetSampleSink()->GetAudioFormat(&format);
   NS_ENSURE_TRUE(format.wFormatTag == WAVE_FORMAT_PCM, NS_ERROR_FAILURE);
 
   mInfo.mAudio.mChannels = mNumChannels = format.nChannels;
   mInfo.mAudio.mRate = mAudioRate = format.nSamplesPerSec;
   mInfo.mAudio.mBitDepth = format.wBitsPerSample;
   mBytesPerSample = format.wBitsPerSample / 8;
 
-  *aInfo = mInfo;
-  // Note: The SourceFilter strips ID3v2 tags out of the stream.
-  *aTags = nullptr;
-
   // Begin decoding!
   hr = mControl->Run();
   NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
   DWORD seekCaps = 0;
   hr = mMediaSeeking->GetCapabilities(&seekCaps);
 
   int64_t duration = mMP3FrameParser.GetDuration();
   if (SUCCEEDED(hr)) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(duration);
+    mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
   }
 
   LOG("Successfully initialized DirectShow MP3 decoder.");
   LOG("Channels=%u Hz=%u duration=%lld bytesPerSample=%d",
       mInfo.mAudio.mChannels,
       mInfo.mAudio.mRate,
       RefTimeToUsecs(duration),
       mBytesPerSample);
 
+  *aInfo = mInfo;
+  // Note: The SourceFilter strips ID3v2 tags out of the stream.
+  *aTags = nullptr;
+
   return NS_OK;
 }
 
 bool
 DirectShowReader::IsMediaSeekable()
 {
   DWORD seekCaps = 0;
   HRESULT hr = mMediaSeeking->GetCapabilities(&seekCaps);
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -27,16 +27,17 @@
 #ifdef MOZ_EME
 #include "mozilla/CDMProxy.h"
 #endif
 
 using mozilla::layers::Image;
 using mozilla::layers::LayerManager;
 using mozilla::layers::ImageContainer;
 using mozilla::layers::LayersBackend;
+using mozilla::media::TimeUnit;
 
 PRLogModuleInfo* GetDemuxerLog() {
   static PRLogModuleInfo* log = nullptr;
   if (!log) {
     log = PR_NewLogModule("MP4Demuxer");
   }
   return log;
 }
@@ -426,18 +427,17 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
 
   // Get the duration, and report it to the decoder if we have it.
   Microseconds duration;
   {
     MonitorAutoLock lock(mDemuxerMonitor);
     duration = mDemuxer->Duration();
   }
   if (duration != -1) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(duration);
+    mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(duration));
   }
 
   *aInfo = mInfo;
   *aTags = nullptr;
 
   if (!IsWaitingOnCDMResource()) {
     NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE);
   }
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/unused.h"
 #include "GStreamerLoader.h"
 #include "gfx2DGlue.h"
 
 namespace mozilla {
 
 using namespace gfx;
 using namespace layers;
+using namespace media;
 
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
 
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define LOG(type, msg, ...) \
   MOZ_LOG(gMediaDecoderLog, type, ("GStreamerReader(%p) " msg, this, ##__VA_ARGS__))
 
@@ -465,35 +466,33 @@ nsresult GStreamerReader::ReadMetadata(M
     return ret;
 
   /* report the duration */
   gint64 duration;
 
   if (isMP3 && mMP3FrameParser.IsMP3()) {
     // The MP3FrameParser has reported a duration; use that over the gstreamer
     // reported duration for inter-platform consistency.
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mUseParserDuration = true;
     mLastParserDuration = mMP3FrameParser.GetDuration();
-    mDecoder->SetMediaDuration(mLastParserDuration);
+    mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(mLastParserDuration));
   } else {
     LOG(LogLevel::Debug, "querying duration");
     // Otherwise use the gstreamer duration.
 #if GST_VERSION_MAJOR >= 1
     if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
           GST_FORMAT_TIME, &duration)) {
 #else
     GstFormat format = GST_FORMAT_TIME;
     if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
       &format, &duration) && format == GST_FORMAT_TIME) {
 #endif
-      ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
       LOG(LogLevel::Debug, "have duration %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
       duration = GST_TIME_AS_USECONDS (duration);
-      mDecoder->SetMediaDuration(duration);
+      mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
     }
   }
 
   int n_video = 0, n_audio = 0;
   g_object_get(mPlayBin, "n-video", &n_video, "n-audio", &n_audio, nullptr);
 
   if (!n_video) {
     mInfo.mVideo = VideoInfo();
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -1132,30 +1132,30 @@ MediaSourceReader::ReadMetadata(MediaInf
     mAudioSourceDecoder = mAudioTrack->Decoders()[0];
 
     const MediaInfo& info = GetAudioReader()->GetMediaInfo();
     MOZ_ASSERT(info.HasAudio());
     mInfo.mAudio = info.mAudio;
     mInfo.mCrypto.AddInitData(info.mCrypto);
     MSE_DEBUG("audio reader=%p duration=%lld",
               mAudioSourceDecoder.get(),
-              mAudioSourceDecoder->GetReader()->GetDecoder()->GetMediaDuration());
+              mInfo.mMetadataDuration.isSome() ? mInfo.mMetadataDuration.ref().ToMicroseconds() : -1);
   }
 
   if (mVideoTrack) {
     MOZ_ASSERT(mVideoTrack->IsReady());
     mVideoSourceDecoder = mVideoTrack->Decoders()[0];
 
     const MediaInfo& info = GetVideoReader()->GetMediaInfo();
     MOZ_ASSERT(info.HasVideo());
     mInfo.mVideo = info.mVideo;
     mInfo.mCrypto.AddInitData(info.mCrypto);
     MSE_DEBUG("video reader=%p duration=%lld",
               GetVideoReader(),
-              GetVideoReader()->GetDecoder()->GetMediaDuration());
+              mInfo.mMetadataDuration.isSome() ? mInfo.mMetadataDuration.ref().ToMicroseconds() : -1);
   }
 
   *aInfo = mInfo;
   *aTags = nullptr; // TODO: Handle metadata.
 
   return NS_OK;
 }
 
--- a/dom/media/mediasource/SourceBufferDecoder.cpp
+++ b/dom/media/mediasource/SourceBufferDecoder.cpp
@@ -32,17 +32,16 @@ NS_IMPL_ISUPPORTS0(SourceBufferDecoder)
 
 SourceBufferDecoder::SourceBufferDecoder(MediaResource* aResource,
                                          AbstractMediaDecoder* aParentDecoder,
                                          int64_t aTimestampOffset)
   : mResource(aResource)
   , mParentDecoder(aParentDecoder)
   , mReader(nullptr)
   , mTimestampOffset(aTimestampOffset)
-  , mMediaDuration(-1)
   , mRealMediaDuration(0)
   , mTrimmedOffset(-1)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(SourceBufferDecoder);
 }
 
 SourceBufferDecoder::~SourceBufferDecoder()
@@ -59,22 +58,16 @@ SourceBufferDecoder::IsShutdown() const
 }
 
 void
 SourceBufferDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
 {
   MSE_DEBUG("UNIMPLEMENTED");
 }
 
-int64_t
-SourceBufferDecoder::GetMediaDuration()
-{
-  return mMediaDuration;
-}
-
 VideoFrameContainer*
 SourceBufferDecoder::GetVideoFrameContainer()
 {
   MSE_DEBUG("UNIMPLEMENTED");
   return nullptr;
 }
 
 bool
@@ -115,22 +108,16 @@ SourceBufferDecoder::QueueMetadata(int64
 }
 
 void
 SourceBufferDecoder::RemoveMediaTracks()
 {
   MSE_DEBUG("UNIMPLEMENTED");
 }
 
-void
-SourceBufferDecoder::SetMediaEndTime(int64_t aTime)
-{
-  MSE_DEBUG("UNIMPLEMENTED");
-}
-
 bool
 SourceBufferDecoder::HasInitializationData()
 {
   return true;
 }
 
 void
 SourceBufferDecoder::OnReadMetadataCompleted()
@@ -175,22 +162,16 @@ SourceBufferDecoder::GetResource() const
 void
 SourceBufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
                                          uint32_t aDropped)
 {
   return mParentDecoder->NotifyDecodedFrames(aParsed, aDecoded, aDropped);
 }
 
 void
-SourceBufferDecoder::SetMediaDuration(int64_t aDuration)
-{
-  mMediaDuration = aDuration;
-}
-
-void
 SourceBufferDecoder::SetRealMediaDuration(int64_t aDuration)
 {
   mRealMediaDuration = aDuration;
 }
 
 void
 SourceBufferDecoder::Trim(int64_t aDuration)
 {
--- a/dom/media/mediasource/SourceBufferDecoder.h
+++ b/dom/media/mediasource/SourceBufferDecoder.h
@@ -31,17 +31,17 @@ 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;
+  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;
@@ -49,18 +49,16 @@ public:
                                 MediaDecoderEventVisibility aEventVisibility) final override;
   virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) final override;
   virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) final override;
   virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) final override;
   virtual void NotifyWaitingForResourcesStatusChanged() final override;
   virtual void OnReadMetadataCompleted() final override;
   virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) final override;
   virtual void RemoveMediaTracks() final override;
-  virtual void SetMediaDuration(int64_t aDuration) final override;
-  virtual void SetMediaEndTime(int64_t aTime) final override;
   virtual void SetMediaSeekable(bool aMediaSeekable) final override;
   virtual void UpdateEstimatedMediaDuration(int64_t aDuration) final override;
   virtual bool HasInitializationData() final override;
 
   // SourceBufferResource specific interface below.
   int64_t GetTimestampOffset() const { return mTimestampOffset; }
   void SetTimestampOffset(int64_t aOffset)  { mTimestampOffset = aOffset; }
 
@@ -145,18 +143,16 @@ private:
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   nsRefPtr<MediaResource> mResource;
 
   AbstractMediaDecoder* mParentDecoder;
   nsRefPtr<MediaDecoderReader> mReader;
   // in microseconds
   int64_t mTimestampOffset;
-  // mMediaDuration contains the apparent buffer duration, excluding trimmed data.
-  int64_t mMediaDuration;
   // mRealMediaDuration contains the real buffer duration, including trimmed data.
   int64_t mRealMediaDuration;
   // in seconds
   double mTrimmedOffset;
 
 #ifdef MOZ_EME
   nsRefPtr<CDMProxy> mCDMProxy;
 #endif
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -804,17 +804,19 @@ TrackBuffer::CompleteInitializeDecoder(S
   if (!RegisterDecoder(aDecoder)) {
     MSE_DEBUG("Reader %p not activated",
               aDecoder->GetReader());
     RemoveDecoder(aDecoder);
     mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
     return;
   }
 
-  int64_t duration = aDecoder->GetMediaDuration();
+
+  int64_t duration = mInfo.mMetadataDuration.isSome()
+    ? mInfo.mMetadataDuration.ref().ToMicroseconds() : -1;
   if (!duration) {
     // Treat a duration of 0 as infinity
     duration = -1;
   }
   mParentDecoder->SetInitialDuration(duration);
 
   // Tell our reader that we have more data to ensure that playback starts if
   // required when data is appended.
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -19,16 +19,17 @@ extern "C" {
 }
 #include "mozilla/TimeStamp.h"
 #include "VorbisUtils.h"
 #include "MediaMetadataManager.h"
 #include "nsISeekableStream.h"
 #include "gfx2DGlue.h"
 
 using namespace mozilla::gfx;
+using namespace mozilla::media;
 
 namespace mozilla {
 
 // On B2G estimate the buffered ranges rather than calculating them explicitly.
 // This prevents us doing I/O on the main thread, which is prohibited in B2G.
 #ifdef MOZ_WIDGET_GONK
 #define OGG_ESTIMATE_BUFFERED 1
 #endif
@@ -284,19 +285,18 @@ void OggReader::SetupTargetSkeleton(Skel
       aSkeletonState->Deactivate();
     } else if (ReadHeaders(aSkeletonState) && aSkeletonState->HasIndex()) {
       // Extract the duration info out of the index, so we don't need to seek to
       // the end of resource to get it.
       nsAutoTArray<uint32_t, 2> tracks;
       BuildSerialList(tracks);
       int64_t duration = 0;
       if (NS_SUCCEEDED(aSkeletonState->GetDuration(tracks, duration))) {
-        ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-        mDecoder->SetMediaDuration(duration);
         LOG(LogLevel::Debug, ("Got duration from Skeleton index %lld", duration));
+        mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
       }
     }
   }
 }
 
 void OggReader::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
 {
   // For each serial number
@@ -469,34 +469,32 @@ nsresult OggReader::ReadMetadata(MediaIn
 
   SetupTargetSkeleton(mSkeletonState);
   SetupMediaTracksInfo(serials);
 
   if (HasAudio() || HasVideo()) {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
     MediaResource* resource = mDecoder->GetResource();
-    if (mDecoder->GetMediaDuration() == -1 &&
-        !mDecoder->IsShutdown() &&
-        resource->GetLength() >= 0 &&
-        mDecoder->IsMediaSeekable())
+    if (mInfo.mMetadataDuration.isNothing() && !mDecoder->IsShutdown() &&
+        resource->GetLength() >= 0 && mDecoder->IsMediaSeekable())
     {
       // We didn't get a duration from the index or a Content-Duration header.
       // Seek to the end of file to find the end time.
       int64_t length = resource->GetLength();
 
       NS_ASSERTION(length > 0, "Must have a content length to get end time");
 
       int64_t endTime = 0;
       {
         ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
         endTime = RangeEndTime(length);
       }
       if (endTime != -1) {
-        mDecoder->SetMediaEndTime(endTime);
+        mInfo.mMetadataEndTime.emplace(TimeUnit::FromMicroseconds(endTime));
         LOG(LogLevel::Debug, ("Got Ogg duration from seeking to end %lld", endTime));
       }
     }
   } else {
     return NS_ERROR_FAILURE;
   }
   *aInfo = mInfo;
 
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -37,16 +37,17 @@
 #include "nsThreadUtils.h"
 #include "ImageContainer.h"
 #include "SharedThreadPool.h"
 #include "VideoFrameContainer.h"
 #include "VideoUtils.h"
 
 using namespace android;
 using namespace mozilla::layers;
+using namespace mozilla::media;
 
 namespace mozilla {
 
 static const int64_t sInvalidDurationUs = INT64_C(-1);
 static const int64_t sInvalidTimestampUs = INT64_C(-1);
 
 // Try not to spend more than this much time (in seconds) in a single call
 // to GetCodecOutputData.
@@ -707,18 +708,17 @@ MediaCodecReader::HandleResourceAllocate
   }
   int64_t videoDuration = INT64_C(-1);
   {
     MonitorAutoLock al(mVideoTrack.mTrackMonitor);
     videoDuration = mVideoTrack.mDurationUs;
   }
   int64_t duration = audioDuration > videoDuration ? audioDuration : videoDuration;
   if (duration >= INT64_C(0)) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(duration);
+    mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(duration));
   }
 
   // Video track's frame sizes will not overflow. Activate the video track.
   VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
   if (container) {
     container->SetCurrentFrame(
       gfxIntSize(mInfo.mVideo.mDisplay.width, mInfo.mVideo.mDisplay.height),
       nullptr,
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -18,16 +18,17 @@
 #include "gfx2DGlue.h"
 #include "MediaStreamSource.h"
 
 #define MAX_DROPPED_FRAMES 25
 // Try not to spend more than this much time in a single call to DecodeVideoFrame.
 #define MAX_VIDEO_DECODE_SECONDS 0.1
 
 using namespace mozilla::gfx;
+using namespace mozilla::media;
 using namespace android;
 
 namespace mozilla {
 
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
 
 class MediaOmxReader::ProcessCachedDataTask : public Task
@@ -276,26 +277,24 @@ void MediaOmxReader::HandleResourceAlloc
   bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
   if (isMP3 && mMP3FrameParser.IsMP3()) {
     // Check if the MP3 frame parser found a duration.
     mLastParserDuration = mMP3FrameParser.GetDuration();
   }
 
   if (mLastParserDuration >= 0) {
     // Prefer the parser duration if we have it.
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(mLastParserDuration);
+    mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(mLastParserDuration));
   } else {
     // MP3 parser failed to find a duration.
     // Set the total duration (the max of the audio and video track).
     int64_t durationUs;
     mOmxDecoder->GetDuration(&durationUs);
     if (durationUs) {
-      ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-      mDecoder->SetMediaDuration(durationUs);
+      mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(durationUs));
     }
   }
 
   if (mOmxDecoder->HasVideo()) {
     int32_t displayWidth, displayHeight, width, height;
     mOmxDecoder->GetVideoParameters(&displayWidth, &displayHeight,
                                     &width, &height);
     nsIntRect pictureRect(0, 0, width, height);
--- a/dom/media/raw/RawReader.cpp
+++ b/dom/media/raw/RawReader.cpp
@@ -7,16 +7,17 @@
 #include "AbstractMediaDecoder.h"
 #include "RawReader.h"
 #include "RawDecoder.h"
 #include "VideoUtils.h"
 #include "nsISeekableStream.h"
 #include "gfx2DGlue.h"
 
 using namespace mozilla;
+using namespace mozilla::media;
 
 RawReader::RawReader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder),
     mCurrentFrame(0), mFrameSize(0)
 {
   MOZ_COUNT_CTOR(RawReader);
 }
 
@@ -92,20 +93,18 @@ nsresult RawReader::ReadMetadata(MediaIn
     return NS_ERROR_FAILURE;
 
   mFrameSize = mMetadata.frameWidth * mMetadata.frameHeight *
     (mMetadata.lumaChannelBpp + mMetadata.chromaChannelBpp) / 8.0 +
     sizeof(RawPacketHeader);
 
   int64_t length = resource->GetLength();
   if (length != -1) {
-    ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(USECS_PER_S *
-                                      (length - sizeof(RawVideoHeader)) /
-                                      (mFrameSize * mFrameRate));
+    mInfo.mMetadataDuration.emplace(TimeUnit::FromSeconds((length - sizeof(RawVideoHeader)) /
+                                                          (mFrameSize * mFrameRate)));
   }
 
   *aInfo = mInfo;
 
   *aTags = nullptr;
 
   return NS_OK;
 }
--- a/dom/media/wave/WaveReader.cpp
+++ b/dom/media/wave/WaveReader.cpp
@@ -12,16 +12,18 @@
 #include "nsISeekableStream.h"
 
 #include <stdint.h>
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Endian.h"
 #include <algorithm>
 
+using namespace mozilla::media;
+
 namespace mozilla {
 
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
 
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
 #ifdef SEEK_LOGGING
@@ -133,25 +135,22 @@ nsresult WaveReader::ReadMetadata(MediaI
 
   bool loadAllChunks = LoadAllChunks(tags);
   if (!loadAllChunks) {
     return NS_ERROR_FAILURE;
   }
 
   mInfo.mAudio.mRate = mSampleRate;
   mInfo.mAudio.mChannels = mChannels;
+  mInfo.mMetadataDuration.emplace(TimeUnit::FromSeconds(BytesToTime(GetDataLength())));
 
   *aInfo = mInfo;
 
   *aTags = tags.forget();
 
-  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-
-  mDecoder->SetMediaDuration(
-    static_cast<int64_t>(BytesToTime(GetDataLength()) * USECS_PER_S));
 
   return NS_OK;
 }
 
 bool
 WaveReader::IsMediaSeekable()
 {
   // not used
--- a/dom/media/webaudio/BufferDecoder.cpp
+++ b/dom/media/webaudio/BufferDecoder.cpp
@@ -88,22 +88,16 @@ BufferDecoder::NotifyDecodedFrames(uint3
 int64_t
 BufferDecoder::GetMediaDuration()
 {
   // unknown
   return -1;
 }
 
 void
-BufferDecoder::SetMediaDuration(int64_t aDuration)
-{
-  // ignore
-}
-
-void
 BufferDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
 {
   // ignore
 }
 
 void
 BufferDecoder::SetMediaSeekable(bool aMediaSeekable)
 {
@@ -156,22 +150,16 @@ BufferDecoder::QueueMetadata(int64_t aTi
 
 void
 BufferDecoder::RemoveMediaTracks()
 {
   // ignore
 }
 
 void
-BufferDecoder::SetMediaEndTime(int64_t aTime)
-{
-  // ignore
-}
-
-void
 BufferDecoder::OnReadMetadataCompleted()
 {
   // ignore
 }
 
 void
 BufferDecoder::NotifyWaitingForResourcesStatusChanged()
 {
--- a/dom/media/webaudio/BufferDecoder.h
+++ b/dom/media/webaudio/BufferDecoder.h
@@ -42,18 +42,16 @@ public:
 
   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 SetMediaDuration(int64_t aDuration) 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;
@@ -64,18 +62,16 @@ public:
                               nsAutoPtr<MetadataTags> aTags,
                               MediaDecoderEventVisibility aEventVisibility) final override;
   virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) final override;
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                 MediaDecoderEventVisibility aEventVisibility) final override;
 
   virtual void RemoveMediaTracks() final override;
 
-  virtual void SetMediaEndTime(int64_t aTime) final override;
-
   virtual void OnReadMetadataCompleted() final override;
 
   virtual MediaDecoderOwner* GetOwner() final override;
 
   virtual void NotifyWaitingForResourcesStatusChanged() final override;
 
   virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) final override;
 
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -41,16 +41,17 @@
 #else
 #define SEEK_LOG(type, msg)
 #endif
 
 namespace mozilla {
 
 using namespace gfx;
 using namespace layers;
+using namespace media;
 
 extern PRLogModuleInfo* gMediaDecoderLog;
 PRLogModuleInfo* gNesteggLog;
 
 // Functions for reading and seeking using MediaResource required for
 // nestegg_io. The 'user data' passed to these functions is the
 // decoder from which the media resource is obtained.
 static int webm_read(void *aBuffer, size_t aLength, void *aUserData)
@@ -338,18 +339,17 @@ nsresult WebMReader::ReadMetadata(MediaI
   int r = nestegg_init(&mContext, io, &webm_log, maxOffset);
   if (r == -1) {
     return NS_ERROR_FAILURE;
   }
 
   uint64_t duration = 0;
   r = nestegg_duration(mContext, &duration);
   if (r == 0) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(duration / NS_PER_USEC);
+    mInfo.mMetadataDuration.emplace(TimeUnit::FromNanoseconds(duration));
   }
 
   unsigned int ntracks = 0;
   r = nestegg_track_count(mContext, &ntracks);
   if (r == -1) {
     Cleanup();
     return NS_ERROR_FAILURE;
   }
--- a/dom/media/wmf/WMFReader.cpp
+++ b/dom/media/wmf/WMFReader.cpp
@@ -22,16 +22,17 @@
 #error We expect 32bit float audio samples on desktop for the Windows Media Foundation media backend.
 #endif
 
 #include "MediaDecoder.h"
 #include "VideoUtils.h"
 #include "gfx2DGlue.h"
 
 using namespace mozilla::gfx;
+using namespace mozilla::media;
 using mozilla::layers::Image;
 using mozilla::layers::LayerManager;
 using mozilla::layers::LayersBackend;
 
 namespace mozilla {
 
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
@@ -530,18 +531,17 @@ WMFReader::ReadMetadata(MediaInfo* aInfo
 
   // Abort if both video and audio failed to initialize.
   NS_ENSURE_TRUE(mInfo.HasValidMedia(), NS_ERROR_FAILURE);
 
   // Get the duration, and report it to the decoder if we have it.
   int64_t duration = 0;
   hr = GetSourceReaderDuration(mSourceReader, duration);
   if (SUCCEEDED(hr)) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaEndTime(duration);
+    mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
   }
 
   *aInfo = mInfo;
   *aTags = nullptr;
   // aTags can be retrieved using techniques like used here:
   // http://blogs.msdn.com/b/mf/archive/2010/01/12/mfmediapropdump.aspx
 
   return NS_OK;