mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix {Opus,Vpx}DecoderWrapper flush() buffer handling.
Currently, input/output buffers can 'leak' if they are dequeued then the decoder is flush()ed. This happens if an input buffer is dequeued then a discontinuity is read, or an output buffer is dequeued and is early. If this happens several times, no more buffers are available. This change makes flush() work like MediaCodec: it returns all dequeued input/output buffers to the codec. Keeping the behavior in line with MediaCodec might make it easier to factor out a common decoder interface in the future. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=109054178
This commit is contained in:
parent
1855a5a97d
commit
c685e27972
4 changed files with 43 additions and 11 deletions
|
|
@ -263,7 +263,7 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputBuffer == null) {
|
if (inputBuffer == null) {
|
||||||
inputBuffer = decoder.getInputBuffer();
|
inputBuffer = decoder.dequeueInputBuffer();
|
||||||
if (inputBuffer == null) {
|
if (inputBuffer == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,10 @@ import java.util.LinkedList;
|
||||||
private final Object lock;
|
private final Object lock;
|
||||||
private final OpusHeader opusHeader;
|
private final OpusHeader opusHeader;
|
||||||
|
|
||||||
|
private final LinkedList<InputBuffer> dequeuedInputBuffers;
|
||||||
private final LinkedList<InputBuffer> queuedInputBuffers;
|
private final LinkedList<InputBuffer> queuedInputBuffers;
|
||||||
private final LinkedList<OutputBuffer> queuedOutputBuffers;
|
private final LinkedList<OutputBuffer> queuedOutputBuffers;
|
||||||
|
private final LinkedList<OutputBuffer> dequeuedOutputBuffers;
|
||||||
private final InputBuffer[] availableInputBuffers;
|
private final InputBuffer[] availableInputBuffers;
|
||||||
private final OutputBuffer[] availableOutputBuffers;
|
private final OutputBuffer[] availableOutputBuffers;
|
||||||
private int availableInputBufferCount;
|
private int availableInputBufferCount;
|
||||||
|
|
@ -66,10 +68,14 @@ import java.util.LinkedList;
|
||||||
long seekPreRollNs) throws OpusDecoderException {
|
long seekPreRollNs) throws OpusDecoderException {
|
||||||
lock = new Object();
|
lock = new Object();
|
||||||
opusHeader = parseOpusHeader(headerBytes);
|
opusHeader = parseOpusHeader(headerBytes);
|
||||||
skipSamples = (codecDelayNs == -1) ? opusHeader.skipSamples : nsToSamples(codecDelayNs);
|
skipSamples = (codecDelayNs == -1) ? opusHeader.skipSamples
|
||||||
seekPreRoll = (seekPreRoll == -1) ? DEFAULT_SEEK_PRE_ROLL : nsToSamples(seekPreRollNs);
|
: nsToSamples(opusHeader, codecDelayNs);
|
||||||
|
seekPreRoll = (seekPreRoll == -1) ? DEFAULT_SEEK_PRE_ROLL
|
||||||
|
: nsToSamples(opusHeader, seekPreRollNs);
|
||||||
|
dequeuedInputBuffers = new LinkedList<>();
|
||||||
queuedInputBuffers = new LinkedList<>();
|
queuedInputBuffers = new LinkedList<>();
|
||||||
queuedOutputBuffers = new LinkedList<>();
|
queuedOutputBuffers = new LinkedList<>();
|
||||||
|
dequeuedOutputBuffers = new LinkedList<>();
|
||||||
availableInputBuffers = new InputBuffer[NUM_BUFFERS];
|
availableInputBuffers = new InputBuffer[NUM_BUFFERS];
|
||||||
availableOutputBuffers = new OutputBuffer[NUM_BUFFERS];
|
availableOutputBuffers = new OutputBuffer[NUM_BUFFERS];
|
||||||
availableInputBufferCount = NUM_BUFFERS;
|
availableInputBufferCount = NUM_BUFFERS;
|
||||||
|
|
@ -80,7 +86,7 @@ import java.util.LinkedList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputBuffer getInputBuffer() throws OpusDecoderException {
|
public InputBuffer dequeueInputBuffer() throws OpusDecoderException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
maybeThrowDecoderError();
|
maybeThrowDecoderError();
|
||||||
if (availableInputBufferCount == 0) {
|
if (availableInputBufferCount == 0) {
|
||||||
|
|
@ -88,6 +94,7 @@ import java.util.LinkedList;
|
||||||
}
|
}
|
||||||
InputBuffer inputBuffer = availableInputBuffers[--availableInputBufferCount];
|
InputBuffer inputBuffer = availableInputBuffers[--availableInputBufferCount];
|
||||||
inputBuffer.reset();
|
inputBuffer.reset();
|
||||||
|
dequeuedInputBuffers.addLast(inputBuffer);
|
||||||
return inputBuffer;
|
return inputBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,6 +102,7 @@ import java.util.LinkedList;
|
||||||
public void queueInputBuffer(InputBuffer inputBuffer) throws OpusDecoderException {
|
public void queueInputBuffer(InputBuffer inputBuffer) throws OpusDecoderException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
maybeThrowDecoderError();
|
maybeThrowDecoderError();
|
||||||
|
dequeuedInputBuffers.remove(inputBuffer);
|
||||||
queuedInputBuffers.addLast(inputBuffer);
|
queuedInputBuffers.addLast(inputBuffer);
|
||||||
maybeNotifyDecodeLoop();
|
maybeNotifyDecodeLoop();
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +114,9 @@ import java.util.LinkedList;
|
||||||
if (queuedOutputBuffers.isEmpty()) {
|
if (queuedOutputBuffers.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return queuedOutputBuffers.removeFirst();
|
OutputBuffer outputBuffer = queuedOutputBuffers.removeFirst();
|
||||||
|
dequeuedOutputBuffers.add(outputBuffer);
|
||||||
|
return outputBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,6 +124,7 @@ import java.util.LinkedList;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
maybeThrowDecoderError();
|
maybeThrowDecoderError();
|
||||||
outputBuffer.reset();
|
outputBuffer.reset();
|
||||||
|
dequeuedOutputBuffers.remove(outputBuffer);
|
||||||
availableOutputBuffers[availableOutputBufferCount++] = outputBuffer;
|
availableOutputBuffers[availableOutputBufferCount++] = outputBuffer;
|
||||||
maybeNotifyDecodeLoop();
|
maybeNotifyDecodeLoop();
|
||||||
}
|
}
|
||||||
|
|
@ -122,12 +133,18 @@ import java.util.LinkedList;
|
||||||
public void flush() {
|
public void flush() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
flushDecodedOutputBuffer = true;
|
flushDecodedOutputBuffer = true;
|
||||||
|
while (!dequeuedInputBuffers.isEmpty()) {
|
||||||
|
availableInputBuffers[availableInputBufferCount++] = dequeuedInputBuffers.removeFirst();
|
||||||
|
}
|
||||||
while (!queuedInputBuffers.isEmpty()) {
|
while (!queuedInputBuffers.isEmpty()) {
|
||||||
availableInputBuffers[availableInputBufferCount++] = queuedInputBuffers.removeFirst();
|
availableInputBuffers[availableInputBufferCount++] = queuedInputBuffers.removeFirst();
|
||||||
}
|
}
|
||||||
while (!queuedOutputBuffers.isEmpty()) {
|
while (!queuedOutputBuffers.isEmpty()) {
|
||||||
availableOutputBuffers[availableOutputBufferCount++] = queuedOutputBuffers.removeFirst();
|
availableOutputBuffers[availableOutputBufferCount++] = queuedOutputBuffers.removeFirst();
|
||||||
}
|
}
|
||||||
|
while (!dequeuedOutputBuffers.isEmpty()) {
|
||||||
|
availableOutputBuffers[availableOutputBufferCount++] = dequeuedOutputBuffers.removeFirst();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,7 +271,7 @@ import java.util.LinkedList;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OpusHeader parseOpusHeader(byte[] headerBytes) throws OpusDecoderException {
|
private static OpusHeader parseOpusHeader(byte[] headerBytes) throws OpusDecoderException {
|
||||||
final int maxChannelCount = 8;
|
final int maxChannelCount = 8;
|
||||||
final int maxChannelCountWithDefaultLayout = 2;
|
final int maxChannelCountWithDefaultLayout = 2;
|
||||||
final int headerSize = 19;
|
final int headerSize = 19;
|
||||||
|
|
@ -300,13 +317,13 @@ import java.util.LinkedList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readLittleEndian16(byte[] input, int offset) {
|
private static int readLittleEndian16(byte[] input, int offset) {
|
||||||
int value = input[offset];
|
int value = input[offset];
|
||||||
value |= input[offset + 1] << 8;
|
value |= input[offset + 1] << 8;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int nsToSamples(long ns) {
|
private static int nsToSamples(OpusHeader opusHeader, long ns) {
|
||||||
return (int) (ns * opusHeader.sampleRate / 1000000000);
|
return (int) (ns * opusHeader.sampleRate / 1000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputBuffer == null) {
|
if (inputBuffer == null) {
|
||||||
inputBuffer = decoder.getInputBuffer();
|
inputBuffer = decoder.dequeueInputBuffer();
|
||||||
if (inputBuffer == null) {
|
if (inputBuffer == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,10 @@ import java.util.LinkedList;
|
||||||
|
|
||||||
private final Object lock;
|
private final Object lock;
|
||||||
|
|
||||||
|
private final LinkedList<InputBuffer> dequeuedInputBuffers;
|
||||||
private final LinkedList<InputBuffer> queuedInputBuffers;
|
private final LinkedList<InputBuffer> queuedInputBuffers;
|
||||||
private final LinkedList<OutputBuffer> queuedOutputBuffers;
|
private final LinkedList<OutputBuffer> queuedOutputBuffers;
|
||||||
|
private final LinkedList<OutputBuffer> dequeuedOutputBuffers;
|
||||||
private final InputBuffer[] availableInputBuffers;
|
private final InputBuffer[] availableInputBuffers;
|
||||||
private final OutputBuffer[] availableOutputBuffers;
|
private final OutputBuffer[] availableOutputBuffers;
|
||||||
private int availableInputBufferCount;
|
private int availableInputBufferCount;
|
||||||
|
|
@ -52,8 +54,10 @@ import java.util.LinkedList;
|
||||||
public VpxDecoderWrapper(int outputMode) {
|
public VpxDecoderWrapper(int outputMode) {
|
||||||
lock = new Object();
|
lock = new Object();
|
||||||
this.outputMode = outputMode;
|
this.outputMode = outputMode;
|
||||||
|
dequeuedInputBuffers = new LinkedList<>();
|
||||||
queuedInputBuffers = new LinkedList<>();
|
queuedInputBuffers = new LinkedList<>();
|
||||||
queuedOutputBuffers = new LinkedList<>();
|
queuedOutputBuffers = new LinkedList<>();
|
||||||
|
dequeuedOutputBuffers = new LinkedList<>();
|
||||||
availableInputBuffers = new InputBuffer[NUM_BUFFERS];
|
availableInputBuffers = new InputBuffer[NUM_BUFFERS];
|
||||||
availableOutputBuffers = new OutputBuffer[NUM_BUFFERS];
|
availableOutputBuffers = new OutputBuffer[NUM_BUFFERS];
|
||||||
availableInputBufferCount = NUM_BUFFERS;
|
availableInputBufferCount = NUM_BUFFERS;
|
||||||
|
|
@ -68,7 +72,7 @@ import java.util.LinkedList;
|
||||||
this.outputMode = outputMode;
|
this.outputMode = outputMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputBuffer getInputBuffer() throws VpxDecoderException {
|
public InputBuffer dequeueInputBuffer() throws VpxDecoderException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
maybeThrowDecoderError();
|
maybeThrowDecoderError();
|
||||||
if (availableInputBufferCount == 0) {
|
if (availableInputBufferCount == 0) {
|
||||||
|
|
@ -77,6 +81,7 @@ import java.util.LinkedList;
|
||||||
InputBuffer inputBuffer = availableInputBuffers[--availableInputBufferCount];
|
InputBuffer inputBuffer = availableInputBuffers[--availableInputBufferCount];
|
||||||
inputBuffer.flags = 0;
|
inputBuffer.flags = 0;
|
||||||
inputBuffer.sampleHolder.clearData();
|
inputBuffer.sampleHolder.clearData();
|
||||||
|
dequeuedInputBuffers.addLast(inputBuffer);
|
||||||
return inputBuffer;
|
return inputBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +89,7 @@ import java.util.LinkedList;
|
||||||
public void queueInputBuffer(InputBuffer inputBuffer) throws VpxDecoderException {
|
public void queueInputBuffer(InputBuffer inputBuffer) throws VpxDecoderException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
maybeThrowDecoderError();
|
maybeThrowDecoderError();
|
||||||
|
dequeuedInputBuffers.remove(inputBuffer);
|
||||||
queuedInputBuffers.addLast(inputBuffer);
|
queuedInputBuffers.addLast(inputBuffer);
|
||||||
maybeNotifyDecodeLoop();
|
maybeNotifyDecodeLoop();
|
||||||
}
|
}
|
||||||
|
|
@ -95,13 +101,16 @@ import java.util.LinkedList;
|
||||||
if (queuedOutputBuffers.isEmpty()) {
|
if (queuedOutputBuffers.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return queuedOutputBuffers.removeFirst();
|
OutputBuffer outputBuffer = queuedOutputBuffers.removeFirst();
|
||||||
|
dequeuedOutputBuffers.add(outputBuffer);
|
||||||
|
return outputBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void releaseOutputBuffer(OutputBuffer outputBuffer) throws VpxDecoderException {
|
public void releaseOutputBuffer(OutputBuffer outputBuffer) throws VpxDecoderException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
maybeThrowDecoderError();
|
maybeThrowDecoderError();
|
||||||
|
dequeuedOutputBuffers.remove(outputBuffer);
|
||||||
availableOutputBuffers[availableOutputBufferCount++] = outputBuffer;
|
availableOutputBuffers[availableOutputBufferCount++] = outputBuffer;
|
||||||
maybeNotifyDecodeLoop();
|
maybeNotifyDecodeLoop();
|
||||||
}
|
}
|
||||||
|
|
@ -110,12 +119,18 @@ import java.util.LinkedList;
|
||||||
public void flush() {
|
public void flush() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
flushDecodedOutputBuffer = true;
|
flushDecodedOutputBuffer = true;
|
||||||
|
while (!dequeuedInputBuffers.isEmpty()) {
|
||||||
|
availableInputBuffers[availableInputBufferCount++] = dequeuedInputBuffers.removeFirst();
|
||||||
|
}
|
||||||
while (!queuedInputBuffers.isEmpty()) {
|
while (!queuedInputBuffers.isEmpty()) {
|
||||||
availableInputBuffers[availableInputBufferCount++] = queuedInputBuffers.removeFirst();
|
availableInputBuffers[availableInputBufferCount++] = queuedInputBuffers.removeFirst();
|
||||||
}
|
}
|
||||||
while (!queuedOutputBuffers.isEmpty()) {
|
while (!queuedOutputBuffers.isEmpty()) {
|
||||||
availableOutputBuffers[availableOutputBufferCount++] = queuedOutputBuffers.removeFirst();
|
availableOutputBuffers[availableOutputBufferCount++] = queuedOutputBuffers.removeFirst();
|
||||||
}
|
}
|
||||||
|
while (!dequeuedOutputBuffers.isEmpty()) {
|
||||||
|
availableOutputBuffers[availableOutputBufferCount++] = dequeuedOutputBuffers.removeFirst();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue