summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/SamplePool.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/SamplePool.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/SamplePool.java154
1 files changed, 154 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/SamplePool.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/SamplePool.java
new file mode 100644
index 0000000000..a2101b3aeb
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/SamplePool.java
@@ -0,0 +1,154 @@
+/* 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 android.util.SparseArray;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.mozilla.gecko.mozglue.SharedMemory;
+
+final class SamplePool {
+ private static final class Impl {
+ private final String mName;
+ private int mDefaultBufferSize = 4096;
+ private final List<Sample> mRecycledSamples = new ArrayList<>();
+ private final boolean mBufferless;
+
+ private int mNextBufferId = Sample.NO_BUFFER + 1;
+ private SparseArray<SampleBuffer> mBuffers = new SparseArray<>();
+
+ private Impl(final String name, final boolean bufferless) {
+ mName = name;
+ mBufferless = bufferless;
+ }
+
+ private void setDefaultBufferSize(final int size) {
+ if (mBufferless) {
+ throw new IllegalStateException("Setting buffer size of a bufferless pool is not allowed");
+ }
+ mDefaultBufferSize = size;
+ }
+
+ private synchronized Sample obtain(final int size) {
+ if (!mRecycledSamples.isEmpty()) {
+ return mRecycledSamples.remove(0);
+ }
+
+ if (mBufferless) {
+ return Sample.obtain();
+ } else {
+ return allocateSampleAndBuffer(size);
+ }
+ }
+
+ private Sample allocateSampleAndBuffer(final int size) {
+ final int id = mNextBufferId++;
+ try {
+ final SharedMemory shm = new SharedMemory(id, Math.max(size, mDefaultBufferSize));
+ mBuffers.put((Integer) id, new SampleBuffer(shm));
+ final Sample s = Sample.obtain();
+ s.bufferId = id;
+ return s;
+ } catch (final NoSuchMethodException | IOException e) {
+ mBuffers.delete(id);
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
+ private synchronized SampleBuffer getBuffer(final int id) {
+ return mBuffers.get(id);
+ }
+
+ private synchronized void recycle(final Sample recycled) {
+ if (mBufferless || isUsefulSample(recycled)) {
+ mRecycledSamples.add(recycled);
+ } else {
+ disposeSample(recycled);
+ }
+ }
+
+ private boolean isUsefulSample(final Sample sample) {
+ return mBuffers.get(sample.bufferId).capacity() >= mDefaultBufferSize;
+ }
+
+ private synchronized void clear() {
+ for (final Sample s : mRecycledSamples) {
+ disposeSample(s);
+ }
+ mRecycledSamples.clear();
+
+ for (int i = 0; i < mBuffers.size(); ++i) {
+ mBuffers.valueAt(i).dispose();
+ }
+ mBuffers.clear();
+ }
+
+ private void disposeSample(final Sample sample) {
+ if (sample.bufferId != Sample.NO_BUFFER) {
+ mBuffers.get(sample.bufferId).dispose();
+ mBuffers.delete(sample.bufferId);
+ }
+ sample.dispose();
+ }
+
+ @Override
+ protected void finalize() {
+ clear();
+ }
+ }
+
+ private final Impl mInputs;
+ private final Impl mOutputs;
+
+ /* package */ SamplePool(final String name, final boolean renderToSurface) {
+ mInputs = new Impl(name + " input sample pool", false);
+ // Buffers are useless when rendering to surface.
+ mOutputs = new Impl(name + " output sample pool", renderToSurface);
+ }
+
+ /* package */ void setInputBufferSize(final int size) {
+ mInputs.setDefaultBufferSize(size);
+ }
+
+ /* package */ void setOutputBufferSize(final int size) {
+ mOutputs.setDefaultBufferSize(size);
+ }
+
+ /* package */ Sample obtainInput(final int size) {
+ final Sample input = mInputs.obtain(size);
+ input.info.set(0, 0, 0, 0);
+ return input;
+ }
+
+ /* package */ Sample obtainOutput(final MediaCodec.BufferInfo info) {
+ final Sample output = mOutputs.obtain(info.size);
+ output.info.set(0, info.size, info.presentationTimeUs, info.flags);
+ return output;
+ }
+
+ /* package */ void recycleInput(final Sample sample) {
+ sample.cryptoInfo = null;
+ mInputs.recycle(sample);
+ }
+
+ /* package */ void recycleOutput(final Sample sample) {
+ mOutputs.recycle(sample);
+ }
+
+ /* package */ void reset() {
+ mInputs.clear();
+ mOutputs.clear();
+ }
+
+ /* package */ SampleBuffer getInputBuffer(final int id) {
+ return mInputs.getBuffer(id);
+ }
+
+ /* package */ SampleBuffer getOutputBuffer(final int id) {
+ return mOutputs.getBuffer(id);
+ }
+}