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
This commit is contained in:
olly 2016-04-18 07:58:28 -07:00 committed by Oliver Woodman
parent 4161dc8d62
commit 17d7a0cb4b
7 changed files with 36 additions and 73 deletions

View file

@ -37,9 +37,8 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe
private final ChunkExtractorWrapper extractorWrapper;
private final long sampleOffsetUs;
private Format sampleFormat;
private DrmInitData drmInitData;
private volatile DrmInitData drmInitData;
private volatile Format sampleFormat;
private volatile int bytesLoaded;
private volatile boolean loadCanceled;

View file

@ -68,15 +68,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad
return bytesLoaded;
}
/**
* 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.
* <p>
@ -86,15 +77,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad
return sampleFormat;
}
/**
* 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.
* <p>

View file

@ -289,8 +289,9 @@ public class DashChunkSource implements ChunkSource {
InitializationChunk initializationChunk = (InitializationChunk) chunk;
RepresentationHolder representationHolder =
representationHolders[getTrackIndex(initializationChunk.format)];
if (initializationChunk.hasSampleFormat()) {
representationHolder.sampleFormat = initializationChunk.getSampleFormat();
Format sampleFormat = initializationChunk.getSampleFormat();
if (sampleFormat != null) {
representationHolder.sampleFormat = sampleFormat;
}
// 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
@ -302,7 +303,7 @@ public class DashChunkSource implements ChunkSource {
}
// 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.
if (drmInitData == null && initializationChunk.hasDrmInitData()) {
if (drmInitData == null) {
drmInitData = initializationChunk.getDrmInitData();
}
}

View file

@ -41,7 +41,6 @@ public class DefaultTrackOutput implements TrackOutput {
// Accessed by both the loading and consuming threads.
private volatile long largestParsedTimestampUs;
private volatile Format format;
/**
* @param allocator An {@link Allocator} from which allocations for sample data can be obtained.
@ -95,18 +94,11 @@ public class DefaultTrackOutput implements TrackOutput {
return rollingBuffer.getReadIndex();
}
/**
* 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.
*/
public Format getFormat() {
return format;
return rollingBuffer.getUpstreamFormat();
}
/**
@ -234,25 +226,25 @@ public class DefaultTrackOutput implements TrackOutput {
@Override
public void format(Format format) {
this.format = format;
rollingBuffer.format(format);
}
@Override
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
return rollingBuffer.appendData(input, length, allowEndOfInput);
return rollingBuffer.sampleData(input, length, allowEndOfInput);
}
@Override
public void sampleData(ParsableByteArray buffer, int length) {
rollingBuffer.appendData(buffer, length);
rollingBuffer.sampleData(buffer, length);
}
@Override
public void sampleMetadata(long timeUs, int flags, int size, int offset, byte[] encryptionKey) {
timeUs += sampleOffsetUs;
largestParsedTimestampUs = Math.max(largestParsedTimestampUs, timeUs);
rollingBuffer.commitSample(timeUs, flags, size, offset, encryptionKey);
rollingBuffer.sampleMetadata(timeUs, flags, size, offset, encryptionKey);
}
}

View file

@ -640,7 +640,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
private boolean haveFormatsForAllTracks() {
for (int i = 0; i < sampleQueues.size(); i++) {
if (!sampleQueues.valueAt(i).hasFormat()) {
if (sampleQueues.valueAt(i).getFormat() == null) {
return false;
}
}

View file

@ -17,6 +17,7 @@ package com.google.android.exoplayer.extractor;
import com.google.android.exoplayer.C;
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.Allocator;
import com.google.android.exoplayer.util.Assertions;
@ -30,7 +31,7 @@ import java.util.concurrent.LinkedBlockingDeque;
/**
* 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;
@ -50,6 +51,9 @@ import java.util.concurrent.LinkedBlockingDeque;
private Allocation lastAllocation;
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.
*/
@ -131,6 +135,13 @@ import java.util.concurrent.LinkedBlockingDeque;
return infoQueue.getReadIndex();
}
/**
* 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.
* <p>
@ -344,19 +355,13 @@ import java.util.concurrent.LinkedBlockingDeque;
// Called by the loading thread.
/**
* Appends data to the rolling buffer.
*
* @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
* 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, boolean allowEndOfInput)
@Override
public void format(Format format) {
upstreamFormat = format;
}
@Override
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
length = prepareForAppend(length);
int bytesAppended = input.read(lastAllocation.data,
@ -372,13 +377,8 @@ import java.util.concurrent.LinkedBlockingDeque;
return bytesAppended;
}
/**
* Appends data to the rolling buffer.
*
* @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) {
@Override
public void sampleData(ParsableByteArray buffer, int length) {
while (length > 0) {
int thisAppendLength = prepareForAppend(length);
buffer.readBytes(lastAllocation.data, lastAllocation.translateOffset(lastAllocationOffset),
@ -389,19 +389,8 @@ import java.util.concurrent.LinkedBlockingDeque;
}
}
/**
* Indicates the end point for the current sample, making it available for consumption.
*
* @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,
@Override
public void sampleMetadata(long sampleTimeUs, int flags, int size, int offset,
byte[] encryptionKey) {
long absoluteOffset = totalBytesWritten - size - offset;
infoQueue.commitSample(sampleTimeUs, flags, absoluteOffset, size, encryptionKey);

View file

@ -81,7 +81,7 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
public boolean isPrepared() {
if (!prepared && tracksBuilt) {
for (int i = 0; i < sampleQueues.size(); i++) {
if (!sampleQueues.valueAt(i).hasFormat()) {
if (sampleQueues.valueAt(i).getFormat() == null) {
return false;
}
}