Clean up expansion of sample buffers.
- The old approach was technically incorrect, because the checks were "capacity < sampleSize" and hence neglected the fact that the buffer position may be greater than 0 (e.g. if the caller wants to prefix the sample with some additional data). - Also proactively throw an exception if the buffer is too small, rather than wait for the failure when we actually do the write.
This commit is contained in:
parent
15c2f9c328
commit
e96e618046
@ -324,7 +324,7 @@ import java.util.LinkedList;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
sampleHolder.data.clear();
|
sampleHolder.clearData();
|
||||||
flags = 0;
|
flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ import java.util.LinkedList;
|
|||||||
}
|
}
|
||||||
InputBuffer inputBuffer = availableInputBuffers[--availableInputBufferCount];
|
InputBuffer inputBuffer = availableInputBuffers[--availableInputBufferCount];
|
||||||
inputBuffer.flags = 0;
|
inputBuffer.flags = 0;
|
||||||
inputBuffer.sampleHolder.data.clear();
|
inputBuffer.sampleHolder.clearData();
|
||||||
return inputBuffer;
|
return inputBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -531,7 +531,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sampleHolder.data = inputBuffers[inputIndex];
|
sampleHolder.data = inputBuffers[inputIndex];
|
||||||
sampleHolder.data.clear();
|
sampleHolder.clearData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
|
if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
|
||||||
@ -579,7 +579,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
||||||
// We received two formats in a row. Clear the current buffer of any reconfiguration data
|
// We received two formats in a row. Clear the current buffer of any reconfiguration data
|
||||||
// associated with the first format.
|
// associated with the first format.
|
||||||
sampleHolder.data.clear();
|
sampleHolder.clearData();
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
||||||
}
|
}
|
||||||
onInputFormatChanged(formatHolder);
|
onInputFormatChanged(formatHolder);
|
||||||
@ -590,7 +590,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
// We received a new format immediately before the end of the stream. We need to clear
|
// We received a new format immediately before the end of the stream. We need to clear
|
||||||
// the corresponding reconfiguration data from the current buffer, but re-write it into
|
// the corresponding reconfiguration data from the current buffer, but re-write it into
|
||||||
// a subsequent buffer if there are any (e.g. if the user seeks backwards).
|
// a subsequent buffer if there are any (e.g. if the user seeks backwards).
|
||||||
sampleHolder.data.clear();
|
sampleHolder.clearData();
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
||||||
}
|
}
|
||||||
inputStreamEnded = true;
|
inputStreamEnded = true;
|
||||||
@ -616,7 +616,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
// TODO: Find out if it's possible to supply samples prior to the first sync
|
// TODO: Find out if it's possible to supply samples prior to the first sync
|
||||||
// frame for HE-AAC.
|
// frame for HE-AAC.
|
||||||
if (!sampleHolder.isSyncFrame()) {
|
if (!sampleHolder.isSyncFrame()) {
|
||||||
sampleHolder.data.clear();
|
sampleHolder.clearData();
|
||||||
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
||||||
// The buffer we just cleared contained reconfiguration data. We need to re-write this
|
// The buffer we just cleared contained reconfiguration data. We need to re-write this
|
||||||
// data into a subsequent buffer (if there is one).
|
// data into a subsequent buffer (if there is one).
|
||||||
|
@ -63,8 +63,8 @@ public final class SampleHolder {
|
|||||||
private final int bufferReplacementMode;
|
private final int bufferReplacementMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bufferReplacementMode Determines the behavior of {@link #replaceBuffer(int)}. One of
|
* @param bufferReplacementMode Determines the behavior of {@link #ensureSpaceForWrite(int)}. One
|
||||||
* {@link #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} and
|
* of {@link #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} and
|
||||||
* {@link #BUFFER_REPLACEMENT_MODE_DIRECT}.
|
* {@link #BUFFER_REPLACEMENT_MODE_DIRECT}.
|
||||||
*/
|
*/
|
||||||
public SampleHolder(int bufferReplacementMode) {
|
public SampleHolder(int bufferReplacementMode) {
|
||||||
@ -73,21 +73,39 @@ public final class SampleHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to replace {@link #data} with a {@link ByteBuffer} of the specified capacity.
|
* Ensures that {@link #data} is large enough to accommodate a write of a given length at its
|
||||||
|
* current position.
|
||||||
|
* <p>
|
||||||
|
* If the capacity of {@link #data} is sufficient this method does nothing. If the capacity is
|
||||||
|
* insufficient then an attempt is made to replace {@link #data} with a new {@link ByteBuffer}
|
||||||
|
* whose capacity is sufficient. Data up to the current position is copied to the new buffer.
|
||||||
*
|
*
|
||||||
* @param capacity The capacity of the replacement buffer, in bytes.
|
* @param length The length of the write that must be accommodated, in bytes.
|
||||||
* @return True if the buffer was replaced. False otherwise.
|
* @throws IllegalStateException If there is insufficient capacity to accommodate the write and
|
||||||
|
* the buffer replacement mode of the holder is {@link #BUFFER_REPLACEMENT_MODE_DISABLED}.
|
||||||
*/
|
*/
|
||||||
public boolean replaceBuffer(int capacity) {
|
public void ensureSpaceForWrite(int length) throws IllegalStateException {
|
||||||
switch (bufferReplacementMode) {
|
if (data == null) {
|
||||||
case BUFFER_REPLACEMENT_MODE_NORMAL:
|
data = createReplacementBuffer(length);
|
||||||
data = ByteBuffer.allocate(capacity);
|
return;
|
||||||
return true;
|
|
||||||
case BUFFER_REPLACEMENT_MODE_DIRECT:
|
|
||||||
data = ByteBuffer.allocateDirect(capacity);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
// Check whether the current buffer is sufficient.
|
||||||
|
int capacity = data.capacity();
|
||||||
|
int position = data.position();
|
||||||
|
int requiredCapacity = position + length;
|
||||||
|
if (capacity >= requiredCapacity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Instantiate a new buffer if possible.
|
||||||
|
ByteBuffer newData = createReplacementBuffer(requiredCapacity);
|
||||||
|
// Copy data up to the current position from the old buffer to the new one.
|
||||||
|
if (position > 0) {
|
||||||
|
data.position(0);
|
||||||
|
data.limit(position);
|
||||||
|
newData.put(data);
|
||||||
|
}
|
||||||
|
// Set the new buffer.
|
||||||
|
data = newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,4 +138,16 @@ public final class SampleHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ByteBuffer createReplacementBuffer(int requiredCapacity) {
|
||||||
|
if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_NORMAL) {
|
||||||
|
return ByteBuffer.allocate(requiredCapacity);
|
||||||
|
} else if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DIRECT) {
|
||||||
|
return ByteBuffer.allocateDirect(requiredCapacity);
|
||||||
|
} else {
|
||||||
|
int currentCapacity = data == null ? 0 : data.capacity();
|
||||||
|
throw new IllegalStateException("Buffer too small (" + currentCapacity + " < "
|
||||||
|
+ requiredCapacity + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -139,9 +139,7 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
|||||||
sampleHolder.timeUs = 0;
|
sampleHolder.timeUs = 0;
|
||||||
sampleHolder.size = sampleSize;
|
sampleHolder.size = sampleSize;
|
||||||
sampleHolder.flags = C.SAMPLE_FLAG_SYNC;
|
sampleHolder.flags = C.SAMPLE_FLAG_SYNC;
|
||||||
if (sampleHolder.data == null || sampleHolder.data.capacity() < sampleSize) {
|
sampleHolder.ensureSpaceForWrite(sampleHolder.size);
|
||||||
sampleHolder.replaceBuffer(sampleHolder.size);
|
|
||||||
}
|
|
||||||
sampleHolder.data.put(sampleData, 0, sampleSize);
|
sampleHolder.data.put(sampleData, 0, sampleSize);
|
||||||
state = STATE_END_OF_STREAM;
|
state = STATE_END_OF_STREAM;
|
||||||
return SAMPLE_READ;
|
return SAMPLE_READ;
|
||||||
|
@ -186,12 +186,8 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
readEncryptionData(sampleHolder, extrasHolder);
|
readEncryptionData(sampleHolder, extrasHolder);
|
||||||
}
|
}
|
||||||
// Write the sample data into the holder.
|
// Write the sample data into the holder.
|
||||||
if (sampleHolder.data == null || sampleHolder.data.capacity() < sampleHolder.size) {
|
sampleHolder.ensureSpaceForWrite(sampleHolder.size);
|
||||||
sampleHolder.replaceBuffer(sampleHolder.size);
|
|
||||||
}
|
|
||||||
if (sampleHolder.data != null) {
|
|
||||||
readData(extrasHolder.offset, sampleHolder.data, sampleHolder.size);
|
readData(extrasHolder.offset, sampleHolder.data, sampleHolder.size);
|
||||||
}
|
|
||||||
// Advance the read head.
|
// Advance the read head.
|
||||||
long nextOffset = infoQueue.moveToNextSample();
|
long nextOffset = infoQueue.moveToNextSample();
|
||||||
dropDownstreamTo(nextOffset);
|
dropDownstreamTo(nextOffset);
|
||||||
|
@ -114,6 +114,7 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
|||||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||||
continueBufferingSource(positionUs);
|
continueBufferingSource(positionUs);
|
||||||
if (!inputStreamEnded && pendingMetadata == null) {
|
if (!inputStreamEnded && pendingMetadata == null) {
|
||||||
|
sampleHolder.clearData();
|
||||||
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
||||||
if (result == SampleSource.SAMPLE_READ) {
|
if (result == SampleSource.SAMPLE_READ) {
|
||||||
pendingMetadataTimestamp = sampleHolder.timeUs;
|
pendingMetadataTimestamp = sampleHolder.timeUs;
|
||||||
@ -122,7 +123,6 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ExoPlaybackException(e);
|
throw new ExoPlaybackException(e);
|
||||||
}
|
}
|
||||||
sampleHolder.data.clear();
|
|
||||||
} else if (result == SampleSource.END_OF_STREAM) {
|
} else if (result == SampleSource.END_OF_STREAM) {
|
||||||
inputStreamEnded = true;
|
inputStreamEnded = true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user