mirror of
https://github.com/samsonjs/media.git
synced 2026-03-28 09:55:48 +00:00
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:
parent
4161dc8d62
commit
17d7a0cb4b
7 changed files with 36 additions and 73 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue