diff --git a/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java b/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java index 5448e94949..e108bd4e25 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java @@ -25,6 +25,7 @@ import androidx.media3.common.C; import androidx.media3.common.ColorInfo; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; +import com.google.common.collect.ImmutableList; import java.nio.ByteBuffer; import java.util.List; @@ -65,6 +66,70 @@ public final class MediaFormatUtil { private static final int MAX_POWER_OF_TWO_INT = 1 << 30; + /** Returns a {@link Format} representing the given {@link MediaFormat}. */ + @SuppressLint("InlinedApi") // Inlined MediaFormat keys. + public static Format createFormatFromMediaFormat(MediaFormat mediaFormat) { + Format.Builder formatBuilder = + new Format.Builder() + .setSampleMimeType(mediaFormat.getString(MediaFormat.KEY_MIME)) + .setLanguage(mediaFormat.getString(MediaFormat.KEY_LANGUAGE)) + .setPeakBitrate( + getInteger(mediaFormat, KEY_MAX_BIT_RATE, /* defaultValue= */ Format.NO_VALUE)) + .setAverageBitrate( + getInteger( + mediaFormat, MediaFormat.KEY_BIT_RATE, /* defaultValue= */ Format.NO_VALUE)) + .setCodecs(mediaFormat.getString(MediaFormat.KEY_CODECS_STRING)) + .setFrameRate(getFrameRate(mediaFormat, /* defaultValue= */ Format.NO_VALUE)) + .setWidth( + getInteger(mediaFormat, MediaFormat.KEY_WIDTH, /* defaultValue= */ Format.NO_VALUE)) + .setHeight( + getInteger( + mediaFormat, MediaFormat.KEY_HEIGHT, /* defaultValue= */ Format.NO_VALUE)) + .setPixelWidthHeightRatio( + getPixelWidthHeightRatio(mediaFormat, /* defaultValue= */ 1.0f)) + .setMaxInputSize( + getInteger( + mediaFormat, + MediaFormat.KEY_MAX_INPUT_SIZE, + /* defaultValue= */ Format.NO_VALUE)) + .setRotationDegrees( + getInteger(mediaFormat, MediaFormat.KEY_ROTATION, /* defaultValue= */ 0)) + // TODO(b/278101856): Disallow invalid values after confirming. + .setColorInfo(getColorInfo(mediaFormat, /* allowInvalidValues= */ true)) + .setSampleRate( + getInteger( + mediaFormat, MediaFormat.KEY_SAMPLE_RATE, /* defaultValue= */ Format.NO_VALUE)) + .setChannelCount( + getInteger( + mediaFormat, + MediaFormat.KEY_CHANNEL_COUNT, + /* defaultValue= */ Format.NO_VALUE)) + .setPcmEncoding( + getInteger( + mediaFormat, + MediaFormat.KEY_PCM_ENCODING, + /* defaultValue= */ Format.NO_VALUE)); + + ImmutableList.Builder csdBuffers = new ImmutableList.Builder<>(); + int csdIndex = 0; + while (true) { + @Nullable ByteBuffer csdByteBuffer = mediaFormat.getByteBuffer("csd-" + csdIndex); + if (csdByteBuffer == null) { + break; + } + byte[] csdBufferData = new byte[csdByteBuffer.remaining()]; + csdByteBuffer.get(csdBufferData); + csdByteBuffer.rewind(); + + csdBuffers.add(csdBufferData); + csdIndex++; + } + + formatBuilder.setInitializationData(csdBuffers.build()); + + return formatBuilder.build(); + } + /** * Returns a {@link MediaFormat} representing the given ExoPlayer {@link Format}. * @@ -203,6 +268,13 @@ public final class MediaFormatUtil { */ @Nullable public static ColorInfo getColorInfo(MediaFormat mediaFormat) { + return getColorInfo(mediaFormat, /* allowInvalidValues= */ false); + } + + // Internal methods. + + @Nullable + private static ColorInfo getColorInfo(MediaFormat mediaFormat, boolean allowInvalidValues) { if (SDK_INT < 24) { // MediaFormat KEY_COLOR_TRANSFER and other KEY_COLOR values available from API 24. return null; @@ -220,16 +292,19 @@ public final class MediaFormatUtil { @Nullable byte[] hdrStaticInfo = hdrStaticInfoByteBuffer != null ? getArray(hdrStaticInfoByteBuffer) : null; - // Some devices may produce invalid values from MediaFormat#getInteger. - // See b/239435670 for more information. - if (!isValidColorSpace(colorSpace)) { - colorSpace = Format.NO_VALUE; - } - if (!isValidColorRange(colorRange)) { - colorRange = Format.NO_VALUE; - } - if (!isValidColorTransfer(colorTransfer)) { - colorTransfer = Format.NO_VALUE; + + if (!allowInvalidValues) { + // Some devices may produce invalid values from MediaFormat#getInteger. + // See b/239435670 for more information. + if (!isValidColorSpace(colorSpace)) { + colorSpace = Format.NO_VALUE; + } + if (!isValidColorRange(colorRange)) { + colorRange = Format.NO_VALUE; + } + if (!isValidColorTransfer(colorTransfer)) { + colorTransfer = Format.NO_VALUE; + } } if (colorSpace != Format.NO_VALUE @@ -246,16 +321,47 @@ public final class MediaFormatUtil { return null; } - /** - * Provides the same functionality as {@link MediaFormat#getInteger(String, int)}. - * - *

{@link MediaFormat#getInteger(String, int)} is only available from API 29. This convenience - * method provides support on lower API versions. - */ + /** Supports {@link MediaFormat#getInteger(String, int)} for {@code API < 29}. */ public static int getInteger(MediaFormat mediaFormat, String name, int defaultValue) { return mediaFormat.containsKey(name) ? mediaFormat.getInteger(name) : defaultValue; } + /** Supports {@link MediaFormat#getFloat(String, float)} for {@code API < 29}. */ + public static float getFloat(MediaFormat mediaFormat, String name, float defaultValue) { + return mediaFormat.containsKey(name) ? mediaFormat.getFloat(name) : defaultValue; + } + + /** + * Returns the frame rate from a {@link MediaFormat}. + * + *

The {@link MediaFormat#KEY_FRAME_RATE} can have both integer and float value so it returns + * which ever value is set. + */ + private static float getFrameRate(MediaFormat mediaFormat, float defaultValue) { + float frameRate = defaultValue; + if (mediaFormat.containsKey(MediaFormat.KEY_FRAME_RATE)) { + try { + frameRate = mediaFormat.getFloat(MediaFormat.KEY_FRAME_RATE); + } catch (ClassCastException ex) { + frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE); + } + } + return frameRate; + } + + /** Returns the ratio between a pixel's width and height for a {@link MediaFormat}. */ + // Inlined MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH and MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT. + @SuppressLint("InlinedApi") + private static float getPixelWidthHeightRatio(MediaFormat mediaFormat, float defaultValue) { + if (mediaFormat.containsKey(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH) + && mediaFormat.containsKey(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT)) { + return (float) mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH) + / (float) mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT); + } + + return defaultValue; + } + public static byte[] getArray(ByteBuffer byteBuffer) { byte[] array = new byte[byteBuffer.remaining()]; byteBuffer.get(array); diff --git a/libraries/common/src/test/java/androidx/media3/common/util/MediaFormatUtilTest.java b/libraries/common/src/test/java/androidx/media3/common/util/MediaFormatUtilTest.java index c38abc7009..c6440562bf 100644 --- a/libraries/common/src/test/java/androidx/media3/common/util/MediaFormatUtilTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/util/MediaFormatUtilTest.java @@ -24,12 +24,96 @@ import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.ImmutableList; +import java.nio.ByteBuffer; import org.junit.Test; import org.junit.runner.RunWith; /** Unit tests for {@link MediaFormatUtil}. */ @RunWith(AndroidJUnit4.class) public class MediaFormatUtilTest { + @Test + public void createFormatFromMediaFormat_withEmptyMap_generatesExpectedFormat() { + Format format = MediaFormatUtil.createFormatFromMediaFormat(new MediaFormat()); + + assertThat(format.sampleMimeType).isNull(); + assertThat(format.language).isNull(); + assertThat(format.peakBitrate).isEqualTo(Format.NO_VALUE); + assertThat(format.averageBitrate).isEqualTo(Format.NO_VALUE); + assertThat(format.codecs).isNull(); + assertThat(format.frameRate).isEqualTo(Format.NO_VALUE); + assertThat(format.width).isEqualTo(Format.NO_VALUE); + assertThat(format.height).isEqualTo(Format.NO_VALUE); + assertThat(format.pixelWidthHeightRatio).isEqualTo(1.0f); + assertThat(format.maxInputSize).isEqualTo(Format.NO_VALUE); + assertThat(format.rotationDegrees).isEqualTo(0); + assertThat(format.colorInfo).isNull(); + assertThat(format.sampleRate).isEqualTo(Format.NO_VALUE); + assertThat(format.channelCount).isEqualTo(Format.NO_VALUE); + assertThat(format.pcmEncoding).isEqualTo(Format.NO_VALUE); + assertThat(format.initializationData).isEmpty(); + } + + @Test + public void createFormatFromMediaFormat_withPopulatedMap_generatesExpectedFormat() { + MediaFormat mediaFormat = new MediaFormat(); + mediaFormat.setString(MediaFormat.KEY_MIME, MimeTypes.VIDEO_H264); + mediaFormat.setString(MediaFormat.KEY_LANGUAGE, "eng"); + mediaFormat.setInteger(MediaFormatUtil.KEY_MAX_BIT_RATE, 128000); + mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 128000); + mediaFormat.setString(MediaFormat.KEY_CODECS_STRING, "avc.123"); + mediaFormat.setFloat(MediaFormat.KEY_FRAME_RATE, 4); + mediaFormat.setInteger(MediaFormat.KEY_WIDTH, 10); + mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, 8); + mediaFormat.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH, 15); + mediaFormat.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT, 5); + mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 10); + mediaFormat.setInteger(MediaFormat.KEY_ROTATION, 90); + mediaFormat.setInteger(MediaFormat.KEY_COLOR_STANDARD, C.COLOR_SPACE_BT601); + mediaFormat.setInteger(MediaFormat.KEY_COLOR_TRANSFER, C.COLOR_TRANSFER_HLG); + mediaFormat.setInteger(MediaFormat.KEY_COLOR_RANGE, C.COLOR_RANGE_FULL); + mediaFormat.setByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, ByteBuffer.wrap(new byte[] {3})); + mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 11); + mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2); + mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, C.ENCODING_PCM_8BIT); + mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(new byte[] {7})); + mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(new byte[] {10})); + + Format format = MediaFormatUtil.createFormatFromMediaFormat(mediaFormat); + + assertThat(format.sampleMimeType).isEqualTo(mediaFormat.getString(MediaFormat.KEY_MIME)); + // Format stores normalized language code. + assertThat(format.language) + .isEqualTo(Util.normalizeLanguageCode(mediaFormat.getString(MediaFormat.KEY_LANGUAGE))); + assertThat(format.peakBitrate) + .isEqualTo(mediaFormat.getInteger(MediaFormatUtil.KEY_MAX_BIT_RATE)); + assertThat(format.averageBitrate).isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_BIT_RATE)); + assertThat(format.codecs).isEqualTo(mediaFormat.getString(MediaFormat.KEY_CODECS_STRING)); + assertThat(format.frameRate).isEqualTo(mediaFormat.getFloat(MediaFormat.KEY_FRAME_RATE)); + assertThat(format.width).isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_WIDTH)); + assertThat(format.height).isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)); + // Ratio of MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH (15) and + // MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT (5). + assertThat(format.pixelWidthHeightRatio).isEqualTo(3.0f); + assertThat(format.maxInputSize) + .isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)); + assertThat(format.rotationDegrees).isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_ROTATION)); + assertThat(format.colorInfo.colorSpace) + .isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_COLOR_STANDARD)); + assertThat(format.colorInfo.colorTransfer) + .isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_COLOR_TRANSFER)); + assertThat(format.colorInfo.colorRange) + .isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_COLOR_RANGE)); + assertThat(format.colorInfo.hdrStaticInfo) + .isEqualTo(mediaFormat.getByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO).array()); + assertThat(format.sampleRate).isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)); + assertThat(format.channelCount) + .isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)); + assertThat(format.pcmEncoding).isEqualTo(mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING)); + assertThat(format.initializationData.get(0)) + .isEqualTo(mediaFormat.getByteBuffer("csd-0").array()); + assertThat(format.initializationData.get(1)) + .isEqualTo(mediaFormat.getByteBuffer("csd-1").array()); + } @Test public void createMediaFormatFromFormat_withEmptyFormat_generatesExpectedEntries() { @@ -146,7 +230,7 @@ public class MediaFormatUtilTest { } @Test - public void createMediaFormatFromFormat_withPcmEncoding_setsCustomPcmEncodingEntry() { + public void createMediaFormatFromFormat_withCustomPcmEncoding_setsCustomPcmEncodingEntry() { Format format = new Format.Builder().setPcmEncoding(C.ENCODING_PCM_16BIT_BIG_ENDIAN).build(); MediaFormat mediaFormat = MediaFormatUtil.createMediaFormatFromFormat(format); assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_PCM_ENCODING_EXTENDED)) diff --git a/libraries/test_data/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump b/libraries/test_data/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump index 7d93cbcbc3..b456a46c27 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump @@ -10,6 +10,7 @@ format 0: data = length 30, hash F6F3D010 data = length 10, hash 7A0D0F2B format 1: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 1 sampleRate = 44100 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.48000hz.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.48000hz.dump index 857f079acb..30e350bbe2 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.48000hz.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.48000hz.dump @@ -12,6 +12,7 @@ format 0: data = length 10, hash 7A0D0F2B container metadata = entries=[xyz: latitude=40.68, longitude=-74.5] format 1: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 1 sampleRate = 48000 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.concatenated_with_high_pitch_and_no_video.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.concatenated_with_high_pitch_and_no_video.dump index d3e35758f1..5f69045593 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.concatenated_with_high_pitch_and_no_video.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.concatenated_with_high_pitch_and_no_video.dump @@ -1,4 +1,5 @@ format 0: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 1 sampleRate = 44100 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio.dump index bea16f1540..a6aca6316b 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio.dump @@ -12,6 +12,7 @@ format 0: data = length 10, hash 7A0D0F2B container metadata = entries=[xyz: latitude=40.68, longitude=-74.5] format 1: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 2 sampleRate = 44100 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio_with_effects.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio_with_effects.dump index ffba5df91a..22e1eef153 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio_with_effects.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silence_then_audio_with_effects.dump @@ -12,6 +12,7 @@ format 0: data = length 10, hash 7A0D0F2B container metadata = entries=[xyz: latitude=40.68, longitude=-74.5] format 1: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 2 sampleRate = 44100 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silentaudio.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silentaudio.dump index 67ab03c944..864b194711 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silentaudio.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample.mp4.silentaudio.dump @@ -12,6 +12,7 @@ format 0: data = length 10, hash 7A0D0F2B container metadata = entries=[xyz: latitude=40.68, longitude=-74.5] format 1: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 2 sampleRate = 44100 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_18byte_nclx_colr.mp4.silentaudio.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_18byte_nclx_colr.mp4.silentaudio.dump index b3520a0e2e..6dfa0e6720 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_18byte_nclx_colr.mp4.silentaudio.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_18byte_nclx_colr.mp4.silentaudio.dump @@ -15,6 +15,7 @@ format 0: data = length 29, hash 4746B5D9 data = length 10, hash 7A0D0F2B format 1: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 2 sampleRate = 44100 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_ac3.mp4.fallback.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_ac3.mp4.fallback.dump index 0bbdc51b48..ca5a7656c8 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_ac3.mp4.fallback.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_ac3.mp4.fallback.dump @@ -1,4 +1,5 @@ format 0: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 6 sampleRate = 48000 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump index 1b78285dc9..a2116c6683 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump @@ -12,6 +12,7 @@ format 0: data = length 10, hash 7A0D0F2B container metadata = entries=[mdta: key=com.android.capture.fps, value=43700000, smta: captureFrameRate=240.0, svcTemporalLayerCount=4, SlowMotion: segments=[Segment: startTimeMs=88, endTimeMs=879, speedDivisor=2, Segment: startTimeMs=1255, endTimeMs=1970, speedDivisor=8]] format 1: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 2 sampleRate = 12000 diff --git a/libraries/test_data/src/test/assets/transformerdumps/wav/sample.wav.aac.dump b/libraries/test_data/src/test/assets/transformerdumps/wav/sample.wav.aac.dump index 73c846c296..3441d39484 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/wav/sample.wav.aac.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/wav/sample.wav.aac.dump @@ -1,4 +1,5 @@ format 0: + averageBitrate = 131072 sampleMimeType = audio/mp4a-latm channelCount = 1 sampleRate = 44100 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 ee42c9156a..235a35e301 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java @@ -41,7 +41,6 @@ import androidx.media3.common.util.TraceUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.decoder.DecoderInputBuffer; -import com.google.common.collect.ImmutableList; import java.io.IOException; import java.nio.ByteBuffer; import org.checkerframework.checker.initialization.qual.UnknownInitialization; @@ -392,43 +391,17 @@ public final class DefaultCodec implements Codec { } private static Format convertToFormat(MediaFormat mediaFormat, boolean isDecoder) { - ImmutableList.Builder csdBuffers = new ImmutableList.Builder<>(); - int csdIndex = 0; - while (true) { - @Nullable ByteBuffer csdByteBuffer = mediaFormat.getByteBuffer("csd-" + csdIndex); - if (csdByteBuffer == null) { - break; - } - byte[] csdBufferData = new byte[csdByteBuffer.remaining()]; - csdByteBuffer.get(csdBufferData); - csdBuffers.add(csdBufferData); - csdIndex++; - } - String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME); Format.Builder formatBuilder = - new Format.Builder().setSampleMimeType(mimeType).setInitializationData(csdBuffers.build()); - if (MimeTypes.isVideo(mimeType)) { - formatBuilder - .setWidth(mediaFormat.getInteger(MediaFormat.KEY_WIDTH)) - .setHeight(mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)) - .setColorInfo(MediaFormatUtil.getColorInfo(mediaFormat)); - } else if (MimeTypes.isAudio(mimeType)) { - formatBuilder - .setChannelCount(mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)) - .setSampleRate(mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)); + MediaFormatUtil.createFormatFromMediaFormat(mediaFormat).buildUpon(); + 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. - 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); - } + // 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(); }