Bug 1168778 - Fix crash when seeking: 1. Replace FlushableMediaTaskQueue by MediaTaskQueue. 2. Refact the seek/DecodeAudioDataTask/DecodeVideoFrameTask functions. r=sotaro
authorBenjamin Chen <bechen@mozilla.com>
Wed, 10 Jun 2015 17:03:26 +0800
changeset 279385 141c6315de6a7e4f6cf300dbb853711b596ffe5b
parent 279384 d8de74f7206770f696e0dc2dc532c441dc3b9ddc
child 279386 417b507708731c8d202e76c6ca8bfb37490398a6
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1168778
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 1168778 - Fix crash when seeking: 1. Replace FlushableMediaTaskQueue by MediaTaskQueue. 2. Refact the seek/DecodeAudioDataTask/DecodeVideoFrameTask functions. r=sotaro
dom/media/omx/MediaCodecReader.cpp
dom/media/omx/MediaCodecReader.h
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -391,19 +391,16 @@ MediaCodecReader::DecodeAudioDataSync()
 
     status = GetCodecOutputData(mAudioTrack, bufferInfo, sInvalidTimestampUs,
                                 timeout);
     if (status == OK || status == ERROR_END_OF_STREAM) {
       break;
     } else if (status == -EAGAIN) {
       if (TimeStamp::Now() > timeout) {
         // Don't let this loop run for too long. Try it again later.
-        if (CheckAudioResources()) {
-          DispatchAudioTask();
-        }
         return;
       }
       continue; // Try it again now.
     } else if (status == INFO_FORMAT_CHANGED) {
       if (UpdateAudioInfo()) {
         continue; // Try it again now.
       } else {
         return;
@@ -436,21 +433,32 @@ MediaCodecReader::DecodeAudioDataSync()
         mInfo.mAudio.mChannels));
   }
   mAudioTrack.mCodec->releaseOutputBuffer(bufferInfo.mIndex);
 }
 
 void
 MediaCodecReader::DecodeAudioDataTask()
 {
+  MOZ_ASSERT(mAudioTrack.mTaskQueue->IsCurrentThreadIn());
+  MonitorAutoLock al(mAudioTrack.mTrackMonitor);
+  if (mAudioTrack.mAudioPromise.IsEmpty()) {
+    // Clear the data in queue because the promise might be canceled by
+    // ResetDecode().
+    AudioQueue().Reset();
+    return;
+  }
   if (AudioQueue().GetSize() == 0 && !AudioQueue().IsFinished()) {
+    MonitorAutoUnlock ul(mAudioTrack.mTrackMonitor);
     DecodeAudioDataSync();
   }
-  MonitorAutoLock al(mAudioTrack.mTrackMonitor);
+  // Since we unlock the monitor above, we should check the promise again
+  // because the promise might be canceled by ResetDecode().
   if (mAudioTrack.mAudioPromise.IsEmpty()) {
+    AudioQueue().Reset();
     return;
   }
   if (AudioQueue().GetSize() > 0) {
     nsRefPtr<AudioData> a = AudioQueue().PopFront();
     if (a) {
       if (mAudioTrack.mDiscontinuity) {
         a->mDiscontinuity = true;
         mAudioTrack.mDiscontinuity = false;
@@ -462,19 +470,32 @@ MediaCodecReader::DecodeAudioDataTask()
   } else if (AudioQueue().GetSize() == 0) {
     DispatchAudioTask();
   }
 }
 
 void
 MediaCodecReader::DecodeVideoFrameTask(int64_t aTimeThreshold)
 {
-  DecodeVideoFrameSync(aTimeThreshold);
+  MOZ_ASSERT(mVideoTrack.mTaskQueue->IsCurrentThreadIn());
   MonitorAutoLock al(mVideoTrack.mTrackMonitor);
   if (mVideoTrack.mVideoPromise.IsEmpty()) {
+    // Clear the data in queue because the promise might be canceled by
+    // ResetDecode().
+    VideoQueue().Reset();
+    return;
+  }
+  {
+    MonitorAutoUnlock ul(mVideoTrack.mTrackMonitor);
+    DecodeVideoFrameSync(aTimeThreshold);
+  }
+  // Since we unlock the monitor above, we should check the promise again
+  // because the promise might be canceled by ResetDecode().
+  if (mVideoTrack.mVideoPromise.IsEmpty()) {
+    VideoQueue().Reset();
     return;
   }
   if (VideoQueue().GetSize() > 0) {
     nsRefPtr<VideoData> v = VideoQueue().PopFront();
     if (v) {
       if (mVideoTrack.mDiscontinuity) {
         v->mDiscontinuity = true;
         mVideoTrack.mDiscontinuity = false;
@@ -735,26 +756,24 @@ MediaCodecReader::HandleResourceAllocate
 
   mMetadataPromise.Resolve(metadata, __func__);
 }
 
 nsresult
 MediaCodecReader::ResetDecode()
 {
   if (CheckAudioResources()) {
-    mAudioTrack.mTaskQueue->Flush();
     MonitorAutoLock al(mAudioTrack.mTrackMonitor);
     if (!mAudioTrack.mAudioPromise.IsEmpty()) {
       mAudioTrack.mAudioPromise.Reject(CANCELED, __func__);
     }
     FlushCodecData(mAudioTrack);
     mAudioTrack.mDiscontinuity = true;
   }
   if (CheckVideoResources()) {
-    mVideoTrack.mTaskQueue->Flush();
     MonitorAutoLock al(mVideoTrack.mTrackMonitor);
     if (!mVideoTrack.mVideoPromise.IsEmpty()) {
       mVideoTrack.mVideoPromise.Reject(CANCELED, __func__);
     }
     FlushCodecData(mVideoTrack);
     mVideoTrack.mDiscontinuity = true;
   }
 
@@ -888,19 +907,16 @@ MediaCodecReader::DecodeVideoFrameSync(i
 
     status = GetCodecOutputData(mVideoTrack, bufferInfo, aTimeThreshold,
                                 timeout);
     if (status == OK || status == ERROR_END_OF_STREAM) {
       break;
     } else if (status == -EAGAIN) {
       if (TimeStamp::Now() > timeout) {
         // Don't let this loop run for too long. Try it again later.
-        if (CheckVideoResources()) {
-          DispatchVideoTask(aTimeThreshold);
-        }
         return;
       }
       continue; // Try it again now.
     } else if (status == INFO_FORMAT_CHANGED) {
       if (UpdateVideoInfo()) {
         continue; // Try it again now.
       } else {
         return;
@@ -1022,53 +1038,64 @@ MediaCodecReader::DecodeVideoFrameSync(i
   }
 }
 
 nsRefPtr<MediaDecoderReader::SeekPromise>
 MediaCodecReader::Seek(int64_t aTime, int64_t aEndTime)
 {
   MOZ_ASSERT(OnTaskQueue());
 
-  mVideoTrack.mSeekTimeUs = aTime;
-  mAudioTrack.mSeekTimeUs = aTime;
-  mVideoTrack.mInputEndOfStream = false;
-  mVideoTrack.mOutputEndOfStream = false;
-  mAudioTrack.mInputEndOfStream = false;
-  mAudioTrack.mOutputEndOfStream = false;
-  mAudioTrack.mFlushed = false;
-  mVideoTrack.mFlushed = false;
+  int64_t timestamp = sInvalidTimestampUs;
 
   if (CheckVideoResources()) {
+    MonitorAutoLock al(mVideoTrack.mTrackMonitor);
+    mVideoTrack.mSeekTimeUs = aTime;
+    mVideoTrack.mInputEndOfStream = false;
+    mVideoTrack.mOutputEndOfStream = false;
+    mVideoTrack.mFlushed = false;
+
     VideoFrameContainer* videoframe = mDecoder->GetVideoFrameContainer();
     if (videoframe) {
       layers::ImageContainer* image = videoframe->GetImageContainer();
       if (image) {
         image->ClearAllImagesExceptFront();
       }
     }
 
     MediaBuffer* source_buffer = nullptr;
     MediaSource::ReadOptions options;
-    int64_t timestamp = sInvalidTimestampUs;
     options.setSeekTo(aTime, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
     if (mVideoTrack.mSource->read(&source_buffer, &options) != OK ||
         source_buffer == nullptr) {
       return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     }
     sp<MetaData> format = source_buffer->meta_data();
     if (format != nullptr) {
       if (format->findInt64(kKeyTime, &timestamp) &&
           IsValidTimestampUs(timestamp)) {
         mVideoTrack.mSeekTimeUs = timestamp;
-        mAudioTrack.mSeekTimeUs = timestamp;
       }
       format = nullptr;
     }
     source_buffer->release();
   }
+
+  {
+    MonitorAutoLock al(mAudioTrack.mTrackMonitor);
+    mAudioTrack.mInputEndOfStream = false;
+    mAudioTrack.mOutputEndOfStream = false;
+    mAudioTrack.mFlushed = false;
+
+    if (IsValidTimestampUs(timestamp)) {
+      mAudioTrack.mSeekTimeUs = timestamp;
+    } else {
+      mAudioTrack.mSeekTimeUs = aTime;
+    }
+  }
+
   return SeekPromise::CreateAndResolve(aTime, __func__);
 }
 
 bool
 MediaCodecReader::IsMediaSeekable()
 {
   // Check the MediaExtract flag if the source is seekable.
   return (mExtractor != nullptr) &&
@@ -1279,21 +1306,21 @@ MediaCodecReader::ShutdownTaskQueues()
     mVideoTrack.mReleaseBufferTaskQueue = nullptr;
   }
 }
 
 bool
 MediaCodecReader::CreateTaskQueues()
 {
   if (mAudioTrack.mSource != nullptr && !mAudioTrack.mTaskQueue) {
-    mAudioTrack.mTaskQueue = CreateFlushableMediaDecodeTaskQueue();
+    mAudioTrack.mTaskQueue = CreateMediaDecodeTaskQueue();
     NS_ENSURE_TRUE(mAudioTrack.mTaskQueue, false);
   }
   if (mVideoTrack.mSource != nullptr && !mVideoTrack.mTaskQueue) {
-    mVideoTrack.mTaskQueue = CreateFlushableMediaDecodeTaskQueue();
+    mVideoTrack.mTaskQueue = CreateMediaDecodeTaskQueue();
     NS_ENSURE_TRUE(mVideoTrack.mTaskQueue, false);
     mVideoTrack.mReleaseBufferTaskQueue = CreateMediaDecodeTaskQueue();
     NS_ENSURE_TRUE(mVideoTrack.mReleaseBufferTaskQueue, false);
   }
 
   return true;
 }
 
--- a/dom/media/omx/MediaCodecReader.h
+++ b/dom/media/omx/MediaCodecReader.h
@@ -143,25 +143,23 @@ protected:
     nsAutoPtr<TrackInputCopier> mInputCopier;
 
     // Protected by mTrackMonitor.
     // mDurationUs might be read or updated from multiple threads.
     int64_t mDurationUs;
 
     // playback parameters
     CheckedUint32 mInputIndex;
-    // mDiscontinuity, mFlushed, mInputEndOfStream, mInputEndOfStream,
-    // mSeekTimeUs don't be protected by a lock because the
-    // mTaskQueue->Flush() will flush all tasks.
+
     bool mInputEndOfStream;
     bool mOutputEndOfStream;
     int64_t mSeekTimeUs;
     bool mFlushed; // meaningless when mSeekTimeUs is invalid.
     bool mDiscontinuity;
-    nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
+    nsRefPtr<MediaTaskQueue> mTaskQueue;
     Monitor mTrackMonitor;
 
   private:
     // Forbidden
     Track(const Track &rhs) = delete;
     const Track &operator=(const Track&) = delete;
   };