From 447d784636c5829b37efc147167a564d9edca685 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 11 Feb 2025 06:42:25 -0800 Subject: [PATCH] Use encoder input format for sample rate fallback. This ensures that when the input sample rate handled by the encoder differs from the output of the AudioGraph, that output audio will not be broken. PiperOrigin-RevId: 725610384 --- .../media3/transformer/AndroidTestUtil.java | 36 ------------------- .../transformer/TransformerEndToEndTest.java | 21 +++-------- .../transformer/AudioSampleExporter.java | 2 +- 3 files changed, 6 insertions(+), 53 deletions(-) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java index 4ca97f0a1a..ce966883a5 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java @@ -1370,42 +1370,6 @@ public final class AndroidTestUtil { throw new AssumptionViolatedException("Profile not supported"); } - /** - * Assumes that the given sample rate is unsupported and returns the fallback sample rate the - * device will use to encode. - * - * @param mimeType The {@linkplain MimeTypes MIME type}. - * @param unsupportedSampleRate An unsupported sample rate. - * @return The fallback sample rate. - * @throws AssumptionViolatedException If the device does not have the required encoder or sample - * rate configuration. - */ - public static int getFallbackAssumingUnsupportedSampleRate( - String mimeType, int unsupportedSampleRate) { - ImmutableList supportedEncoders = EncoderUtil.getSupportedEncoders(mimeType); - if (supportedEncoders.isEmpty()) { - throw new AssumptionViolatedException("No supported encoders for mime type: " + mimeType); - } - - int closestSupportedSampleRate = -1; - int minSampleRateCost = Integer.MAX_VALUE; - for (int i = 0; i < supportedEncoders.size(); i++) { - int actualFallbackSampleRate = - EncoderUtil.getClosestSupportedSampleRate( - supportedEncoders.get(i), mimeType, unsupportedSampleRate); - int sampleRateCost = Math.abs(actualFallbackSampleRate - unsupportedSampleRate); - if (sampleRateCost < minSampleRateCost) { - minSampleRateCost = sampleRateCost; - closestSupportedSampleRate = actualFallbackSampleRate; - } - } - if (closestSupportedSampleRate == unsupportedSampleRate) { - throw new AssumptionViolatedException( - String.format("Expected sample rate %s to be unsupported", unsupportedSampleRate)); - } - return closestSupportedSampleRate; - } - /** Returns a {@link Muxer.Factory} depending upon the API level. */ public static Muxer.Factory getMuxerFactoryBasedOnApi() { // MediaMuxer supports B-frame from API > 24. diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java index 7051011e03..c895bb8506 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -45,7 +45,6 @@ import static androidx.media3.transformer.AndroidTestUtil.assumeFormatsSupported import static androidx.media3.transformer.AndroidTestUtil.createFrameCountingEffect; import static androidx.media3.transformer.AndroidTestUtil.createOpenGlObjects; import static androidx.media3.transformer.AndroidTestUtil.generateTextureFromBitmap; -import static androidx.media3.transformer.AndroidTestUtil.getFallbackAssumingUnsupportedSampleRate; import static androidx.media3.transformer.AndroidTestUtil.getMuxerFactoryBasedOnApi; import static androidx.media3.transformer.AndroidTestUtil.recordTestSkipped; import static androidx.media3.transformer.ExportResult.CONVERSION_PROCESS_NA; @@ -119,7 +118,6 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; @@ -2430,12 +2428,8 @@ public class TransformerEndToEndTest { } @Test - @Ignore("TODO: b/389068218 - Fix this test and re-enable it") - public void export_withUnsupportedSampleRateAndFallbackEnabled_exportsWithFallbackSampleRate() + public void export_withHighSampleRateAndFallbackEnabled_exportsWithCorrectDuration() throws Exception { - int unsupportedSampleRate = 96_000; - int fallbackSampleRate = - getFallbackAssumingUnsupportedSampleRate(MimeTypes.AUDIO_AAC, unsupportedSampleRate); Transformer transformer = new Transformer.Builder(context) .setEncoderFactory( @@ -2451,19 +2445,14 @@ public class TransformerEndToEndTest { .build() .run(testId, editedMediaItem); - assertThat(result.exportResult.sampleRate).isEqualTo(fallbackSampleRate); + // The original clip is 1 second long. assertThat(result.exportResult.durationMs).isWithin(50).of(1_000); assertThat(new File(result.filePath).length()).isGreaterThan(0); } @Test - @Ignore("TODO: b/389068218 - Fix this test and re-enable it") - public void - export_withTwoUnsupportedAndOneSupportedSampleRateAndFallbackEnabled_exportsWithFallbackSampleRate() - throws Exception { - int unsupportedSampleRate = 192_000; - int fallbackSampleRate = - getFallbackAssumingUnsupportedSampleRate(MimeTypes.AUDIO_AAC, unsupportedSampleRate); + public void export_withMultipleHighSampleRatesAndFallbackEnabled_exportsWithCorrectDuration() + throws Exception { Transformer transformer = new Transformer.Builder(context) .setEncoderFactory( @@ -2488,7 +2477,7 @@ public class TransformerEndToEndTest { .build() .run(testId, composition); - assertThat(result.exportResult.sampleRate).isEqualTo(fallbackSampleRate); + // Each original clip is 1 second long. assertThat(result.exportResult.durationMs).isWithin(150).of(3_000); assertThat(new File(result.filePath).length()).isGreaterThan(0); } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSampleExporter.java b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSampleExporter.java index 77df472270..5a246d7e74 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSampleExporter.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSampleExporter.java @@ -98,7 +98,7 @@ import org.checkerframework.dataflow.qual.Pure; muxerWrapper.getSupportedSampleMimeTypes(C.TRACK_TYPE_AUDIO))) .build()); - AudioFormat actualEncoderAudioFormat = new AudioFormat(encoder.getConfigurationFormat()); + AudioFormat actualEncoderAudioFormat = new AudioFormat(encoder.getInputFormat()); // This occurs when the encoder does not support the requested format. In this case, the audio // graph output needs to be resampled to a sample rate matching the encoder input to avoid // distorted audio.