mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
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:
parent
d8af120b98
commit
d9071710cf
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user