Include channel count in capabilities check

Issue: #4690

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=220640737
This commit is contained in:
andrewlewis 2018-11-08 08:18:44 -08:00 committed by Oliver Woodman
parent b5beb32618
commit d9462b9d2b
9 changed files with 46 additions and 30 deletions

View File

@ -1,5 +1,10 @@
# Release notes # # Release notes #
### 2.9.2 ###
* Include channel count in audio capabilities check
([#4690](https://github.com/google/ExoPlayer/issues/4690)).
### 2.9.1 ### ### 2.9.1 ###
* Add convenience methods `Player.next`, `Player.previous`, `Player.hasNext` * Add convenience methods `Player.next`, `Player.previous`, `Player.hasNext`

View File

@ -145,12 +145,13 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
} }
private boolean isOutputSupported(Format inputFormat) { private boolean isOutputSupported(Format inputFormat) {
return shouldUseFloatOutput(inputFormat) || supportsOutputEncoding(C.ENCODING_PCM_16BIT); return shouldUseFloatOutput(inputFormat)
|| supportsOutput(inputFormat.channelCount, C.ENCODING_PCM_16BIT);
} }
private boolean shouldUseFloatOutput(Format inputFormat) { private boolean shouldUseFloatOutput(Format inputFormat) {
Assertions.checkNotNull(inputFormat.sampleMimeType); Assertions.checkNotNull(inputFormat.sampleMimeType);
if (!enableFloatOutput || !supportsOutputEncoding(C.ENCODING_PCM_FLOAT)) { if (!enableFloatOutput || !supportsOutput(inputFormat.channelCount, C.ENCODING_PCM_FLOAT)) {
return false; return false;
} }
switch (inputFormat.sampleMimeType) { switch (inputFormat.sampleMimeType) {

View File

@ -53,7 +53,7 @@ public class LibflacAudioRenderer extends SimpleDecoderAudioRenderer {
if (!FlacLibrary.isAvailable() if (!FlacLibrary.isAvailable()
|| !MimeTypes.AUDIO_FLAC.equalsIgnoreCase(format.sampleMimeType)) { || !MimeTypes.AUDIO_FLAC.equalsIgnoreCase(format.sampleMimeType)) {
return FORMAT_UNSUPPORTED_TYPE; return FORMAT_UNSUPPORTED_TYPE;
} else if (!supportsOutputEncoding(C.ENCODING_PCM_16BIT)) { } else if (!supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) {
return FORMAT_UNSUPPORTED_SUBTYPE; return FORMAT_UNSUPPORTED_SUBTYPE;
} else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { } else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) {
return FORMAT_UNSUPPORTED_DRM; return FORMAT_UNSUPPORTED_DRM;

View File

@ -78,7 +78,7 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
if (!OpusLibrary.isAvailable() if (!OpusLibrary.isAvailable()
|| !MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType)) { || !MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType)) {
return FORMAT_UNSUPPORTED_TYPE; return FORMAT_UNSUPPORTED_TYPE;
} else if (!supportsOutputEncoding(C.ENCODING_PCM_16BIT)) { } else if (!supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) {
return FORMAT_UNSUPPORTED_SUBTYPE; return FORMAT_UNSUPPORTED_SUBTYPE;
} else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { } else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) {
return FORMAT_UNSUPPORTED_DRM; return FORMAT_UNSUPPORTED_DRM;

View File

@ -29,11 +29,11 @@ import java.util.Arrays;
@TargetApi(21) @TargetApi(21)
public final class AudioCapabilities { public final class AudioCapabilities {
/** private static final int DEFAULT_MAX_CHANNEL_COUNT = 8;
* The minimum audio capabilities supported by all devices.
*/ /** The minimum audio capabilities supported by all devices. */
public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES = public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES =
new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, 2); new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT);
/** /**
* Returns the current audio capabilities for the device. * Returns the current audio capabilities for the device.
@ -52,8 +52,10 @@ public final class AudioCapabilities {
if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) {
return DEFAULT_AUDIO_CAPABILITIES; return DEFAULT_AUDIO_CAPABILITIES;
} }
return new AudioCapabilities(intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS), return new AudioCapabilities(
intent.getIntExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, 0)); intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS),
intent.getIntExtra(
AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT));
} }
private final int[] supportedEncodings; private final int[] supportedEncodings;

View File

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio;
import android.media.AudioTrack; import android.media.AudioTrack;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -165,12 +166,13 @@ public interface AudioSink {
void setListener(Listener listener); void setListener(Listener listener);
/** /**
* Returns whether it's possible to play audio in the specified encoding. * Returns whether the sink supports the audio format.
* *
* @param encoding The audio encoding. * @param channelCount The number of channels, or {@link Format#NO_VALUE} if not known.
* @return Whether it's possible to play audio in the specified encoding. * @param encoding The audio encoding, or {@link Format#NO_VALUE} if not known.
* @return Whether the sink supports the audio format.
*/ */
boolean isEncodingSupported(@C.Encoding int encoding); boolean supportsOutput(int channelCount, @C.Encoding int encoding);
/** /**
* Returns the playback position in the stream starting at zero, in microseconds, or * Returns the playback position in the stream starting at zero, in microseconds, or

View File

@ -377,14 +377,18 @@ public final class DefaultAudioSink implements AudioSink {
} }
@Override @Override
public boolean isEncodingSupported(@C.Encoding int encoding) { public boolean supportsOutput(int channelCount, @C.Encoding int encoding) {
if (Util.isEncodingLinearPcm(encoding)) { if (Util.isEncodingLinearPcm(encoding)) {
// AudioTrack supports 16-bit integer PCM output in all platform API versions, and float // AudioTrack supports 16-bit integer PCM output in all platform API versions, and float
// output from platform API version 21 only. Other integer PCM encodings are resampled by this // output from platform API version 21 only. Other integer PCM encodings are resampled by this
// sink to 16-bit PCM. // sink to 16-bit PCM. We assume that the audio framework will downsample any number of
// channels to the output device's required number of channels.
return encoding != C.ENCODING_PCM_FLOAT || Util.SDK_INT >= 21; return encoding != C.ENCODING_PCM_FLOAT || Util.SDK_INT >= 21;
} else { } else {
return audioCapabilities != null && audioCapabilities.supportsEncoding(encoding); return audioCapabilities != null
&& audioCapabilities.supportsEncoding(encoding)
&& (channelCount == Format.NO_VALUE
|| channelCount <= audioCapabilities.getMaxChannelCount());
} }
} }
@ -415,7 +419,7 @@ public final class DefaultAudioSink implements AudioSink {
isInputPcm = Util.isEncodingLinearPcm(inputEncoding); isInputPcm = Util.isEncodingLinearPcm(inputEncoding);
shouldConvertHighResIntPcmToFloat = shouldConvertHighResIntPcmToFloat =
enableConvertHighResIntPcmToFloat enableConvertHighResIntPcmToFloat
&& isEncodingSupported(C.ENCODING_PCM_32BIT) && supportsOutput(channelCount, C.ENCODING_PCM_32BIT)
&& Util.isEncodingHighResolutionIntegerPcm(inputEncoding); && Util.isEncodingHighResolutionIntegerPcm(inputEncoding);
if (isInputPcm) { if (isInputPcm) {
pcmFrameSize = Util.getPcmFrameSize(inputEncoding, channelCount); pcmFrameSize = Util.getPcmFrameSize(inputEncoding, channelCount);

View File

@ -272,12 +272,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED; int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED;
boolean supportsFormatDrm = supportsFormatDrm(drmSessionManager, format.drmInitData); boolean supportsFormatDrm = supportsFormatDrm(drmSessionManager, format.drmInitData);
if (supportsFormatDrm && allowPassthrough(mimeType) if (supportsFormatDrm
&& allowPassthrough(format.channelCount, mimeType)
&& mediaCodecSelector.getPassthroughDecoderInfo() != null) { && mediaCodecSelector.getPassthroughDecoderInfo() != null) {
return ADAPTIVE_NOT_SEAMLESS | tunnelingSupport | FORMAT_HANDLED; return ADAPTIVE_NOT_SEAMLESS | tunnelingSupport | FORMAT_HANDLED;
} }
if ((MimeTypes.AUDIO_RAW.equals(mimeType) && !audioSink.isEncodingSupported(format.pcmEncoding)) if ((MimeTypes.AUDIO_RAW.equals(mimeType)
|| !audioSink.isEncodingSupported(C.ENCODING_PCM_16BIT)) { && !audioSink.supportsOutput(format.channelCount, format.pcmEncoding))
|| !audioSink.supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) {
// Assume the decoder outputs 16-bit PCM, unless the input is raw. // Assume the decoder outputs 16-bit PCM, unless the input is raw.
return FORMAT_UNSUPPORTED_SUBTYPE; return FORMAT_UNSUPPORTED_SUBTYPE;
} }
@ -316,7 +318,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
protected List<MediaCodecInfo> getDecoderInfos( protected List<MediaCodecInfo> getDecoderInfos(
MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder)
throws DecoderQueryException { throws DecoderQueryException {
if (allowPassthrough(format.sampleMimeType)) { if (allowPassthrough(format.channelCount, format.sampleMimeType)) {
MediaCodecInfo passthroughDecoderInfo = mediaCodecSelector.getPassthroughDecoderInfo(); MediaCodecInfo passthroughDecoderInfo = mediaCodecSelector.getPassthroughDecoderInfo();
if (passthroughDecoderInfo != null) { if (passthroughDecoderInfo != null) {
return Collections.singletonList(passthroughDecoderInfo); return Collections.singletonList(passthroughDecoderInfo);
@ -330,12 +332,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
* This implementation returns true if the {@link AudioSink} indicates that encoded audio output * This implementation returns true if the {@link AudioSink} indicates that encoded audio output
* is supported. * is supported.
* *
* @param channelCount The number of channels in the input media, or {@link Format#NO_VALUE} if
* not known.
* @param mimeType The type of input media. * @param mimeType The type of input media.
* @return Whether passthrough playback is supported. * @return Whether passthrough playback is supported.
*/ */
protected boolean allowPassthrough(String mimeType) { protected boolean allowPassthrough(int channelCount, String mimeType) {
@C.Encoding int encoding = MimeTypes.getEncoding(mimeType); return audioSink.supportsOutput(channelCount, MimeTypes.getEncoding(mimeType));
return encoding != C.ENCODING_INVALID && audioSink.isEncodingSupported(encoding);
} }
@Override @Override

View File

@ -249,13 +249,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
DrmSessionManager<ExoMediaCrypto> drmSessionManager, Format format); DrmSessionManager<ExoMediaCrypto> drmSessionManager, Format format);
/** /**
* Returns whether the audio sink can accept audio in the specified encoding. * Returns whether the sink supports the audio format.
* *
* @param encoding The audio encoding. * @see AudioSink#supportsOutput(int, int)
* @return Whether the audio sink can accept audio in the specified encoding.
*/ */
protected final boolean supportsOutputEncoding(@C.Encoding int encoding) { protected final boolean supportsOutput(int channelCount, @C.Encoding int encoding) {
return audioSink.isEncodingSupported(encoding); return audioSink.supportsOutput(channelCount, encoding);
} }
@Override @Override