Cleanup - Make RollingSampleBuffer append methods more consistent.

This commit is contained in:
Oliver Woodman 2015-07-30 17:13:24 +01:00
parent 0d42032ada
commit 5f51a4ff83
12 changed files with 101 additions and 64 deletions

View File

@ -57,8 +57,8 @@ public final class FakeTrackOutput implements TrackOutput {
}
@Override
public int sampleData(ExtractorInput input, int length) throws IOException,
InterruptedException {
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
byte[] newData = new byte[length];
input.readFully(newData, 0, length);
sampleData = TestUtil.joinByteArrays(sampleData, newData);

View File

@ -127,8 +127,9 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
}
@Override
public int sampleData(ExtractorInput input, int length) throws IOException, InterruptedException {
return output.sampleData(input, length);
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
return output.sampleData(input, length, allowEndOfInput);
}
@Override

View File

@ -106,8 +106,9 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
}
@Override
public int sampleData(ExtractorInput input, int length) throws IOException, InterruptedException {
return getOutput().sampleData(input, length);
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
return getOutput().sampleData(input, length, allowEndOfInput);
}
@Override

View File

@ -138,7 +138,8 @@ public final class InitializationChunk extends Chunk implements SingleTrackOutpu
}
@Override
public int sampleData(ExtractorInput input, int length) throws IOException, InterruptedException {
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
throw new IllegalStateException("Unexpected sample data in initialization chunk");
}

View File

