mirror of
https://github.com/androidx/media.git
synced 2025-05-08 08:00:49 +08:00
Remove layer of indirection when piping sample data.
For DASH + SS, sample data is currently plumbed through: Extractor ->ChunkExtractorWrapper ->ContainerMediaChunk ->DefaultTrackOutput ->RollingSampleNBuffer This change bypasses the ContainerMediaChunk layer. It should be possible to completely delete DefaultTrackOutput in the future, but such a change may well be tied to changes in HLS format splicing + how we buffer (or don't buffer) disabled tracks. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=119853857
This commit is contained in:
parent
628a209b9b
commit
28e926602f
@ -35,7 +35,7 @@ public abstract class BaseMediaChunk extends MediaChunk {
|
||||
*/
|
||||
public final boolean isSampleFormatFinal;
|
||||
|
||||
private DefaultTrackOutput output;
|
||||
private DefaultTrackOutput trackOutput;
|
||||
private int firstSampleIndex;
|
||||
|
||||
/**
|
||||
@ -61,11 +61,11 @@ public abstract class BaseMediaChunk extends MediaChunk {
|
||||
* Initializes the chunk for loading, setting the {@link DefaultTrackOutput} that will receive
|
||||
* samples as they are loaded.
|
||||
*
|
||||
* @param output The output that will receive the loaded samples.
|
||||
* @param trackOutput The output that will receive the loaded samples.
|
||||
*/
|
||||
public void init(DefaultTrackOutput output) {
|
||||
this.output = output;
|
||||
this.firstSampleIndex = output.getWriteIndex();
|
||||
public void init(DefaultTrackOutput trackOutput) {
|
||||
this.trackOutput = trackOutput;
|
||||
this.firstSampleIndex = trackOutput.getWriteIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,10 +97,10 @@ public abstract class BaseMediaChunk extends MediaChunk {
|
||||
public abstract DrmInitData getDrmInitData();
|
||||
|
||||
/**
|
||||
* Returns the output most recently passed to {@link #init(DefaultTrackOutput)}.
|
||||
* Returns the track output most recently passed to {@link #init(DefaultTrackOutput)}.
|
||||
*/
|
||||
protected final DefaultTrackOutput getOutput() {
|
||||
return output;
|
||||
protected final DefaultTrackOutput getTrackOutput() {
|
||||
return trackOutput;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,14 +30,15 @@ import java.io.IOException;
|
||||
/**
|
||||
* An {@link Extractor} wrapper for loading chunks containing a single track.
|
||||
* <p>
|
||||
* The wrapper allows switching of the {@link SingleTrackOutput} that receives parsed data.
|
||||
* The wrapper allows switching of the {@link SingleTrackMetadataOutput} and {@link TrackOutput}
|
||||
* which receive parsed data.
|
||||
*/
|
||||
public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput {
|
||||
|
||||
/**
|
||||
* Receives stream level data extracted by the wrapped {@link Extractor}.
|
||||
* Receives metadata associated with the track as extracted by the wrapped {@link Extractor}.
|
||||
*/
|
||||
public interface SingleTrackOutput extends TrackOutput {
|
||||
public interface SingleTrackMetadataOutput {
|
||||
|
||||
/**
|
||||
* @see ExtractorOutput#seekMap(SeekMap)
|
||||
@ -49,11 +50,17 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
|
||||
*/
|
||||
void drmInitData(DrmInitData drmInitData);
|
||||
|
||||
/**
|
||||
* @see TrackOutput#format(Format)
|
||||
*/
|
||||
void format(Format format);
|
||||
|
||||
}
|
||||
|
||||
private final Extractor extractor;
|
||||
private boolean extractorInitialized;
|
||||
private SingleTrackOutput output;
|
||||
private SingleTrackMetadataOutput metadataOutput;
|
||||
private TrackOutput trackOutput;
|
||||
|
||||
// Accessed only on the loader thread.
|
||||
private boolean seenTrack;
|
||||
@ -66,13 +73,15 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the extractor to output to the provided {@link SingleTrackOutput}, and configures
|
||||
* it to receive data from a new chunk.
|
||||
* Initializes the extractor to output to the provided {@link SingleTrackMetadataOutput} and
|
||||
* {@link TrackOutput} instances, and configures it to receive data from a new chunk.
|
||||
*
|
||||
* @param output The {@link SingleTrackOutput} that will receive the parsed data.
|
||||
* @param metadataOutput The {@link SingleTrackMetadataOutput} that will receive metadata.
|
||||
* @param trackOutput The {@link TrackOutput} that will receive sample data.
|
||||
*/
|
||||
public void init(SingleTrackOutput output) {
|
||||
this.output = output;
|
||||
public void init(SingleTrackMetadataOutput metadataOutput, TrackOutput trackOutput) {
|
||||
this.metadataOutput = metadataOutput;
|
||||
this.trackOutput = trackOutput;
|
||||
if (!extractorInitialized) {
|
||||
extractor.init(this);
|
||||
extractorInitialized = true;
|
||||
@ -111,35 +120,36 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
|
||||
|
||||
@Override
|
||||
public void seekMap(SeekMap seekMap) {
|
||||
output.seekMap(seekMap);
|
||||
metadataOutput.seekMap(seekMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drmInitData(DrmInitData drmInitData) {
|
||||
output.drmInitData(drmInitData);
|
||||
metadataOutput.drmInitData(drmInitData);
|
||||
}
|
||||
|
||||
// TrackOutput implementation.
|
||||
|
||||
@Override
|
||||
public void format(Format format) {
|
||||
output.format(format);
|
||||
// Redirect the format to the metadata output. The track output doesn't need it.
|
||||
metadataOutput.format(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
|
||||
throws IOException, InterruptedException {
|
||||
return output.sampleData(input, length, allowEndOfInput);
|
||||
return trackOutput.sampleData(input, length, allowEndOfInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sampleData(ParsableByteArray data, int length) {
|
||||
output.sampleData(data, length);
|
||||
trackOutput.sampleData(data, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sampleMetadata(long timeUs, int flags, int size, int offset, byte[] encryptionKey) {
|
||||
output.sampleMetadata(timeUs, flags, size, offset, encryptionKey);
|
||||
trackOutput.sampleMetadata(timeUs, flags, size, offset, encryptionKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,15 +16,15 @@
|
||||
package com.google.android.exoplayer.chunk;
|
||||
|
||||
import com.google.android.exoplayer.Format;
|
||||
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackOutput;
|
||||
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackMetadataOutput;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.extractor.DefaultExtractorInput;
|
||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
||||
import com.google.android.exoplayer.extractor.Extractor;
|
||||
import com.google.android.exoplayer.extractor.ExtractorInput;
|
||||
import com.google.android.exoplayer.extractor.SeekMap;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -32,7 +32,7 @@ import java.io.IOException;
|
||||
/**
|
||||
* A {@link BaseMediaChunk} that uses an {@link Extractor} to parse sample data.
|
||||
*/
|
||||
public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOutput {
|
||||
public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMetadataOutput {
|
||||
|
||||
private final ChunkExtractorWrapper extractorWrapper;
|
||||
private final long sampleOffsetUs;
|
||||
@ -88,7 +88,7 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
|
||||
return drmInitData;
|
||||
}
|
||||
|
||||
// SingleTrackOutput implementation.
|
||||
// SingleTrackMetadataOutput implementation.
|
||||
|
||||
@Override
|
||||
public final void seekMap(SeekMap seekMap) {
|
||||
@ -105,23 +105,6 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
|
||||
this.sampleFormat = getAdjustedSampleFormat(format, sampleOffsetUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
|
||||
throws IOException, InterruptedException {
|
||||
return getOutput().sampleData(input, length, allowEndOfInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void sampleData(ParsableByteArray data, int length) {
|
||||
getOutput().sampleData(data, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void sampleMetadata(long timeUs, int flags, int size, int offset,
|
||||
byte[] encryptionKey) {
|
||||
getOutput().sampleMetadata(timeUs + sampleOffsetUs, flags, size, offset, encryptionKey);
|
||||
}
|
||||
|
||||
// Loadable implementation.
|
||||
|
||||
@Override
|
||||
@ -144,7 +127,9 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
|
||||
loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
|
||||
if (bytesLoaded == 0) {
|
||||
// Set the target to ourselves.
|
||||
extractorWrapper.init(this);
|
||||
DefaultTrackOutput trackOutput = getTrackOutput();
|
||||
trackOutput.setSampleOffsetUs(sampleOffsetUs);
|
||||
extractorWrapper.init(this, trackOutput);
|
||||
}
|
||||
// Load and parse the initialization data.
|
||||
try {
|
||||
|
@ -16,12 +16,13 @@
|
||||
package com.google.android.exoplayer.chunk;
|
||||
|
||||
import com.google.android.exoplayer.Format;
|
||||
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackOutput;
|
||||
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackMetadataOutput;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.extractor.DefaultExtractorInput;
|
||||
import com.google.android.exoplayer.extractor.Extractor;
|
||||
import com.google.android.exoplayer.extractor.ExtractorInput;
|
||||
import com.google.android.exoplayer.extractor.SeekMap;
|
||||
import com.google.android.exoplayer.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||
@ -32,7 +33,8 @@ import java.io.IOException;
|
||||
/**
|
||||
* A {@link Chunk} that uses an {@link Extractor} to parse initialization data for single track.
|
||||
*/
|
||||
public final class InitializationChunk extends Chunk implements SingleTrackOutput {
|
||||
public final class InitializationChunk extends Chunk implements SingleTrackMetadataOutput,
|
||||
TrackOutput {
|
||||
|
||||
private final ChunkExtractorWrapper extractorWrapper;
|
||||
|
||||
@ -120,7 +122,7 @@ public final class InitializationChunk extends Chunk implements SingleTrackOutpu
|
||||
return seekMap;
|
||||
}
|
||||
|
||||
// SingleTrackOutput implementation.
|
||||
// SingleTrackMetadataOutput implementation.
|
||||
|
||||
@Override
|
||||
public void seekMap(SeekMap seekMap) {
|
||||
@ -137,6 +139,8 @@ public final class InitializationChunk extends Chunk implements SingleTrackOutpu
|
||||
this.sampleFormat = format;
|
||||
}
|
||||
|
||||
// TrackOutput implementation.
|
||||
|
||||
@Override
|
||||
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
|
||||
throws IOException, InterruptedException {
|
||||
@ -175,7 +179,7 @@ public final class InitializationChunk extends Chunk implements SingleTrackOutpu
|
||||
loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
|
||||
if (bytesLoaded == 0) {
|
||||
// Set the target to ourselves.
|
||||
extractorWrapper.init(this);
|
||||
extractorWrapper.init(this, this);
|
||||
}
|
||||
// Load and parse the initialization data.
|
||||
try {
|
||||
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.Format;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.extractor.DefaultExtractorInput;
|
||||
import com.google.android.exoplayer.extractor.ExtractorInput;
|
||||
import com.google.android.exoplayer.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
@ -95,14 +96,15 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
|
||||
length += bytesLoaded;
|
||||
}
|
||||
ExtractorInput extractorInput = new DefaultExtractorInput(dataSource, bytesLoaded, length);
|
||||
TrackOutput trackOutput = getTrackOutput();
|
||||
// Load the sample data.
|
||||
int result = 0;
|
||||
while (result != C.RESULT_END_OF_INPUT) {
|
||||
bytesLoaded += result;
|
||||
result = getOutput().sampleData(extractorInput, Integer.MAX_VALUE, true);
|
||||
result = trackOutput.sampleData(extractorInput, Integer.MAX_VALUE, true);
|
||||
}
|
||||
int sampleSize = bytesLoaded;
|
||||
getOutput().sampleMetadata(startTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||
trackOutput.sampleMetadata(startTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||
} finally {
|
||||
dataSource.close();
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ public class DefaultTrackOutput implements TrackOutput {
|
||||
private final RollingSampleBuffer rollingBuffer;
|
||||
private final DecoderInputBuffer sampleBuffer;
|
||||
|
||||
// Accessed only by the loading thread.
|
||||
private long sampleOffsetUs;
|
||||
|
||||
// Accessed only by the consuming thread.
|
||||
private boolean needKeyframe;
|
||||
private long lastReadTimeUs;
|
||||
@ -222,6 +225,18 @@ public class DefaultTrackOutput implements TrackOutput {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called by the loading thread.
|
||||
|
||||
/**
|
||||
* Sets an offset that will be added to the timestamps passed to
|
||||
* {@link #sampleMetadata(long, int, int, int, byte[])}.
|
||||
*
|
||||
* @param sampleOffsetUs The offset in microseconds.
|
||||
*/
|
||||
public void setSampleOffsetUs(long sampleOffsetUs) {
|
||||
this.sampleOffsetUs = sampleOffsetUs;
|
||||
}
|
||||
|
||||
// TrackOutput implementation. Called by the loading thread.
|
||||
|
||||
@Override
|
||||
@ -242,6 +257,7 @@ public class DefaultTrackOutput implements TrackOutput {
|
||||
|
||||
@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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user