Bug 1308071. Part 1 - Change the type of MDSM::mInfo to Maybe<MediaInfo>. draft
authorJW Wang <jwwang@mozilla.com>
Thu, 06 Oct 2016 11:25:24 +0800
changeset 424176 9d9f3bc60e394865ef0eb3bef137e8eb470e95a0
parent 424175 0e6fa17ad98ab6f030b8bfae09c7f96dab613cd2
child 424177 b43069b4a5e87190a418f99d1757a3fe88152cf3
push id32093
push userjwwang@mozilla.com
push dateWed, 12 Oct 2016 10:15:24 +0000
bugs1308071
milestone52.0a1
Bug 1308071. Part 1 - Change the type of MDSM::mInfo to Maybe<MediaInfo>. MozReview-Commit-ID: 4rJfO1w9jYr
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -232,16 +232,17 @@ public:
   virtual void DumpDebugInfo() {}
 
 protected:
   using Master = MediaDecoderStateMachine;
   explicit StateObject(Master* aPtr) : mMaster(aPtr) {}
   TaskQueue* OwnerThread() const { return mMaster->mTaskQueue; }
   MediaResource* Resource() const { return mMaster->mResource; }
   MediaDecoderReaderWrapper* Reader() const { return mMaster->mReader; }
+  const MediaInfo& Info() const { return mMaster->Info(); }
 
   // Note this function will delete the current state object.
   // Don't access members to avoid UAF after this call.
   void SetState(State aState) { mMaster->SetState(aState); }
 
   // Take a raw pointer in order not to change the life cycle of MDSM.
   // It is guaranteed to be valid by MDSM.
   Master* mMaster;
@@ -304,29 +305,30 @@ private:
       // No need to store mQueuedSeek because we are at position 0.
       SetState(DECODER_STATE_DORMANT);
       return;
     }
 
     // Set mode to PLAYBACK after reading metadata.
     Resource()->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
 
-    mMaster->mInfo = aMetadata->mInfo;
+    mMaster->mInfo = Some(aMetadata->mInfo);
     mMaster->mMetadataTags = aMetadata->mTags.forget();
 