@ -109,10 +109,8 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
// Load the sample data.
int result = 0;
while (result != C.RESULT_END_OF_INPUT) {
result = getOutput().sampleData(dataSource, Integer.MAX_VALUE);
if (result != C.RESULT_END_OF_INPUT) {
bytesLoaded += result;
}
bytesLoaded += result;
result = getOutput().sampleData(dataSource, Integer.MAX_VALUE, true);
}
int sampleSize = bytesLoaded;
if (headerData != null) {

View File

@ -15,12 +15,14 @@
*/
package com.google.android.exoplayer.extractor;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.upstream.Allocator;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.util.ParsableByteArray;
import java.io.EOFException;
import java.io.IOException;
/**
@ -225,8 +227,20 @@ public class DefaultTrackOutput implements TrackOutput {
// Called by the loading thread.
public int sampleData(DataSource dataSource, int length) throws IOException {
return rollingBuffer.appendData(dataSource, length);
/**
* Invoked to write sample data to the output.
*
* @param dataSource A {@link DataSource} from which to read the sample data.
* @param length The maximum length to read from the input.
* @param allowEndOfInput True if encountering the end of the input having read no data is
* allowed, and should result in {@link C#RESULT_END_OF_INPUT} being returned. False if it
* should be considered an error, causing an {@link EOFException} to be thrown.
* @return The number of bytes appended.
* @throws IOException If an error occurred reading from the input.
*/
public int sampleData(DataSource dataSource, int length, boolean allowEndOfInput)
throws IOException {
return rollingBuffer.appendData(dataSource, length, allowEndOfInput);
}
// TrackOutput implementation. Called by the loading thread.
@ -237,8 +251,9 @@ public class DefaultTrackOutput implements TrackOutput {
}
@Override
public int sampleData(ExtractorInput input, int length) throws IOException, InterruptedException {
return rollingBuffer.appendData(input, length);
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
return rollingBuffer.appendData(input, length, allowEndOfInput);
}
@Override

View File

@ -23,6 +23,7 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.ParsableByteArray;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingDeque;
@ -350,26 +351,27 @@ import java.util.concurrent.LinkedBlockingDeque;
* Appends data to the rolling buffer.
*
* @param dataSource The source from which to read.
* @param length The maximum length of the read, or {@link C#LENGTH_UNBOUNDED} if the caller does
* not wish to impose a limit.
* @return The number of bytes appended.
* @param length The maximum length of the read.
* @param allowEndOfInput True if encountering the end of the input having appended no data is
* allowed, and should result in {@link C#RESULT_END_OF_INPUT} being returned. False if it
* should be considered an error, causing an {@link EOFException} to be thrown.
* @return The number of bytes appended, or {@link C#RESULT_END_OF_INPUT} if the input has ended.
* @throws IOException If an error occurs reading from the source.
*/
public int appendData(DataSource dataSource, int length) throws IOException {
ensureSpaceForWrite();
int remainingAllocationCapacity = allocationLength - lastAllocationOffset;
length = length != C.LENGTH_UNBOUNDED ? Math.min(length, remainingAllocationCapacity)
: remainingAllocationCapacity;
int bytesRead = dataSource.read(lastAllocation.data,
public int appendData(DataSource dataSource, int length, boolean allowEndOfInput)
throws IOException {
length = prepareForAppend(length);
int bytesAppended = dataSource.read(lastAllocation.data,
lastAllocation.translateOffset(lastAllocationOffset), length);
if (bytesRead == C.RESULT_END_OF_INPUT) {
return C.RESULT_END_OF_INPUT;
if (bytesAppended == C.RESULT_END_OF_INPUT) {
if (allowEndOfInput) {
return C.RESULT_END_OF_INPUT;
}
throw new EOFException();
}
lastAllocationOffset += bytesRead;
totalBytesWritten += bytesRead;
return bytesRead;
lastAllocationOffset += bytesAppended;
totalBytesWritten += bytesAppended;
return bytesAppended;
}
/**
@ -377,17 +379,27 @@ import java.util.concurrent.LinkedBlockingDeque;
*
* @param input The source from which to read.
* @param length The maximum length of the read.
* @return The number of bytes appended.
* @param allowEndOfInput True if encountering the end of the input having appended no data is
* allowed, and should result in {@link C#RESULT_END_OF_INPUT} being returned. False if it
* should be considered an error, causing an {@link EOFException} to be thrown.
* @return The number of bytes appended, or {@link C#RESULT_END_OF_INPUT} if the input has ended.
* @throws IOException If an error occurs reading from the source.
* @throws InterruptedException If the thread has been interrupted.
*/
public int appendData(ExtractorInput input, int length) throws IOException, InterruptedException {
ensureSpaceForWrite();
int thisWriteLength = Math.min(length, allocationLength - lastAllocationOffset);
input.readFully(lastAllocation.data, lastAllocation.translateOffset(lastAllocationOffset),
thisWriteLength);
lastAllocationOffset += thisWriteLength;
totalBytesWritten += thisWriteLength;
return thisWriteLength;
public int appendData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
length = prepareForAppend(length);
int bytesAppended = input.read(lastAllocation.data,
lastAllocation.translateOffset(lastAllocationOffset), length);
if (bytesAppended == C.RESULT_END_OF_INPUT) {
if (allowEndOfInput) {
return C.RESULT_END_OF_INPUT;
}
throw new EOFException();
}
lastAllocationOffset += bytesAppended;
totalBytesWritten += bytesAppended;
return bytesAppended;
}
/**
@ -397,16 +409,14 @@ import java.util.concurrent.LinkedBlockingDeque;
* @param length The length of the data to append.
*/
public void appendData(ParsableByteArray buffer, int length) {
int remainingWriteLength = length;
while (remainingWriteLength > 0) {
ensureSpaceForWrite();
int thisWriteLength = Math.min(remainingWriteLength, allocationLength - lastAllocationOffset);
while (length > 0) {
int thisAppendLength = prepareForAppend(length);
buffer.readBytes(lastAllocation.data, lastAllocation.translateOffset(lastAllocationOffset),
thisWriteLength);
lastAllocationOffset += thisWriteLength;
remainingWriteLength -= thisWriteLength;
thisAppendLength);
lastAllocationOffset += thisAppendLength;
totalBytesWritten += thisAppendLength;
length -= thisAppendLength;
}
totalBytesWritten += length;
}
/**
@ -424,14 +434,16 @@ import java.util.concurrent.LinkedBlockingDeque;
}
/**
* Ensures at least one byte can be written, obtaining an additional allocation if necessary.
* Prepares the rolling sample buffer for an append of up to {@code length} bytes, returning the
* number of bytes that can actually be appended.
*/
private void ensureSpaceForWrite() {
private int prepareForAppend(int length) {
if (lastAllocationOffset == allocationLength) {
lastAllocationOffset = 0;
lastAllocation = allocator.allocate();
dataQueue.add(lastAllocation);
}
return Math.min(length, allocationLength - lastAllocationOffset);
}
/**

View File

@ -15,10 +15,12 @@
*/
package com.google.android.exoplayer.extractor;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.util.ParsableByteArray;
import java.io.EOFException;
import java.io.IOException;
/**
@ -38,11 +40,15 @@ public interface TrackOutput {
*
* @param input An {@link ExtractorInput} from which to read the sample data.
* @param length The maximum length to read from the input.
* @param allowEndOfInput True if encountering the end of the input having read no data is
* allowed, and should result in {@link C#RESULT_END_OF_INPUT} being returned. False if it
* should be considered an error, causing an {@link EOFException} to be thrown.
* @return The number of bytes appended.
* @throws IOException If an error occurred reading from the input.
* @throws InterruptedException If the thread was interrupted.
*/
int sampleData(ExtractorInput input, int length) throws IOException, InterruptedException;
int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException;
/**
* Invoked to write sample data to the output.
@ -56,14 +62,16 @@ public interface TrackOutput {
* Invoked when metadata associated with a sample has been extracted from the stream.
* <p>
* The corresponding sample data will have already been passed to the output via calls to
* {@link #sampleData(ExtractorInput, int)} or {@link #sampleData(ParsableByteArray, int)}.
* {@link #sampleData(ExtractorInput, int, boolean)} or
* {@link #sampleData(ParsableByteArray, int)}.
*
* @param timeUs The media timestamp associated with the sample, in microseconds.
* @param flags Flags associated with the sample. See {@link SampleHolder#flags}.
* @param size The size of the sample data, in bytes.
* @param offset The number of bytes that have been passed to
* {@link #sampleData(ExtractorInput, int)} or {@link #sampleData(ParsableByteArray, int)}
* since the last byte belonging to the sample whose metadata is being passed.
* {@link #sampleData(ExtractorInput, int, boolean)} or
* {@link #sampleData(ParsableByteArray, int)} since the last byte belonging to the sample
* whose metadata is being passed.
* @param encryptionKey The encryption key associated with the sample. May be null.
*/
void sampleMetadata(long timeUs, int flags, int size, int offset, byte[] encryptionKey);

View File

@ -170,11 +170,11 @@ public final class Mp3Extractor implements Extractor {
sampleBytesRemaining -= inputBuffer.drainToOutput(trackOutput, sampleBytesRemaining);
if (sampleBytesRemaining > 0) {
inputBuffer.mark();
try {
sampleBytesRemaining -= trackOutput.sampleData(extractorInput, sampleBytesRemaining);
} catch (EOFException e) {
int bytesAppended = trackOutput.sampleData(extractorInput, sampleBytesRemaining, true);
if (bytesAppended == C.RESULT_END_OF_INPUT) {
return RESULT_END_OF_INPUT;
}
sampleBytesRemaining -= bytesAppended;
// Return if we still need more data.
if (sampleBytesRemaining > 0) {
return RESULT_CONTINUE;

View File

@ -663,14 +663,14 @@ public final class FragmentedMp4Extractor implements Extractor {
sampleSize += nalUnitLengthFieldLengthDiff;
} else {
// Write the payload of the NAL unit.
int writtenBytes = trackOutput.sampleData(input, sampleCurrentNalBytesRemaining);
int writtenBytes = trackOutput.sampleData(input, sampleCurrentNalBytesRemaining, false);
sampleBytesWritten += writtenBytes;
sampleCurrentNalBytesRemaining -= writtenBytes;
}
}
} else {
while (sampleBytesWritten < sampleSize) {
int writtenBytes = trackOutput.sampleData(input, sampleSize - sampleBytesWritten);
int writtenBytes = trackOutput.sampleData(input, sampleSize - sampleBytesWritten, false);
sampleBytesWritten += writtenBytes;
}
}

View File

@ -298,6 +298,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
return RESULT_END_OF_INPUT;
}
Mp4Track track = tracks[trackIndex];
TrackOutput trackOutput = track.trackOutput;
int sampleIndex = track.sampleIndex;
long position = track.sampleTable.offsets[sampleIndex];
long skipAmount = position - input.getPosition() + sampleBytesWritten;
@ -327,24 +328,24 @@ public final class Mp4Extractor implements Extractor, SeekMap {
sampleCurrentNalBytesRemaining = nalLength.readUnsignedIntToInt();
// Write a start code for the current NAL unit.
nalStartCode.setPosition(0);
track.trackOutput.sampleData(nalStartCode, 4);
trackOutput.sampleData(nalStartCode, 4);
sampleBytesWritten += 4;
sampleSize += nalUnitLengthFieldLengthDiff;
} else {
// Write the payload of the NAL unit.
int writtenBytes = track.trackOutput.sampleData(input, sampleCurrentNalBytesRemaining);
int writtenBytes = trackOutput.sampleData(input, sampleCurrentNalBytesRemaining, false);
sampleBytesWritten += writtenBytes;
sampleCurrentNalBytesRemaining -= writtenBytes;
}
}
} else {
while (sampleBytesWritten < sampleSize) {
int writtenBytes = track.trackOutput.sampleData(input, sampleSize - sampleBytesWritten);
int writtenBytes = trackOutput.sampleData(input, sampleSize - sampleBytesWritten, false);
sampleBytesWritten += writtenBytes;
sampleCurrentNalBytesRemaining -= writtenBytes;
}
}
track.trackOutput.sampleMetadata(track.sampleTable.timestampsUs[sampleIndex],
trackOutput.sampleMetadata(track.sampleTable.timestampsUs[sampleIndex],
track.sampleTable.flags[sampleIndex], sampleSize, 0, null);
track.sampleIndex++;
sampleBytesWritten = 0;

View File

@ -885,7 +885,7 @@ public final class WebmExtractor implements Extractor {
bytesRead = Math.min(length, strippedBytesLeft);
output.sampleData(sampleStrippedBytes, bytesRead);
} else {
bytesRead = output.sampleData(input, length);
bytesRead = output.sampleData(input, length, false);
}
sampleBytesRead += bytesRead;
sampleBytesWritten += bytesRead;