Some ErrorProne warnings have been enabled by [1], that broke the Chromium Roll into WebRTC, this CL should have taken care of all the problems. [1] - https://chromium-review.googlesource.com/c/chromium/src/+/1935889 Bug: None Change-Id: I2670e948c320984a122fdb774b891c98e05f582e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/160862 Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Sami Kalliomäki <sakal@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29933}
202 lines
7.9 KiB
Java
202 lines
7.9 KiB
Java
/*
|
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
package org.webrtc;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertNotNull;
|
|
|
|
import android.support.annotation.Nullable;
|
|
import android.support.test.filters.SmallTest;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.concurrent.BlockingQueue;
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
import java.util.concurrent.TimeUnit;
|
|
import org.chromium.base.test.params.BaseJUnit4RunnerDelegate;
|
|
import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
|
|
import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
|
|
import org.chromium.base.test.params.ParameterSet;
|
|
import org.chromium.base.test.params.ParameterizedRunner;
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
|
|
/** Unit tests for {@link AndroidVideoDecoder}. */
|
|
@RunWith(ParameterizedRunner.class)
|
|
@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
|
|
public final class AndroidVideoDecoderInstrumentationTest {
|
|
@ClassParameter private static List<ParameterSet> CLASS_PARAMS = new ArrayList<>();
|
|
|
|
static {
|
|
CLASS_PARAMS.add(new ParameterSet()
|
|
.value(/* codecName= */ "VP8", false /* useEglContext */)
|
|
.name("VP8WithoutEglContext"));
|
|
CLASS_PARAMS.add(new ParameterSet()
|
|
.value(/* codecName= */ "VP8", true /* useEglContext */)
|
|
.name("VP8WithEglContext"));
|
|
CLASS_PARAMS.add(new ParameterSet()
|
|
.value(/* codecName= */ "H264", false /* useEglContext */)
|
|
.name("H264WithoutEglContext"));
|
|
CLASS_PARAMS.add(new ParameterSet()
|
|
.value(/* codecName= */ "H264", true /* useEglContext */)
|
|
.name("H264WithEglContext"));
|
|
}
|
|
|
|
private final VideoCodecInfo codecType;
|
|
private final boolean useEglContext;
|
|
|
|
public AndroidVideoDecoderInstrumentationTest(String codecName, boolean useEglContext) {
|
|
if (codecName.equals("H264")) {
|
|
this.codecType = H264Utils.DEFAULT_H264_BASELINE_PROFILE_CODEC;
|
|
} else {
|
|
this.codecType = new VideoCodecInfo(codecName, new HashMap<>());
|
|
}
|
|
this.useEglContext = useEglContext;
|
|
}
|
|
|
|
private static final String TAG = "AndroidVideoDecoderInstrumentationTest";
|
|
|
|
private static final int TEST_FRAME_COUNT = 10;
|
|
private static final int TEST_FRAME_WIDTH = 640;
|
|
private static final int TEST_FRAME_HEIGHT = 360;
|
|
private VideoFrame.I420Buffer[] TEST_FRAMES;
|
|
|
|
private static final boolean ENABLE_INTEL_VP8_ENCODER = true;
|
|
private static final boolean ENABLE_H264_HIGH_PROFILE = true;
|
|
private static final VideoEncoder.Settings ENCODER_SETTINGS =
|
|
new VideoEncoder.Settings(1 /* core */, TEST_FRAME_WIDTH, TEST_FRAME_HEIGHT, 300 /* kbps */,
|
|
30 /* fps */, 1 /* numberOfSimulcastStreams */, true /* automaticResizeOn */,
|
|
/* capabilities= */ new VideoEncoder.Capabilities(false /* lossNotification */));
|
|
|
|
private static final int DECODE_TIMEOUT_MS = 1000;
|
|
private static final VideoDecoder.Settings SETTINGS =
|
|
new VideoDecoder.Settings(1 /* core */, TEST_FRAME_WIDTH, TEST_FRAME_HEIGHT);
|
|
|
|
private static class MockDecodeCallback implements VideoDecoder.Callback {
|
|
private BlockingQueue<VideoFrame> frameQueue = new LinkedBlockingQueue<>();
|
|
|
|
@Override
|
|
public void onDecodedFrame(VideoFrame frame, Integer decodeTimeMs, Integer qp) {
|
|
assertNotNull(frame);
|
|
frameQueue.offer(frame);
|
|
}
|
|
|
|
public void assertFrameDecoded(EncodedImage testImage, VideoFrame.I420Buffer testBuffer) {
|
|
VideoFrame decodedFrame = poll();
|
|
VideoFrame.Buffer decodedBuffer = decodedFrame.getBuffer();
|
|
assertEquals(testImage.encodedWidth, decodedBuffer.getWidth());
|
|
assertEquals(testImage.encodedHeight, decodedBuffer.getHeight());
|
|
// TODO(sakal): Decoder looses the nanosecond precision. This is not a problem in practice
|
|
// because C++ EncodedImage stores the timestamp in milliseconds.
|
|
assertEquals(testImage.captureTimeNs / 1000, decodedFrame.getTimestampNs() / 1000);
|
|
assertEquals(testImage.rotation, decodedFrame.getRotation());
|
|
}
|
|
|
|
public VideoFrame poll() {
|
|
try {
|
|
VideoFrame frame = frameQueue.poll(DECODE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
|
assertNotNull("Timed out waiting for the frame to be decoded.", frame);
|
|
return frame;
|
|
} catch (InterruptedException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static VideoFrame.I420Buffer[] generateTestFrames() {
|
|
VideoFrame.I420Buffer[] result = new VideoFrame.I420Buffer[TEST_FRAME_COUNT];
|
|
for (int i = 0; i < TEST_FRAME_COUNT; i++) {
|
|
result[i] = JavaI420Buffer.allocate(TEST_FRAME_WIDTH, TEST_FRAME_HEIGHT);
|
|
// TODO(sakal): Generate content for the test frames.
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private final EncodedImage[] encodedTestFrames = new EncodedImage[TEST_FRAME_COUNT];
|
|
private EglBase14 eglBase;
|
|
|
|
private VideoDecoderFactory createDecoderFactory(EglBase.Context eglContext) {
|
|
return new HardwareVideoDecoderFactory(eglContext);
|
|
}
|
|
|
|
private @Nullable VideoDecoder createDecoder() {
|
|
VideoDecoderFactory factory =
|
|
createDecoderFactory(useEglContext ? eglBase.getEglBaseContext() : null);
|
|
return factory.createDecoder(codecType);
|
|
}
|
|
|
|
private void encodeTestFrames() {
|
|
VideoEncoderFactory encoderFactory = new HardwareVideoEncoderFactory(
|
|
eglBase.getEglBaseContext(), ENABLE_INTEL_VP8_ENCODER, ENABLE_H264_HIGH_PROFILE);
|
|
VideoEncoder encoder = encoderFactory.createEncoder(codecType);
|
|
HardwareVideoEncoderTest.MockEncoderCallback encodeCallback =
|
|
new HardwareVideoEncoderTest.MockEncoderCallback();
|
|
assertEquals(VideoCodecStatus.OK, encoder.initEncode(ENCODER_SETTINGS, encodeCallback));
|
|
|
|
long lastTimestampNs = 0;
|
|
for (int i = 0; i < TEST_FRAME_COUNT; i++) {
|
|
lastTimestampNs += TimeUnit.SECONDS.toNanos(1) / ENCODER_SETTINGS.maxFramerate;
|
|
VideoEncoder.EncodeInfo info = new VideoEncoder.EncodeInfo(
|
|
new EncodedImage.FrameType[] {EncodedImage.FrameType.VideoFrameDelta});
|
|
HardwareVideoEncoderTest.testEncodeFrame(
|
|
encoder, new VideoFrame(TEST_FRAMES[i], 0 /* rotation */, lastTimestampNs), info);
|
|
encodedTestFrames[i] = encodeCallback.poll();
|
|
}
|
|
|
|
assertEquals(VideoCodecStatus.OK, encoder.release());
|
|
}
|
|
|
|
@Before
|
|
public void setUp() {
|
|
NativeLibrary.initialize(new NativeLibrary.DefaultLoader(), TestConstants.NATIVE_LIBRARY);
|
|
|
|
TEST_FRAMES = generateTestFrames();
|
|
|
|
eglBase = EglBase.createEgl14(EglBase.CONFIG_PLAIN);
|
|
eglBase.createDummyPbufferSurface();
|
|
eglBase.makeCurrent();
|
|
|
|
encodeTestFrames();
|
|
}
|
|
|
|
@After
|
|
public void tearDown() {
|
|
eglBase.release();
|
|
}
|
|
|
|
@Test
|
|
@SmallTest
|
|
public void testInitialize() {
|
|
VideoDecoder decoder = createDecoder();
|
|
assertEquals(VideoCodecStatus.OK, decoder.initDecode(SETTINGS, null /* decodeCallback */));
|
|
assertEquals(VideoCodecStatus.OK, decoder.release());
|
|
}
|
|
|
|
@Test
|
|
@SmallTest
|
|
public void testDecode() {
|
|
VideoDecoder decoder = createDecoder();
|
|
MockDecodeCallback callback = new MockDecodeCallback();
|
|
assertEquals(VideoCodecStatus.OK, decoder.initDecode(SETTINGS, callback));
|
|
|
|
for (int i = 0; i < TEST_FRAME_COUNT; i++) {
|
|
assertEquals(VideoCodecStatus.OK,
|
|
decoder.decode(encodedTestFrames[i],
|
|
new VideoDecoder.DecodeInfo(false /* isMissingFrames */, 0 /* renderTimeMs */)));
|
|
callback.assertFrameDecoded(encodedTestFrames[i], TEST_FRAMES[i]);
|
|
}
|
|
|
|
assertEquals(VideoCodecStatus.OK, decoder.release());
|
|
}
|
|
}
|