-    if (mMaster->mInfo.mMetadataDuration.isSome()) {
+    if (Info().mMetadataDuration.isSome()) {
       mMaster->RecomputeDuration();
-    } else if (mMaster->mInfo.mUnadjustedMetadataEndTime.isSome()) {
+    } else if (Info().mUnadjustedMetadataEndTime.isSome()) {
       RefPtr<Master> master = mMaster;
       Reader()->AwaitStartTime()->Then(OwnerThread(), __func__,
         [master] () {
           NS_ENSURE_TRUE_VOID(!master->IsShutdown());
-          TimeUnit unadjusted = master->mInfo.mUnadjustedMetadataEndTime.ref();
+          auto& info = master->mInfo.ref();
+          TimeUnit unadjusted = info.mUnadjustedMetadataEndTime.ref();
           TimeUnit adjustment = master->mReader->StartTime();
-          master->mInfo.mMetadataDuration.emplace(unadjusted - adjustment);
+          info.mMetadataDuration.emplace(unadjusted - adjustment);
           master->RecomputeDuration();
         }, [master, this] () {
           SWARN("Adjusting metadata end time failed");
         }
       );
     }
 
     if (mMaster->HasVideo()) {
@@ -337,17 +339,17 @@ private:
     }
 
     // In general, we wait until we know the duration before notifying the decoder.
     // However, we notify  unconditionally in this case without waiting for the start
     // time, since the caller might be waiting on metadataloaded to be fired before
     // feeding in the CDM, which we need to decode the first frame (and
     // thus get the metadata). We could fix this if we could compute the start
     // time by demuxing without necessaring decoding.
-    bool waitingForCDM = mMaster->mInfo.IsEncrypted() && !mMaster->mCDMProxy;
+    bool waitingForCDM = Info().IsEncrypted() && !mMaster->mCDMProxy;
 
     mMaster->mNotifyMetadataBeforeFirstFrame =
       mMaster->mDuration.Ref().isSome() || waitingForCDM;
 
     if (mMaster->mNotifyMetadataBeforeFirstFrame) {
       mMaster->EnqueueLoadedMetadataEvent();
     }
 
@@ -739,21 +741,21 @@ public:
     // SeekTask will register its callbacks to MediaDecoderReaderWrapper.
     mMaster->CancelMediaDecoderReaderWrapperCallback();
 
     // Create a new SeekTask instance for the incoming seek task.
     if (mSeekJob.mTarget.IsAccurate() ||
         mSeekJob.mTarget.IsFast()) {
       mSeekTask = new AccurateSeekTask(
         mMaster->mDecoderID, OwnerThread(), Reader(), mSeekJob.mTarget,
-        mMaster->mInfo, mMaster->Duration(), mMaster->GetMediaTime());
+        Info(), mMaster->Duration(), mMaster->GetMediaTime());
     } else if (mSeekJob.mTarget.IsNextFrame()) {
       mSeekTask = new NextFrameSeekTask(
         mMaster->mDecoderID, OwnerThread(), Reader(), mSeekJob.mTarget,
-        mMaster->mInfo, mMaster->Duration(),mMaster->GetMediaTime(),
+        Info(), mMaster->Duration(),mMaster->GetMediaTime(),
         mMaster->AudioQueue(), mMaster->VideoQueue());
     } else {
       MOZ_DIAGNOSTIC_ASSERT(false, "Cannot handle this seek task.");
     }
 
     // Don't stop playback for a video-only seek since audio is playing.
     if (!mSeekJob.mTarget.IsVideoOnly()) {
       mMaster->StopPlayback();
@@ -951,17 +953,17 @@ private:
 
     // Ensure timestamps are up to date.
     mMaster->UpdatePlaybackPositionInternal(newCurrentTime);
 
     // Try to decode another frame to detect if we're at the end...
     SLOG("Seek completed, mCurrentPosition=%lld", mMaster->mCurrentPosition.Ref());
 
     if (video) {
-      mMaster->mMediaSink->Redraw(mMaster->mInfo.mVideo);
+      mMaster->mMediaSink->Redraw(Info().mVideo);
       mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
     }
 
     SetState(nextState);
   }
 
   SeekJob mSeekJob;
   MozPromiseRequestHolder<SeekTask::SeekTaskPromise> mSeekTaskRequest;
@@ -1352,17 +1354,17 @@ MediaDecoderStateMachine::AudioAudibleCh
 media::MediaSink*
 MediaDecoderStateMachine::CreateAudioSink()
 {
   RefPtr<MediaDecoderStateMachine> self = this;
   auto audioSinkCreator = [self] () {
     MOZ_ASSERT(self->OnTaskQueue());
     DecodedAudioDataSink* audioSink = new DecodedAudioDataSink(
       self->mTaskQueue, self->mAudioQueue, self->GetMediaTime(),
-      self->mInfo.mAudio, self->mAudioChannel);
+      self->Info().mAudio, self->mAudioChannel);
 
     self->mAudibleListener = audioSink->AudibleEvent().Connect(
       self->mTaskQueue, self.get(), &MediaDecoderStateMachine::AudioAudibleChanged);
     return audioSink;
   };
   return new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
 }
 
@@ -1968,18 +1970,18 @@ void MediaDecoderStateMachine::Recompute
       // any other duration sources), but the duration isn't ready yet.
       return;
     }
     // We don't fire duration changed for this case because it should have
     // already been fired on the main thread when the explicit duration was set.
     duration = TimeUnit::FromSeconds(d);
   } else if (mEstimatedDuration.Ref().isSome()) {
     duration = mEstimatedDuration.Ref().ref();
-  } else if (mInfo.mMetadataDuration.isSome()) {
-    duration = mInfo.mMetadataDuration.ref();
+  } else if (Info().mMetadataDuration.isSome()) {
+    duration = Info().mMetadataDuration.ref();
   } else {
     return;
   }
 
   // Only adjust the duration when an explicit duration isn't set (MSE).
   // The duration is always exactly known with MSE and there's no need to adjust
   // it based on what may have been seen in the past; in particular as this data
   // may no longer exist such as when the mediasource duration was reduced.
