Bug 1365205 - Part 1: Check for buffer validness before processing it. r=esawin, a=jcristau
authorJohn Lin <jolin@mozilla.com>
Mon, 17 Jul 2017 11:36:49 +0800
changeset 414385 3b374998e442cd3ff4d0120273b6f65be367abf4
parent 414384 74382cf3e203d15085bc28f4467b6fbc469defb0
child 414386 823d66f7bf9879302b69bd71682b773752151c5b
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersesawin, jcristau
bugs1365205
milestone55.0
Bug 1365205 - Part 1: Check for buffer validness before processing it. r=esawin, a=jcristau flush() invalidates all buffers so buffer callbacks emitted earlier than that should not proceed when they're executed after. MozReview-Commit-ID: 3KjCmW2VwTy
mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java
@@ -106,17 +106,17 @@ import org.mozilla.gecko.gfx.GeckoSurfac
             try {
                 feedSampleToBuffer();
             } catch (Exception e) {
                 reportError(Error.FATAL, e);
             }
         }
 
         private synchronized void onBuffer(int index) {
-            if (mStopped) {
+            if (mStopped || !isValidBuffer(index)) {
                 return;
             }
 
             if (!mHasInputCapacitySet) {
                 int capacity = mCodec.getInputBuffer(index).capacity();
                 if (capacity > 0) {
                     mSamplePool.setInputBufferSize(capacity);
                     mHasInputCapacitySet = true;
@@ -126,16 +126,25 @@ import org.mozilla.gecko.gfx.GeckoSurfac
             if (mAvailableInputBuffers.offer(index)) {
                 feedSampleToBuffer();
             } else {
                 reportError(Error.FATAL, new Exception("FAIL: input buffer queue is full"));
             }
 
         }
 
+        private boolean isValidBuffer(final int index) {
+            try {
+                return mCodec.getInputBuffer(index) != null;
+            } catch (IllegalStateException e) {
+                if (DEBUG) { Log.d(LOGTAG, "invalid input buffer#" + index, e); }
+                return false;
+            }
+        }
+
         private void feedSampleToBuffer() {
             while (!mAvailableInputBuffers.isEmpty() && !mInputSamples.isEmpty()) {
                 int index = mAvailableInputBuffers.poll();
                 int len = 0;
                 final Sample sample = mInputSamples.poll().sample;
                 long pts = sample.info.presentationTimeUs;
                 int flags = sample.info.flags;
                 MediaCodec.CryptoInfo cryptoInfo = sample.cryptoInfo;
@@ -229,17 +238,17 @@ import org.mozilla.gecko.gfx.GeckoSurfac
         private Queue<Output> mSentOutputs = new LinkedList<>();
         private boolean mStopped;
 
         private OutputProcessor(boolean renderToSurface) {
             mRenderToSurface = renderToSurface;
         }
 
         private synchronized void onBuffer(int index, MediaCodec.BufferInfo info) {
-            if (mStopped) {
+            if (mStopped || !isValidBuffer(index)) {
                 return;
             }
 
             try {
                 Sample output = obtainOutputSample(index, info);
                 mSentOutputs.add(new Output(output, index));
                 mCallbacks.onOutput(output);
             } catch (Exception e) {
@@ -248,16 +257,25 @@ import org.mozilla.gecko.gfx.GeckoSurfac
             }
 
             boolean eos = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
             if (DEBUG && eos) {
                 Log.d(LOGTAG, "output EOS");
             }
         }
 
+        private boolean isValidBuffer(final int index) {
+            try {
+                return mCodec.getOutputBuffer(index) != null;
+            } catch (IllegalStateException e) {
+                if (DEBUG) { Log.e(LOGTAG, "invalid buffer#" + index, e); }
+                return false;
+            }
+        }
+
         private Sample obtainOutputSample(int index, MediaCodec.BufferInfo info) {
             Sample sample = mSamplePool.obtainOutput(info);
 
             if (mRenderToSurface) {
                 return sample;
             }
 
             ByteBuffer output = mCodec.getOutputBuffer(index);