diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java index f089c48f15..13f09f88df 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java @@ -90,8 +90,17 @@ public class DashRendererBuilder implements RendererBuilder, private static final int SECURITY_LEVEL_1 = 1; private static final int SECURITY_LEVEL_3 = 3; - private static final String AC_3_CODEC = "ac-3"; - private static final String E_AC_3_CODEC = "ec-3"; + /** + * Passthrough audio formats (encodings) in order of decreasing priority. + */ + private static final int[] PASSTHROUGH_ENCODINGS_PRIORITY = + new int[] {C.ENCODING_E_AC3, C.ENCODING_AC3}; + /** + * Passthrough audio codecs corresponding to the encodings in + * {@link #PASSTHROUGH_ENCODINGS_PRIORITY}. + */ + private static final String[] PASSTHROUGH_CODECS_PRIORITY = + new String[] {"ec-3", "ac-3"}; private final String userAgent; private final String url; @@ -252,13 +261,14 @@ public class DashRendererBuilder implements RendererBuilder, } // Build the audio chunk sources. - boolean haveAc3Tracks = false; List audioChunkSourceList = new ArrayList(); List audioTrackNameList = new ArrayList(); + int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; if (audioAdaptationSet != null) { DataSource audioDataSource = new UriDataSource(userAgent, bandwidthMeter); FormatEvaluator audioEvaluator = new FormatEvaluator.FixedEvaluator(); List audioRepresentations = audioAdaptationSet.representations; + List codecs = new ArrayList(); for (int i = 0; i < audioRepresentations.size(); i++) { Format format = audioRepresentations.get(i).format; audioTrackNameList.add(format.id + " (" + format.numChannels + "ch, " + @@ -266,16 +276,27 @@ public class DashRendererBuilder implements RendererBuilder, audioChunkSourceList.add(new DashChunkSource(manifestFetcher, audioAdaptationSetIndex, new int[] {i}, audioDataSource, audioEvaluator, LIVE_EDGE_LATENCY_MS, elapsedRealtimeOffset)); - haveAc3Tracks |= AC_3_CODEC.equals(format.codecs) || E_AC_3_CODEC.equals(format.codecs); + codecs.add(format.codecs); } - // Filter out non-AC-3 tracks if there is an AC-3 track, to avoid having to switch renderers. - if (haveAc3Tracks) { - for (int i = audioRepresentations.size() - 1; i >= 0; i--) { - Format format = audioRepresentations.get(i).format; - if (!AC_3_CODEC.equals(format.codecs) && !E_AC_3_CODEC.equals(format.codecs)) { - audioTrackNameList.remove(i); - audioChunkSourceList.remove(i); + + if (audioCapabilities != null) { + // If there are any passthrough audio encodings available, select the highest priority + // supported format (e.g. E-AC-3) and remove other tracks. + for (int i = 0; i < PASSTHROUGH_CODECS_PRIORITY.length; i++) { + String codec = PASSTHROUGH_CODECS_PRIORITY[i]; + int encoding = PASSTHROUGH_ENCODINGS_PRIORITY[i]; + if (codecs.indexOf(codec) == -1 || !audioCapabilities.supportsEncoding(encoding)) { + continue; } + + audioEncoding = encoding; + for (int j = audioRepresentations.size() - 1; j >= 0; j--) { + if (!audioRepresentations.get(j).format.codecs.equals(codec)) { + audioTrackNameList.remove(j); + audioChunkSourceList.remove(j); + } + } + break; } } } @@ -295,11 +316,8 @@ public class DashRendererBuilder implements RendererBuilder, SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, mainHandler, player, DemoPlayer.TYPE_AUDIO); - // TODO: There needs to be some logic to filter out non-AC3 tracks when selecting to use AC3. - boolean useAc3Passthrough = haveAc3Tracks && audioCapabilities != null - && (audioCapabilities.supportsAc3() || audioCapabilities.supportsEAc3()); audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, drmSessionManager, true, - mainHandler, player, useAc3Passthrough ? C.ENCODING_AC3 : AudioFormat.ENCODING_PCM_16BIT); + mainHandler, player, audioEncoding); } // Build the text chunk sources. diff --git a/library/src/main/java/com/google/android/exoplayer/C.java b/library/src/main/java/com/google/android/exoplayer/C.java index 9b75afdbbb..3c9c679000 100644 --- a/library/src/main/java/com/google/android/exoplayer/C.java +++ b/library/src/main/java/com/google/android/exoplayer/C.java @@ -56,6 +56,12 @@ public final class C { @SuppressWarnings("InlinedApi") public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3; + /** + * @see AudioFormat#ENCODING_E_AC3 + */ + @SuppressWarnings("InlinedApi") + public static final int ENCODING_E_AC3 = AudioFormat.ENCODING_E_AC3; + /** * @see MediaExtractor#SAMPLE_FLAG_SYNC */ diff --git a/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilities.java b/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilities.java index 24bcccaf03..dae8de0d49 100644 --- a/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilities.java +++ b/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilities.java @@ -15,13 +15,9 @@ */ package com.google.android.exoplayer.audio; -import com.google.android.exoplayer.util.Util; - import android.annotation.TargetApi; -import android.media.AudioFormat; -import java.util.HashSet; -import java.util.Set; +import java.util.Arrays; /** * Represents the set of audio formats a device is capable of playing back. @@ -29,7 +25,7 @@ import java.util.Set; @TargetApi(21) public final class AudioCapabilities { - private final Set supportedEncodings; + private final int[] supportedEncodings; private final int maxChannelCount; /** @@ -41,28 +37,20 @@ public final class AudioCapabilities { * @param maxChannelCount The maximum number of audio channels that can be played simultaneously. */ public AudioCapabilities(int[] supportedEncodings, int maxChannelCount) { - this.supportedEncodings = new HashSet(); - if (supportedEncodings != null) { - for (int i : supportedEncodings) { - this.supportedEncodings.add(i); - } - } + this.supportedEncodings = supportedEncodings != null ? supportedEncodings : new int[0]; this.maxChannelCount = maxChannelCount; + + Arrays.sort(supportedEncodings); } - /** Returns whether the device supports playback of AC-3. */ - public boolean supportsAc3() { - return Util.SDK_INT >= 21 && supportedEncodings.contains(AudioFormat.ENCODING_AC3); - } - - /** Returns whether the device supports playback of enhanced AC-3. */ - public boolean supportsEAc3() { - return Util.SDK_INT >= 21 && supportedEncodings.contains(AudioFormat.ENCODING_E_AC3); - } - - /** Returns whether the device supports playback of 16-bit PCM. */ - public boolean supportsPcm() { - return supportedEncodings.contains(AudioFormat.ENCODING_PCM_16BIT); + /** + * Returns whether this device supports playback of the specified audio {@code encoding}. + * + * @param encoding One of {@link android.media.AudioFormat}'s {@code ENCODING_*} constants. + * @return Whether this device supports playback the specified audio {@code encoding}. + */ + public boolean supportsEncoding(int encoding) { + return Arrays.binarySearch(supportedEncodings, encoding) >= 0; } /** Returns the maximum number of channels the device can play at the same time. */ @@ -79,19 +67,19 @@ public final class AudioCapabilities { return false; } AudioCapabilities audioCapabilities = (AudioCapabilities) other; - return supportedEncodings.equals(audioCapabilities.supportedEncodings) + return Arrays.equals(supportedEncodings, audioCapabilities.supportedEncodings) && maxChannelCount == audioCapabilities.maxChannelCount; } @Override public int hashCode() { - return maxChannelCount + 31 * supportedEncodings.hashCode(); + return maxChannelCount + 31 * Arrays.hashCode(supportedEncodings); } @Override public String toString() { return "AudioCapabilities[maxChannelCount=" + maxChannelCount - + ", supportedEncodings=" + supportedEncodings + "]"; + + ", supportedEncodings=" + Arrays.toString(supportedEncodings) + "]"; } }