зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1295106 - Part 5: allocate samples from a pool. r=snorp
MozReview-Commit-ID: CIn9CH9k9i4 --HG-- extra : rebase_source : 6e0178881ee8c46832c064027907f43310f6f548
This commit is contained in:
Родитель
ce9e7de84b
Коммит
9d4d55e04d
|
@ -17,6 +17,7 @@ import android.view.Surface;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
|
||||
/* package */ final class Codec extends ICodec.Stub implements IBinder.DeathRecipient {
|
||||
|
@ -29,6 +30,8 @@ import java.util.Queue;
|
|||
|
||||
private final class Callbacks implements AsyncCodec.Callbacks {
|
||||
private ICodecCallbacks mRemote;
|
||||
private boolean mHasInputCapacitySet;
|
||||
private boolean mHasOutputCapacitySet;
|
||||
|
||||
public Callbacks(ICodecCallbacks remote) {
|
||||
mRemote = remote;
|
||||
|
@ -40,6 +43,13 @@ import java.util.Queue;
|
|||
// Flush invalidates all buffers.
|
||||
return;
|
||||
}
|
||||
if (!mHasInputCapacitySet) {
|
||||
int capacity = codec.getInputBuffer(index).capacity();
|
||||
if (capacity > 0) {
|
||||
mSamplePool.setInputBufferSize(capacity);
|
||||
mHasInputCapacitySet = true;
|
||||
}
|
||||
}
|
||||
if (!mInputProcessor.onBuffer(index)) {
|
||||
reportError(Error.FATAL, new Exception("FAIL: input buffer queue is full"));
|
||||
}
|
||||
|
@ -51,8 +61,24 @@ import java.util.Queue;
|
|||
// Flush invalidates all buffers.
|
||||
return;
|
||||
}
|
||||
ByteBuffer output = codec.getOutputBuffer(index);
|
||||
if (!mHasOutputCapacitySet) {
|
||||
int capacity = output.capacity();
|
||||
if (capacity > 0) {
|
||||
mSamplePool.setOutputBufferSize(capacity);
|
||||
mHasOutputCapacitySet = true;
|
||||
}
|
||||
}
|
||||
Sample copy = mSamplePool.obtainOutput(info);
|
||||
try {
|
||||
mRemote.onOutput(Sample.create(codec.getOutputBuffer(index), info, null));
|
||||
if (info.size > 0) {
|
||||
copy.buffer.readFromByteBuffer(output, info.offset, info.size);
|
||||
}
|
||||
mSentOutputs.add(copy);
|
||||
mRemote.onOutput(copy);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "Fail to read output buffer:" + e.getMessage());
|
||||
outputDummy(info);
|
||||
} catch (TransactionTooLargeException ttle) {
|
||||
Log.e(LOGTAG, "Output is too large:" + ttle.getMessage());
|
||||
outputDummy(info);
|
||||
|
@ -60,6 +86,7 @@ import java.util.Queue;
|
|||
// Dead recipient.
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
mCodec.releaseOutputBuffer(index, true);
|
||||
boolean eos = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
|
||||
if (DEBUG && eos) {
|
||||
|
@ -94,10 +121,29 @@ import java.util.Queue;
|
|||
}
|
||||
|
||||
private final class InputProcessor {
|
||||
private Queue<Sample> mInputSamples = new LinkedList<Sample>();
|
||||
private Queue<Integer> mAvailableInputBuffers = new LinkedList<Integer>();
|
||||
private Queue<Sample> mInputSamples = new LinkedList<>();
|
||||
private Queue<Integer> mAvailableInputBuffers = new LinkedList<>();
|
||||
private Queue<Sample> mDequeuedSamples = new LinkedList<>();
|
||||
|
||||
private synchronized Sample onAllocate(int size) {
|
||||
Sample sample = mSamplePool.obtainInput(size);
|
||||
mDequeuedSamples.add(sample);
|
||||
return sample;
|
||||
}
|
||||
|
||||
private synchronized boolean onSample(Sample sample) {
|
||||
if (sample == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sample.isEOS()) {
|
||||
Sample temp = sample;
|
||||
sample = mDequeuedSamples.remove();
|
||||
sample.info = temp.info;
|
||||
sample.cryptoInfo = temp.cryptoInfo;
|
||||
temp.dispose();
|
||||
}
|
||||
|
||||
if (!mInputSamples.offer(sample)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -116,8 +162,10 @@ import java.util.Queue;
|
|||
private void feedSampleToBuffer() {
|
||||
while (!mAvailableInputBuffers.isEmpty() && !mInputSamples.isEmpty()) {
|
||||
int index = mAvailableInputBuffers.poll();
|
||||
Sample sample = mInputSamples.poll();
|
||||
int len = 0;
|
||||
Sample sample = mInputSamples.poll();
|
||||
long pts = sample.info.presentationTimeUs;
|
||||
int flags = sample.info.flags;
|
||||
if (!sample.isEOS() && sample.buffer != null) {
|
||||
len = sample.info.size;
|
||||
ByteBuffer buf = mCodec.getInputBuffer(index);
|
||||
|
@ -129,8 +177,9 @@ import java.util.Queue;
|
|||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mSamplePool.recycleInput(sample);
|
||||
}
|
||||
mCodec.queueInputBuffer(index, 0, len, sample.info.presentationTimeUs, sample.info.flags);
|
||||
mCodec.queueInputBuffer(index, 0, len, pts, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,6 +192,8 @@ import java.util.Queue;
|
|||
private AsyncCodec mCodec;
|
||||
private InputProcessor mInputProcessor;
|
||||
private volatile boolean mFlushing = false;
|
||||
private SamplePool mSamplePool;
|
||||
private Queue<Sample> mSentOutputs = new LinkedList<>();
|
||||
|
||||
public synchronized void setCallbacks(ICodecCallbacks callbacks) throws RemoteException {
|
||||
mCallbacks = callbacks;
|
||||
|
@ -187,6 +238,7 @@ import java.util.Queue;
|
|||
codec.configure(fmt, surface, flags);
|
||||
mCodec = codec;
|
||||
mInputProcessor = new InputProcessor();
|
||||
mSamplePool = new SamplePool(codecName);
|
||||
if (DEBUG) Log.d(LOGTAG, codec.toString() + " created");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
@ -279,7 +331,7 @@ import java.util.Queue;
|
|||
|
||||
@Override
|
||||
public synchronized Sample dequeueInput(int size) {
|
||||
return Sample.create();
|
||||
return mInputProcessor.onAllocate(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -291,12 +343,20 @@ import java.util.Queue;
|
|||
|
||||
@Override
|
||||
public synchronized void releaseOutput(Sample sample) {
|
||||
try {
|
||||
mSamplePool.recycleOutput(mSentOutputs.remove());
|
||||
} catch (NoSuchElementException e) {
|
||||
Log.e(LOGTAG, "releaseOutput not found: " + sample + "sent: " + mSentOutputs);
|
||||
}
|
||||
sample.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void release() throws RemoteException {
|
||||
if (DEBUG) Log.d(LOGTAG, "release " + this);
|
||||
releaseCodec();
|
||||
mSamplePool.reset();
|
||||
mSamplePool = null;
|
||||
mCallbacks.asBinder().unlinkToDeath(this, 0);
|
||||
mCallbacks = null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.media;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
|
||||
import org.mozilla.gecko.mozglue.SharedMemory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
final class SamplePool {
|
||||
private final class Impl {
|
||||
private final String mName;
|
||||
private int mNextId = 0;
|
||||
private int mDefaultBufferSize = 4096;
|
||||
private final List<Sample> mRecycledSamples = new ArrayList<>();
|
||||
|
||||
private Impl(String name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
private void setDefaultBufferSize(int size) {
|
||||
mDefaultBufferSize = size;
|
||||
}
|
||||
|
||||
private synchronized Sample allocate(int size) {
|
||||
Sample sample;
|
||||
if (!mRecycledSamples.isEmpty()) {
|
||||
sample = mRecycledSamples.remove(0);
|
||||
sample.info.set(0, 0, 0, 0);
|
||||
} else {
|
||||
SharedMemory shm = null;
|
||||
try {
|
||||
shm = new SharedMemory(mNextId++, Math.max(size, mDefaultBufferSize));
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (shm != null) {
|
||||
sample = Sample.create(shm);
|
||||
} else {
|
||||
sample = Sample.create();
|
||||
}
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
private synchronized void recycle(Sample recycled) {
|
||||
if (recycled.buffer.capacity() >= mDefaultBufferSize) {
|
||||
mRecycledSamples.add(recycled);
|
||||
} else {
|
||||
recycled.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void clear() {
|
||||
for (Sample s : mRecycledSamples) {
|
||||
s.dispose();
|
||||
}
|
||||
|
||||
mRecycledSamples.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
private final Impl mInputs;
|
||||
private final Impl mOutputs;
|
||||
|
||||
/* package */ SamplePool(String name) {
|
||||
mInputs = new Impl(name + " input buffer pool");
|
||||
mOutputs = new Impl(name + " output buffer pool");
|
||||
}
|
||||
|
||||
/* package */ void setInputBufferSize(int size) {
|
||||
mInputs.setDefaultBufferSize(size);
|
||||
}
|
||||
|
||||
/* package */ void setOutputBufferSize(int size) {
|
||||
mOutputs.setDefaultBufferSize(size);
|
||||
}
|
||||
|
||||
/* package */ Sample obtainInput(int size) {
|
||||
return mInputs.allocate(size);
|
||||
}
|
||||
|
||||
/* package */ Sample obtainOutput(MediaCodec.BufferInfo info) {
|
||||
Sample output = mOutputs.allocate(info.size);
|
||||
output.info.set(0, info.size, info.presentationTimeUs, info.flags);
|
||||
return output;
|
||||
}
|
||||
|
||||
/* package */ void recycleInput(Sample sample) {
|
||||
sample.cryptoInfo = null;
|
||||
mInputs.recycle(sample);
|
||||
}
|
||||
|
||||
/* package */ void recycleOutput(Sample sample) {
|
||||
mOutputs.recycle(sample);
|
||||
}
|
||||
|
||||
/* package */ void reset() {
|
||||
mInputs.clear();
|
||||
mOutputs.clear();
|
||||
}
|
||||
}
|
|
@ -561,6 +561,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
|||
'media/MediaManager.java',
|
||||
'media/RemoteManager.java',
|
||||
'media/Sample.java',
|
||||
'media/SamplePool.java',
|
||||
'media/VideoPlayer.java',
|
||||
'MediaCastingBar.java',
|
||||
'MemoryMonitor.java',
|
||||
|
|
Загрузка…
Ссылка в новой задаче