@@ -2198,17 +2200,17 @@ void MediaDecoderStateMachine::Visibilit
     // one to catch up.
     if (mState == DECODER_STATE_SEEKING || mQueuedSeek.Exists()) {
       return;
     }
 
     // Start counting recovery time from right now.
     TimeStamp start = TimeStamp::Now();
     // Local reference to mInfo, so that it will be copied in the lambda below.
-    MediaInfo& info = mInfo;
+    auto& info = Info();
     bool hw = mReader->VideoIsHardwareAccelerated();
 
     // Start video-only seek to the current time.
     SeekJob seekJob;
 
     const SeekTarget::Type type = HasAudio()
                                   ? SeekTarget::Type::Accurate
                                   : SeekTarget::Type::PrevSyncPoint;
@@ -2467,17 +2469,17 @@ MediaDecoderStateMachine::RequestVideoDa
 }
 
 void
 MediaDecoderStateMachine::StartMediaSink()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (!mMediaSink->IsStarted()) {
     mAudioCompleted = false;
-    mMediaSink->Start(GetMediaTime(), mInfo);
+    mMediaSink->Start(GetMediaTime(), Info());
 
     auto videoPromise = mMediaSink->OnEnded(TrackInfo::kVideoTrack);
     auto audioPromise = mMediaSink->OnEnded(TrackInfo::kAudioTrack);
 
     if (audioPromise) {
       mMediaSinkAudioPromise.Begin(audioPromise->Then(
         OwnerThread(), __func__, this,
         &MediaDecoderStateMachine::OnMediaSinkAudioComplete,
@@ -2592,17 +2594,17 @@ MediaDecoderStateMachine::DecodeError(co
 
 void
 MediaDecoderStateMachine::EnqueueLoadedMetadataEvent()
 {
   MOZ_ASSERT(OnTaskQueue());
   MediaDecoderEventVisibility visibility =
     mSentLoadedMetadataEvent ? MediaDecoderEventVisibility::Suppressed
                              : MediaDecoderEventVisibility::Observable;
-  mMetadataLoadedEvent.Notify(nsAutoPtr<MediaInfo>(new MediaInfo(mInfo)),
+  mMetadataLoadedEvent.Notify(nsAutoPtr<MediaInfo>(new MediaInfo(Info())),
                               Move(mMetadataTags),
                               visibility);
   mSentLoadedMetadataEvent = true;
 }
 
 void
 MediaDecoderStateMachine::EnqueueFirstFrameLoadedEvent()
 {
@@ -2617,42 +2619,42 @@ MediaDecoderStateMachine::EnqueueFirstFr
     __func__,
     // Resolve
     [self, firstFrameBeenLoaded]() {
       self->mBufferedUpdateRequest.Complete();
       MediaDecoderEventVisibility visibility =
         firstFrameBeenLoaded ? MediaDecoderEventVisibility::Suppressed
                              : MediaDecoderEventVisibility::Observable;
       self->mFirstFrameLoadedEvent.Notify(
-        nsAutoPtr<MediaInfo>(new MediaInfo(self->mInfo)), visibility);
+        nsAutoPtr<MediaInfo>(new MediaInfo(self->Info())), visibility);
     },
     // Reject
     []() { MOZ_CRASH("Should not reach"); }));
 }
 
 void
 MediaDecoderStateMachine::FinishDecodeFirstFrame()
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(!mSentFirstFrameLoadedEvent);
   DECODER_LOG("FinishDecodeFirstFrame");
 
-  mMediaSink->Redraw(mInfo.mVideo);
+  mMediaSink->Redraw(Info().mVideo);
 
   // If we don't know the duration by this point, we assume infinity, per spec.
   if (mDuration.Ref().isNothing()) {
     mDuration = Some(TimeUnit::FromInfinity());
   }
 
   DECODER_LOG("Media duration %lld, "
               "transportSeekable=%d, mediaSeekable=%d",
               Duration().ToMicroseconds(), mResource->IsTransportSeekable(), mMediaSeekable.Ref());
 
   // Get potentially updated metadata
-  mReader->ReadUpdatedMetadata(&mInfo);
+  mReader->ReadUpdatedMetadata(mInfo.ptr());
 
   if (!mNotifyMetadataBeforeFirstFrame) {
     // If we didn't have duration and/or start time before, we should now.
     EnqueueLoadedMetadataEvent();
   }
 
   EnqueueFirstFrameLoadedEvent();
 }
@@ -2925,59 +2927,59 @@ MediaDecoderStateMachine::VideoEndTime()
   }
   return -1;
 }
 
 void
 MediaDecoderStateMachine::OnMediaSinkVideoComplete()
 {
   MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mInfo.HasVideo());
