Commit 17d7a0cb by olly Committed by Oliver Woodman

Make RollingSampleBuffer implement TrackOutput

This is the first step toward merging of RollingSampleBuffer
and DefaultTrackOutput, which is a precursor to removing some
indirection for DASH/SS playbacks, and to moving HLS playbacks
to use a single output buffer per track (with inline splicing).

Where this is heading is that sample format changes will
eventually be attached to samples in the rolling buffer. This
will eliminate the need for piping sample formats around the
edges of the rolling buffer (e.g. via redirection in
ChunkExtractorWrapper and BaseMediaChunk.getSampleFormat).
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=120123093
parent 4161dc8d
...@@ -37,9 +37,8 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe ...@@ -37,9 +37,8 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe
private final ChunkExtractorWrapper extractorWrapper; private final ChunkExtractorWrapper extractorWrapper;
private final long sampleOffsetUs; private final long sampleOffsetUs;
private Format sampleFormat; private volatile DrmInitData drmInitData;
private DrmInitData drmInitData; private volatile Format sampleFormat;
private volatile int bytesLoaded; private volatile int bytesLoaded;
private volatile boolean loadCanceled; private volatile boolean loadCanceled;
......
...@@ -69,15 +69,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad ...@@ -69,15 +69,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad
} }
/** /**
* True if a {@link Format} was parsed from the chunk. False otherwise.
* <p>
* Should be called after loading has completed.
*/
public boolean hasSampleFormat() {
return sampleFormat != null;
}
/**
* Returns a {@link Format} parsed from the chunk, or null. * Returns a {@link Format} parsed from the chunk, or null.
* <p> * <p>
* Should be called after loading has completed. * Should be called after loading has completed.
...@@ -87,15 +78,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad ...@@ -87,15 +78,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad
} }
/** /**
* True if a {@link DrmInitData} was parsed from the chunk. False otherwise.
* <p>
* Should be called after loading has completed.
*/
public boolean hasDrmInitData() {
return drmInitData != null;
}
/**
* Returns a {@link DrmInitData} parsed from the chunk, or null. * Returns a {@link DrmInitData} parsed from the chunk, or null.
* <p> * <p>
* Should be called after loading has completed. * Should be called after loading has completed.
......
...@@ -289,8 +289,9 @@ public class DashChunkSource implements ChunkSource { ...@@ -289,8 +289,9 @@ public class DashChunkSource implements ChunkSource {
InitializationChunk initializationChunk = (InitializationChunk) chunk; InitializationChunk initializationChunk = (InitializationChunk) chunk;
RepresentationHolder representationHolder = RepresentationHolder representationHolder =
representationHolders[getTrackIndex(initializationChunk.format)]; representationHolders[getTrackIndex(initializationChunk.format)];
if (initializationChunk.hasSampleFormat()) { Format sampleFormat = initializationChunk.getSampleFormat();
representationHolder.sampleFormat = initializationChunk.getSampleFormat(); if (sampleFormat != null) {
representationHolder.sampleFormat = sampleFormat;
} }
// The null check avoids overwriting an index obtained from the manifest with one obtained // The null check avoids overwriting an index obtained from the manifest with one obtained
// from the stream. If the manifest defines an index then the stream shouldn't, but in cases // from the stream. If the manifest defines an index then the stream shouldn't, but in cases
...@@ -302,7 +303,7 @@ public class DashChunkSource implements ChunkSource { ...@@ -302,7 +303,7 @@ public class DashChunkSource implements ChunkSource {
} }
// The null check avoids overwriting drmInitData obtained from the manifest with drmInitData // The null check avoids overwriting drmInitData obtained from the manifest with drmInitData
// obtained from the stream, as per DASH IF Interoperability Recommendations V3.0, 7.5.3. // obtained from the stream, as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
if (drmInitData == null && initializationChunk.hasDrmInitData()) { if (drmInitData == null) {
drmInitData = initializationChunk.getDrmInitData(); drmInitData = initializationChunk.getDrmInitData();
} }
} }
......
...@@ -41,7 +41,6 @@ public class DefaultTrackOutput implements TrackOutput { ...@@ -41,7 +41,6 @@ public class DefaultTrackOutput implements TrackOutput {
// Accessed by both the loading and consuming threads. // Accessed by both the loading and consuming threads.
private volatile long largestParsedTimestampUs; private volatile long largestParsedTimestampUs;
private volatile Format format;
/** /**
* @param allocator An {@link Allocator} from which allocations for sample data can be obtained. * @param allocator An {@link Allocator} from which allocations for sample data can be obtained.
...@@ -96,17 +95,10 @@ public class DefaultTrackOutput implements TrackOutput { ...@@ -96,17 +95,10 @@ public class DefaultTrackOutput implements TrackOutput {
} }
/** /**
* True if the output has received a format. False otherwise.
*/
public boolean hasFormat() {
return format != null;
}
/**
* The format most recently received by the output, or null if a format has yet to be received. * The format most recently received by the output, or null if a format has yet to be received.
*/ */
public Format getFormat() { public Format getFormat() {
return format; return rollingBuffer.getUpstreamFormat();
} }
/** /**
...@@ -234,25 +226,25 @@ public class DefaultTrackOutput implements TrackOutput { ...@@ -234,25 +226,25 @@ public class DefaultTrackOutput implements TrackOutput {
@Override @Override
public void format(Format format) { public void format(Format format) {
this.format = format; rollingBuffer.format(format);
} }
@Override @Override
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput) public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException { throws IOException, InterruptedException {
return rollingBuffer.appendData(input, length, allowEndOfInput); return rollingBuffer.sampleData(input, length, allowEndOfInput);
} }
@Override @Override
public void sampleData(ParsableByteArray buffer, int length) { public void sampleData(ParsableByteArray buffer, int length) {
rollingBuffer.appendData(buffer, length); rollingBuffer.sampleData(buffer, length);
} }
@Override @Override
public void sampleMetadata(long timeUs, int flags, int size, int offset, byte[] encryptionKey) { public void sampleMetadata(long timeUs, int flags, int size, int offset, byte[] encryptionKey) {
timeUs += sampleOffsetUs; timeUs += sampleOffsetUs;
largestParsedTimestampUs = Math.max(largestParsedTimestampUs, timeUs); largestParsedTimestampUs = Math.max(largestParsedTimestampUs, timeUs);
rollingBuffer.commitSample(timeUs, flags, size, offset, encryptionKey); rollingBuffer.sampleMetadata(timeUs, flags, size, offset, encryptionKey);
} }
} }
...@@ -640,7 +640,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -640,7 +640,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
private boolean haveFormatsForAllTracks() { private boolean haveFormatsForAllTracks() {
for (int i = 0; i < sampleQueues.size(); i++) { for (int i = 0; i < sampleQueues.size(); i++) {
if (!sampleQueues.valueAt(i).hasFormat()) { if (sampleQueues.valueAt(i).getFormat() == null) {
return false; return false;
} }
} }
......
...@@ -17,6 +17,7 @@ package com.google.android.exoplayer.extractor; ...@@ -17,6 +17,7 @@ package com.google.android.exoplayer.extractor;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.DecoderInputBuffer; import com.google.android.exoplayer.DecoderInputBuffer;
import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.upstream.Allocation; import com.google.android.exoplayer.upstream.Allocation;
import com.google.android.exoplayer.upstream.Allocator; import com.google.android.exoplayer.upstream.Allocator;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
...@@ -30,7 +31,7 @@ import java.util.concurrent.LinkedBlockingDeque; ...@@ -30,7 +31,7 @@ import java.util.concurrent.LinkedBlockingDeque;
/** /**
* A rolling buffer of sample data and corresponding sample information. * A rolling buffer of sample data and corresponding sample information.
*/ */
/* package */ final class RollingSampleBuffer { /* package */ final class RollingSampleBuffer implements TrackOutput {
private static final int INITIAL_SCRATCH_SIZE = 32; private static final int INITIAL_SCRATCH_SIZE = 32;
...@@ -50,6 +51,9 @@ import java.util.concurrent.LinkedBlockingDeque; ...@@ -50,6 +51,9 @@ import java.util.concurrent.LinkedBlockingDeque;
private Allocation lastAllocation; private Allocation lastAllocation;
private int lastAllocationOffset; private int lastAllocationOffset;
// Accessed by both the loading and consuming threads.
private volatile Format upstreamFormat;
/** /**
* @param allocator An {@link Allocator} from which allocations for sample data can be obtained. * @param allocator An {@link Allocator} from which allocations for sample data can be obtained.
*/ */
...@@ -132,6 +136,13 @@ import java.util.concurrent.LinkedBlockingDeque; ...@@ -132,6 +136,13 @@ import java.util.concurrent.LinkedBlockingDeque;
} }
/** /**
* Returns the current upstream format.
*/
public Format getUpstreamFormat() {
return upstreamFormat;
}
/**
* Fills {@code buffer} with information about the current sample, but does not write its data. * Fills {@code buffer} with information about the current sample, but does not write its data.
* <p> * <p>
* Populates {@link DecoderInputBuffer#size}, {@link DecoderInputBuffer#timeUs} and the buffer * Populates {@link DecoderInputBuffer#size}, {@link DecoderInputBuffer#timeUs} and the buffer
...@@ -344,19 +355,13 @@ import java.util.concurrent.LinkedBlockingDeque; ...@@ -344,19 +355,13 @@ import java.util.concurrent.LinkedBlockingDeque;
// Called by the loading thread. // Called by the loading thread.
/** @Override
* Appends data to the rolling buffer. public void format(Format format) {
* upstreamFormat = format;
* @param input The source from which to read. }
* @param length The maximum length of the read.
* @param allowEndOfInput True if encountering the end of the input having appended no data is @Override
* allowed, and should result in {@link C#RESULT_END_OF_INPUT} being returned. False if it public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
* 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, boolean allowEndOfInput)
throws IOException, InterruptedException { throws IOException, InterruptedException {
length = prepareForAppend(length); length = prepareForAppend(length);
int bytesAppended = input.read(lastAllocation.data, int bytesAppended = input.read(lastAllocation.data,
...@@ -372,13 +377,8 @@ import java.util.concurrent.LinkedBlockingDeque; ...@@ -372,13 +377,8 @@ import java.util.concurrent.LinkedBlockingDeque;
return bytesAppended; return bytesAppended;
} }
/** @Override
* Appends data to the rolling buffer. public void sampleData(ParsableByteArray buffer, int length) {
*
* @param buffer A buffer containing the data to append.
* @param length The length of the data to append.
*/
public void appendData(ParsableByteArray buffer, int length) {
while (length > 0) { while (length > 0) {
int thisAppendLength = prepareForAppend(length); int thisAppendLength = prepareForAppend(length);
buffer.readBytes(lastAllocation.data, lastAllocation.translateOffset(lastAllocationOffset), buffer.readBytes(lastAllocation.data, lastAllocation.translateOffset(lastAllocationOffset),
...@@ -389,19 +389,8 @@ import java.util.concurrent.LinkedBlockingDeque; ...@@ -389,19 +389,8 @@ import java.util.concurrent.LinkedBlockingDeque;
} }
} }
/** @Override
* Indicates the end point for the current sample, making it available for consumption. public void sampleMetadata(long sampleTimeUs, int flags, int size, int offset,
*
* @param sampleTimeUs The sample timestamp.
* @param flags Flags that accompany the sample. See {@code C.BUFFER_FLAG_*}.
* @param size The size of the sample, in bytes.
* @param offset The number of bytes that have been passed to
* {@link #appendData(ExtractorInput, int, boolean)} or
* {@link #appendData(ParsableByteArray, int)} since the last byte belonging to the sample
* being committed.
* @param encryptionKey The encryption key associated with the sample, or null.
*/
public void commitSample(long sampleTimeUs, int flags, int size, int offset,
byte[] encryptionKey) { byte[] encryptionKey) {
long absoluteOffset = totalBytesWritten - size - offset; long absoluteOffset = totalBytesWritten - size - offset;
infoQueue.commitSample(sampleTimeUs, flags, absoluteOffset, size, encryptionKey); infoQueue.commitSample(sampleTimeUs, flags, absoluteOffset, size, encryptionKey);
......
...@@ -81,7 +81,7 @@ public final class HlsExtractorWrapper implements ExtractorOutput { ...@@ -81,7 +81,7 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
public boolean isPrepared() { public boolean isPrepared() {
if (!prepared && tracksBuilt) { if (!prepared && tracksBuilt) {
for (int i = 0; i < sampleQueues.size(); i++) { for (int i = 0; i < sampleQueues.size(); i++) {
if (!sampleQueues.valueAt(i).hasFormat()) { if (sampleQueues.valueAt(i).getFormat() == null) {
return false; return false;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment