Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try input format PCM encoding first in MediaCodecAudioRenderer #2218

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2241,6 +2241,52 @@ public static boolean isEncodingHighResolutionPcm(@C.PcmEncoding int encoding) {
|| encoding == C.ENCODING_PCM_FLOAT;
}

/**
* Returns the closest platform PCM encodings supported on the current API level for
* {@code encoding}. The results never include 16-bit PCM, which should be used if none of the
* suggested formats can be used for playback.
*
* @param encoding The encoding of the audio data.
* @return The closest platform encodings, sorted by descending order of preference. May be empty.
*/
@UnstableApi
public static int[] getClosestPlatformPcmEncodings(@C.PcmEncoding int encoding) {
switch (encoding) {
case C.ENCODING_PCM_FLOAT:
return Util.SDK_INT >= 31
? new int[] {
AudioFormat.ENCODING_PCM_FLOAT,
AudioFormat.ENCODING_PCM_32BIT,
AudioFormat.ENCODING_PCM_24BIT_PACKED
}
: new int[] {AudioFormat.ENCODING_PCM_FLOAT};
case C.ENCODING_PCM_32BIT:
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
return Util.SDK_INT >= 31
? new int[] {
AudioFormat.ENCODING_PCM_32BIT,
AudioFormat.ENCODING_PCM_FLOAT,
AudioFormat.ENCODING_PCM_24BIT_PACKED
}
: new int[] {AudioFormat.ENCODING_PCM_FLOAT};
case C.ENCODING_PCM_24BIT:
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
return Util.SDK_INT >= 31
? new int[] {
AudioFormat.ENCODING_PCM_24BIT_PACKED,
AudioFormat.ENCODING_PCM_32BIT,
AudioFormat.ENCODING_PCM_FLOAT
}
: new int[] {AudioFormat.ENCODING_PCM_FLOAT};
case C.ENCODING_PCM_8BIT:
return new int[] {AudioFormat.ENCODING_PCM_8BIT};
case C.ENCODING_PCM_16BIT:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
default:
return new int[] {};
}
}

/**
* Returns the audio track channel configuration for the given channel count, or {@link
* AudioFormat#CHANNEL_INVALID} if output is not possible.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
Expand Down Expand Up @@ -334,14 +333,38 @@ public String getName() {
}
// If the input is PCM then it will be passed directly to the sink. Hence the sink must support
// the input format directly.
if (MimeTypes.AUDIO_RAW.equals(format.sampleMimeType) && !audioSink.supportsFormat(format)) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
}
// For all other input formats, we expect the decoder to output 16-bit PCM.
if (!audioSink.supportsFormat(
Util.getPcmFormat(C.ENCODING_PCM_16BIT, format.channelCount, format.sampleRate))) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
if (MimeTypes.AUDIO_RAW.equals(format.sampleMimeType)) {
if (!audioSink.supportsFormat(format)) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
}
} else {
// For all other input formats, MediaCodec can do some conversions for us. Check if the sink
// supports any of the formats we can get out of MediaCodec.
boolean pcmEncodingSupported = false;
// On API levels before 24, any non-PCM input format is decoded to 16-bit PCM.
if (Util.SDK_INT >= 24) {
int[] platformEncodings = Util.getClosestPlatformPcmEncodings(format.pcmEncoding);
for (int platformEncoding : platformEncodings) {
if (audioSink.getFormatSupport(
Util.getPcmFormat(platformEncoding, format.channelCount, format.sampleRate))
== AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY) {
pcmEncodingSupported = true;
break;
}
}
}
// If none of the suggested encodings are supported, fall back to MediaCodec's default value
// of 16-bit PCM.
if (!pcmEncodingSupported
&& audioSink.supportsFormat(
Util.getPcmFormat(C.ENCODING_PCM_16BIT, format.channelCount, format.sampleRate))) {
pcmEncodingSupported = true;
}
if (!pcmEncodingSupported) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
}
}

List<MediaCodecInfo> decoderInfos =
getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */ false, audioSink);
if (decoderInfos.isEmpty()) {
Expand Down Expand Up @@ -1005,11 +1028,18 @@ protected MediaFormat getMediaFormat(
// not sync frames. Set a format key to override this.
mediaFormat.setInteger("ac4-is-sync", 1);
}
if (Util.SDK_INT >= 24
&& audioSink.getFormatSupport(
Util.getPcmFormat(C.ENCODING_PCM_FLOAT, format.channelCount, format.sampleRate))
if (Util.SDK_INT >= 24) {
int[] platformEncodings = Util.getClosestPlatformPcmEncodings(format.pcmEncoding);
for (int platformEncoding : platformEncodings) {
if (audioSink.getFormatSupport(
Util.getPcmFormat(platformEncoding, format.channelCount, format.sampleRate))
== AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY) {
mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_FLOAT);
mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, platformEncoding);
break;
}
}
// If none of the suggested encodings are supported, fall back to MediaCodec's default value
// of 16-bit PCM.
}
if (Util.SDK_INT >= 32) {
mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99);
Expand Down