+  MOZ_ASSERT(HasVideo());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkVideoPromise.Complete();
   mVideoCompleted = true;
   ScheduleStateMachine();
 }
 
 void
 MediaDecoderStateMachine::OnMediaSinkVideoError()
 {
   MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mInfo.HasVideo());
+  MOZ_ASSERT(HasVideo());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkVideoPromise.Complete();
   mVideoCompleted = true;
   if (HasAudio()) {
     return;
   }
   DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
 }
 
 void MediaDecoderStateMachine::OnMediaSinkAudioComplete()
 {
   MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mInfo.HasAudio());
+  MOZ_ASSERT(HasAudio());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkAudioPromise.Complete();
   mAudioCompleted = true;
   // To notify PlaybackEnded as soon as possible.
   ScheduleStateMachine();
 
   // Report OK to Decoder Doctor (to know if issue may have been resolved).
   mOnDecoderDoctorEvent.Notify(
     DecoderDoctorEvent{DecoderDoctorEvent::eAudioSinkStartup, NS_OK});
 }
 
 void MediaDecoderStateMachine::OnMediaSinkAudioError(nsresult aResult)
 {
   MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mInfo.HasAudio());
+  MOZ_ASSERT(HasAudio());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkAudioPromise.Complete();
   mAudioCompleted = true;
 
   // Result should never be NS_OK in this *error* handler. Report to Dec-Doc.
   MOZ_ASSERT(NS_FAILED(aResult));
   mOnDecoderDoctorEvent.Notify(
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -300,29 +300,19 @@ private:
   // Only called on the decoder thread. Must be called with
   // the decode monitor held.
   void UpdatePlaybackPosition(int64_t aTime);
 
   bool CanPlayThrough();
 
   MediaStatistics GetStatistics();
 
-  // This is called on the state machine thread and audio thread.
-  // The decoder monitor must be obtained before calling this.
-  bool HasAudio() const {
-    MOZ_ASSERT(OnTaskQueue());
-    return mInfo.HasAudio();
-  }
-
-  // This is called on the state machine thread and audio thread.
-  // The decoder monitor must be obtained before calling this.
-  bool HasVideo() const {
-    MOZ_ASSERT(OnTaskQueue());
-    return mInfo.HasVideo();
-  }
+  bool HasAudio() const { return mInfo.ref().HasAudio(); }
+  bool HasVideo() const { return mInfo.ref().HasVideo(); }
+  const MediaInfo& Info() const { return mInfo.ref(); }
 
   // Should be called by main thread.
   bool HaveNextFrameData();
 
   // Returns the state machine task queue.
   TaskQueue* OwnerThread() const { return mTaskQueue; }
 
   // Schedules the shared state machine thread to run the state machine.
@@ -738,19 +728,18 @@ private:
   // memory and CPU overhead.
   bool mMinimizePreroll;
 
   // True if the decode thread has gone filled its buffers and is now
   // waiting to be awakened before it continues decoding. Synchronized
   // by the decoder monitor.
   bool mDecodeThreadWaiting;
 
-  // Stores presentation info required for playback. The decoder monitor
-  // must be held when accessing this.
-  MediaInfo mInfo;
+  // Stores presentation info required for playback.
+  Maybe<MediaInfo> mInfo;
 
   nsAutoPtr<MetadataTags> mMetadataTags;
 
   mozilla::MediaMetadataManager mMetadataManager;
 
   // Track our request to update the buffered ranges
   MozPromiseRequestHolder<MediaDecoderReader::BufferedUpdatePromise> mBufferedUpdateRequest;