diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java index 97e9a75686..4fe30582fb 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java @@ -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 diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java index 8b05b27046..ff04314e2e 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java @@ -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 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 fakeSampleStreamItems, + int timeUsIncrement) { this.format = format; this.eventDispatcher = eventDispatcher; - this.sampleData = sampleData; + this.fakeSampleStreamItems = new ArrayDeque<>(fakeSampleStreamItems); + this.timeUsIncrement = timeUsIncrement; } @Override @@ -75,29 +130,34 @@ 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; - buffer.ensureSpaceForWrite(sampleData.length); - buffer.data.put(sampleData); - readSample = true; - return C.RESULT_BUFFER_READ; - } else { - buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); - return C.RESULT_BUFFER_READ; } + 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); + 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 @@ -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); + } + } }