Commit 570769ac by claincly Committed by Ian Baker

Add checks for device capability in tests.

PiperOrigin-RevId: 442751310
parent 6c80a82b
......@@ -15,13 +15,19 @@
*/
package com.google.android.exoplayer2.transformer;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.content.Context;
import android.os.Build;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
......@@ -31,19 +37,67 @@ import org.json.JSONObject;
/** Utilities for instrumentation tests. */
public final class AndroidTestUtil {
// TODO(b/228865104): Add device capability based test skipping.
public static final String MP4_ASSET_URI_STRING = "asset:///media/mp4/sample.mp4";
public static final Format MP4_ASSET_FORMAT =
new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setWidth(1080)
.setHeight(720)
.setFrameRate(29.97f)
.build();
public static final String MP4_ASSET_WITH_INCREASING_TIMESTAMPS_URI_STRING =
"asset:///media/mp4/sample_with_increasing_timestamps.mp4";
public static final Format MP4_ASSET_WITH_INCREASING_TIMESTAMPS_FORMAT =
new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setWidth(1920)
.setHeight(1080)
.setFrameRate(30.00f)
.build();
public static final String MP4_ASSET_SEF_URI_STRING =
"asset:///media/mp4/sample_sef_slow_motion.mp4";
public static final Format MP4_ASSET_SEF_FORMAT =
new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setWidth(320)
.setHeight(240)
.setFrameRate(30.472f)
.build();
public static final String MP4_REMOTE_10_SECONDS_URI_STRING =
"https://storage.googleapis.com/exoplayer-test-media-1/mp4/android-screens-10s.mp4";
public static final Format MP4_REMOTE_10_SECONDS_FORMAT =
new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setWidth(1280)
.setHeight(720)
.setFrameRate(29.97f)
.build();
/** Test clip transcoded from {@link #MP4_REMOTE_10_SECONDS_URI_STRING} with H264 and MP3. */
public static final String MP4_REMOTE_H264_MP3_URI_STRING =
"https://storage.googleapis.com/exoplayer-test-media-1/mp4/%20android-screens-10s-h264-mp3.mp4";
public static final Format MP4_REMOTE_H264_MP3_FORMAT =
new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setWidth(1280)
.setHeight(720)
.setFrameRate(29.97f)
.build();
public static final String MP4_REMOTE_4K60_PORTRAIT_URI_STRING =
"https://storage.googleapis.com/exoplayer-test-media-1/mp4/portrait_4k60.mp4";
public static final Format MP4_REMOTE_4K60_PORTRAIT_FORMAT =
new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setWidth(3840)
.setHeight(2160)
.setFrameRate(57.39f)
.build();
/**
* Log in logcat and in an analysis file that this test was skipped.
......@@ -145,6 +199,70 @@ public final class AndroidTestUtil {
}
/**
* Checks whether the test should be skipped because the device is incapable of decoding and
* encoding the given formats. If the test should be skipped, logs the reason for skipping.
*
* @param context The {@link Context context}.
* @param testId The test ID.
* @param decodingFormat The {@link Format format} to decode.
* @param encodingFormat The {@link Format format} to encode.
* @return Whether the test should be skipped.
*/
public static boolean skipAndLogIfInsufficientCodecSupport(
Context context, String testId, Format decodingFormat, Format encodingFormat)
throws IOException, JSONException {
boolean canDecode = false;
@Nullable MediaCodecUtil.DecoderQueryException queryException = null;
try {
canDecode = canDecode(decodingFormat);
} catch (MediaCodecUtil.DecoderQueryException e) {
queryException = e;
}
boolean canEncode = canEncode(encodingFormat);
if (canDecode && canEncode) {
return false;
}
StringBuilder skipReasonBuilder = new StringBuilder();
if (!canDecode) {
skipReasonBuilder.append("Cannot decode ").append(decodingFormat).append('\n');
if (queryException != null) {
skipReasonBuilder.append(queryException).append('\n');
}
}
if (!canEncode) {
skipReasonBuilder.append("Cannot encode ").append(encodingFormat);
}
recordTestSkipped(context, testId, skipReasonBuilder.toString());
return true;
}
private static boolean canDecode(Format format) throws MediaCodecUtil.DecoderQueryException {
@Nullable
MediaCodecInfo decoderInfo =
MediaCodecUtil.getDecoderInfo(
checkNotNull(format.sampleMimeType), /* secure= */ false, /* tunneling= */ false);
if (decoderInfo == null) {
return false;
}
return decoderInfo.isVideoSizeAndRateSupportedV21(
format.width, format.height, format.frameRate);
}
private static boolean canEncode(Format format) {
String mimeType = checkNotNull(format.sampleMimeType);
ImmutableList<android.media.MediaCodecInfo> supportedEncoders =
EncoderUtil.getSupportedEncoders(mimeType);
if (supportedEncoders.isEmpty()) {
return false;
}
return EncoderUtil.areSizeAndRateSupported(
supportedEncoders.get(0), mimeType, format.width, format.height, format.frameRate);
}
/**
* Creates a {@link File} of the {@code fileName} in the application cache directory.
*
* <p>If a file of that name already exists, it is overwritten.
......
......@@ -49,7 +49,41 @@ public final class TranscodeQualityTest {
new TransformerAndroidTestRunner.Builder(context, transformer)
.setCalculateSsim(true)
.build()
.run(/* testId= */ "singleTranscode_ssim", AndroidTestUtil.MP4_ASSET_URI_STRING);
.run(
/* testId= */ "transformWithDecodeEncode_ssim",
AndroidTestUtil.MP4_ASSET_URI_STRING);
assertThat(result.ssim).isGreaterThan(0.90);
}
@Test
public void transcodeAvcToHevc_ssimIsGreaterThan90Percent() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
String testId = "transcodeAvcToHevc_ssim";
if (AndroidTestUtil.skipAndLogIfInsufficientCodecSupport(
context,
testId,
/* decodingFormat= */ AndroidTestUtil.MP4_ASSET_FORMAT,
/* encodingFormat= */ AndroidTestUtil.MP4_ASSET_FORMAT
.buildUpon()
.setSampleMimeType(MimeTypes.VIDEO_H265)
.build())) {
return;
}
Transformer transformer =
new Transformer.Builder(context)
.setTransformationRequest(
new TransformationRequest.Builder().setVideoMimeType(MimeTypes.VIDEO_H265).build())
.setRemoveAudio(true)
.build();
TransformationTestResult result =
new TransformerAndroidTestRunner.Builder(context, transformer)
.setCalculateSsim(true)
.build()
.run(testId, AndroidTestUtil.MP4_ASSET_URI_STRING);
assertThat(result.ssim).isGreaterThan(0.90);
}
......
......@@ -65,6 +65,26 @@ public final class EncoderUtil {
}
/**
* Returns whether the {@linkplain MediaCodecInfo encoder} supports the given resolution and frame
* rate.
*/
public static boolean areSizeAndRateSupported(
MediaCodecInfo encoderInfo, String mimeType, int width, int height, double frameRate) {
// VideoCapabilities.areSizeAndRateSupported incorrectly returns false if frameRate < 1 on all
// current versions of Android, so only checks the width and height in this case [b/153940404].
if (frameRate == Format.NO_VALUE || frameRate < 1) {
return encoderInfo
.getCapabilitiesForType(mimeType)
.getVideoCapabilities()
.isSizeSupported(width, height);
}
return encoderInfo
.getCapabilitiesForType(mimeType)
.getVideoCapabilities()
.areSizeAndRateSupported(width, height, frameRate);
}
/**
* Returns a {@link Range} of supported heights for the given {@link MediaCodecInfo encoder},
* {@linkplain MimeTypes MIME type} and {@code width}.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment