Select E-AC-3 in preference to AC-3, and remove other tracks.

This commit is contained in:
Oliver Woodman 2015-04-17 20:01:06 +01:00
parent 3f1638de95
commit e84c852169
3 changed files with 55 additions and 43 deletions

View File

@ -90,8 +90,17 @@ public class DashRendererBuilder implements RendererBuilder,
private static final int SECURITY_LEVEL_1 = 1; private static final int SECURITY_LEVEL_1 = 1;
private static final int SECURITY_LEVEL_3 = 3; 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 userAgent;
private final String url; private final String url;
@ -252,13 +261,14 @@ public class DashRendererBuilder implements RendererBuilder,
} }
// Build the audio chunk sources. // Build the audio chunk sources.
boolean haveAc3Tracks = false;
List<ChunkSource> audioChunkSourceList = new ArrayList<ChunkSource>(); List<ChunkSource> audioChunkSourceList = new ArrayList<ChunkSource>();
List<String> audioTrackNameList = new ArrayList<String>(); List<String> audioTrackNameList = new ArrayList<String>();
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
if (audioAdaptationSet != null) { if (audioAdaptationSet != null) {
DataSource audioDataSource = new UriDataSource(userAgent, bandwidthMeter); DataSource audioDataSource = new UriDataSource(userAgent, bandwidthMeter);
FormatEvaluator audioEvaluator = new FormatEvaluator.FixedEvaluator(); FormatEvaluator audioEvaluator = new FormatEvaluator.FixedEvaluator();
List<Representation> audioRepresentations = audioAdaptationSet.representations; List<Representation> audioRepresentations = audioAdaptationSet.representations;
List<String> codecs = new ArrayList<String>();
for (int i = 0; i < audioRepresentations.size(); i++) { for (int i = 0; i < audioRepresentations.size(); i++) {
Format format = audioRepresentations.get(i).format; Format format = audioRepresentations.get(i).format;
audioTrackNameList.add(format.id + " (" + format.numChannels + "ch, " + audioTrackNameList.add(format.id + " (" + format.numChannels + "ch, " +
@ -266,16 +276,27 @@ public class DashRendererBuilder implements RendererBuilder,
audioChunkSourceList.add(new DashChunkSource(manifestFetcher, audioAdaptationSetIndex, audioChunkSourceList.add(new DashChunkSource(manifestFetcher, audioAdaptationSetIndex,
new int[] {i}, audioDataSource, audioEvaluator, LIVE_EDGE_LATENCY_MS, new int[] {i}, audioDataSource, audioEvaluator, LIVE_EDGE_LATENCY_MS,
elapsedRealtimeOffset)); 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) { if (audioCapabilities != null) {
for (int i = audioRepresentations.size() - 1; i >= 0; i--) { // If there are any passthrough audio encodings available, select the highest priority
Format format = audioRepresentations.get(i).format; // supported format (e.g. E-AC-3) and remove other tracks.
if (!AC_3_CODEC.equals(format.codecs) && !E_AC_3_CODEC.equals(format.codecs)) { for (int i = 0; i < PASSTHROUGH_CODECS_PRIORITY.length; i++) {
audioTrackNameList.remove(i); String codec = PASSTHROUGH_CODECS_PRIORITY[i];
audioChunkSourceList.remove(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, SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, mainHandler, player, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, mainHandler, player,
DemoPlayer.TYPE_AUDIO); 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, audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, drmSessionManager, true,
mainHandler, player, useAc3Passthrough ? C.ENCODING_AC3 : AudioFormat.ENCODING_PCM_16BIT); mainHandler, player, audioEncoding);
} }
// Build the text chunk sources. // Build the text chunk sources.

View File

@ -56,6 +56,12 @@ public final class C {
@SuppressWarnings("InlinedApi") @SuppressWarnings("InlinedApi")
public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3; 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 * @see MediaExtractor#SAMPLE_FLAG_SYNC
*/ */

View File

@ -15,13 +15,9 @@
*/ */
package com.google.android.exoplayer.audio; package com.google.android.exoplayer.audio;
import com.google.android.exoplayer.util.Util;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.media.AudioFormat;
import java.util.HashSet; import java.util.Arrays;
import java.util.Set;
/** /**
* Represents the set of audio formats a device is capable of playing back. * Represents the set of audio formats a device is capable of playing back.
@ -29,7 +25,7 @@ import java.util.Set;
@TargetApi(21) @TargetApi(21)
public final class AudioCapabilities { public final class AudioCapabilities {
private final Set<Integer> supportedEncodings; private final int[] supportedEncodings;
private final int maxChannelCount; 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. * @param maxChannelCount The maximum number of audio channels that can be played simultaneously.
*/ */
public AudioCapabilities(int[] supportedEncodings, int maxChannelCount) { public AudioCapabilities(int[] supportedEncodings, int maxChannelCount) {
this.supportedEncodings = new HashSet<Integer>(); this.supportedEncodings = supportedEncodings != null ? supportedEncodings : new int[0];
if (supportedEncodings != null) {
for (int i : supportedEncodings) {
this.supportedEncodings.add(i);
}
}
this.maxChannelCount = maxChannelCount; this.maxChannelCount = maxChannelCount;
Arrays.sort(supportedEncodings);
} }
/** Returns whether the device supports playback of AC-3. */ /**
public boolean supportsAc3() { * Returns whether this device supports playback of the specified audio {@code encoding}.
return Util.SDK_INT >= 21 && supportedEncodings.contains(AudioFormat.ENCODING_AC3); *
} * @param encoding One of {@link android.media.AudioFormat}'s {@code ENCODING_*} constants.
* @return Whether this device supports playback the specified audio {@code encoding}.
/** Returns whether the device supports playback of enhanced AC-3. */ */
public boolean supportsEAc3() { public boolean supportsEncoding(int encoding) {
return Util.SDK_INT >= 21 && supportedEncodings.contains(AudioFormat.ENCODING_E_AC3); return Arrays.binarySearch(supportedEncodings, encoding) >= 0;
}
/** Returns whether the device supports playback of 16-bit PCM. */
public boolean supportsPcm() {
return supportedEncodings.contains(AudioFormat.ENCODING_PCM_16BIT);
} }
/** Returns the maximum number of channels the device can play at the same time. */ /** Returns the maximum number of channels the device can play at the same time. */
@ -79,19 +67,19 @@ public final class AudioCapabilities {
return false; return false;
} }
AudioCapabilities audioCapabilities = (AudioCapabilities) other; AudioCapabilities audioCapabilities = (AudioCapabilities) other;
return supportedEncodings.equals(audioCapabilities.supportedEncodings) return Arrays.equals(supportedEncodings, audioCapabilities.supportedEncodings)
&& maxChannelCount == audioCapabilities.maxChannelCount; && maxChannelCount == audioCapabilities.maxChannelCount;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return maxChannelCount + 31 * supportedEncodings.hashCode(); return maxChannelCount + 31 * Arrays.hashCode(supportedEncodings);
} }
@Override @Override
public String toString() { public String toString() {
return "AudioCapabilities[maxChannelCount=" + maxChannelCount return "AudioCapabilities[maxChannelCount=" + maxChannelCount
+ ", supportedEncodings=" + supportedEncodings + "]"; + ", supportedEncodings=" + Arrays.toString(supportedEncodings) + "]";
} }
} }