From bef936525ff5e52051d41bf730a3058787761de0 Mon Sep 17 00:00:00 2001 From: John Lin Date: Thu, 6 Apr 2017 16:37:08 +0800 Subject: [PATCH] Bug 1349883 - part 2: reveal more input buffer status to callbacks. r=esawin,jya Promise based MediaDataDecoder expects one response per request, but ICodecCallbacks was not designed that way. onInputExhausted() is called only when there are none or just a few input buffers waiting to be queued, and onOutput() is called as soon as output buffers are available. It means these 2 kinds of events are usually interleaved and hard to align with pending promises. Reporting each input buffer status makes it easier for RemoteDataDecoder to resolve promise properly. MozReview-Commit-ID: K09txmHTtmX --HG-- extra : rebase_source : 9ad331c54a24eab6ce5e0195f354afce52247572 --- .../mozilla/gecko/media/ICodecCallbacks.aidl | 3 +- .../java/org/mozilla/gecko/media/Codec.java | 42 +++++++++++++------ .../org/mozilla/gecko/media/CodecProxy.java | 9 +++- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodecCallbacks.aidl b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodecCallbacks.aidl index 59e637f55e0d..58ee1e2b1b4b 100644 --- a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodecCallbacks.aidl +++ b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodecCallbacks.aidl @@ -9,7 +9,8 @@ import org.mozilla.gecko.media.FormatParam; import org.mozilla.gecko.media.Sample; interface ICodecCallbacks { - oneway void onInputExhausted(); + oneway void onInputQueued(long timestamp); + oneway void onInputPending(long timestamp); oneway void onOutputFormatChanged(in FormatParam format); oneway void onOutput(in Sample sample); oneway void onError(boolean fatal); diff --git 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 index 27b7c4490115..e30c197728af 100644 --- 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 @@ -50,12 +50,20 @@ import java.util.concurrent.ConcurrentLinkedQueue; } } + private static final class Input { + public final Sample sample; + public boolean reported; + + public Input(final Sample sample) { + this.sample = sample; + } + } + private final class InputProcessor { - private static final int FEW_PENDING_INPUTS = 2; private boolean mHasInputCapacitySet; private Queue mAvailableInputBuffers = new LinkedList<>(); private Queue mDequeuedSamples = new LinkedList<>(); - private Queue mInputSamples = new LinkedList<>(); + private Queue mInputSamples = new LinkedList<>(); private boolean mStopped; private synchronized Sample onAllocate(int size) { @@ -86,7 +94,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; } private void queueSample(Sample sample) { - if (!mInputSamples.offer(sample)) { + if (!mInputSamples.offer(new Input(sample))) { reportError(Error.FATAL, new Exception("FAIL: input sample queue is full")); return; } @@ -123,7 +131,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; while (!mAvailableInputBuffers.isEmpty() && !mInputSamples.isEmpty()) { int index = mAvailableInputBuffers.poll(); int len = 0; - Sample sample = mInputSamples.poll(); + final Sample sample = mInputSamples.poll().sample; long pts = sample.info.presentationTimeUs; int flags = sample.info.flags; MediaCodec.CryptoInfo cryptoInfo = sample.cryptoInfo; @@ -144,22 +152,32 @@ import java.util.concurrent.ConcurrentLinkedQueue; } else { mCodec.queueInputBuffer(index, 0, len, pts, flags); } - } - // To avoid input queue flood, request more input samples only when - // there are just a few waiting to be processed. - if (mDequeuedSamples.size() + mInputSamples.size() <= FEW_PENDING_INPUTS) { try { - mCallbacks.onInputExhausted(); + mCallbacks.onInputQueued(pts); } catch (RemoteException e) { e.printStackTrace(); } } + reportPendingInputs(); + } + + private void reportPendingInputs() { + try { + for (Input i : mInputSamples) { + if (!i.reported) { + i.reported = true; + mCallbacks.onInputPending(i.sample.info.presentationTimeUs); + } + } + } catch (RemoteException e) { + e.printStackTrace(); + } } private synchronized void reset() { - for (Sample s : mInputSamples) { - if (!s.isEOS()) { - mSamplePool.recycleInput(s); + for (Input i : mInputSamples) { + if (!i.sample.isEOS()) { + mSamplePool.recycleInput(i.sample); } } mInputSamples.clear(); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java index bfc2f421b32a..dc56419377c1 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java @@ -63,7 +63,14 @@ public final class CodecProxy { } @Override - public void onInputExhausted() throws RemoteException { + public synchronized void onInputQueued(long timestamp) throws RemoteException { + if (!mEndOfInput) { + mCallbacks.onInputExhausted(); + } + } + + @Override + public synchronized void onInputPending(long timestamp) throws RemoteException { if (!mEndOfInput) { mCallbacks.onInputExhausted(); }