diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FallbackDetails.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FallbackDetails.java new file mode 100644 index 0000000000..816fd6018b --- /dev/null +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FallbackDetails.java @@ -0,0 +1,94 @@ +/* + * Copyright 2022 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 androidx.media3.transformer; + +import androidx.annotation.Nullable; +import androidx.media3.common.C; +import androidx.media3.transformer.TransformationRequest.HdrMode; +import java.util.Objects; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * A test only class for holding the details of what fallbacks were applied during a test + * transformation. + */ +/* package */ final class FallbackDetails { + + private static final String INFERRED_FROM_SOURCE = "Inferred from source."; + + public final int originalOutputHeight; + public final int fallbackOutputHeight; + + @Nullable public final String originalAudioMimeType; + @Nullable public final String fallbackAudioMimeType; + + @Nullable public final String originalVideoMimeType; + @Nullable public final String fallbackVideoMimeType; + + public final @HdrMode int originalHdrMode; + public final @HdrMode int fallbackHdrMode; + + public FallbackDetails( + int originalOutputHeight, + int fallbackOutputHeight, + @Nullable String originalAudioMimeType, + @Nullable String fallbackAudioMimeType, + @Nullable String originalVideoMimeType, + @Nullable String fallbackVideoMimeType, + @HdrMode int originalHdrMode, + @HdrMode int fallbackHdrMode) { + this.originalOutputHeight = originalOutputHeight; + this.fallbackOutputHeight = fallbackOutputHeight; + + this.originalAudioMimeType = originalAudioMimeType; + this.fallbackAudioMimeType = fallbackAudioMimeType; + + this.originalVideoMimeType = originalVideoMimeType; + this.fallbackVideoMimeType = fallbackVideoMimeType; + + this.originalHdrMode = originalHdrMode; + this.fallbackHdrMode = fallbackHdrMode; + } + + /** Returns a {@link JSONObject} detailing all the fallbacks that have been applied. */ + public JSONObject asJsonObject() throws JSONException { + JSONObject jsonObject = new JSONObject(); + if (fallbackOutputHeight != originalOutputHeight) { + jsonObject.put( + "originalOutputHeight", + originalOutputHeight != C.LENGTH_UNSET ? originalOutputHeight : INFERRED_FROM_SOURCE); + jsonObject.put("fallbackOutputHeight", fallbackOutputHeight); + } + if (!Objects.equals(fallbackAudioMimeType, originalAudioMimeType)) { + jsonObject.put( + "originalAudioMimeType", + originalAudioMimeType != null ? originalAudioMimeType : INFERRED_FROM_SOURCE); + jsonObject.put("fallbackAudioMimeType", fallbackAudioMimeType); + } + if (!Objects.equals(fallbackVideoMimeType, originalVideoMimeType)) { + jsonObject.put( + "originalVideoMimeType", + originalVideoMimeType != null ? originalVideoMimeType : INFERRED_FROM_SOURCE); + jsonObject.put("fallbackVideoMimeType", fallbackVideoMimeType); + } + if (fallbackHdrMode != originalHdrMode) { + jsonObject.put("originalHdrMode", originalHdrMode); + jsonObject.put("fallbackHdrMode", fallbackHdrMode); + } + return jsonObject; + } +} diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java index 04cfd71b3f..c9c9d450da 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java @@ -32,6 +32,7 @@ public class TransformationTestResult { @Nullable private String filePath; private long elapsedTimeMs; private double ssim; + @Nullable private FallbackDetails fallbackDetails; @Nullable private Exception testException; @Nullable private Exception analysisException; @@ -85,6 +86,21 @@ public class TransformationTestResult { return this; } + /** + * Sets an {@link FallbackDetails} object that describes the fallbacks that occurred during + * post-transformation analysis. + * + *
{@code null} represents no fallback was applied. + * + * @param fallbackDetails The {@link FallbackDetails}. + * @return This {@link Builder}. + */ + @CanIgnoreReturnValue + public Builder setFallbackDetails(@Nullable FallbackDetails fallbackDetails) { + this.fallbackDetails = fallbackDetails; + return this; + } + /** * Sets an {@link Exception} that occurred during the test. * @@ -116,7 +132,13 @@ public class TransformationTestResult { /** Builds the {@link TransformationTestResult} instance. */ public TransformationTestResult build() { return new TransformationTestResult( - transformationResult, filePath, elapsedTimeMs, ssim, testException, analysisException); + transformationResult, + filePath, + elapsedTimeMs, + ssim, + fallbackDetails, + testException, + analysisException); } } @@ -134,7 +156,11 @@ public class TransformationTestResult { public final long elapsedTimeMs; /** The SSIM score of the transformation, {@link #SSIM_UNSET} if unavailable. */ public final double ssim; - + /** + * The {@link FallbackDetails} describing the fallbacks that occurred doing transformation, or + * {@code null} if no fallback occurred. + */ + @Nullable public final FallbackDetails fallbackDetails; /** * The {@link Exception} that was thrown during the test, or {@code null} if nothing was thrown. */ @@ -185,6 +211,9 @@ public class TransformationTestResult { if (ssim != TransformationTestResult.SSIM_UNSET) { jsonObject.put("ssim", ssim); } + if (fallbackDetails != null) { + jsonObject.put("fallbackDetails", fallbackDetails.asJsonObject()); + } if (testException != null) { jsonObject.put("testException", AndroidTestUtil.exceptionAsJsonObject(testException)); } @@ -199,12 +228,14 @@ public class TransformationTestResult { @Nullable String filePath, long elapsedTimeMs, double ssim, + @Nullable FallbackDetails fallbackDetails, @Nullable Exception testException, @Nullable Exception analysisException) { this.transformationResult = transformationResult; this.filePath = filePath; this.elapsedTimeMs = elapsedTimeMs; this.ssim = ssim; + this.fallbackDetails = fallbackDetails; this.testException = testException; this.analysisException = analysisException; this.throughputFps = diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java index a40f20e3cd..e98427886f 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java @@ -24,6 +24,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.Uri; import androidx.annotation.Nullable; +import androidx.media3.common.C; import androidx.media3.common.MediaItem; import androidx.media3.common.util.Log; import androidx.media3.common.util.SystemClock; @@ -36,7 +37,6 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.checkerframework.checker.nullness.compatqual.NullableType; import org.json.JSONObject; @@ -233,13 +233,14 @@ public class TransformerAndroidTestRunner { + mediaItemUri); } + AtomicReference<@NullableType FallbackDetails> fallbackDetailsReference = + new AtomicReference<>(); AtomicReference<@NullableType TransformationException> transformationExceptionReference = new AtomicReference<>(); AtomicReference<@NullableType Exception> unexpectedExceptionReference = new AtomicReference<>(); AtomicReference<@NullableType TransformationResult> transformationResultReference = new AtomicReference<>(); CountDownLatch countDownLatch = new CountDownLatch(1); - AtomicBoolean fallbackResolutionApplied = new AtomicBoolean(false); long startTimeMs = SystemClock.DEFAULT.elapsedRealtime(); Transformer testTransformer = @@ -272,10 +273,16 @@ public class TransformerAndroidTestRunner { // Note: As TransformationRequest only reports the output height but not the // output width, it's not possible to check whether the encoder has changed // the output aspect ratio. - if (originalTransformationRequest.outputHeight - != fallbackTransformationRequest.outputHeight) { - fallbackResolutionApplied.set(true); - } + fallbackDetailsReference.set( + new FallbackDetails( + originalTransformationRequest.outputHeight, + fallbackTransformationRequest.outputHeight, + originalTransformationRequest.audioMimeType, + fallbackTransformationRequest.audioMimeType, + originalTransformationRequest.videoMimeType, + fallbackTransformationRequest.videoMimeType, + originalTransformationRequest.hdrMode, + fallbackTransformationRequest.hdrMode)); } }) .build(); @@ -318,6 +325,7 @@ public class TransformerAndroidTestRunner { if (testException != null) { return new TransformationTestResult.Builder(checkNotNull(transformationResultReference.get())) .setElapsedTimeMs(elapsedTimeMs) + .setFallbackDetails(fallbackDetailsReference.get()) .setTestException(testException) .build(); } @@ -330,12 +338,14 @@ public class TransformerAndroidTestRunner { .setFileSizeBytes(outputVideoFile.length()) .build()) .setElapsedTimeMs(elapsedTimeMs) + .setFallbackDetails(fallbackDetailsReference.get()) .setFilePath(outputVideoFile.getPath()); if (!requestCalculateSsim) { return testResultBuilder.build(); } - if (fallbackResolutionApplied.get()) { + if (fallbackDetailsReference.get() != null + && checkNotNull(fallbackDetailsReference.get()).fallbackOutputHeight != C.LENGTH_UNSET) { Log.i( TAG, testId