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
This commit is contained in:
Googler 2025-02-11 06:42:25 -08:00 committed by Copybara-Service
parent 1b882fec0c
commit 447d784636
3 changed files with 6 additions and 53 deletions

View File

@ -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<MediaCodecInfo> 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.

View File

@ -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);
}

View File

@ -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.