Bug 1250054. Part 2 - implement MediaDecoderReaderWrapper. r=jya.
☠☠ backed out by dfda3d7872c6 ☠ ☠
authorJW Wang <jwwang@mozilla.com>
Wed, 02 Mar 2016 21:16:00 +0800
changeset 290913 fe425b8cb8cbe0260d3ce1ff1746831f3b65ad02
parent 290912 15058cd337313e26ee0cc699826dcbe7f448c977
child 290914 ea3d6ace0405500743997bceb4561559272e15a3
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1250054
milestone48.0a1
Bug 1250054. Part 2 - implement MediaDecoderReaderWrapper. r=jya.
dom/media/MediaDecoderReaderWrapper.cpp
dom/media/MediaDecoderReaderWrapper.h
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -140,9 +140,146 @@ private:
   }
 
   MozPromiseHolder<HaveStartTimePromise> mHaveStartTimePromise;
   RefPtr<AbstractThread> mOwnerThread;
   Maybe<int64_t> mAudioStartTime;
   Maybe<int64_t> mVideoStartTime;
 };
 
+MediaDecoderReaderWrapper::MediaDecoderReaderWrapper(bool aIsRealTime,
+                                                     AbstractThread* aOwnerThread,
+                                                     MediaDecoderReader* aReader)
+  : mForceZeroStartTime(aIsRealTime || aReader->ForceZeroStartTime())
+  , mOwnerThread(aOwnerThread)
+  , mReader(aReader)
+{}
+
+MediaDecoderReaderWrapper::~MediaDecoderReaderWrapper()
+{}
+
+media::TimeUnit
+MediaDecoderReaderWrapper::StartTime() const
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  return media::TimeUnit::FromMicroseconds(mStartTimeRendezvous->StartTime());
+}
+
+RefPtr<MediaDecoderReaderWrapper::MetadataPromise>
+MediaDecoderReaderWrapper::ReadMetadata()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+                     &MediaDecoderReader::AsyncReadMetadata)
+         ->Then(mOwnerThread, __func__, this,
+                &MediaDecoderReaderWrapper::OnMetadataRead,
+                &MediaDecoderReaderWrapper::OnMetadataNotRead)
+         ->CompletionPromise();
+}
+
+RefPtr<HaveStartTimePromise>
+MediaDecoderReaderWrapper::AwaitStartTime()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  return mStartTimeRendezvous->AwaitStartTime();
+}
+
+RefPtr<MediaDecoderReaderWrapper::AudioDataPromise>
+MediaDecoderReaderWrapper::RequestAudioData()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+
+  auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+                       &MediaDecoderReader::RequestAudioData);
+
+  if (!mStartTimeRendezvous->HaveStartTime()) {
+    p = p->Then(mOwnerThread, __func__, mStartTimeRendezvous.get(),
+                &StartTimeRendezvous::ProcessFirstSample<AudioDataPromise, MediaData::AUDIO_DATA>,
+                &StartTimeRendezvous::FirstSampleRejected<MediaData::AUDIO_DATA>)
+         ->CompletionPromise();
+  }
+
+  return p->Then(mOwnerThread, __func__, this,
+                 &MediaDecoderReaderWrapper::OnSampleDecoded,
+                 &MediaDecoderReaderWrapper::OnNotDecoded)
+          ->CompletionPromise();
+}
+
+RefPtr<MediaDecoderReaderWrapper::VideoDataPromise>
+MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe,
+                                            media::TimeUnit aTimeThreshold)
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+
+  if (aTimeThreshold.ToMicroseconds() > 0 &&
+      mStartTimeRendezvous->HaveStartTime()) {
+    aTimeThreshold += StartTime();
+  }
+
+  auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+                       &MediaDecoderReader::RequestVideoData,
+                       aSkipToNextKeyframe, aTimeThreshold.ToMicroseconds());
+
+  if (!mStartTimeRendezvous->HaveStartTime()) {
+    p = p->Then(mOwnerThread, __func__, mStartTimeRendezvous.get(),
+                &StartTimeRendezvous::ProcessFirstSample<VideoDataPromise, MediaData::VIDEO_DATA>,
+                &StartTimeRendezvous::FirstSampleRejected<MediaData::VIDEO_DATA>)
+         ->CompletionPromise();
+  }
+
+  return p->Then(mOwnerThread, __func__, this,
+                 &MediaDecoderReaderWrapper::OnSampleDecoded,
+                 &MediaDecoderReaderWrapper::OnNotDecoded)
+          ->CompletionPromise();
+}
+
+RefPtr<MediaDecoderReader::SeekPromise>
+MediaDecoderReaderWrapper::Seek(SeekTarget aTarget, media::TimeUnit aEndTime)
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  aTarget.SetTime(aTarget.GetTime() + StartTime());
+  return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+                     &MediaDecoderReader::Seek, aTarget,
+                     aEndTime.ToMicroseconds());
+}
+
+void
+MediaDecoderReaderWrapper::Shutdown()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  mShutdown = true;
+  if (mStartTimeRendezvous) {
+    mStartTimeRendezvous->Destroy();
+  }
+}
+
+void
+MediaDecoderReaderWrapper::OnMetadataRead(MetadataHolder* aMetadata)
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  // Set up the start time rendezvous if it doesn't already exist (which is
+  // generally the case, unless we're coming out of dormant mode).
+  if (!mStartTimeRendezvous) {
+    mStartTimeRendezvous = new StartTimeRendezvous(
+      mOwnerThread, aMetadata->mInfo.HasAudio(),
+      aMetadata->mInfo.HasVideo(), mForceZeroStartTime);
+
+    RefPtr<MediaDecoderReaderWrapper> self = this;
+    mStartTimeRendezvous->AwaitStartTime()->Then(
+      mOwnerThread, __func__,
+      [self] ()  {
+        NS_ENSURE_TRUE_VOID(!self->mShutdown);
+        self->mReader->DispatchSetStartTime(self->StartTime().ToMicroseconds());
+      },
+      [] () {
+        NS_WARNING("Setting start time on reader failed");
+      });
+  }
+}
+
+void
+MediaDecoderReaderWrapper::OnSampleDecoded(MediaData* aSample)
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  aSample->AdjustForStartTime(StartTime().ToMicroseconds());
+}
+
 } // namespace mozilla
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -14,11 +14,54 @@
 #include "MediaDecoderReader.h"
 
 namespace mozilla {
 
 class StartTimeRendezvous;
 
 typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
 
+/**
+ * A wrapper around MediaDecoderReader to offset the timestamps of Audio/Video
+ * samples by the start time to ensure MDSM can always assume zero start time.
+ * It also adjusts the seek target passed to Seek() to ensure correct seek time
+ * is passed to the underlying reader.
+ */
+class MediaDecoderReaderWrapper {
+  typedef MediaDecoderReader::MetadataPromise MetadataPromise;
+  typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
+  typedef MediaDecoderReader::VideoDataPromise VideoDataPromise;
+  typedef MediaDecoderReader::SeekPromise SeekPromise;
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
+
+public:
+  MediaDecoderReaderWrapper(bool aIsRealTime,
+                            AbstractThread* aOwnerThread,
+                            MediaDecoderReader* aReader);
+
+  media::TimeUnit StartTime() const;
+  RefPtr<MetadataPromise> ReadMetadata();
+  RefPtr<HaveStartTimePromise> AwaitStartTime();
+  RefPtr<AudioDataPromise> RequestAudioData();
+  RefPtr<VideoDataPromise> RequestVideoData(bool aSkipToNextKeyframe,
+                                            media::TimeUnit aTimeThreshold);
+  RefPtr<SeekPromise> Seek(SeekTarget aTarget, media::TimeUnit aEndTime);
+  void Shutdown();
+
+private:
+  ~MediaDecoderReaderWrapper();
+
+  void OnMetadataRead(MetadataHolder* aMetadata);
+  void OnMetadataNotRead() {}
+  void OnSampleDecoded(MediaData* aSample);
+  void OnNotDecoded() {}
+
+  const bool mForceZeroStartTime;
+  const RefPtr<AbstractThread> mOwnerThread;
+  const RefPtr<MediaDecoderReader> mReader;
+
+  bool mShutdown = false;
+  RefPtr<StartTimeRendezvous> mStartTimeRendezvous;
+};
+
 } // namespace mozilla
 
 #endif // MediaDecoderReaderWrapper_h_