Skip to content

Commit

Permalink
Simplify chunk package ahead of EMSG/608 piping
Browse files Browse the repository at this point in the history
Issue: #2362
Issue: #2176

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=146243681
  • Loading branch information
ojw28 committed Feb 15, 2017
1 parent 025a67c commit ee3c5f8
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.util.MimeTypes;
import java.util.Arrays;
import java.util.HashMap;
import org.mockito.Mock;
Expand Down Expand Up @@ -217,7 +218,11 @@ private static AdaptationSet newAdaptationSets(Representation... representations
}

private static Representation newRepresentations(DrmInitData drmInitData) {
Format format = Format.createVideoSampleFormat("", "", "", 0, 0, 0, 0, 0, null, drmInitData);
Format format = Format.createVideoContainerFormat("id", MimeTypes.VIDEO_MP4,
MimeTypes.VIDEO_H264, "", Format.NO_VALUE, 1024, 768, Format.NO_VALUE, null, 0);
if (drmInitData != null) {
format = format.copyWithDrmInitData(drmInitData);
}
return Representation.newInstance("", 0, format, "", new SingleSegmentBase());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,13 @@ public byte[] download(HttpDataSource dataSource, DashManifest dashManifest)
Representation representation = adaptationSet.representations.get(0);
DrmInitData drmInitData = representation.format.drmInitData;
if (drmInitData == null) {
InitializationChunk initializationChunk = loadInitializationChunk(dataSource, representation);
ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(representation.format);
InitializationChunk initializationChunk = loadInitializationChunk(dataSource, representation,
extractorWrapper);
if (initializationChunk == null) {
return null;
}
Format sampleFormat = initializationChunk.getSampleFormat();
Format sampleFormat = extractorWrapper.getSampleFormat();
if (sampleFormat != null) {
drmInitData = sampleFormat.drmInitData;
}
Expand Down Expand Up @@ -288,8 +290,9 @@ private DrmSession<T> openBlockingKeyRequest(@Mode int licenseMode, byte[] offli
return session;
}

private static InitializationChunk loadInitializationChunk(final DataSource dataSource,
final Representation representation) throws IOException, InterruptedException {
private static InitializationChunk loadInitializationChunk(DataSource dataSource,
Representation representation, ChunkExtractorWrapper extractorWrapper)
throws IOException, InterruptedException {
RangedUri rangedUri = representation.getInitializationUri();
if (rangedUri == null) {
return null;
Expand All @@ -298,7 +301,7 @@ private static InitializationChunk loadInitializationChunk(final DataSource data
rangedUri.length, representation.getCacheKey());
InitializationChunk initializationChunk = new InitializationChunk(dataSource, dataSpec,
representation.format, C.SELECTION_REASON_UNKNOWN, null /* trackSelectionData */,
newWrappedExtractor(representation.format));
extractorWrapper);
initializationChunk.load();
return initializationChunk;
}
Expand All @@ -308,8 +311,7 @@ private static ChunkExtractorWrapper newWrappedExtractor(final Format format) {
final boolean isWebm = mimeType.startsWith(MimeTypes.VIDEO_WEBM)
|| mimeType.startsWith(MimeTypes.AUDIO_WEBM);
final Extractor extractor = isWebm ? new MatroskaExtractor() : new FragmentedMp4Extractor();
return new ChunkExtractorWrapper(extractor, format, false /* preferManifestDrmInitData */,
false /* resendFormatOnInit */);
return new ChunkExtractorWrapper(extractor, format, false /* preferManifestDrmInitData */);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public interface UpstreamFormatChangedListener {
private Format downstreamFormat;

// Accessed only by the loading thread (or the consuming thread when there is no loading thread).
private boolean pendingFormatAdjustment;
private Format lastUnadjustedFormat;
private long sampleOffsetUs;
private long totalBytesWritten;
private Allocation lastAllocation;
Expand Down Expand Up @@ -445,23 +447,24 @@ public void setUpstreamFormatChangeListener(UpstreamFormatChangedListener listen
}

/**
* Like {@link #format(Format)}, but with an offset that will be added to the timestamps of
* samples subsequently queued to the buffer. The offset is also used to adjust
* {@link Format#subsampleOffsetUs} for both the {@link Format} passed and those subsequently
* passed to {@link #format(Format)}.
* Sets an offset that will be added to the timestamps (and sub-sample timestamps) of samples
* subsequently queued to the buffer.
*
* @param format The format.
* @param sampleOffsetUs The timestamp offset in microseconds.
*/
public void formatWithOffset(Format format, long sampleOffsetUs) {
this.sampleOffsetUs = sampleOffsetUs;
format(format);
public void setSampleOffsetUs(long sampleOffsetUs) {
if (this.sampleOffsetUs != sampleOffsetUs) {
this.sampleOffsetUs = sampleOffsetUs;
pendingFormatAdjustment = true;
}
}

@Override
public void format(Format format) {
Format adjustedFormat = getAdjustedSampleFormat(format, sampleOffsetUs);
boolean formatChanged = infoQueue.format(adjustedFormat);
lastUnadjustedFormat = format;
pendingFormatAdjustment = false;
if (upstreamFormatChangeListener != null && formatChanged) {
upstreamFormatChangeListener.onUpstreamFormatChanged(adjustedFormat);
}
Expand Down Expand Up @@ -518,6 +521,9 @@ public void sampleData(ParsableByteArray buffer, int length) {
@Override
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
byte[] encryptionKey) {
if (pendingFormatAdjustment) {
format(lastUnadjustedFormat);
}
if (!startWriteOperation()) {
infoQueue.commitSampleTimestamp(timeUs);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,19 @@
/**
* An {@link Extractor} wrapper for loading chunks containing a single track.
* <p>
* The wrapper allows switching of the {@link SeekMapOutput} and {@link TrackOutput} that receive
* parsed data.
* The wrapper allows switching of the {@link TrackOutput} that receives parsed data.
*/
public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput {

/**
* Receives {@link SeekMap}s extracted by the wrapped {@link Extractor}.
*/
public interface SeekMapOutput {

/**
* @see ExtractorOutput#seekMap(SeekMap)
*/
void seekMap(SeekMap seekMap);

}

public final Extractor extractor;

private final Format manifestFormat;
private final boolean preferManifestDrmInitData;
private final boolean resendFormatOnInit;

private boolean extractorInitialized;
private SeekMapOutput seekMapOutput;
private TrackOutput trackOutput;
private Format sentFormat;
private SeekMap seekMap;
private Format sampleFormat;

// Accessed only on the loader thread.
private boolean seenTrack;
Expand All @@ -68,34 +54,43 @@ public interface SeekMapOutput {
* sample {@link Format} output from the {@link Extractor}.
* @param preferManifestDrmInitData Whether {@link DrmInitData} defined in {@code manifestFormat}
* should be preferred when the sample and manifest {@link Format}s are merged.
* @param resendFormatOnInit Whether the extractor should resend the previous {@link Format} when
* it is initialized via {@link #init(SeekMapOutput, TrackOutput)}.
*/
public ChunkExtractorWrapper(Extractor extractor, Format manifestFormat,
boolean preferManifestDrmInitData, boolean resendFormatOnInit) {
boolean preferManifestDrmInitData) {
this.extractor = extractor;
this.manifestFormat = manifestFormat;
this.preferManifestDrmInitData = preferManifestDrmInitData;
this.resendFormatOnInit = resendFormatOnInit;
}

/**
* Initializes the extractor to output to the provided {@link SeekMapOutput} and
* {@link TrackOutput} instances, and configures it to receive data from a new chunk.
* Returns the {@link SeekMap} most recently output by the extractor, or null.
*/
public SeekMap getSeekMap() {
return seekMap;
}

/**
* Returns the sample {@link Format} most recently output by the extractor, or null.
*/
public Format getSampleFormat() {
return sampleFormat;
}

/**
* Initializes the extractor to output to the provided {@link TrackOutput}, and configures it to
* receive data from a new chunk.
*
* @param seekMapOutput The {@link SeekMapOutput} that will receive extracted {@link SeekMap}s.
* @param trackOutput The {@link TrackOutput} that will receive sample data.
*/
public void init(SeekMapOutput seekMapOutput, TrackOutput trackOutput) {
this.seekMapOutput = seekMapOutput;
public void init(TrackOutput trackOutput) {
this.trackOutput = trackOutput;
if (!extractorInitialized) {
extractor.init(this);
extractorInitialized = true;
} else {
extractor.seek(0, 0);
if (resendFormatOnInit && sentFormat != null) {
trackOutput.format(sentFormat);
if (sampleFormat != null) {
trackOutput.format(sampleFormat);
}
}
}
Expand All @@ -117,15 +112,17 @@ public void endTracks() {

@Override
public void seekMap(SeekMap seekMap) {
seekMapOutput.seekMap(seekMap);
this.seekMap = seekMap;
}

// TrackOutput implementation.

@Override
public void format(Format format) {
sentFormat = format.copyWithManifestFormatInfo(manifestFormat, preferManifestDrmInitData);
trackOutput.format(sentFormat);
sampleFormat = format.copyWithManifestFormatInfo(manifestFormat, preferManifestDrmInitData);
if (trackOutput != null) {
trackOutput.format(sampleFormat);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
import com.google.android.exoplayer2.extractor.DefaultTrackOutput;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.SeekMapOutput;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
Expand All @@ -31,12 +29,11 @@
/**
* A {@link BaseMediaChunk} that uses an {@link Extractor} to decode sample data.
*/
public class ContainerMediaChunk extends BaseMediaChunk implements SeekMapOutput {
public class ContainerMediaChunk extends BaseMediaChunk {

private final int chunkCount;
private final long sampleOffsetUs;
private final ChunkExtractorWrapper extractorWrapper;
private final Format sampleFormat;

private volatile int bytesLoaded;
private volatile boolean loadCanceled;
Expand All @@ -56,19 +53,15 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SeekMapOutput
* underlying media are being merged into a single load.
* @param sampleOffsetUs An offset to add to the sample timestamps parsed by the extractor.
* @param extractorWrapper A wrapped extractor to use for parsing the data.
* @param sampleFormat The {@link Format} of the samples in the chunk, if known. May be null if
* the data is known to define its own sample format.
*/
public ContainerMediaChunk(DataSource dataSource, DataSpec dataSpec, Format trackFormat,
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs,
int chunkIndex, int chunkCount, long sampleOffsetUs, ChunkExtractorWrapper extractorWrapper,
Format sampleFormat) {
int chunkIndex, int chunkCount, long sampleOffsetUs, ChunkExtractorWrapper extractorWrapper) {
super(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs,
endTimeUs, chunkIndex);
this.chunkCount = chunkCount;
this.sampleOffsetUs = sampleOffsetUs;
this.extractorWrapper = extractorWrapper;
this.sampleFormat = sampleFormat;
}

@Override
Expand All @@ -86,13 +79,6 @@ public final long bytesLoaded() {
return bytesLoaded;
}

// SeekMapOutput implementation.

@Override
public final void seekMap(SeekMap seekMap) {
// Do nothing.
}

// Loadable implementation.

@Override
Expand All @@ -116,8 +102,8 @@ public final void load() throws IOException, InterruptedException {
if (bytesLoaded == 0) {
// Set the target to ourselves.
DefaultTrackOutput trackOutput = getTrackOutput();
trackOutput.formatWithOffset(sampleFormat, sampleOffsetUs);
extractorWrapper.init(this, trackOutput);
trackOutput.setSampleOffsetUs(sampleOffsetUs);
extractorWrapper.init(trackOutput);
}
// Load and decode the sample data.
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,19 @@
import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.SeekMapOutput;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;

/**
* A {@link Chunk} that uses an {@link Extractor} to decode initialization data for single track.
*/
public final class InitializationChunk extends Chunk implements SeekMapOutput,
TrackOutput {
public final class InitializationChunk extends Chunk {

private final ChunkExtractorWrapper extractorWrapper;

// Initialization results. Set by the loader thread and read by any thread that knows loading
// has completed. These variables do not need to be volatile, since a memory barrier must occur
// for the reading thread to know that loading has completed.
private Format sampleFormat;
private SeekMap seekMap;

private volatile int bytesLoaded;
private volatile boolean loadCanceled;

Expand All @@ -68,55 +57,6 @@ public long bytesLoaded() {
return bytesLoaded;
}

/**
* Returns a {@link Format} parsed from the chunk, or null.
* <p>
* Should be called after loading has completed.
*/
public Format getSampleFormat() {
return sampleFormat;
}

/**
* Returns a {@link SeekMap} parsed from the chunk, or null.
* <p>
* Should be called after loading has completed.
*/
public SeekMap getSeekMap() {
return seekMap;
}

// SeekMapOutput implementation.

@Override
public void seekMap(SeekMap seekMap) {
this.seekMap = seekMap;
}

// TrackOutput implementation.

@Override
public void format(Format format) {
this.sampleFormat = format;
}

@Override
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
throw new IllegalStateException("Unexpected sample data in initialization chunk");
}

@Override
public void sampleData(ParsableByteArray data, int length) {
throw new IllegalStateException("Unexpected sample data in initialization chunk");
}

@Override
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
byte[] encryptionKey) {
throw new IllegalStateException("Unexpected sample data in initialization chunk");
}

// Loadable implementation.

@Override
Expand All @@ -138,8 +78,7 @@ public void load() throws IOException, InterruptedException {
ExtractorInput input = new DefaultExtractorInput(dataSource,
loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
if (bytesLoaded == 0) {
// Set the target to ourselves.
extractorWrapper.init(this, this);
extractorWrapper.init(null);
}
// Load and decode the initialization data.
try {
Expand Down
Loading

0 comments on commit ee3c5f8

Please sign in to comment.