Avoid input/output copies in SonicAudioProcessor.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=151431376
This commit is contained in:
parent
422c2d0ab7
commit
1dcfae452a
@ -17,6 +17,7 @@
|
|||||||
package com.google.android.exoplayer2.audio;
|
package com.google.android.exoplayer2.audio;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,60 +113,39 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes {@code numBytes} from {@code buffer} as input.
|
* Queues remaining data from {@code buffer}, and advances its position by the number of bytes
|
||||||
|
* consumed.
|
||||||
*
|
*
|
||||||
* @param buffer A buffer containing input data.
|
* @param buffer A {@link ShortBuffer} containing input data between its position and limit.
|
||||||
* @param numBytes The number of bytes of input data to read from {@code buffer}.
|
|
||||||
*/
|
*/
|
||||||
public void writeBytesToStream(byte[] buffer, int numBytes) {
|
public void queueInput(ShortBuffer buffer) {
|
||||||
int numSamples = numBytes / (2 * numChannels);
|
int samplesToWrite = buffer.remaining() / numChannels;
|
||||||
short sample;
|
int bytesToWrite = samplesToWrite * numChannels * 2;
|
||||||
|
enlargeInputBufferIfNeeded(samplesToWrite);
|
||||||
enlargeInputBufferIfNeeded(numSamples);
|
buffer.get(inputBuffer, numInputSamples * numChannels, bytesToWrite / 2);
|
||||||
int xBuffer = numInputSamples * numChannels;
|
numInputSamples += samplesToWrite;
|
||||||
for (int xByte = 0; xByte + 1 < numBytes; xByte += 2) {
|
|
||||||
sample = (short) ((buffer[xByte] & 0xff) | (buffer[xByte + 1] << 8));
|
|
||||||
inputBuffer[xBuffer++] = sample;
|
|
||||||
}
|
|
||||||
numInputSamples += numSamples;
|
|
||||||
processStreamInput();
|
processStreamInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads up to {@code maxBytes} of output into {@code buffer}.
|
* Gets available output, outputting to the start of {@code buffer}. The buffer's position will be
|
||||||
|
* advanced by the number of bytes written.
|
||||||
*
|
*
|
||||||
* @param buffer The buffer into which output will be written.
|
* @param buffer A {@link ShortBuffer} into which output will be written.
|
||||||
* @param maxBytes The maximum number of bytes to write.
|
|
||||||
* @return The number of bytes read from the stream.
|
|
||||||
*/
|
*/
|
||||||
public int readBytesFromStream(byte[] buffer, int maxBytes) {
|
public void getOutput(ShortBuffer buffer) {
|
||||||
int maxSamples = maxBytes / (2 * numChannels);
|
int samplesToRead = Math.min(buffer.remaining() / numChannels, numOutputSamples);
|
||||||
int numSamples = numOutputSamples;
|
buffer.put(outputBuffer, 0, samplesToRead * numChannels);
|
||||||
int remainingSamples = 0;
|
numOutputSamples -= samplesToRead;
|
||||||
|
System.arraycopy(outputBuffer, samplesToRead * numChannels, outputBuffer, 0,
|
||||||
if (numSamples == 0 || maxSamples == 0) {
|
numOutputSamples * numChannels);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (numSamples > maxSamples) {
|
|
||||||
remainingSamples = numSamples - maxSamples;
|
|
||||||
numSamples = maxSamples;
|
|
||||||
}
|
|
||||||
for (int xSample = 0; xSample < numSamples * numChannels; xSample++) {
|
|
||||||
short sample = outputBuffer[xSample];
|
|
||||||
buffer[xSample << 1] = (byte) (sample & 0xff);
|
|
||||||
buffer[(xSample << 1) + 1] = (byte) (sample >> 8);
|
|
||||||
}
|
|
||||||
System.arraycopy(outputBuffer, numSamples * numChannels, outputBuffer, 0,
|
|
||||||
remainingSamples * numChannels);
|
|
||||||
numOutputSamples = remainingSamples;
|
|
||||||
return 2 * numSamples * numChannels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces generating output using whatever data has been queued already. No extra delay will be
|
* Forces generating output using whatever data has been queued already. No extra delay will be
|
||||||
* added to the output, but flushing in the middle of words could introduce distortion.
|
* added to the output, but flushing in the middle of words could introduce distortion.
|
||||||
*/
|
*/
|
||||||
public void flushStream() {
|
public void queueEndOfStream() {
|
||||||
int remainingSamples = numInputSamples;
|
int remainingSamples = numInputSamples;
|
||||||
float s = speed / pitch;
|
float s = speed / pitch;
|
||||||
int expectedOutputSamples =
|
int expectedOutputSamples =
|
||||||
@ -189,10 +169,9 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of output samples that can be read with
|
* Returns the number of output samples that can be read with {@link #getOutput(ShortBuffer)}.
|
||||||
* {@link #readBytesFromStream(byte[], int)}.
|
|
||||||
*/
|
*/
|
||||||
public int samplesAvailable() {
|
public int getSamplesAvailable() {
|
||||||
return numOutputSamples;
|
return numOutputSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format;
|
|||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link AudioProcessor} that uses the Sonic library to modify the speed/pitch of audio.
|
* An {@link AudioProcessor} that uses the Sonic library to modify the speed/pitch of audio.
|
||||||
@ -50,8 +51,6 @@ import java.nio.ByteOrder;
|
|||||||
*/
|
*/
|
||||||
private static final float CLOSE_THRESHOLD = 0.01f;
|
private static final float CLOSE_THRESHOLD = 0.01f;
|
||||||
|
|
||||||
private static final byte[] EMPTY_ARRAY = new byte[0];
|
|
||||||
|
|
||||||
private int channelCount;
|
private int channelCount;
|
||||||
private int sampleRateHz;
|
private int sampleRateHz;
|
||||||
|
|
||||||
@ -59,9 +58,9 @@ import java.nio.ByteOrder;
|
|||||||
private float speed;
|
private float speed;
|
||||||
private float pitch;
|
private float pitch;
|
||||||
|
|
||||||
private byte[] inputArray;
|
private ShortBuffer shortBuffer;
|
||||||
|
|
||||||
private ByteBuffer buffer;
|
private ByteBuffer buffer;
|
||||||
private byte[] bufferArray;
|
|
||||||
private ByteBuffer outputBuffer;
|
private ByteBuffer outputBuffer;
|
||||||
private long inputBytes;
|
private long inputBytes;
|
||||||
private long outputBytes;
|
private long outputBytes;
|
||||||
@ -76,9 +75,8 @@ import java.nio.ByteOrder;
|
|||||||
channelCount = Format.NO_VALUE;
|
channelCount = Format.NO_VALUE;
|
||||||
sampleRateHz = Format.NO_VALUE;
|
sampleRateHz = Format.NO_VALUE;
|
||||||
buffer = EMPTY_BUFFER;
|
buffer = EMPTY_BUFFER;
|
||||||
|
shortBuffer = buffer.asShortBuffer();
|
||||||
outputBuffer = EMPTY_BUFFER;
|
outputBuffer = EMPTY_BUFFER;
|
||||||
inputArray = EMPTY_ARRAY;
|
|
||||||
bufferArray = EMPTY_ARRAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,31 +140,32 @@ import java.nio.ByteOrder;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queueInput(ByteBuffer inputBuffer) {
|
public void queueInput(ByteBuffer inputBuffer) {
|
||||||
// TODO: Remove this extra copy.
|
if (inputBuffer.hasRemaining()) {
|
||||||
int inputBytesToRead = inputBuffer.remaining();
|
ShortBuffer shortBuffer = inputBuffer.asShortBuffer();
|
||||||
if (inputArray == null || inputArray.length < inputBytesToRead) {
|
int inputSize = inputBuffer.remaining();
|
||||||
inputArray = new byte[inputBytesToRead];
|
inputBytes += inputSize;
|
||||||
|
sonic.queueInput(shortBuffer);
|
||||||
|
inputBuffer.position(inputBuffer.position() + inputSize);
|
||||||
}
|
}
|
||||||
inputBuffer.get(inputArray, 0, inputBytesToRead);
|
int outputSize = sonic.getSamplesAvailable() * channelCount * 2;
|
||||||
sonic.writeBytesToStream(inputArray, inputBytesToRead);
|
if (outputSize > 0) {
|
||||||
int outputSize = sonic.samplesAvailable() * channelCount * 2;
|
if (buffer.capacity() < outputSize) {
|
||||||
if (buffer.capacity() < outputSize) {
|
buffer = ByteBuffer.allocateDirect(outputSize).order(ByteOrder.nativeOrder());
|
||||||
buffer = ByteBuffer.allocateDirect(outputSize).order(ByteOrder.nativeOrder());
|
shortBuffer = buffer.asShortBuffer();
|
||||||
bufferArray = new byte[outputSize];
|
} else {
|
||||||
} else {
|
buffer.clear();
|
||||||
buffer.clear();
|
shortBuffer.clear();
|
||||||
|
}
|
||||||
|
sonic.getOutput(shortBuffer);
|
||||||
|
outputBytes += outputSize;
|
||||||
|
buffer.limit(outputSize);
|
||||||
|
outputBuffer = buffer;
|
||||||
}
|
}
|
||||||
inputBytes += inputBytesToRead;
|
|
||||||
int outputBytesRead = sonic.readBytesFromStream(bufferArray, outputSize);
|
|
||||||
buffer.put(bufferArray, 0, outputBytesRead);
|
|
||||||
buffer.flip();
|
|
||||||
outputBytes += outputSize;
|
|
||||||
outputBuffer = buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queueEndOfStream() {
|
public void queueEndOfStream() {
|
||||||
sonic.flushStream();
|
sonic.queueEndOfStream();
|
||||||
inputEnded = true;
|
inputEnded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +178,7 @@ import java.nio.ByteOrder;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnded() {
|
public boolean isEnded() {
|
||||||
return inputEnded && (sonic == null || sonic.samplesAvailable() == 0);
|
return inputEnded && (sonic == null || sonic.getSamplesAvailable() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -198,8 +197,7 @@ import java.nio.ByteOrder;
|
|||||||
sonic = null;
|
sonic = null;
|
||||||
buffer = EMPTY_BUFFER;
|
buffer = EMPTY_BUFFER;
|
||||||
outputBuffer = EMPTY_BUFFER;
|
outputBuffer = EMPTY_BUFFER;
|
||||||
inputArray = EMPTY_ARRAY;
|
shortBuffer = null;
|
||||||
bufferArray = EMPTY_ARRAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user