Bug 1324530 - part 2: rewrite the logic of discarding invalid buffers for flush. r=esawin
MozReview-Commit-ID: EwTRMaJOJhK
--- 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