mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Allow late HLS sample queue building
Issue:#3149 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=177836048
This commit is contained in:
parent
fbfa43f5a3
commit
002df729a5
@ -1,3 +1,5 @@
|
|||||||
|
*** ISSUES THAT IGNORE THIS TEMPLATE WILL BE CLOSED WITHOUT INVESTIGATION ***
|
||||||
|
|
||||||
Before filing an issue:
|
Before filing an issue:
|
||||||
-----------------------
|
-----------------------
|
||||||
- Search existing issues, including issues that are closed.
|
- Search existing issues, including issues that are closed.
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.hls;
|
package com.google.android.exoplayer2.source.hls;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.FormatHolder;
|
import com.google.android.exoplayer2.FormatHolder;
|
||||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer2.source.SampleStream;
|
import com.google.android.exoplayer2.source.SampleStream;
|
||||||
@ -25,33 +26,60 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
/* package */ final class HlsSampleStream implements SampleStream {
|
/* package */ final class HlsSampleStream implements SampleStream {
|
||||||
|
|
||||||
public final int sampleQueueIndex;
|
private final int trackGroupIndex;
|
||||||
|
|
||||||
private final HlsSampleStreamWrapper sampleStreamWrapper;
|
private final HlsSampleStreamWrapper sampleStreamWrapper;
|
||||||
|
private int sampleQueueIndex;
|
||||||
|
|
||||||
public HlsSampleStream(HlsSampleStreamWrapper sampleStreamWrapper, int sampleQueueIndex) {
|
public HlsSampleStream(HlsSampleStreamWrapper sampleStreamWrapper, int trackGroupIndex) {
|
||||||
this.sampleStreamWrapper = sampleStreamWrapper;
|
this.sampleStreamWrapper = sampleStreamWrapper;
|
||||||
this.sampleQueueIndex = sampleQueueIndex;
|
this.trackGroupIndex = trackGroupIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unbindSampleQueue() {
|
||||||
|
if (sampleQueueIndex != C.INDEX_UNSET) {
|
||||||
|
sampleStreamWrapper.unbindSampleQueue(trackGroupIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SampleStream implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return sampleStreamWrapper.isReady(sampleQueueIndex);
|
return ensureBoundSampleQueue() && sampleStreamWrapper.isReady(sampleQueueIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void maybeThrowError() throws IOException {
|
public void maybeThrowError() throws IOException {
|
||||||
|
if (!ensureBoundSampleQueue()) {
|
||||||
|
throw new SampleQueueMappingException(
|
||||||
|
sampleStreamWrapper.getTrackGroups().get(trackGroupIndex).getFormat(0).sampleMimeType);
|
||||||
|
}
|
||||||
sampleStreamWrapper.maybeThrowError();
|
sampleStreamWrapper.maybeThrowError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) {
|
||||||
|
if (!ensureBoundSampleQueue()) {
|
||||||
|
return C.RESULT_NOTHING_READ;
|
||||||
|
}
|
||||||
return sampleStreamWrapper.readData(sampleQueueIndex, formatHolder, buffer, requireFormat);
|
return sampleStreamWrapper.readData(sampleQueueIndex, formatHolder, buffer, requireFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int skipData(long positionUs) {
|
public int skipData(long positionUs) {
|
||||||
|
if (!ensureBoundSampleQueue()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return sampleStreamWrapper.skipData(sampleQueueIndex, positionUs);
|
return sampleStreamWrapper.skipData(sampleQueueIndex, positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal methods.
|
||||||
|
|
||||||
|
private boolean ensureBoundSampleQueue() {
|
||||||
|
if (sampleQueueIndex != C.INDEX_UNSET) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
sampleQueueIndex = sampleStreamWrapper.bindSampleQueueToSampleStream(trackGroupIndex);
|
||||||
|
return sampleQueueIndex != C.INDEX_UNSET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,13 +88,14 @@ import java.util.Arrays;
|
|||||||
private final HlsChunkSource.HlsChunkHolder nextChunkHolder;
|
private final HlsChunkSource.HlsChunkHolder nextChunkHolder;
|
||||||
private final ArrayList<HlsMediaChunk> mediaChunks;
|
private final ArrayList<HlsMediaChunk> mediaChunks;
|
||||||
private final Runnable maybeFinishPrepareRunnable;
|
private final Runnable maybeFinishPrepareRunnable;
|
||||||
|
private final Runnable onTracksEndedRunnable;
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
|
|
||||||
private SampleQueue[] sampleQueues;
|
private SampleQueue[] sampleQueues;
|
||||||
private int[] sampleQueueTrackIds;
|
private int[] sampleQueueTrackIds;
|
||||||
private boolean sampleQueuesBuilt;
|
private boolean sampleQueuesBuilt;
|
||||||
private boolean prepared;
|
private boolean prepared;
|
||||||
private int enabledSampleQueueCount;
|
private int enabledTrackGroupCount;
|
||||||
private Format downstreamTrackFormat;
|
private Format downstreamTrackFormat;
|
||||||
private boolean released;
|
private boolean released;
|
||||||
|
|
||||||
@ -108,13 +109,16 @@ import java.util.Arrays;
|
|||||||
private boolean[] sampleQueuesEnabledStates;
|
private boolean[] sampleQueuesEnabledStates;
|
||||||
private boolean[] sampleQueueIsAudioVideoFlags;
|
private boolean[] sampleQueueIsAudioVideoFlags;
|
||||||
|
|
||||||
private long sampleOffsetUs;
|
|
||||||
private long lastSeekPositionUs;
|
private long lastSeekPositionUs;
|
||||||
private long pendingResetPositionUs;
|
private long pendingResetPositionUs;
|
||||||
private boolean pendingResetUpstreamFormats;
|
private boolean pendingResetUpstreamFormats;
|
||||||
private boolean seenFirstTrackSelection;
|
private boolean seenFirstTrackSelection;
|
||||||
private boolean loadingFinished;
|
private boolean loadingFinished;
|
||||||
|
|
||||||
|
// Accessed only by the loading thread.
|
||||||
|
private boolean tracksEnded;
|
||||||
|
private long sampleOffsetUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param trackType The type of the track. One of the {@link C} {@code TRACK_TYPE_*} constants.
|
* @param trackType The type of the track. One of the {@link C} {@code TRACK_TYPE_*} constants.
|
||||||
* @param callback A callback for the wrapper.
|
* @param callback A callback for the wrapper.
|
||||||
@ -143,12 +147,20 @@ import java.util.Arrays;
|
|||||||
sampleQueueIsAudioVideoFlags = new boolean[0];
|
sampleQueueIsAudioVideoFlags = new boolean[0];
|
||||||
sampleQueuesEnabledStates = new boolean[0];
|
sampleQueuesEnabledStates = new boolean[0];
|
||||||
mediaChunks = new ArrayList<>();
|
mediaChunks = new ArrayList<>();
|
||||||
maybeFinishPrepareRunnable = new Runnable() {
|
maybeFinishPrepareRunnable =
|
||||||
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
maybeFinishPrepare();
|
maybeFinishPrepare();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
onTracksEndedRunnable =
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
onTracksEnded();
|
||||||
|
}
|
||||||
|
};
|
||||||
handler = new Handler();
|
handler = new Handler();
|
||||||
lastSeekPositionUs = positionUs;
|
lastSeekPositionUs = positionUs;
|
||||||
pendingResetPositionUs = positionUs;
|
pendingResetPositionUs = positionUs;
|
||||||
@ -166,8 +178,8 @@ import java.util.Arrays;
|
|||||||
*/
|
*/
|
||||||
public void prepareSingleTrack(Format format) {
|
public void prepareSingleTrack(Format format) {
|
||||||
track(0, C.TRACK_TYPE_UNKNOWN).format(format);
|
track(0, C.TRACK_TYPE_UNKNOWN).format(format);
|
||||||
sampleQueuesBuilt = true;
|
tracksEnded = true;
|
||||||
maybeFinishPrepare();
|
onTracksEnded();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void maybeThrowPrepareError() throws IOException {
|
public void maybeThrowPrepareError() throws IOException {
|
||||||
@ -178,6 +190,19 @@ import java.util.Arrays;
|
|||||||
return trackGroups;
|
return trackGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int bindSampleQueueToSampleStream(int trackGroupIndex) {
|
||||||
|
int sampleQueueIndex = trackGroupToSampleQueueIndex[trackGroupIndex];
|
||||||
|
if (sampleQueueIndex == C.INDEX_UNSET) {
|
||||||
|
return C.INDEX_UNSET;
|
||||||
|
}
|
||||||
|
setSampleQueueEnabledState(sampleQueueIndex, true);
|
||||||
|
return sampleQueueIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unbindSampleQueue(int trackGroupIndex) {
|
||||||
|
setSampleQueueEnabledState(trackGroupToSampleQueueIndex[trackGroupIndex], false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the parent {@link HlsMediaPeriod} when a track selection occurs.
|
* Called by the parent {@link HlsMediaPeriod} when a track selection occurs.
|
||||||
*
|
*
|
||||||
@ -198,19 +223,22 @@ import java.util.Arrays;
|
|||||||
public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
|
public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
|
||||||
SampleStream[] streams, boolean[] streamResetFlags, long positionUs, boolean forceReset) {
|
SampleStream[] streams, boolean[] streamResetFlags, long positionUs, boolean forceReset) {
|
||||||
Assertions.checkState(prepared);
|
Assertions.checkState(prepared);
|
||||||
int oldEnabledSampleQueueCount = enabledSampleQueueCount;
|
int oldEnabledTrackGroupCount = enabledTrackGroupCount;
|
||||||
// Deselect old tracks.
|
// Deselect old tracks.
|
||||||
for (int i = 0; i < selections.length; i++) {
|
for (int i = 0; i < selections.length; i++) {
|
||||||
if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
|
if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
|
||||||
setSampleQueueEnabledState(((HlsSampleStream) streams[i]).sampleQueueIndex, false);
|
enabledTrackGroupCount--;
|
||||||
|
((HlsSampleStream) streams[i]).unbindSampleQueue();
|
||||||
streams[i] = null;
|
streams[i] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We'll always need to seek if we're being forced to reset, or if this is a first selection to
|
// We'll always need to seek if we're being forced to reset, or if this is a first selection to
|
||||||
// a position other than the one we started preparing with, or if we're making a selection
|
// a position other than the one we started preparing with, or if we're making a selection
|
||||||
// having previously disabled all tracks.
|
// having previously disabled all tracks.
|
||||||
boolean seekRequired = forceReset
|
boolean seekRequired =
|
||||||
|| (seenFirstTrackSelection ? oldEnabledSampleQueueCount == 0
|
forceReset
|
||||||
|
|| (seenFirstTrackSelection
|
||||||
|
? oldEnabledTrackGroupCount == 0
|
||||||
: positionUs != lastSeekPositionUs);
|
: positionUs != lastSeekPositionUs);
|
||||||
// Get the old (i.e. current before the loop below executes) primary track selection. The new
|
// Get the old (i.e. current before the loop below executes) primary track selection. The new
|
||||||
// primary selection will equal the old one unless it's changed in the loop.
|
// primary selection will equal the old one unless it's changed in the loop.
|
||||||
@ -219,19 +247,18 @@ import java.util.Arrays;
|
|||||||
// Select new tracks.
|
// Select new tracks.
|
||||||
for (int i = 0; i < selections.length; i++) {
|
for (int i = 0; i < selections.length; i++) {
|
||||||
if (streams[i] == null && selections[i] != null) {
|
if (streams[i] == null && selections[i] != null) {
|
||||||
|
enabledTrackGroupCount++;
|
||||||
TrackSelection selection = selections[i];
|
TrackSelection selection = selections[i];
|
||||||
int trackGroupIndex = trackGroups.indexOf(selection.getTrackGroup());
|
int trackGroupIndex = trackGroups.indexOf(selection.getTrackGroup());
|
||||||
int sampleQueueIndex = trackGroupToSampleQueueIndex[trackGroupIndex];
|
|
||||||
setSampleQueueEnabledState(sampleQueueIndex, true);
|
|
||||||
if (trackGroupIndex == primaryTrackGroupIndex) {
|
if (trackGroupIndex == primaryTrackGroupIndex) {
|
||||||
primaryTrackSelection = selection;
|
primaryTrackSelection = selection;
|
||||||
chunkSource.selectTracks(selection);
|
chunkSource.selectTracks(selection);
|
||||||
}
|
}
|
||||||
streams[i] = new HlsSampleStream(this, sampleQueueIndex);
|
streams[i] = new HlsSampleStream(this, trackGroupIndex);
|
||||||
streamResetFlags[i] = true;
|
streamResetFlags[i] = true;
|
||||||
// If there's still a chance of avoiding a seek, try and seek within the sample queue.
|
// If there's still a chance of avoiding a seek, try and seek within the sample queue.
|
||||||
if (!seekRequired) {
|
if (sampleQueuesBuilt && !seekRequired) {
|
||||||
SampleQueue sampleQueue = sampleQueues[sampleQueueIndex];
|
SampleQueue sampleQueue = sampleQueues[trackGroupToSampleQueueIndex[trackGroupIndex]];
|
||||||
sampleQueue.rewind();
|
sampleQueue.rewind();
|
||||||
// A seek can be avoided if we're able to advance to the current playback position in the
|
// A seek can be avoided if we're able to advance to the current playback position in the
|
||||||
// sample queue, or if we haven't read anything from the queue since the previous seek
|
// sample queue, or if we haven't read anything from the queue since the previous seek
|
||||||
@ -243,15 +270,17 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabledSampleQueueCount == 0) {
|
if (enabledTrackGroupCount == 0) {
|
||||||
chunkSource.reset();
|
chunkSource.reset();
|
||||||
downstreamTrackFormat = null;
|
downstreamTrackFormat = null;
|
||||||
mediaChunks.clear();
|
mediaChunks.clear();
|
||||||
if (loader.isLoading()) {
|
if (loader.isLoading()) {
|
||||||
|
if (sampleQueuesBuilt) {
|
||||||
// Discard as much as we can synchronously.
|
// Discard as much as we can synchronously.
|
||||||
for (SampleQueue sampleQueue : sampleQueues) {
|
for (SampleQueue sampleQueue : sampleQueues) {
|
||||||
sampleQueue.discardToEnd();
|
sampleQueue.discardToEnd();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
loader.cancelLoading();
|
loader.cancelLoading();
|
||||||
} else {
|
} else {
|
||||||
resetSampleQueues();
|
resetSampleQueues();
|
||||||
@ -297,6 +326,9 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void discardBuffer(long positionUs, boolean toKeyframe) {
|
public void discardBuffer(long positionUs, boolean toKeyframe) {
|
||||||
|
if (!sampleQueuesBuilt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int sampleQueueCount = sampleQueues.length;
|
int sampleQueueCount = sampleQueues.length;
|
||||||
for (int i = 0; i < sampleQueueCount; i++) {
|
for (int i = 0; i < sampleQueueCount; i++) {
|
||||||
sampleQueues[i].discardTo(positionUs, toKeyframe, sampleQueuesEnabledStates[i]);
|
sampleQueues[i].discardTo(positionUs, toKeyframe, sampleQueuesEnabledStates[i]);
|
||||||
@ -314,7 +346,7 @@ import java.util.Arrays;
|
|||||||
public boolean seekToUs(long positionUs, boolean forceReset) {
|
public boolean seekToUs(long positionUs, boolean forceReset) {
|
||||||
lastSeekPositionUs = positionUs;
|
lastSeekPositionUs = positionUs;
|
||||||
// If we're not forced to reset nor have a pending reset, see if we can seek within the buffer.
|
// If we're not forced to reset nor have a pending reset, see if we can seek within the buffer.
|
||||||
if (!forceReset && !isPendingReset() && seekInsideBufferUs(positionUs)) {
|
if (sampleQueuesBuilt && !forceReset && !isPendingReset() && seekInsideBufferUs(positionUs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We were unable to seek within the buffer, so need to reset.
|
// We were unable to seek within the buffer, so need to reset.
|
||||||
@ -426,9 +458,11 @@ import java.util.Arrays;
|
|||||||
if (lastCompletedMediaChunk != null) {
|
if (lastCompletedMediaChunk != null) {
|
||||||
bufferedPositionUs = Math.max(bufferedPositionUs, lastCompletedMediaChunk.endTimeUs);
|
bufferedPositionUs = Math.max(bufferedPositionUs, lastCompletedMediaChunk.endTimeUs);
|
||||||
}
|
}
|
||||||
|
if (sampleQueuesBuilt) {
|
||||||
for (SampleQueue sampleQueue : sampleQueues) {
|
for (SampleQueue sampleQueue : sampleQueues) {
|
||||||
bufferedPositionUs = Math.max(bufferedPositionUs,
|
bufferedPositionUs =
|
||||||
sampleQueue.getLargestQueuedTimestampUs());
|
Math.max(bufferedPositionUs, sampleQueue.getLargestQueuedTimestampUs());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return bufferedPositionUs;
|
return bufferedPositionUs;
|
||||||
}
|
}
|
||||||
@ -513,7 +547,7 @@ import java.util.Arrays;
|
|||||||
loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded());
|
loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded());
|
||||||
if (!released) {
|
if (!released) {
|
||||||
resetSampleQueues();
|
resetSampleQueues();
|
||||||
if (enabledSampleQueueCount > 0) {
|
if (enabledTrackGroupCount > 0) {
|
||||||
callback.onContinueLoadingRequested(this);
|
callback.onContinueLoadingRequested(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -582,7 +616,7 @@ import java.util.Arrays;
|
|||||||
return sampleQueues[i];
|
return sampleQueues[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sampleQueuesBuilt) {
|
if (tracksEnded) {
|
||||||
Log.w(TAG, "Unmapped track with id " + id + " of type " + type);
|
Log.w(TAG, "Unmapped track with id " + id + " of type " + type);
|
||||||
return new DummyTrackOutput();
|
return new DummyTrackOutput();
|
||||||
}
|
}
|
||||||
@ -603,8 +637,8 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTracks() {
|
public void endTracks() {
|
||||||
sampleQueuesBuilt = true;
|
tracksEnded = true;
|
||||||
handler.post(maybeFinishPrepareRunnable);
|
handler.post(onTracksEndedRunnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -616,10 +650,8 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpstreamFormatChanged(Format format) {
|
public void onUpstreamFormatChanged(Format format) {
|
||||||
if (!prepared) {
|
|
||||||
handler.post(maybeFinishPrepareRunnable);
|
handler.post(maybeFinishPrepareRunnable);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the loading thread.
|
// Called by the loading thread.
|
||||||
|
|
||||||
@ -650,6 +682,11 @@ import java.util.Arrays;
|
|||||||
pendingResetUpstreamFormats = false;
|
pendingResetUpstreamFormats = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onTracksEnded() {
|
||||||
|
sampleQueuesBuilt = true;
|
||||||
|
maybeFinishPrepare();
|
||||||
|
}
|
||||||
|
|
||||||
private void maybeFinishPrepare() {
|
private void maybeFinishPrepare() {
|
||||||
if (released || prepared || !sampleQueuesBuilt) {
|
if (released || prepared || !sampleQueuesBuilt) {
|
||||||
return;
|
return;
|
||||||
@ -739,14 +776,14 @@ import java.util.Arrays;
|
|||||||
if (i == primaryExtractorTrackIndex) {
|
if (i == primaryExtractorTrackIndex) {
|
||||||
Format[] formats = new Format[chunkSourceTrackCount];
|
Format[] formats = new Format[chunkSourceTrackCount];
|
||||||
for (int j = 0; j < chunkSourceTrackCount; j++) {
|
for (int j = 0; j < chunkSourceTrackCount; j++) {
|
||||||
formats[j] = deriveFormat(chunkSourceTrackGroup.getFormat(j), sampleFormat);
|
formats[j] = deriveFormat(chunkSourceTrackGroup.getFormat(j), sampleFormat, true);
|
||||||
}
|
}
|
||||||
trackGroups[i] = new TrackGroup(formats);
|
trackGroups[i] = new TrackGroup(formats);
|
||||||
primaryTrackGroupIndex = i;
|
primaryTrackGroupIndex = i;
|
||||||
} else {
|
} else {
|
||||||
Format trackFormat = primaryExtractorTrackType == PRIMARY_TYPE_VIDEO
|
Format trackFormat = primaryExtractorTrackType == PRIMARY_TYPE_VIDEO
|
||||||
&& MimeTypes.isAudio(sampleFormat.sampleMimeType) ? muxedAudioFormat : null;
|
&& MimeTypes.isAudio(sampleFormat.sampleMimeType) ? muxedAudioFormat : null;
|
||||||
trackGroups[i] = new TrackGroup(deriveFormat(trackFormat, sampleFormat));
|
trackGroups[i] = new TrackGroup(deriveFormat(trackFormat, sampleFormat, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.trackGroups = new TrackGroupArray(trackGroups);
|
this.trackGroups = new TrackGroupArray(trackGroups);
|
||||||
@ -761,7 +798,6 @@ import java.util.Arrays;
|
|||||||
private void setSampleQueueEnabledState(int sampleQueueIndex, boolean enabledState) {
|
private void setSampleQueueEnabledState(int sampleQueueIndex, boolean enabledState) {
|
||||||
Assertions.checkState(sampleQueuesEnabledStates[sampleQueueIndex] != enabledState);
|
Assertions.checkState(sampleQueuesEnabledStates[sampleQueueIndex] != enabledState);
|
||||||
sampleQueuesEnabledStates[sampleQueueIndex] = enabledState;
|
sampleQueuesEnabledStates[sampleQueueIndex] = enabledState;
|
||||||
enabledSampleQueueCount = enabledSampleQueueCount + (enabledState ? 1 : -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HlsMediaChunk getLastMediaChunk() {
|
private HlsMediaChunk getLastMediaChunk() {
|
||||||
@ -797,22 +833,30 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives a track format corresponding to a given container format, by combining it with sample
|
* Derives a track format using master playlist and sample format information.
|
||||||
* level information obtained from the samples.
|
|
||||||
*
|
*
|
||||||
* @param containerFormat The container format for which the track format should be derived.
|
* @param playlistFormat The format information obtained from the master playlist.
|
||||||
* @param sampleFormat A sample format from which to obtain sample level information.
|
* @param sampleFormat The format information obtained from the samples.
|
||||||
|
* @param propagateBitrate Whether the bitrate from the playlist format should be included in the
|
||||||
|
* derived format.
|
||||||
* @return The derived track format.
|
* @return The derived track format.
|
||||||
*/
|
*/
|
||||||
private static Format deriveFormat(Format containerFormat, Format sampleFormat) {
|
private static Format deriveFormat(
|
||||||
if (containerFormat == null) {
|
Format playlistFormat, Format sampleFormat, boolean propagateBitrate) {
|
||||||
|
if (playlistFormat == null) {
|
||||||
return sampleFormat;
|
return sampleFormat;
|
||||||
}
|
}
|
||||||
|
int bitrate = propagateBitrate ? playlistFormat.bitrate : Format.NO_VALUE;
|
||||||
int sampleTrackType = MimeTypes.getTrackType(sampleFormat.sampleMimeType);
|
int sampleTrackType = MimeTypes.getTrackType(sampleFormat.sampleMimeType);
|
||||||
String codecs = Util.getCodecsOfType(containerFormat.codecs, sampleTrackType);
|
String codecs = Util.getCodecsOfType(playlistFormat.codecs, sampleTrackType);
|
||||||
return sampleFormat.copyWithContainerInfo(containerFormat.id, codecs, containerFormat.bitrate,
|
return sampleFormat.copyWithContainerInfo(
|
||||||
containerFormat.width, containerFormat.height, containerFormat.selectionFlags,
|
playlistFormat.id,
|
||||||
containerFormat.language);
|
codecs,
|
||||||
|
bitrate,
|
||||||
|
playlistFormat.width,
|
||||||
|
playlistFormat.height,
|
||||||
|
playlistFormat.selectionFlags,
|
||||||
|
playlistFormat.language);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isMediaChunk(Chunk chunk) {
|
private static boolean isMediaChunk(Chunk chunk) {
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.source.hls;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.source.SampleQueue;
|
||||||
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/** Thrown when it is not possible to map a {@link TrackGroup} to a {@link SampleQueue}. */
|
||||||
|
public final class SampleQueueMappingException extends IOException {
|
||||||
|
|
||||||
|
/** @param mimeType The mime type of the track group whose mapping failed. */
|
||||||
|
public SampleQueueMappingException(String mimeType) {
|
||||||
|
super("Unable to bind a sample queue to TrackGroup with mime type " + mimeType + ".");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user