Bug 1090300 - Repopulate input buffers when necessary in Android media decoder. r=gcp, a=lmandel
authorJames Willcox <snorp@snorp.net>
Fri, 20 Feb 2015 13:52:21 -0600
changeset 252089 2cca5b090036
parent 252088 b8ec30b0a437
child 252090 19b630388dda
push id698
push userjlund@mozilla.com
push date2015-03-23 22:08 +0000
treeherdermozilla-release@b0c0ae7b02a3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgcp, lmandel
bugs1090300
milestone37.0
Bug 1090300 - Repopulate input buffers when necessary in Android media decoder. r=gcp, a=lmandel
dom/media/fmp4/android/AndroidDecoderModule.cpp
dom/media/fmp4/android/AndroidDecoderModule.h
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -359,16 +359,39 @@ nsresult MediaCodecDataDecoder::InitDeco
 
 #define HANDLE_DECODER_ERROR() \
   if (NS_FAILED(res)) { \
     NS_WARNING("exiting decoder loop due to exception"); \
     mCallback->Error(); \
     break; \
   }
 
+nsresult MediaCodecDataDecoder::GetInputBuffer(JNIEnv* env, int index, jni::Object::LocalRef* buffer)
+{
+  bool retried = false;
+  while (!*buffer) {
+    *buffer = jni::Object::LocalRef::Adopt(env->GetObjectArrayElement(mInputBuffers.Get(), index));
+    if (!*buffer) {
+      if (!retried) {
+        // Reset the input buffers and then try again
+        nsresult res = ResetInputBuffers();
+        if (NS_FAILED(res)) {
+          return res;
+        }
+        retried = true;
+      } else {
+        // We already tried resetting the input buffers, return an error
+        return NS_ERROR_FAILURE;
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
 void MediaCodecDataDecoder::DecoderLoop()
 {
   bool outputDone = false;
 
   bool draining = false;
   bool waitingEOF = false;
 
   AutoLocalJNIFrame frame(GetJNIForThread(), 1);
@@ -428,18 +451,20 @@ void MediaCodecDataDecoder::DecoderLoop(
 
     if (sample) {
       // We have a sample, try to feed it to the decoder
       int inputIndex;
       res = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &inputIndex);
       HANDLE_DECODER_ERROR();
 
       if (inputIndex >= 0) {
-        auto buffer = jni::Object::LocalRef::Adopt(
-            frame.GetEnv()->GetObjectArrayElement(mInputBuffers.Get(), inputIndex));
+        jni::Object::LocalRef buffer(frame.GetEnv());
+        res = GetInputBuffer(frame.GetEnv(), inputIndex, &buffer);
+        HANDLE_DECODER_ERROR();
+
         void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
 
         MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->size,
           "Decoder buffer is not large enough for sample");
 
         {
           // We're feeding this to the decoder, so remove it from the queue
           MonitorAutoLock lock(mMonitor);
--- a/dom/media/fmp4/android/AndroidDecoderModule.h
+++ b/dom/media/fmp4/android/AndroidDecoderModule.h
@@ -87,14 +87,15 @@ protected:
   virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
   virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
   virtual void Cleanup() {};
 
   nsresult ResetInputBuffers();
   nsresult ResetOutputBuffers();
 
   void DecoderLoop();
+  nsresult GetInputBuffer(JNIEnv* env, int index, jni::Object::LocalRef* buffer);
   virtual void ClearQueue();
 };
 
 } // namwspace mozilla
 
 #endif