mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Make FakeRenderer more realistic
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=183643457
This commit is contained in:
parent
91c52a4730
commit
67a812c1c2
5 changed files with 70 additions and 24 deletions
|
|
@ -379,10 +379,12 @@ public class DefaultMediaClockTest {
|
||||||
|
|
||||||
private static class MediaClockRenderer extends FakeMediaClockRenderer {
|
private static class MediaClockRenderer extends FakeMediaClockRenderer {
|
||||||
|
|
||||||
public long positionUs;
|
|
||||||
public PlaybackParameters playbackParameters;
|
|
||||||
|
|
||||||
private final boolean playbackParametersAreMutable;
|
private final boolean playbackParametersAreMutable;
|
||||||
|
private final boolean isReady;
|
||||||
|
private final boolean isEnded;
|
||||||
|
|
||||||
|
public PlaybackParameters playbackParameters;
|
||||||
|
public long positionUs;
|
||||||
|
|
||||||
public MediaClockRenderer() throws ExoPlaybackException {
|
public MediaClockRenderer() throws ExoPlaybackException {
|
||||||
this(PlaybackParameters.DEFAULT, false, true, false, false);
|
this(PlaybackParameters.DEFAULT, false, true, false, false);
|
||||||
|
|
@ -403,11 +405,11 @@ public class DefaultMediaClockTest {
|
||||||
boolean playbackParametersAreMutable, boolean isReady, boolean isEnded,
|
boolean playbackParametersAreMutable, boolean isReady, boolean isEnded,
|
||||||
boolean hasReadStreamToEnd)
|
boolean hasReadStreamToEnd)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
this.positionUs = TEST_POSITION_US;
|
|
||||||
this.playbackParameters = playbackParameters;
|
this.playbackParameters = playbackParameters;
|
||||||
this.playbackParametersAreMutable = playbackParametersAreMutable;
|
this.playbackParametersAreMutable = playbackParametersAreMutable;
|
||||||
this.isReady = isReady;
|
this.isReady = isReady;
|
||||||
this.isEnded = isEnded;
|
this.isEnded = isEnded;
|
||||||
|
this.positionUs = TEST_POSITION_US;
|
||||||
if (!hasReadStreamToEnd) {
|
if (!hasReadStreamToEnd) {
|
||||||
resetPosition(0);
|
resetPosition(0);
|
||||||
}
|
}
|
||||||
|
|
@ -436,6 +438,10 @@ public class DefaultMediaClockTest {
|
||||||
return isReady;
|
return isReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnded() {
|
||||||
|
return isEnded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ public final class ExoPlayerTest {
|
||||||
testRunner.assertNoPositionDiscontinuities();
|
testRunner.assertNoPositionDiscontinuities();
|
||||||
testRunner.assertTimelinesEqual(timeline);
|
testRunner.assertTimelinesEqual(timeline);
|
||||||
assertThat(renderer.formatReadCount).isEqualTo(0);
|
assertThat(renderer.formatReadCount).isEqualTo(0);
|
||||||
assertThat(renderer.bufferReadCount).isEqualTo(0);
|
assertThat(renderer.sampleBufferReadCount).isEqualTo(0);
|
||||||
assertThat(renderer.isEnded).isFalse();
|
assertThat(renderer.isEnded).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ public final class ExoPlayerTest {
|
||||||
testRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED);
|
testRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED);
|
||||||
testRunner.assertTrackGroupsEqual(new TrackGroupArray(new TrackGroup(Builder.VIDEO_FORMAT)));
|
testRunner.assertTrackGroupsEqual(new TrackGroupArray(new TrackGroup(Builder.VIDEO_FORMAT)));
|
||||||
assertThat(renderer.formatReadCount).isEqualTo(1);
|
assertThat(renderer.formatReadCount).isEqualTo(1);
|
||||||
assertThat(renderer.bufferReadCount).isEqualTo(1);
|
assertThat(renderer.sampleBufferReadCount).isEqualTo(1);
|
||||||
assertThat(renderer.isEnded).isTrue();
|
assertThat(renderer.isEnded).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ public final class ExoPlayerTest {
|
||||||
testRunner.assertTimelinesEqual(timeline);
|
testRunner.assertTimelinesEqual(timeline);
|
||||||
testRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED);
|
testRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED);
|
||||||
assertThat(renderer.formatReadCount).isEqualTo(3);
|
assertThat(renderer.formatReadCount).isEqualTo(3);
|
||||||
assertThat(renderer.bufferReadCount).isEqualTo(1);
|
assertThat(renderer.sampleBufferReadCount).isEqualTo(3);
|
||||||
assertThat(renderer.isEnded).isTrue();
|
assertThat(renderer.isEnded).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +155,7 @@ public final class ExoPlayerTest {
|
||||||
testRunner.assertTimelinesEqual(timeline);
|
testRunner.assertTimelinesEqual(timeline);
|
||||||
testRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED);
|
testRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED);
|
||||||
assertThat(renderer.formatReadCount).isEqualTo(100);
|
assertThat(renderer.formatReadCount).isEqualTo(100);
|
||||||
assertThat(renderer.bufferReadCount).isEqualTo(1);
|
assertThat(renderer.sampleBufferReadCount).isEqualTo(100);
|
||||||
assertThat(renderer.isEnded).isTrue();
|
assertThat(renderer.isEnded).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,13 @@ public class SimpleDecoderAudioRendererTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testImmediatelyReadEndOfStreamPlaysAudioSinkToEndOfStream() throws Exception {
|
public void testImmediatelyReadEndOfStreamPlaysAudioSinkToEndOfStream() throws Exception {
|
||||||
audioRenderer.enable(RendererConfiguration.DEFAULT, new Format[] {FORMAT},
|
audioRenderer.enable(
|
||||||
new FakeSampleStream(FORMAT), 0, false, 0);
|
RendererConfiguration.DEFAULT,
|
||||||
|
new Format[] {FORMAT},
|
||||||
|
new FakeSampleStream(FORMAT, false),
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
0);
|
||||||
audioRenderer.setCurrentStreamFinal();
|
audioRenderer.setCurrentStreamFinal();
|
||||||
when(mockAudioSink.isEnded()).thenReturn(true);
|
when(mockAudioSink.isEnded()).thenReturn(true);
|
||||||
while (!audioRenderer.isEnded()) {
|
while (!audioRenderer.isEnded()) {
|
||||||
|
|
@ -116,7 +121,7 @@ public class SimpleDecoderAudioRendererTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DecoderInputBuffer createInputBuffer() {
|
protected DecoderInputBuffer createInputBuffer() {
|
||||||
return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.FormatHolder;
|
import com.google.android.exoplayer2.FormatHolder;
|
||||||
import com.google.android.exoplayer2.Renderer;
|
import com.google.android.exoplayer2.Renderer;
|
||||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -35,51 +36,72 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class FakeRenderer extends BaseRenderer {
|
public class FakeRenderer extends BaseRenderer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of time ahead of the current playback position that the renderer reads from the
|
||||||
|
* source. A real renderer will typically read ahead by a small amount due to pipelining through
|
||||||
|
* decoders and the media output path.
|
||||||
|
*/
|
||||||
|
private static final long SOURCE_READAHEAD_US = 250000;
|
||||||
|
|
||||||
private final List<Format> expectedFormats;
|
private final List<Format> expectedFormats;
|
||||||
private final DecoderInputBuffer buffer;
|
private final DecoderInputBuffer buffer;
|
||||||
|
private final FormatHolder formatHolder;
|
||||||
|
|
||||||
|
private long playbackPositionUs;
|
||||||
|
private long lastSamplePositionUs;
|
||||||
|
|
||||||
|
public boolean isEnded;
|
||||||
public int positionResetCount;
|
public int positionResetCount;
|
||||||
public int formatReadCount;
|
public int formatReadCount;
|
||||||
public int bufferReadCount;
|
public int sampleBufferReadCount;
|
||||||
public boolean isEnded;
|
|
||||||
public boolean isReady;
|
|
||||||
|
|
||||||
public FakeRenderer(Format... expectedFormats) {
|
public FakeRenderer(Format... expectedFormats) {
|
||||||
super(expectedFormats.length == 0 ? C.TRACK_TYPE_UNKNOWN
|
super(expectedFormats.length == 0 ? C.TRACK_TYPE_UNKNOWN
|
||||||
: MimeTypes.getTrackType(expectedFormats[0].sampleMimeType));
|
: MimeTypes.getTrackType(expectedFormats[0].sampleMimeType));
|
||||||
this.expectedFormats = Collections.unmodifiableList(Arrays.asList(expectedFormats));
|
this.expectedFormats = Collections.unmodifiableList(Arrays.asList(expectedFormats));
|
||||||
this.buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||||
|
formatHolder = new FormatHolder();
|
||||||
|
lastSamplePositionUs = Long.MIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
|
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||||
|
playbackPositionUs = positionUs;
|
||||||
|
lastSamplePositionUs = Long.MIN_VALUE;
|
||||||
positionResetCount++;
|
positionResetCount++;
|
||||||
isEnded = false;
|
isEnded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||||
if (!isEnded) {
|
if (isEnded) {
|
||||||
// Verify the format matches the expected format.
|
return;
|
||||||
FormatHolder formatHolder = new FormatHolder();
|
}
|
||||||
|
playbackPositionUs = positionUs;
|
||||||
|
while (lastSamplePositionUs < positionUs + SOURCE_READAHEAD_US) {
|
||||||
|
formatHolder.format = null;
|
||||||
|
buffer.clear();
|
||||||
int result = readSource(formatHolder, buffer, false);
|
int result = readSource(formatHolder, buffer, false);
|
||||||
buffer.data = null;
|
|
||||||
if (result == C.RESULT_FORMAT_READ) {
|
if (result == C.RESULT_FORMAT_READ) {
|
||||||
formatReadCount++;
|
formatReadCount++;
|
||||||
assertThat(expectedFormats).contains(formatHolder.format);
|
assertThat(expectedFormats).contains(formatHolder.format);
|
||||||
} else if (result == C.RESULT_BUFFER_READ) {
|
} else if (result == C.RESULT_BUFFER_READ) {
|
||||||
bufferReadCount++;
|
|
||||||
if (buffer.isEndOfStream()) {
|
if (buffer.isEndOfStream()) {
|
||||||
isEnded = true;
|
isEnded = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
lastSamplePositionUs = buffer.timeUs;
|
||||||
|
sampleBufferReadCount++;
|
||||||
|
} else {
|
||||||
|
Assertions.checkState(result == C.RESULT_NOTHING_READ);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isReady = buffer.timeUs >= positionUs || hasReadStreamToEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return isReady || isSourceReady();
|
return lastSamplePositionUs >= playbackPositionUs || isSourceReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -23,17 +23,23 @@ import com.google.android.exoplayer2.source.SampleStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fake {@link SampleStream} that outputs a given {@link Format} then sets the end of stream flag
|
* Fake {@link SampleStream} that outputs a given {@link Format}, an optional sample containing a
|
||||||
* on its input buffer.
|
* single zero byte, then end of stream.
|
||||||
*/
|
*/
|
||||||
public final class FakeSampleStream implements SampleStream {
|
public final class FakeSampleStream implements SampleStream {
|
||||||
|
|
||||||
private final Format format;
|
private final Format format;
|
||||||
|
|
||||||
private boolean readFormat;
|
private boolean readFormat;
|
||||||
|
private boolean readSample;
|
||||||
|
|
||||||
public FakeSampleStream(Format format) {
|
public FakeSampleStream(Format format) {
|
||||||
|
this(format, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FakeSampleStream(Format format, boolean shouldOutputSample) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
readSample = !shouldOutputSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -48,6 +54,13 @@ public final class FakeSampleStream implements SampleStream {
|
||||||
formatHolder.format = format;
|
formatHolder.format = format;
|
||||||
readFormat = true;
|
readFormat = true;
|
||||||
return C.RESULT_FORMAT_READ;
|
return C.RESULT_FORMAT_READ;
|
||||||
|
} else if (!readSample) {
|
||||||
|
buffer.timeUs = 0;
|
||||||
|
buffer.ensureSpaceForWrite(1);
|
||||||
|
buffer.data.put((byte) 0);
|
||||||
|
buffer.flip();
|
||||||
|
readSample = true;
|
||||||
|
return C.RESULT_BUFFER_READ;
|
||||||
} else {
|
} else {
|
||||||
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
return C.RESULT_BUFFER_READ;
|
return C.RESULT_BUFFER_READ;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue