Improve customisability of FakeSampleStream.

PiperOrigin-RevId: 289829592
This commit is contained in:
samrobinson 2020-01-15 11:44:31 +00:00 committed by Oliver Woodman
parent a225e887fa
commit 96c648c2d6
2 changed files with 112 additions and 35 deletions

View File

@ -27,10 +27,12 @@ import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.metadata.scte35.TimeSignalCommand;
import com.google.android.exoplayer2.testutil.FakeSampleStream;
import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
@ -141,7 +143,11 @@ public class MetadataRendererTest {
MetadataRenderer renderer = new MetadataRenderer(metadata::add, /* outputLooper= */ null);
renderer.replaceStream(
new Format[] {EMSG_FORMAT},
new FakeSampleStream(EMSG_FORMAT, /* eventDispatcher= */ null, input),
new FakeSampleStream(
EMSG_FORMAT,
/* eventDispatcher= */ null,
Arrays.asList(new FakeSampleStreamItem(input)),
0),
/* offsetUs= */ 0L);
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the format
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the data

View File

@ -23,20 +23,64 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.SampleStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Fake {@link SampleStream} that outputs a given {@link Format}, an optional sample containing a
* single zero byte, then end of stream.
* Fake {@link SampleStream} that outputs a given {@link Format}, any amount of {@link
* FakeSampleStreamItem items}, then end of stream.
*/
public final class FakeSampleStream implements SampleStream {
private final Format format;
@Nullable private final EventDispatcher eventDispatcher;
private final byte[] sampleData;
/** Item to customize a return value of {@link FakeSampleStream#readData}. */
public static final class FakeSampleStreamItem {
@Nullable Format format;
@Nullable byte[] sampleData;
int flags;
private boolean notifiedDownstreamFormat;
/**
* Item that, when {@link #readData(FormatHolder, DecoderInputBuffer, boolean)} is called, will
* return {@link C#RESULT_FORMAT_READ} with the new format.
*
* @param format The format to be returned.
*/
public FakeSampleStreamItem(Format format) {
this.format = format;
}
/**
* Item that, when {@link #readData(FormatHolder, DecoderInputBuffer, boolean)} is called, will
* return {@link C#RESULT_BUFFER_READ} with the sample data.
*
* @param sampleData The sample data to be read.
*/
public FakeSampleStreamItem(byte[] sampleData) {
this.sampleData = sampleData.clone();
}
/**
* Item that, when {@link #readData(FormatHolder, DecoderInputBuffer, boolean)} is called, will
* return {@link C#RESULT_BUFFER_READ} with the sample data.
*
* @param sampleData The sample data to be read.
* @param flags The buffer flags to be set.
*/
public FakeSampleStreamItem(byte[] sampleData, int flags) {
this.sampleData = sampleData.clone();
this.flags = flags;
}
}
private final ArrayDeque<FakeSampleStreamItem> fakeSampleStreamItems;
private final int timeUsIncrement;
@Nullable private final EventDispatcher eventDispatcher;
private Format format;
private int timeUs;
private boolean readFormat;
private boolean readSample;
/**
* Creates fake sample stream which outputs the given {@link Format}, optionally one sample with
@ -48,23 +92,34 @@ public final class FakeSampleStream implements SampleStream {
*/
public FakeSampleStream(
Format format, @Nullable EventDispatcher eventDispatcher, boolean shouldOutputSample) {
this(format, eventDispatcher, new byte[] {0});
readSample = !shouldOutputSample;
this(
format,
eventDispatcher,
shouldOutputSample
? Arrays.asList(new FakeSampleStreamItem(new byte[] {0}))
: Collections.emptyList(),
/* timeUsIncrement= */ 0);
}
/**
* Creates fake sample stream which outputs the given {@link Format}, one sample with the provided
* bytes, then end of stream.
* Creates a fake sample stream which outputs the given {@link Format}, any amount of {@link
* FakeSampleStreamItem items}, then end of stream.
*
* @param format The {@link Format} to output.
* @param eventDispatcher An {@link EventDispatcher} to notify of read events.
* @param sampleData The sample data to output.
* @param fakeSampleStreamItems The list of {@link FakeSampleStreamItem items} to customize the
* return values of {@link #readData(FormatHolder, DecoderInputBuffer, boolean)}.
* @param timeUsIncrement The time each sample should increase by, in microseconds.
*/
public FakeSampleStream(
Format format, @Nullable EventDispatcher eventDispatcher, byte[] sampleData) {
Format format,
@Nullable EventDispatcher eventDispatcher,
List<FakeSampleStreamItem> fakeSampleStreamItems,
int timeUsIncrement) {
this.format = format;
this.eventDispatcher = eventDispatcher;
this.sampleData = sampleData;
this.fakeSampleStreamItems = new ArrayDeque<>(fakeSampleStreamItems);
this.timeUsIncrement = timeUsIncrement;
}
@Override
@ -75,30 +130,35 @@ public final class FakeSampleStream implements SampleStream {
@Override
public int readData(
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) {
if (eventDispatcher != null && !notifiedDownstreamFormat) {
eventDispatcher.downstreamFormatChanged(
C.TRACK_TYPE_UNKNOWN,
format,
C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
/* mediaTimeUs= */ 0);
notifiedDownstreamFormat = true;
}
if (formatRequired || !readFormat) {
formatHolder.format = format;
if (!readFormat || formatRequired) {
readFormat = true;
formatHolder.format = format;
notifyEventDispatcher(formatHolder);
return C.RESULT_FORMAT_READ;
} else if (!readSample) {
buffer.timeUs = 0;
}
if (!fakeSampleStreamItems.isEmpty()) {
FakeSampleStreamItem fakeSampleStreamItem = fakeSampleStreamItems.remove();
if (fakeSampleStreamItem.format != null) {
format = fakeSampleStreamItem.format;
formatHolder.format = format;
notifyEventDispatcher(formatHolder);
return C.RESULT_FORMAT_READ;
}
if (fakeSampleStreamItem.sampleData != null) {
byte[] sampleData = fakeSampleStreamItem.sampleData;
buffer.timeUs = timeUs;
timeUs += timeUsIncrement;
buffer.ensureSpaceForWrite(sampleData.length);
buffer.data.put(sampleData);
readSample = true;
return C.RESULT_BUFFER_READ;
} else {
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
if (fakeSampleStreamItem.flags != 0) {
buffer.setFlags(fakeSampleStreamItem.flags);
}
return C.RESULT_BUFFER_READ;
}
}
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
return C.RESULT_BUFFER_READ;
}
@Override
public void maybeThrowError() throws IOException {
@ -109,4 +169,15 @@ public final class FakeSampleStream implements SampleStream {
public int skipData(long positionUs) {
return 0;
}
private void notifyEventDispatcher(FormatHolder formatHolder) {
if (eventDispatcher != null) {
eventDispatcher.downstreamFormatChanged(
C.TRACK_TYPE_UNKNOWN,
formatHolder.format,
C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
/* mediaTimeUs= */ timeUs);
}
}
}