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
This commit is contained in:
John Lin 2017-04-06 16:37:08 +08:00
Родитель d1e7871c6f
Коммит bef936525f
3 изменённых файлов: 40 добавлений и 14 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<Integer> mAvailableInputBuffers = new LinkedList<>();
private Queue<Sample> mDequeuedSamples = new LinkedList<>();
private Queue<Sample> mInputSamples = new LinkedList<>();
private Queue<Input> 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();

Просмотреть файл

@ -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();
}