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.
This commit is contained in:
Oliver Woodman 2015-05-08 17:08:13 +01:00
parent d8af120b98
commit d9071710cf
4 changed files with 49 additions and 10 deletions

View File

@ -229,7 +229,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
return new DashRendererBuilder(this, userAgent, contentUri.toString(),
new WidevineTestMediaDrmCallback(contentId), debugTextView, audioCapabilities);
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_MP4:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
@ -239,7 +240,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
new Mp3Extractor());
case DemoUtil.TYPE_TS:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
new TsExtractor());
new TsExtractor(0, audioCapabilities));
case DemoUtil.TYPE_AAC:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
new AdtsExtractor());

View File

@ -19,6 +19,7 @@ import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
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.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
@ -56,15 +57,18 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
private final String userAgent;
private final String url;
private final TextView debugTextView;
private final AudioCapabilities audioCapabilities;
private DemoPlayer player;
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.userAgent = userAgent;
this.url = url;
this.debugTextView = debugTextView;
this.audioCapabilities = audioCapabilities;
}
@Override
@ -101,7 +105,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
DataSource dataSource = new DefaultUriDataSource(userAgent, 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,
REQUESTED_BUFFER_DURATION_MS, mainHandler, player, DemoPlayer.TYPE_VIDEO);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer.extractor.ts;
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.ExtractorInput;
import com.google.android.exoplayer.extractor.ExtractorOutput;
@ -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_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_ID3 = 0x15;
private static final int TS_STREAM_TYPE_EIA608 = 0x100; // 0xFF + 1
@ -51,6 +53,7 @@ public final class TsExtractor implements Extractor, SeekMap {
private final ParsableByteArray tsPacketBuffer;
private final SparseBooleanArray streamTypes;
private final SparseBooleanArray allowedPassthroughStreamTypes;
private final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid
private final long firstSampleTimestampUs;
private final ParsableBitArray tsScratch;
@ -61,14 +64,15 @@ public final class TsExtractor implements Extractor, SeekMap {
private long lastPts;
public TsExtractor() {
this(0);
this(0, null);
}
public TsExtractor(long firstSampleTimestampUs) {
public TsExtractor(long firstSampleTimestampUs, AudioCapabilities audioCapabilities) {
this.firstSampleTimestampUs = firstSampleTimestampUs;
tsScratch = new ParsableBitArray(new byte[3]);
tsPacketBuffer = new ParsableByteArray(TS_PACKET_SIZE);
streamTypes = new SparseBooleanArray();
allowedPassthroughStreamTypes = getPassthroughStreamTypes(audioCapabilities);
tsPayloadReaders = new SparseArray<TsPayloadReader>();
tsPayloadReaders.put(TS_PAT_PID, new PatReader());
lastPts = Long.MIN_VALUE;
@ -173,6 +177,24 @@ public final class TsExtractor implements Extractor, SeekMap {
return timeUs + timestampOffsetUs;
}
/**
* 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.
*/
@ -313,7 +335,11 @@ public final class TsExtractor implements Extractor, SeekMap {
case TS_STREAM_TYPE_AAC:
pesPayloadReader = new AdtsReader(output.track(TS_STREAM_TYPE_AAC));
break;
case TS_STREAM_TYPE_ATSC_E_AC3:
case TS_STREAM_TYPE_ATSC_AC3:
if (!allowedPassthroughStreamTypes.get(streamType)) {
continue;
}
pesPayloadReader = new Ac3Reader(output.track(streamType));
break;
case TS_STREAM_TYPE_H264:

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer.hls;
import com.google.android.exoplayer.C;
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.Chunk;
import com.google.android.exoplayer.chunk.DataChunk;
@ -125,6 +126,7 @@ public class HlsChunkSource {
private final int maxHeight;
private final long minBufferDurationToSwitchUpUs;
private final long maxBufferDurationToSwitchDownUs;
private final AudioCapabilities audioCapabilities;
/* package */ byte[] scratchSpace;
/* package */ final HlsMediaPlaylist[] mediaPlaylists;
@ -140,9 +142,11 @@ public class HlsChunkSource {
private byte[] encryptionIv;
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,
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 {
* for a switch to a higher quality variant to be considered.
* @param maxBufferDurationToSwitchDownMs The maximum duration of media that needs to be buffered
* 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,
BandwidthMeter bandwidthMeter, int[] variantIndices, int adaptiveMode,
long minBufferDurationToSwitchUpMs, long maxBufferDurationToSwitchDownMs) {
long minBufferDurationToSwitchUpMs, long maxBufferDurationToSwitchDownMs,
AudioCapabilities audioCapabilities) {
this.dataSource = dataSource;
this.bandwidthMeter = bandwidthMeter;
this.adaptiveMode = adaptiveMode;
this.audioCapabilities = audioCapabilities;
minBufferDurationToSwitchUpUs = minBufferDurationToSwitchUpMs * 1000;
maxBufferDurationToSwitchDownUs = maxBufferDurationToSwitchDownMs * 1000;
baseUri = playlist.baseUri;
@ -334,7 +342,7 @@ public class HlsChunkSource {
if (previousTsChunk == null || segment.discontinuity || switchingVariant || liveDiscontinuity) {
Extractor extractor = chunkUri.getLastPathSegment().endsWith(AAC_FILE_EXTENSION)
? new AdtsExtractor(startTimeUs)
: new TsExtractor(startTimeUs);
: new TsExtractor(startTimeUs, audioCapabilities);
extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor,
switchingVariantSpliced);
} else {