Bug 1365205 - part 1: check for buffer validness before processing it. r=esawin
authorJohn Lin <jolin@mozilla.com>
Mon, 17 Jul 2017 11:36:49 +0800
changeset 418264 73b2bebfcc18a2ec4fa8da0e227b5f512ca38004
parent 418263 6b2aee46289f08fe16932e60f72954c6ed701cc3
child 418265 9286e4085ee0daeb687ecee84c52ff9854f59ee1
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersesawin
bugs1365205
milestone56.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 1365205 - part 1: check for buffer validness before processing it. r=esawin 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);