diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java index 045ad5ac69..dbd1aa4e06 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java @@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.decoder.DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT; import static androidx.media3.decoder.DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED; +import static androidx.media3.transformer.DefaultCodec.DEFAULT_PCM_ENCODING; import static java.lang.Math.min; import androidx.annotation.Nullable; @@ -92,13 +93,14 @@ import org.checkerframework.dataflow.qual.Pure; } audioProcessingPipeline = new AudioProcessingPipeline(audioProcessors); + // TODO(b/267301878): Once decoder format propagated, remove setting default PCM encoding. AudioFormat pipelineInputAudioFormat = new AudioFormat( firstInputFormat.sampleRate, firstInputFormat.channelCount, - // The decoder uses ENCODING_PCM_16BIT by default. - // https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers - C.ENCODING_PCM_16BIT); + firstInputFormat.pcmEncoding != Format.NO_VALUE + ? firstInputFormat.pcmEncoding + : DEFAULT_PCM_ENCODING); try { encoderInputAudioFormat = audioProcessingPipeline.configure(pipelineInputAudioFormat); @@ -117,6 +119,7 @@ import org.checkerframework.dataflow.qual.Pure; : checkNotNull(firstInputFormat.sampleMimeType)) .setSampleRate(encoderInputAudioFormat.sampleRate) .setChannelCount(encoderInputAudioFormat.channelCount) + .setPcmEncoding(encoderInputAudioFormat.encoding) .setAverageBitrate(DEFAULT_ENCODER_BITRATE) .build(); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java index 68a1d283b4..c4a82346b8 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java @@ -52,13 +52,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** A default {@link Codec} implementation that uses {@link MediaCodec}. */ @UnstableApi public final class DefaultCodec implements Codec { + // MediaCodec decoders output 16 bit PCM, unless configured to output PCM float. + // https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers. + public static final int DEFAULT_PCM_ENCODING = C.ENCODING_PCM_16BIT; private static final String TAG = "DefaultCodec"; - // MediaCodec decoders always output 16 bit PCM, unless configured to output PCM float. - // https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers. - private static final int MEDIA_CODEC_PCM_ENCODING = C.ENCODING_PCM_16BIT; - private final BufferInfo outputBufferInfo; /** The {@link MediaFormat} used to configure the underlying {@link MediaCodec}. */ private final MediaFormat configurationMediaFormat; @@ -325,7 +324,7 @@ public final class DefaultCodec implements Codec { } if (outputBufferIndex < 0) { if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { - outputFormat = convertToFormat(mediaCodec.getOutputFormat()); + outputFormat = convertToFormat(mediaCodec.getOutputFormat(), isDecoder); ColorInfo expectedColorInfo = isSdrToneMappingEnabled(configurationMediaFormat) ? ColorInfo.SDR_BT709_LIMITED @@ -402,7 +401,7 @@ public final class DefaultCodec implements Codec { return transfer1 == transfer2; } - private static Format convertToFormat(MediaFormat mediaFormat) { + private static Format convertToFormat(MediaFormat mediaFormat, boolean isDecoder) { ImmutableList.Builder csdBuffers = new ImmutableList.Builder<>(); int csdIndex = 0; while (true) { @@ -424,12 +423,22 @@ public final class DefaultCodec implements Codec { .setHeight(mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)) .setColorInfo(MediaFormatUtil.getColorInfo(mediaFormat)); } else if (MimeTypes.isAudio(mimeType)) { - // TODO(b/178685617): Only set the PCM encoding for audio/raw, once we have a way to - // simulate more realistic codec input/output formats in tests. formatBuilder .setChannelCount(mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)) - .setSampleRate(mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)) - .setPcmEncoding(MEDIA_CODEC_PCM_ENCODING); + .setSampleRate(mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)); + + if (SDK_INT >= 24 && mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)) { + formatBuilder.setPcmEncoding(mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING)); + } else if (isDecoder) { + // TODO(b/178685617): Restrict this to only set the PCM encoding for audio/raw once we have + // a way to simulate more realistic codec input/output formats in tests. + + // With Robolectric, codecs do not actually encode/decode. The format of buffers is passed + // through. However downstream components need to know the PCM encoding of the data being + // output, so if a decoder is not outputting raw audio, we need to set the PCM + // encoding to the default. + formatBuilder.setPcmEncoding(DEFAULT_PCM_ENCODING); + } } return formatBuilder.build(); }