Bug 1034957 - Don't spin decode task queue waiting for audio frames since it hangs with gstreamer 1.0. r=cpearce, a=sledru
authorJW Wang <jwwang@mozilla.com>
Wed, 03 Sep 2014 23:04:00 -0400
changeset 216659 46ffe60377d9
parent 216658 03029d16e697
child 216660 8865201cd18e
push id3864
push userryanvm@gmail.com
push date2014-09-04 13:00 +0000
treeherdermozilla-beta@e47ff024eec1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, sledru
bugs1034957, 1046837
milestone33.0
Bug 1034957 - Don't spin decode task queue waiting for audio frames since it hangs with gstreamer 1.0. r=cpearce, a=sledru Bug 1046837 - reset |mDispatchedDecodeMetadataTask| only after finishinig decoding metadata to avoid MediaDecoderStateMachine::CallDecodeMetadata() may run more than once. r=cpearce
content/media/MediaDecoderReader.cpp
content/media/MediaDecoderStateMachine.cpp
content/media/gstreamer/GStreamerReader.cpp
--- a/content/media/MediaDecoderReader.cpp
+++ b/content/media/MediaDecoderReader.cpp
@@ -243,16 +243,27 @@ MediaDecoderReader::RequestVideoData(boo
 
 void
 MediaDecoderReader::RequestAudioData()
 {
   while (AudioQueue().GetSize() == 0 &&
          !AudioQueue().IsFinished()) {
     if (!DecodeAudioData()) {
       AudioQueue().Finish();
+      break;
+    }
+    // AudioQueue size is still zero, post a task to try again. Don't spin
+    // waiting in this while loop since it somehow prevents audio EOS from
+    // coming in gstreamer 1.x when there is still video buffer waiting to be
+    // consumed. (|mVideoSinkBufferCount| > 0)
+    if (AudioQueue().GetSize() == 0 && mTaskQueue) {
+      RefPtr<nsIRunnable> task(NS_NewRunnableMethod(
+          this, &MediaDecoderReader::RequestAudioData));
+      mTaskQueue->Dispatch(task.forget());
+      return;
     }
   }
   if (AudioQueue().GetSize() > 0) {
     AudioData* a = AudioQueue().PopFront();
     if (mAudioDiscontinuity) {
       a->mDiscontinuity = true;
       mAudioDiscontinuity = false;
     }
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -1513,27 +1513,26 @@ nsresult
 MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
 {
   AssertCurrentThreadInMonitor();
 
   if (mState != DECODER_STATE_DECODING_METADATA ||
       mDispatchedDecodeMetadataTask) {
     return NS_OK;
   }
+
+  mDispatchedDecodeMetadataTask = true;
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
   nsresult rv = mDecodeTaskQueue->Dispatch(task);
-  if (NS_SUCCEEDED(rv)) {
-    mDispatchedDecodeMetadataTask = true;
-  } else {
+  if (NS_FAILED(rv)) {
     NS_WARNING("Dispatch ReadMetadata task failed.");
-    return rv;
+    mDispatchedDecodeMetadataTask = false;
   }
-
-  return NS_OK;
+  return rv;
 }
 
 void
 MediaDecoderStateMachine::SetReaderIdle()
 {
 #ifdef PR_LOGGING
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
@@ -1837,17 +1836,16 @@ MediaDecoderStateMachine::DecodeError()
     NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
   }
 }
 
 void
 MediaDecoderStateMachine::CallDecodeMetadata()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  AutoSetOnScopeExit<bool> unsetOnExit(mDispatchedDecodeMetadataTask, false);
   if (mState != DECODER_STATE_DECODING_METADATA) {
     return;
   }
   if (NS_FAILED(DecodeMetadata())) {
     DECODER_LOG(PR_LOG_WARNING, "Decode metadata failed, shutting down decoder");
     DecodeError();
   }
 }
@@ -1869,16 +1867,17 @@ nsresult MediaDecoderStateMachine::Decod
   }
 
   if (NS_SUCCEEDED(res)) {
     if (mState == DECODER_STATE_DECODING_METADATA &&
         mReader->IsWaitingMediaResources()) {
       // change state to DECODER_STATE_WAIT_FOR_RESOURCES
       StartWaitForResources();
       // affect values only if ReadMetadata succeeds
+      mDispatchedDecodeMetadataTask = false;
       return NS_OK;
     }
   }
 
   if (NS_SUCCEEDED(res)) {
     mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
   }
 
@@ -1991,16 +1990,17 @@ MediaDecoderStateMachine::FinishDecodeMe
 
   if ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_COMPLETED) &&
       mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
       !IsPlaying())
   {
     StartPlayback();
   }
 
+  mDispatchedDecodeMetadataTask = false;
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::DecodeSeek()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   if (mState != DECODER_STATE_SEEKING) {
--- a/content/media/gstreamer/GStreamerReader.cpp
+++ b/content/media/gstreamer/GStreamerReader.cpp
@@ -625,19 +625,21 @@ bool GStreamerReader::DecodeAudioData()
 #else
     buffer = gst_app_sink_pull_buffer(mAudioAppSink);
 #endif
 
     mAudioSinkBufferCount--;
   }
 
   int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer);
-  timestamp = gst_segment_to_stream_time(&mAudioSegment,
-      GST_FORMAT_TIME, timestamp);
-
+  {
+    ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
+    timestamp = gst_segment_to_stream_time(&mAudioSegment,
+                                           GST_FORMAT_TIME, timestamp);
+  }
   timestamp = GST_TIME_AS_USECONDS(timestamp);
 
   int64_t offset = GST_BUFFER_OFFSET(buffer);
   guint8* data;
 #if GST_VERSION_MAJOR >= 1
   GstMapInfo info;
   gst_buffer_map(buffer, &info, GST_MAP_READ);
   unsigned int size = info.size;