mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +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;
|
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 static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.Format;
|
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.Log;
|
||||||
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -31,19 +37,67 @@ import org.json.JSONObject;
|
||||||
|
|
||||||
/** Utilities for instrumentation tests. */
|
/** Utilities for instrumentation tests. */
|
||||||
public final class AndroidTestUtil {
|
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 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 =
|
public static final String MP4_ASSET_WITH_INCREASING_TIMESTAMPS_URI_STRING =
|
||||||
"asset:///media/mp4/sample_with_increasing_timestamps.mp4";
|
"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 =
|
public static final String MP4_ASSET_SEF_URI_STRING =
|
||||||
"asset:///media/mp4/sample_sef_slow_motion.mp4";
|
"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 =
|
public static final String MP4_REMOTE_10_SECONDS_URI_STRING =
|
||||||
"https://storage.googleapis.com/exoplayer-test-media-1/mp4/android-screens-10s.mp4";
|
"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. */
|
/** 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 =
|
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";
|
"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 =
|
public static final String MP4_REMOTE_4K60_PORTRAIT_URI_STRING =
|
||||||
"https://storage.googleapis.com/exoplayer-test-media-1/mp4/portrait_4k60.mp4";
|
"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.
|
* 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.
|
* 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)
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
.setCalculateSsim(true)
|
.setCalculateSsim(true)
|
||||||
.build()
|
.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);
|
assertThat(result.ssim).isGreaterThan(0.90);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,26 @@ public final class EncoderUtil {
|
||||||
return checkNotNull(MIME_TYPE_TO_ENCODERS.get()).keySet();
|
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},
|
* Returns a {@link Range} of supported heights for the given {@link MediaCodecInfo encoder},
|
||||||
* {@linkplain MimeTypes MIME type} and {@code width}.
|
* {@linkplain MimeTypes MIME type} and {@code width}.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue