Publish MediaCodec-based renderer tests
Switch to snapshot Robolectric to pick up the latest version of shadows required by MediaCodecVideoRendererTest and MediaCodecAudioRendererTest. PiperOrigin-RevId: 312030332
This commit is contained in:
parent
f6d0e34cea
commit
ceddc60296
@ -26,6 +26,7 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
|
||||
}
|
||||
project.ext {
|
||||
exoplayerPublishEnabled = false
|
||||
|
@ -23,7 +23,7 @@ project.ext {
|
||||
junitVersion = '4.13-rc-2'
|
||||
guavaVersion = '28.2-android'
|
||||
mockitoVersion = '2.25.0'
|
||||
robolectricVersion = '4.3.1'
|
||||
robolectricVersion = '4.4-SNAPSHOT'
|
||||
checkerframeworkVersion = '2.5.0'
|
||||
jsr305Version = '3.0.2'
|
||||
kotlinAnnotationsVersion = '1.3.70'
|
||||
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.RendererConfiguration;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Unit tests for {@link MediaCodecAudioRenderer} */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MediaCodecAudioRendererTest {
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
private static final Format AUDIO_AAC =
|
||||
new Format.Builder()
|
||||
.setSampleMimeType(MimeTypes.AUDIO_AAC)
|
||||
.setPcmEncoding(C.ENCODING_PCM_16BIT)
|
||||
.setChannelCount(2)
|
||||
.setSampleRate(44100)
|
||||
.setEncoderDelay(100)
|
||||
.setEncoderPadding(150)
|
||||
.build();
|
||||
|
||||
private MediaCodecAudioRenderer mediaCodecAudioRenderer;
|
||||
|
||||
@Mock private AudioSink audioSink;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// audioSink isEnded can always be true because the MediaCodecAudioRenderer isEnded =
|
||||
// super.isEnded && audioSink.isEnded.
|
||||
when(audioSink.isEnded()).thenReturn(true);
|
||||
|
||||
when(audioSink.handleBuffer(any(), anyLong(), anyInt())).thenReturn(true);
|
||||
|
||||
MediaCodecSelector mediaCodecSelector =
|
||||
new MediaCodecSelector() {
|
||||
@Override
|
||||
public List<MediaCodecInfo> getDecoderInfos(
|
||||
String mimeType, boolean requiresSecureDecoder, boolean requiresTunnelingDecoder) {
|
||||
return Collections.singletonList(
|
||||
MediaCodecInfo.newInstance(
|
||||
/* name= */ "name",
|
||||
/* mimeType= */ mimeType,
|
||||
/* codecMimeType= */ mimeType,
|
||||
/* capabilities= */ null,
|
||||
/* hardwareAccelerated= */ false,
|
||||
/* softwareOnly= */ true,
|
||||
/* vendor= */ false,
|
||||
/* forceDisableAdaptive= */ false,
|
||||
/* forceSecure= */ false));
|
||||
}
|
||||
};
|
||||
|
||||
mediaCodecAudioRenderer =
|
||||
new MediaCodecAudioRenderer(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
mediaCodecSelector,
|
||||
/* enableDecoderFallback= */ false,
|
||||
/* eventHandler= */ null,
|
||||
/* eventListener= */ null,
|
||||
audioSink) {
|
||||
@Override
|
||||
protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format format)
|
||||
throws DecoderQueryException {
|
||||
return RendererCapabilities.create(FORMAT_HANDLED);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void render_configuresAudioSink() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ AUDIO_AAC,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
|
||||
mediaCodecAudioRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {AUDIO_AAC},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* offsetUs */ 0);
|
||||
|
||||
mediaCodecAudioRenderer.start();
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 250, SystemClock.elapsedRealtime() * 1000);
|
||||
mediaCodecAudioRenderer.setCurrentStreamFinal();
|
||||
|
||||
int positionUs = 500;
|
||||
do {
|
||||
mediaCodecAudioRenderer.render(positionUs, SystemClock.elapsedRealtime() * 1000);
|
||||
positionUs += 250;
|
||||
} while (!mediaCodecAudioRenderer.isEnded());
|
||||
|
||||
verify(audioSink)
|
||||
.configure(
|
||||
AUDIO_AAC.pcmEncoding,
|
||||
AUDIO_AAC.channelCount,
|
||||
AUDIO_AAC.sampleRate,
|
||||
/* specifiedBufferSize= */ 0,
|
||||
/* outputChannels= */ null,
|
||||
AUDIO_AAC.encoderDelay,
|
||||
AUDIO_AAC.encoderPadding);
|
||||
}
|
||||
}
|
@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.video;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.view.Surface;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.RendererConfiguration;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.robolectric.annotation.LooperMode;
|
||||
|
||||
/** Unit test for {@link MediaCodecVideoRenderer}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LooperMode(LooperMode.Mode.LEGACY)
|
||||
public class MediaCodecVideoRendererTest {
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
private static final Format VIDEO_H264 =
|
||||
new Format.Builder()
|
||||
.setSampleMimeType(MimeTypes.VIDEO_H264)
|
||||
.setWidth(1920)
|
||||
.setHeight(1080)
|
||||
.build();
|
||||
|
||||
private MediaCodecVideoRenderer mediaCodecVideoRenderer;
|
||||
@Nullable private Format currentOutputFormat;
|
||||
|
||||
@Mock private VideoRendererEventListener eventListener;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MediaCodecSelector mediaCodecSelector =
|
||||
new MediaCodecSelector() {
|
||||
@Override
|
||||
public List<MediaCodecInfo> getDecoderInfos(
|
||||
String mimeType, boolean requiresSecureDecoder, boolean requiresTunnelingDecoder) {
|
||||
return Collections.singletonList(
|
||||
MediaCodecInfo.newInstance(
|
||||
/* name= */ "name",
|
||||
/* mimeType= */ mimeType,
|
||||
/* codecMimeType= */ mimeType,
|
||||
/* capabilities= */ null,
|
||||
/* hardwareAccelerated= */ false,
|
||||
/* softwareOnly= */ true,
|
||||
/* vendor= */ false,
|
||||
/* forceDisableAdaptive= */ false,
|
||||
/* forceSecure= */ false));
|
||||
}
|
||||
};
|
||||
|
||||
mediaCodecVideoRenderer =
|
||||
new MediaCodecVideoRenderer(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
mediaCodecSelector,
|
||||
/* allowedJoiningTimeMs= */ 0,
|
||||
/* eventHandler= */ new Handler(),
|
||||
/* eventListener= */ eventListener,
|
||||
/* maxDroppedFramesToNotify= */ 1) {
|
||||
@Override
|
||||
@Capabilities
|
||||
protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format format)
|
||||
throws DecoderQueryException {
|
||||
return RendererCapabilities.create(FORMAT_HANDLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onOutputFormatChanged(Format outputFormat) {
|
||||
super.onOutputFormatChanged(outputFormat);
|
||||
currentOutputFormat = outputFormat;
|
||||
}
|
||||
};
|
||||
|
||||
mediaCodecVideoRenderer.handleMessage(
|
||||
Renderer.MSG_SET_SURFACE, new Surface(new SurfaceTexture(/* texName= */ 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void render_dropsLateBuffer() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50_000,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), // First buffer.
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), // Late buffer.
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), // Last buffer.
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* offsetUs */ 0);
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||
mediaCodecVideoRenderer.render(40_000, SystemClock.elapsedRealtime() * 1000);
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
int posUs = 80_001; // Ensures buffer will be 30_001us late.
|
||||
while (!mediaCodecVideoRenderer.isEnded()) {
|
||||
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
||||
posUs += 40_000;
|
||||
}
|
||||
|
||||
verify(eventListener).onDroppedFrames(eq(1), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void render_sendsVideoSizeChangeWithCurrentFormatValues() throws Exception {
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 0,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM),
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* offsetUs */ 0);
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
mediaCodecVideoRenderer.start();
|
||||
|
||||
int positionUs = 0;
|
||||
do {
|
||||
mediaCodecVideoRenderer.render(positionUs, SystemClock.elapsedRealtime() * 1000);
|
||||
positionUs += 10;
|
||||
} while (!mediaCodecVideoRenderer.isEnded());
|
||||
|
||||
verify(eventListener)
|
||||
.onVideoSizeChanged(
|
||||
VIDEO_H264.width,
|
||||
VIDEO_H264.height,
|
||||
VIDEO_H264.rotationDegrees,
|
||||
VIDEO_H264.pixelWidthHeightRatio);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
render_withMultipleQueued_sendsVideoSizeChangedWithCorrectPixelAspectRatioWhenMultipleQueued()
|
||||
throws Exception {
|
||||
Format pAsp1 = VIDEO_H264.buildUpon().setPixelWidthHeightRatio(1f).build();
|
||||
Format pAsp2 = VIDEO_H264.buildUpon().setPixelWidthHeightRatio(2f).build();
|
||||
Format pAsp3 = VIDEO_H264.buildUpon().setPixelWidthHeightRatio(3f).build();
|
||||
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ pAsp1,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 5000,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {pAsp1, pAsp2, pAsp3},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* offsetUs */ 0);
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 250, SystemClock.elapsedRealtime() * 1000);
|
||||
|
||||
fakeSampleStream.addFakeSampleStreamItem(new FakeSampleStreamItem(pAsp2));
|
||||
fakeSampleStream.addFakeSampleStreamItem(
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
fakeSampleStream.addFakeSampleStreamItem(
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
fakeSampleStream.addFakeSampleStreamItem(new FakeSampleStreamItem(pAsp3));
|
||||
fakeSampleStream.addFakeSampleStreamItem(
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
fakeSampleStream.addFakeSampleStreamItem(
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
fakeSampleStream.addFakeSampleStreamItem(FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
|
||||
int pos = 500;
|
||||
do {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ pos, SystemClock.elapsedRealtime() * 1000);
|
||||
pos += 250;
|
||||
} while (!mediaCodecVideoRenderer.isEnded());
|
||||
|
||||
InOrder orderVerifier = inOrder(eventListener);
|
||||
orderVerifier.verify(eventListener).onVideoSizeChanged(anyInt(), anyInt(), anyInt(), eq(1f));
|
||||
orderVerifier.verify(eventListener).onVideoSizeChanged(anyInt(), anyInt(), anyInt(), eq(2f));
|
||||
orderVerifier.verify(eventListener).onVideoSizeChanged(anyInt(), anyInt(), anyInt(), eq(3f));
|
||||
orderVerifier.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void render_includingResetPosition_keepsOutputFormatInVideoFrameMetadataListener()
|
||||
throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* offsetUs */ 0);
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
mediaCodecVideoRenderer.resetPosition(0);
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
fakeSampleStream.addFakeSampleStreamItem(
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
fakeSampleStream.addFakeSampleStreamItem(FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
int positionUs = 10;
|
||||
do {
|
||||
mediaCodecVideoRenderer.render(positionUs, SystemClock.elapsedRealtime() * 1000);
|
||||
positionUs += 10;
|
||||
} while (!mediaCodecVideoRenderer.isEnded());
|
||||
|
||||
assertThat(currentOutputFormat).isEqualTo(VIDEO_H264);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enable_withMayRenderStartOfStream_rendersFirstFrameBeforeStart() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* offsetUs */ 0);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
}
|
||||
|
||||
verify(eventListener).onRenderedFirstFrame(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enable_withoutMayRenderStartOfStream_doesNotRenderFirstFrameBeforeStart()
|
||||
throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* offsetUs */ 0);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
}
|
||||
|
||||
verify(eventListener, never()).onRenderedFirstFrame(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enable_withoutMayRenderStartOfStream_rendersFirstFrameAfterStart() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
|
||||
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* offsetUs */ 0);
|
||||
mediaCodecVideoRenderer.start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
}
|
||||
|
||||
verify(eventListener).onRenderedFirstFrame(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceStream_whenStarted_rendersFirstFrameOfNewStream() throws Exception {
|
||||
FakeSampleStream fakeSampleStream1 =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream1,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* offsetUs */ 0);
|
||||
mediaCodecVideoRenderer.start();
|
||||
|
||||
boolean replacedStream = false;
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
mediaCodecVideoRenderer.render(
|
||||
/* positionUs= */ i * 10, SystemClock.elapsedRealtime() * 1000);
|
||||
if (!replacedStream && mediaCodecVideoRenderer.hasReadStreamToEnd()) {
|
||||
mediaCodecVideoRenderer.replaceStream(
|
||||
new Format[] {VIDEO_H264}, fakeSampleStream2, /* offsetUs= */ 100);
|
||||
replacedStream = true;
|
||||
}
|
||||
}
|
||||
|
||||
verify(eventListener, times(2)).onRenderedFirstFrame(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceStream_whenNotStarted_doesNotRenderFirstFrameOfNewStream() throws Exception {
|
||||
FakeSampleStream fakeSampleStream1 =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
new FakeSampleStream(
|
||||
/* format= */ VIDEO_H264,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream1,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* offsetUs */ 0);
|
||||
|
||||
boolean replacedStream = false;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(
|
||||
/* positionUs= */ i * 10, SystemClock.elapsedRealtime() * 1000);
|
||||
if (!replacedStream && mediaCodecVideoRenderer.hasReadStreamToEnd()) {
|
||||
mediaCodecVideoRenderer.replaceStream(
|
||||
new Format[] {VIDEO_H264}, fakeSampleStream2, /* offsetUs= */ 100);
|
||||
replacedStream = true;
|
||||
}
|
||||
}
|
||||
|
||||
verify(eventListener).onRenderedFirstFrame(any());
|
||||
|
||||
// Render to streamOffsetUs and verify the new first frame gets rendered.
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 100, SystemClock.elapsedRealtime() * 1000);
|
||||
|
||||
verify(eventListener, times(2)).onRenderedFirstFrame(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onVideoFrameProcessingOffset_isCalledAfterOutputFormatChanges()
|
||||
throws ExoPlaybackException {
|
||||
Format mp4Uhd = VIDEO_H264.buildUpon().setWidth(3840).setHeight(2160).build();
|
||||
byte[] sampleData = new byte[0];
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* format= */ mp4Uhd,
|
||||
/* eventDispatcher= */ null,
|
||||
/* firstSampleTimeUs= */ 0,
|
||||
/* timeUsIncrement= */ 50,
|
||||
new FakeSampleStreamItem(mp4Uhd),
|
||||
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME),
|
||||
new FakeSampleStreamItem(VIDEO_H264),
|
||||
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME),
|
||||
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME),
|
||||
new FakeSampleStreamItem(mp4Uhd),
|
||||
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME),
|
||||
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME),
|
||||
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME),
|
||||
new FakeSampleStreamItem(VIDEO_H264),
|
||||
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM);
|
||||
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {mp4Uhd},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* offsetUs */ 0);
|
||||
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
mediaCodecVideoRenderer.start();
|
||||
|
||||
int positionUs = 10;
|
||||
do {
|
||||
mediaCodecVideoRenderer.render(positionUs, SystemClock.elapsedRealtime() * 1000);
|
||||
positionUs += 10;
|
||||
} while (!mediaCodecVideoRenderer.isEnded());
|
||||
mediaCodecVideoRenderer.stop();
|
||||
|
||||
InOrder orderVerifier = inOrder(eventListener);
|
||||
orderVerifier.verify(eventListener).onVideoFrameProcessingOffset(anyLong(), eq(1), eq(mp4Uhd));
|
||||
orderVerifier
|
||||
.verify(eventListener)
|
||||
.onVideoFrameProcessingOffset(anyLong(), eq(2), eq(VIDEO_H264));
|
||||
orderVerifier.verify(eventListener).onVideoFrameProcessingOffset(anyLong(), eq(3), eq(mp4Uhd));
|
||||
orderVerifier
|
||||
.verify(eventListener)
|
||||
.onVideoFrameProcessingOffset(anyLong(), eq(1), eq(VIDEO_H264));
|
||||
orderVerifier.verifyNoMoreInteractions();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user