Commit d9071710 by Oliver Woodman

Read AC-3 tracks in MPEG TSs only if AC-3 playback is supported.

Partly fixes #434 as the AC-3 stream will now be ignored if the
audio capabilities don't allow it to be played back.
parent d8af120b
...@@ -229,7 +229,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -229,7 +229,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
return new DashRendererBuilder(this, userAgent, contentUri.toString(), return new DashRendererBuilder(this, userAgent, contentUri.toString(),
new WidevineTestMediaDrmCallback(contentId), debugTextView, audioCapabilities); new WidevineTestMediaDrmCallback(contentId), debugTextView, audioCapabilities);
case DemoUtil.TYPE_HLS: case DemoUtil.TYPE_HLS:
return new HlsRendererBuilder(this, userAgent, contentUri.toString(), debugTextView); return new HlsRendererBuilder(this, userAgent, contentUri.toString(), debugTextView,
audioCapabilities);
case DemoUtil.TYPE_M4A: // There are no file format differences between M4A and MP4. case DemoUtil.TYPE_M4A: // There are no file format differences between M4A and MP4.
case DemoUtil.TYPE_MP4: case DemoUtil.TYPE_MP4:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView, return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
...@@ -239,7 +240,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -239,7 +240,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
new Mp3Extractor()); new Mp3Extractor());
case DemoUtil.TYPE_TS: case DemoUtil.TYPE_TS:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView, return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
new TsExtractor()); new TsExtractor(0, audioCapabilities));
case DemoUtil.TYPE_AAC: case DemoUtil.TYPE_AAC:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView, return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
new AdtsExtractor()); new AdtsExtractor());
......
...@@ -19,6 +19,7 @@ import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; ...@@ -19,6 +19,7 @@ import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.chunk.VideoFormatSelectorUtil; import com.google.android.exoplayer.chunk.VideoFormatSelectorUtil;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback; import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
...@@ -56,15 +57,18 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls ...@@ -56,15 +57,18 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
private final String userAgent; private final String userAgent;
private final String url; private final String url;
private final TextView debugTextView; private final TextView debugTextView;
private final AudioCapabilities audioCapabilities;
private DemoPlayer player; private DemoPlayer player;
private RendererBuilderCallback callback; private RendererBuilderCallback callback;
public HlsRendererBuilder(Context context, String userAgent, String url, TextView debugTextView) { public HlsRendererBuilder(Context context, String userAgent, String url, TextView debugTextView,
AudioCapabilities audioCapabilities) {
this.context = context; this.context = context;
this.userAgent = userAgent; this.userAgent = userAgent;
this.url = url; this.url = url;
this.debugTextView = debugTextView; this.debugTextView = debugTextView;
this.audioCapabilities = audioCapabilities;
} }
@Override @Override
...@@ -101,7 +105,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls ...@@ -101,7 +105,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
DataSource dataSource = new DefaultUriDataSource(userAgent, bandwidthMeter); DataSource dataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
HlsChunkSource chunkSource = new HlsChunkSource(dataSource, url, manifest, bandwidthMeter, HlsChunkSource chunkSource = new HlsChunkSource(dataSource, url, manifest, bandwidthMeter,
variantIndices, HlsChunkSource.ADAPTIVE_MODE_SPLICE); variantIndices, HlsChunkSource.ADAPTIVE_MODE_SPLICE, audioCapabilities);
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, true, 3, REQUESTED_BUFFER_SIZE, HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, true, 3, REQUESTED_BUFFER_SIZE,
REQUESTED_BUFFER_DURATION_MS, mainHandler, player, DemoPlayer.TYPE_VIDEO); REQUESTED_BUFFER_DURATION_MS, mainHandler, player, DemoPlayer.TYPE_VIDEO);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource, MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer.extractor.ts; package com.google.android.exoplayer.extractor.ts;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.extractor.Extractor; import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorInput; import com.google.android.exoplayer.extractor.ExtractorInput;
import com.google.android.exoplayer.extractor.ExtractorOutput; import com.google.android.exoplayer.extractor.ExtractorOutput;
...@@ -43,6 +44,7 @@ public final class TsExtractor implements Extractor, SeekMap { ...@@ -43,6 +44,7 @@ public final class TsExtractor implements Extractor, SeekMap {
private static final int TS_STREAM_TYPE_AAC = 0x0F; private static final int TS_STREAM_TYPE_AAC = 0x0F;
private static final int TS_STREAM_TYPE_ATSC_AC3 = 0x81; private static final int TS_STREAM_TYPE_ATSC_AC3 = 0x81;
private static final int TS_STREAM_TYPE_ATSC_E_AC3 = 0x87;
private static final int TS_STREAM_TYPE_H264 = 0x1B; private static final int TS_STREAM_TYPE_H264 = 0x1B;
private static final int TS_STREAM_TYPE_ID3 = 0x15; private static final int TS_STREAM_TYPE_ID3 = 0x15;
private static final int TS_STREAM_TYPE_EIA608 = 0x100; // 0xFF + 1 private static final int TS_STREAM_TYPE_EIA608 = 0x100; // 0xFF + 1
...@@ -51,6 +53,7 @@ public final class TsExtractor implements Extractor, SeekMap { ...@@ -51,6 +53,7 @@ public final class TsExtractor implements Extractor, SeekMap {
private final ParsableByteArray tsPacketBuffer; private final ParsableByteArray tsPacketBuffer;
private final SparseBooleanArray streamTypes; private final SparseBooleanArray streamTypes;
private final SparseBooleanArray allowedPassthroughStreamTypes;
private final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid private final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid
private final long firstSampleTimestampUs; private final long firstSampleTimestampUs;
private final ParsableBitArray tsScratch; private final ParsableBitArray tsScratch;
...@@ -61,14 +64,15 @@ public final class TsExtractor implements Extractor, SeekMap { ...@@ -61,14 +64,15 @@ public final class TsExtractor implements Extractor, SeekMap {
private long lastPts; private long lastPts;
public TsExtractor() { public TsExtractor() {
this(0); this(0, null);
} }
public TsExtractor(long firstSampleTimestampUs) { public TsExtractor(long firstSampleTimestampUs, AudioCapabilities audioCapabilities) {
this.firstSampleTimestampUs = firstSampleTimestampUs; this.firstSampleTimestampUs = firstSampleTimestampUs;
tsScratch = new ParsableBitArray(new byte[3]); tsScratch = new ParsableBitArray(new byte[3]);
tsPacketBuffer = new ParsableByteArray(TS_PACKET_SIZE); tsPacketBuffer = new ParsableByteArray(TS_PACKET_SIZE);
streamTypes = new SparseBooleanArray(); streamTypes = new SparseBooleanArray();
allowedPassthroughStreamTypes = getPassthroughStreamTypes(audioCapabilities);
tsPayloadReaders = new SparseArray<TsPayloadReader>(); tsPayloadReaders = new SparseArray<TsPayloadReader>();
tsPayloadReaders.put(TS_PAT_PID, new PatReader()); tsPayloadReaders.put(TS_PAT_PID, new PatReader());
lastPts = Long.MIN_VALUE; lastPts = Long.MIN_VALUE;
...@@ -174,6 +178,24 @@ public final class TsExtractor implements Extractor, SeekMap { ...@@ -174,6 +178,24 @@ public final class TsExtractor implements Extractor, SeekMap {
} }
/** /**
* Returns a sparse boolean array of stream types that can be played back based on
* {@code audioCapabilities}.
*/
private static SparseBooleanArray getPassthroughStreamTypes(AudioCapabilities audioCapabilities) {
SparseBooleanArray streamTypes = new SparseBooleanArray();
if (audioCapabilities != null) {
if (audioCapabilities.supportsEncoding(C.ENCODING_AC3)) {
streamTypes.put(TS_STREAM_TYPE_ATSC_AC3, true);
}
if (audioCapabilities.supportsEncoding(C.ENCODING_E_AC3)) {
// TODO: Uncomment when Ac3Reader supports enhanced AC-3.
// streamTypes.put(TS_STREAM_TYPE_ATSC_E_AC3, true);
}
}
return streamTypes;
}
/**
* Parses TS packet payload data. * Parses TS packet payload data.
*/ */
private abstract static class TsPayloadReader { private abstract static class TsPayloadReader {
...@@ -313,7 +335,11 @@ public final class TsExtractor implements Extractor, SeekMap { ...@@ -313,7 +335,11 @@ public final class TsExtractor implements Extractor, SeekMap {
case TS_STREAM_TYPE_AAC: case TS_STREAM_TYPE_AAC:
pesPayloadReader = new AdtsReader(output.track(TS_STREAM_TYPE_AAC)); pesPayloadReader = new AdtsReader(output.track(TS_STREAM_TYPE_AAC));
break; break;
case TS_STREAM_TYPE_ATSC_E_AC3:
case TS_STREAM_TYPE_ATSC_AC3: case TS_STREAM_TYPE_ATSC_AC3:
if (!allowedPassthroughStreamTypes.get(streamType)) {
continue;
}
pesPayloadReader = new Ac3Reader(output.track(streamType)); pesPayloadReader = new Ac3Reader(output.track(streamType));
break; break;
case TS_STREAM_TYPE_H264: case TS_STREAM_TYPE_H264:
......
...@@ -17,6 +17,7 @@ package com.google.android.exoplayer.hls; ...@@ -17,6 +17,7 @@ package com.google.android.exoplayer.hls;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener; import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
import com.google.android.exoplayer.chunk.Chunk; import com.google.android.exoplayer.chunk.Chunk;
import com.google.android.exoplayer.chunk.DataChunk; import com.google.android.exoplayer.chunk.DataChunk;
...@@ -125,6 +126,7 @@ public class HlsChunkSource { ...@@ -125,6 +126,7 @@ public class HlsChunkSource {
private final int maxHeight; private final int maxHeight;
private final long minBufferDurationToSwitchUpUs; private final long minBufferDurationToSwitchUpUs;
private final long maxBufferDurationToSwitchDownUs; private final long maxBufferDurationToSwitchDownUs;
private final AudioCapabilities audioCapabilities;
/* package */ byte[] scratchSpace; /* package */ byte[] scratchSpace;
/* package */ final HlsMediaPlaylist[] mediaPlaylists; /* package */ final HlsMediaPlaylist[] mediaPlaylists;
...@@ -140,9 +142,11 @@ public class HlsChunkSource { ...@@ -140,9 +142,11 @@ public class HlsChunkSource {
private byte[] encryptionIv; private byte[] encryptionIv;
public HlsChunkSource(DataSource dataSource, String playlistUrl, HlsPlaylist playlist, public HlsChunkSource(DataSource dataSource, String playlistUrl, HlsPlaylist playlist,
BandwidthMeter bandwidthMeter, int[] variantIndices, int adaptiveMode) { BandwidthMeter bandwidthMeter, int[] variantIndices, int adaptiveMode,
AudioCapabilities audioCapabilities) {
this(dataSource, playlistUrl, playlist, bandwidthMeter, variantIndices, adaptiveMode, this(dataSource, playlistUrl, playlist, bandwidthMeter, variantIndices, adaptiveMode,
DEFAULT_MIN_BUFFER_TO_SWITCH_UP_MS, DEFAULT_MAX_BUFFER_TO_SWITCH_DOWN_MS); DEFAULT_MIN_BUFFER_TO_SWITCH_UP_MS, DEFAULT_MAX_BUFFER_TO_SWITCH_DOWN_MS,
audioCapabilities);
} }
/** /**
...@@ -160,13 +164,17 @@ public class HlsChunkSource { ...@@ -160,13 +164,17 @@ public class HlsChunkSource {
* for a switch to a higher quality variant to be considered. * for a switch to a higher quality variant to be considered.
* @param maxBufferDurationToSwitchDownMs The maximum duration of media that needs to be buffered * @param maxBufferDurationToSwitchDownMs The maximum duration of media that needs to be buffered
* for a switch to a lower quality variant to be considered. * for a switch to a lower quality variant to be considered.
* @param audioCapabilities The audio capabilities for playback on this device, or {@code null} if
* the default capabilities should be assumed.
*/ */
public HlsChunkSource(DataSource dataSource, String playlistUrl, HlsPlaylist playlist, public HlsChunkSource(DataSource dataSource, String playlistUrl, HlsPlaylist playlist,
BandwidthMeter bandwidthMeter, int[] variantIndices, int adaptiveMode, BandwidthMeter bandwidthMeter, int[] variantIndices, int adaptiveMode,
long minBufferDurationToSwitchUpMs, long maxBufferDurationToSwitchDownMs) { long minBufferDurationToSwitchUpMs, long maxBufferDurationToSwitchDownMs,
AudioCapabilities audioCapabilities) {
this.dataSource = dataSource; this.dataSource = dataSource;
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeter = bandwidthMeter;
this.adaptiveMode = adaptiveMode; this.adaptiveMode = adaptiveMode;
this.audioCapabilities = audioCapabilities;
minBufferDurationToSwitchUpUs = minBufferDurationToSwitchUpMs * 1000; minBufferDurationToSwitchUpUs = minBufferDurationToSwitchUpMs * 1000;
maxBufferDurationToSwitchDownUs = maxBufferDurationToSwitchDownMs * 1000; maxBufferDurationToSwitchDownUs = maxBufferDurationToSwitchDownMs * 1000;
baseUri = playlist.baseUri; baseUri = playlist.baseUri;
...@@ -334,7 +342,7 @@ public class HlsChunkSource { ...@@ -334,7 +342,7 @@ public class HlsChunkSource {
if (previousTsChunk == null || segment.discontinuity || switchingVariant || liveDiscontinuity) { if (previousTsChunk == null || segment.discontinuity || switchingVariant || liveDiscontinuity) {
Extractor extractor = chunkUri.getLastPathSegment().endsWith(AAC_FILE_EXTENSION) Extractor extractor = chunkUri.getLastPathSegment().endsWith(AAC_FILE_EXTENSION)
? new AdtsExtractor(startTimeUs) ? new AdtsExtractor(startTimeUs)
: new TsExtractor(startTimeUs); : new TsExtractor(startTimeUs, audioCapabilities);
extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor, extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor,
switchingVariantSpliced); switchingVariantSpliced);
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment