mirror of
https://github.com/samsonjs/media.git
synced 2026-04-16 13:05:46 +00:00
Add checks for device capability in tests.
PiperOrigin-RevId: 442751310
This commit is contained in:
parent
6c80a82bae
commit
570769ac9a
3 changed files with 173 additions and 1 deletions
|
|
@ -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.
|
||||
|
|
@ -144,6 +198,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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,26 @@ public final class EncoderUtil {
|
|||
return checkNotNull(MIME_TYPE_TO_ENCODERS.get()).keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
|
|
|
|||
Loading…
Reference in a new issue