Bug 1324530 - part 2: rewrite the logic of discarding invalid buffers for flush. r=esawin draft
authorJohn Lin <jolin@mozilla.com>
Wed, 28 Dec 2016 15:56:42 +0800
changeset 456914 f7bcddf4d7b6177900be4f013849e84d396544c1
parent 456913 249dbf6a03eee2f0646590cf8d164841cd882577
child 456915 4b89cbe8e5874848af343321ae465a97bd2399e3
push id40642
push userbmo:jolin@mozilla.com
push dateFri, 06 Jan 2017 14:13:15 +0000
reviewersesawin
bugs1324530
milestone53.0a1
Bug 1324530 - part 2: rewrite the logic of discarding invalid buffers for flush. r=esawin MozReview-Commit-ID: EwTRMaJOJhK
mobile/android/base/java/org/mozilla/gecko/media/Codec.java
--- a/mobile/android/base/java/org/mozilla/gecko/media/Codec.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/Codec.java
@@ -27,31 +27,21 @@ import java.util.concurrent.ConcurrentLi
 
     public enum Error {
         DECODE, FATAL
     }
 
     private final class Callbacks implements AsyncCodec.Callbacks {
         @Override
         public void onInputBufferAvailable(AsyncCodec codec, int index) {
-            if (mFlushing) {
-                // Flush invalidates all buffers.
-                return;
-            }
-
             mInputProcessor.onBuffer(index);
         }
 
         @Override
         public void onOutputBufferAvailable(AsyncCodec codec, int index, MediaCodec.BufferInfo info) {
-            if (mFlushing) {
-                // Flush invalidates all buffers.
-                return;
-            }
-
             mOutputProcessor.onBuffer(index, info);
         }
 
         @Override
         public void onError(AsyncCodec codec, int error) {
             reportError(Error.FATAL, new Exception("codec error:" + error));
         }
 
@@ -61,16 +51,17 @@ import java.util.concurrent.ConcurrentLi
         }
     }
 
     private final class InputProcessor {
         private boolean mHasInputCapacitySet;
         private Queue<Integer> mAvailableInputBuffers = new LinkedList<>();
         private Queue<Sample> mDequeuedSamples = new LinkedList<>();
         private Queue<Sample> mInputSamples = new LinkedList<>();
+        private boolean mStopped;
 
         private synchronized Sample onAllocate(int size) {
             Sample sample = mSamplePool.obtainInput(size);
             mDequeuedSamples.add(sample);
             return sample;
         }
 
         private synchronized void onSample(Sample sample) {
@@ -90,16 +81,20 @@ import java.util.concurrent.ConcurrentLi
             if (mInputSamples.offer(sample)) {
                 feedSampleToBuffer();
             } else {
                 reportError(Error.FATAL, new Exception("FAIL: input sample queue is full"));
             }
         }
 
         private synchronized void onBuffer(int index) {
+            if (mStopped) {
+                return;
+            }
+
             if (!mHasInputCapacitySet) {
                 int capacity = mCodec.getInputBuffer(index).capacity();
                 if (capacity > 0) {
                     mSamplePool.setInputBufferSize(capacity);
                     mHasInputCapacitySet = true;
                 }
             }
 
@@ -149,25 +144,44 @@ import java.util.concurrent.ConcurrentLi
 
             for (Sample s : mDequeuedSamples) {
                 mSamplePool.recycleInput(s);
             }
             mDequeuedSamples.clear();
 
             mAvailableInputBuffers.clear();
         }
+
+        private synchronized void start() {
+            if (!mStopped) {
+                return;
+            }
+            mStopped = false;
+        }
+
+        private synchronized void stop() {
+            if (mStopped) {
+                return;
+            }
+            mStopped = true;
+            reset();
+        }
     }
 
     private class OutputProcessor {
         private boolean mHasOutputCapacitySet;
         private Queue<Integer> mSentIndices = new LinkedList<>();
         private Queue<Sample> mSentOutputs = new LinkedList<>();
-
+        private boolean mStopped;
 
         private synchronized void onBuffer(int index, MediaCodec.BufferInfo info) {
+            if (mStopped) {
+                return;
+            }
+
             ByteBuffer output = mCodec.getOutputBuffer(index);
             if (!mHasOutputCapacitySet) {
                 int capacity = output.capacity();
                 if (capacity > 0) {
                     mSamplePool.setOutputBufferSize(capacity);
                     mHasOutputCapacitySet = true;
                 }
             }
@@ -233,23 +247,37 @@ import java.util.concurrent.ConcurrentLi
                 mCodec.releaseOutputBuffer(i, false);
             }
             mSentIndices.clear();
             for (Sample s : mSentOutputs) {
                 mSamplePool.recycleOutput(s);
             }
             mSentOutputs.clear();
         }
+
+        private synchronized void start() {
+            if (!mStopped) {
+                return;
+            }
+            mStopped = false;
+        }
+
+        private synchronized void stop() {
+            if (mStopped) {
+                return;
+            }
+            mStopped = true;
+            reset();
+        }
     }
 
     private volatile ICodecCallbacks mCallbacks;
     private AsyncCodec mCodec;
     private InputProcessor mInputProcessor;
     private OutputProcessor mOutputProcessor;
-    private volatile boolean mFlushing = false;
     private SamplePool mSamplePool;
     private Queue<Sample> mSentOutputs = new ConcurrentLinkedQueue<>();
     // Value will be updated after configure called.
     private volatile boolean mIsAdaptivePlaybackSupported = false;
 
     public synchronized void setCallbacks(ICodecCallbacks callbacks) throws RemoteException {
         mCallbacks = callbacks;
         callbacks.asBinder().linkToDeath(this, 0);
@@ -328,18 +356,19 @@ import java.util.concurrent.ConcurrentLi
     }
 
     @Override
     public synchronized boolean isAdaptivePlaybackSupported() {
         return mIsAdaptivePlaybackSupported;
     }
 
     private void releaseCodec() {
-        mInputProcessor.reset();
-        mOutputProcessor.reset();
+        // In case Codec.stop() is not called yet.
+        mInputProcessor.stop();
+        mOutputProcessor.stop();
         try {
             mCodec.release();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
         mCodec = null;
     }
 
@@ -365,17 +394,18 @@ import java.util.concurrent.ConcurrentLi
         // TODO: API 21+ is simpler.
         //static MediaCodecList sCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
         //return sCodecList.findDecoderForFormat(format);
     }
 
     @Override
     public synchronized void start() throws RemoteException {
         if (DEBUG) { Log.d(LOGTAG, "start " + this); }
-        mFlushing = false;
+        mInputProcessor.start();
+        mOutputProcessor.start();
         try {
             mCodec.start();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
     }
 
     private void reportError(Error error, Exception e) {
@@ -387,38 +417,39 @@ import java.util.concurrent.ConcurrentLi
         } catch (RemoteException re) {
             re.printStackTrace();
         }
     }
 
     @Override
     public synchronized void stop() throws RemoteException {
         if (DEBUG) { Log.d(LOGTAG, "stop " + this); }
+        mInputProcessor.stop();
+        mOutputProcessor.stop();
         try {
             mCodec.stop();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
     }
 
     @Override
     public synchronized void flush() throws RemoteException {
-        mFlushing = true;
         if (DEBUG) { Log.d(LOGTAG, "flush " + this); }
-        mInputProcessor.reset();
-        mOutputProcessor.reset();
+        mInputProcessor.stop();
+        mOutputProcessor.stop();
         try {
             mCodec.flush();
+            if (DEBUG) { Log.d(LOGTAG, "flushed " + this); }
+            mInputProcessor.start();
+            mOutputProcessor.start();
+            mCodec.resumeReceivingInputs();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
-
-        mFlushing = false;
-        if (DEBUG) { Log.d(LOGTAG, "flushed " + this); }
-        mCodec.resumeReceivingInputs();
     }
 
     @Override
     public synchronized Sample dequeueInput(int size) {
         return mInputProcessor.onAllocate(size);
     }
 
     @Override