Bug 1091008 - Teach MediaDecoderReader about its start time. r=cpearce
☠☠ backed out by 43a51201545a ☠ ☠
authorBobby Holley <bobbyholley@gmail.com>
Wed, 05 Nov 2014 10:08:58 +0100
changeset 214066 856016c0118ab665cf79f947e2ee03e207b1fa38
parent 214065 8aaa10a8d95656121d06939273d8de0d485a19d9
child 214067 9de4746aa59a3236c122fc9fba27bd4fe2f6c544
push id27771
push userryanvm@gmail.com
push dateWed, 05 Nov 2014 19:04:24 +0000
treeherdermozilla-central@305b4fecce99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1091008
milestone36.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 1091008 - Teach MediaDecoderReader about its start time. r=cpearce Duplicating state is never great, but this lets the reader make calculations using this immutable state variable without involving the state machine. We could alternatively punch a hole from MediaDecoderReader to MediaDecoderStateMachine and access it there, but that would create tighter coupling, and weird relationships for MSE.
dom/media/MediaDecoderReader.cpp
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/mediasource/MediaSourceReader.cpp
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -56,16 +56,17 @@ public:
 
   size_t mSize;
 };
 
 MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
   : mAudioCompactor(mAudioQueue)
   , mDecoder(aDecoder)
   , mIgnoreAudioOutputFormat(false)
+  , mStartTime(-1)
   , mAudioDiscontinuity(false)
   , mVideoDiscontinuity(false)
 {
   MOZ_COUNT_CTOR(MediaDecoderReader);
 }
 
 MediaDecoderReader::~MediaDecoderReader()
 {
@@ -115,16 +116,23 @@ VideoData* MediaDecoderReader::DecodeToF
   }
   if (eof) {
     VideoQueue().Finish();
   }
   VideoData* d = nullptr;
   return (d = VideoQueue().PeekFront()) ? d : nullptr;
 }
 
+void
+MediaDecoderReader::SetStartTime(int64_t aStartTime)
+{
+  mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
+  mStartTime = aStartTime;
+}
+
 nsresult
 MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
                                 int64_t aStartTime)
 {
   MediaResource* stream = mDecoder->GetResource();
   int64_t durationUs = 0;
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -174,16 +174,17 @@ public:
   // TODO: DEPRECATED.  This uses synchronous decoding.
   VideoData* DecodeToFirstVideoData();
 
   MediaInfo GetMediaInfo() { return mInfo; }
 
   // Indicates if the media is seekable.
   // ReadMetada should be called before calling this method.
   virtual bool IsMediaSeekable() = 0;
+  void SetStartTime(int64_t aStartTime);
 
 protected:
   virtual ~MediaDecoderReader();
 
   // Overrides of this function should decodes an unspecified amount of
   // audio data, enqueuing the audio data in mAudioQueue. Returns true
   // when there's more audio to decode, false if the audio is finished,
   // end of file has been reached, or an un-recoverable read error has
@@ -230,16 +231,21 @@ protected:
   // Stores presentation info required for playback.
   MediaInfo mInfo;
 
   // 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(),
+  // after which point it never changes.
+  int64_t mStartTime;
 private:
 
   nsRefPtr<RequestSampleCallback> mSampleDecodedCallback;
 
   nsRefPtr<MediaTaskQueue> mTaskQueue;
 
   // Flags whether a the next audio/video sample comes after a "gap" or
   // "discontinuity" in the stream. For example after a seek.
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2885,16 +2885,21 @@ void MediaDecoderStateMachine::SetStartT
       NS_ASSERTION(mEndTime != -1,
                    "We should have mEndTime as supplied duration here");
       // We were specified a duration from a Content-Duration HTTP header.
       // Adjust mEndTime so that mEndTime-mStartTime matches the specified
       // duration.
       mEndTime = mStartTime + mEndTime;
     }
   }
+
+  // Pass along this immutable value to the reader so that it can make
+  // calculations independently of the state machine.
+  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;
   DECODER_LOG("Set media start time to %lld", mStartTime);
 }
 
 void MediaDecoderStateMachine::UpdateReadyState() {
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -304,16 +304,25 @@ MediaSourceReader::CreateSubDecoder(cons
   }
   MOZ_ASSERT(GetTaskQueue());
   nsRefPtr<SourceBufferDecoder> decoder =
     new SourceBufferDecoder(new SourceBufferResource(aType), mDecoder);
   nsRefPtr<MediaDecoderReader> reader(CreateReaderForType(aType, decoder));
   if (!reader) {
     return nullptr;
   }
+
+  // MSE uses a start time of 0 everywhere. Set that immediately on the
+  // subreader to make sure that it's always in a state where we can invoke
+  // GetBuffered on it.
+  {
+    ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
+    reader->SetStartTime(0);
+  }
+
   // Set a callback on the subreader that forwards calls to this reader.
   // This reader will then forward them onto the state machine via this
   // reader's callback.
   RefPtr<MediaDataDecodedListener<MediaSourceReader>> callback =
     new MediaDataDecodedListener<MediaSourceReader>(this, GetTaskQueue());
   reader->SetCallback(callback);
   reader->SetTaskQueue(GetTaskQueue());
   reader->Init(nullptr);