mirror of
https://github.com/androidx/media.git
synced 2025-05-05 06:30:24 +08:00
Fix HlsTrackStreamWrapper chunk queue updating
Also fix possible repeat-preparation for HlsTrackStreamWrapper and ExtractorSampleSource. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=126640380
This commit is contained in:
parent
7b9e47ec6b
commit
8db06a332f
@ -111,6 +111,15 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a source identifier for subsequent samples.
|
||||||
|
*
|
||||||
|
* @param sourceId The source identifier.
|
||||||
|
*/
|
||||||
|
public void sourceId(int sourceId) {
|
||||||
|
infoQueue.sourceId(sourceId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that samples subsequently queued to the buffer should be spliced into those already
|
* Indicates that samples subsequently queued to the buffer should be spliced into those already
|
||||||
* queued.
|
* queued.
|
||||||
@ -187,6 +196,16 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
return infoQueue.getReadIndex();
|
return infoQueue.getReadIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peeks the source id of the next sample, or the current upstream source id if the buffer is
|
||||||
|
* empty.
|
||||||
|
*
|
||||||
|
* @return The source id.
|
||||||
|
*/
|
||||||
|
public int peekSourceId() {
|
||||||
|
return infoQueue.peekSourceId();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the upstream {@link Format} in which samples are being queued.
|
* Returns the upstream {@link Format} in which samples are being queued.
|
||||||
*/
|
*/
|
||||||
@ -581,6 +600,7 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
|
|
||||||
private int capacity;
|
private int capacity;
|
||||||
|
|
||||||
|
private int[] sourceIds;
|
||||||
private long[] offsets;
|
private long[] offsets;
|
||||||
private int[] sizes;
|
private int[] sizes;
|
||||||
private int[] flags;
|
private int[] flags;
|
||||||
@ -596,9 +616,11 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
private long largestDequeuedTimestampUs;
|
private long largestDequeuedTimestampUs;
|
||||||
private long largestQueuedTimestampUs;
|
private long largestQueuedTimestampUs;
|
||||||
private Format upstreamFormat;
|
private Format upstreamFormat;
|
||||||
|
private int upstreamSourceId;
|
||||||
|
|
||||||
public InfoQueue() {
|
public InfoQueue() {
|
||||||
capacity = SAMPLE_CAPACITY_INCREMENT;
|
capacity = SAMPLE_CAPACITY_INCREMENT;
|
||||||
|
sourceIds = new int[capacity];
|
||||||
offsets = new long[capacity];
|
offsets = new long[capacity];
|
||||||
timesUs = new long[capacity];
|
timesUs = new long[capacity];
|
||||||
flags = new int[capacity];
|
flags = new int[capacity];
|
||||||
@ -664,6 +686,10 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
return offsets[relativeWriteIndex];
|
return offsets[relativeWriteIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sourceId(int sourceId) {
|
||||||
|
upstreamSourceId = sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
// Called by the consuming thread.
|
// Called by the consuming thread.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -673,6 +699,14 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
return absoluteReadIndex;
|
return absoluteReadIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peeks the source id of the next sample, or the current upstream source id if the queue is
|
||||||
|
* empty.
|
||||||
|
*/
|
||||||
|
public int peekSourceId() {
|
||||||
|
return queueSize == 0 ? upstreamSourceId : sourceIds[relativeReadIndex];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the queue is empty.
|
* Returns whether the queue is empty.
|
||||||
*/
|
*/
|
||||||
@ -815,11 +849,13 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
flags[relativeWriteIndex] = sampleFlags;
|
flags[relativeWriteIndex] = sampleFlags;
|
||||||
encryptionKeys[relativeWriteIndex] = encryptionKey;
|
encryptionKeys[relativeWriteIndex] = encryptionKey;
|
||||||
formats[relativeWriteIndex] = upstreamFormat;
|
formats[relativeWriteIndex] = upstreamFormat;
|
||||||
|
sourceIds[relativeWriteIndex] = upstreamSourceId;
|
||||||
// Increment the write index.
|
// Increment the write index.
|
||||||
queueSize++;
|
queueSize++;
|
||||||
if (queueSize == capacity) {
|
if (queueSize == capacity) {
|
||||||
// Increase the capacity.
|
// Increase the capacity.
|
||||||
int newCapacity = capacity + SAMPLE_CAPACITY_INCREMENT;
|
int newCapacity = capacity + SAMPLE_CAPACITY_INCREMENT;
|
||||||
|
int[] newSourceIds = new int[newCapacity];
|
||||||
long[] newOffsets = new long[newCapacity];
|
long[] newOffsets = new long[newCapacity];
|
||||||
long[] newTimesUs = new long[newCapacity];
|
long[] newTimesUs = new long[newCapacity];
|
||||||
int[] newFlags = new int[newCapacity];
|
int[] newFlags = new int[newCapacity];
|
||||||
@ -833,6 +869,7 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
System.arraycopy(sizes, relativeReadIndex, newSizes, 0, beforeWrap);
|
System.arraycopy(sizes, relativeReadIndex, newSizes, 0, beforeWrap);
|
||||||
System.arraycopy(encryptionKeys, relativeReadIndex, newEncryptionKeys, 0, beforeWrap);
|
System.arraycopy(encryptionKeys, relativeReadIndex, newEncryptionKeys, 0, beforeWrap);
|
||||||
System.arraycopy(formats, relativeReadIndex, newFormats, 0, beforeWrap);
|
System.arraycopy(formats, relativeReadIndex, newFormats, 0, beforeWrap);
|
||||||
|
System.arraycopy(sourceIds, relativeReadIndex, newSourceIds, 0, beforeWrap);
|
||||||
int afterWrap = relativeReadIndex;
|
int afterWrap = relativeReadIndex;
|
||||||
System.arraycopy(offsets, 0, newOffsets, beforeWrap, afterWrap);
|
System.arraycopy(offsets, 0, newOffsets, beforeWrap, afterWrap);
|
||||||
System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap);
|
System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap);
|
||||||
@ -840,12 +877,14 @@ public final class DefaultTrackOutput implements TrackOutput {
|
|||||||
System.arraycopy(sizes, 0, newSizes, beforeWrap, afterWrap);
|
System.arraycopy(sizes, 0, newSizes, beforeWrap, afterWrap);
|
||||||
System.arraycopy(encryptionKeys, 0, newEncryptionKeys, beforeWrap, afterWrap);
|
System.arraycopy(encryptionKeys, 0, newEncryptionKeys, beforeWrap, afterWrap);
|
||||||
System.arraycopy(formats, 0, newFormats, beforeWrap, afterWrap);
|
System.arraycopy(formats, 0, newFormats, beforeWrap, afterWrap);
|
||||||
|
System.arraycopy(sourceIds, 0, newSourceIds, beforeWrap, afterWrap);
|
||||||
offsets = newOffsets;
|
offsets = newOffsets;
|
||||||
timesUs = newTimesUs;
|
timesUs = newTimesUs;
|
||||||
flags = newFlags;
|
flags = newFlags;
|
||||||
sizes = newSizes;
|
sizes = newSizes;
|
||||||
encryptionKeys = newEncryptionKeys;
|
encryptionKeys = newEncryptionKeys;
|
||||||
formats = newFormats;
|
formats = newFormats;
|
||||||
|
sourceIds = newSourceIds;
|
||||||
relativeReadIndex = 0;
|
relativeReadIndex = 0;
|
||||||
relativeWriteIndex = capacity;
|
relativeWriteIndex = capacity;
|
||||||
queueSize = capacity;
|
queueSize = capacity;
|
||||||
|
@ -544,7 +544,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private void maybeFinishPrepare() {
|
private void maybeFinishPrepare() {
|
||||||
if (seekMap == null || !tracksBuilt) {
|
if (prepared || seekMap == null || !tracksBuilt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
||||||
|
@ -25,12 +25,20 @@ import com.google.android.exoplayer.upstream.DataSpec;
|
|||||||
import com.google.android.exoplayer.util.Util;
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An HLS {@link MediaChunk}.
|
* An HLS {@link MediaChunk}.
|
||||||
*/
|
*/
|
||||||
/* package */ final class HlsMediaChunk extends MediaChunk {
|
/* package */ final class HlsMediaChunk extends MediaChunk {
|
||||||
|
|
||||||
|
private static final AtomicInteger UID_SOURCE = new AtomicInteger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique identifier for the chunk.
|
||||||
|
*/
|
||||||
|
public final int uid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The discontinuity sequence number of the chunk.
|
* The discontinuity sequence number of the chunk.
|
||||||
*/
|
*/
|
||||||
@ -80,6 +88,7 @@ import java.io.IOException;
|
|||||||
this.shouldSpliceIn = shouldSpliceIn;
|
this.shouldSpliceIn = shouldSpliceIn;
|
||||||
// Note: this.dataSource and dataSource may be different.
|
// Note: this.dataSource and dataSource may be different.
|
||||||
this.isEncrypted = this.dataSource instanceof Aes128DataSource;
|
this.isEncrypted = this.dataSource instanceof Aes128DataSource;
|
||||||
|
uid = UID_SOURCE.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,9 +98,7 @@ import java.io.IOException;
|
|||||||
* @param output The output that will receive the loaded samples.
|
* @param output The output that will receive the loaded samples.
|
||||||
*/
|
*/
|
||||||
public void init(HlsTrackStreamWrapper output) {
|
public void init(HlsTrackStreamWrapper output) {
|
||||||
if (shouldSpliceIn) {
|
output.init(uid, shouldSpliceIn);
|
||||||
output.splice();
|
|
||||||
}
|
|
||||||
if (extractorNeedsInit) {
|
if (extractorNeedsInit) {
|
||||||
extractor.init(output);
|
extractor.init(output);
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ import java.util.List;
|
|||||||
private boolean prepared;
|
private boolean prepared;
|
||||||
private int enabledTrackCount;
|
private int enabledTrackCount;
|
||||||
private Format downstreamFormat;
|
private Format downstreamFormat;
|
||||||
|
private int upstreamChunkUid;
|
||||||
|
|
||||||
// Tracks are complicated in HLS. See documentation of buildTracks for details.
|
// Tracks are complicated in HLS. See documentation of buildTracks for details.
|
||||||
// Indexed by track (as exposed by this source).
|
// Indexed by track (as exposed by this source).
|
||||||
@ -254,10 +255,9 @@ import java.util.List;
|
|||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO[REFACTOR]: Restore this.
|
while (mediaChunks.size() > 1 && finishedReadingChunk(mediaChunks.getFirst())) {
|
||||||
// while (mediaChunks.size() > 1 && mediaChunks.get(1).startTimeUs <= downstreamPositionUs) {
|
mediaChunks.removeFirst();
|
||||||
// mediaChunks.removeFirst();
|
}
|
||||||
// }
|
|
||||||
HlsMediaChunk currentChunk = mediaChunks.getFirst();
|
HlsMediaChunk currentChunk = mediaChunks.getFirst();
|
||||||
Format format = currentChunk.format;
|
Format format = currentChunk.format;
|
||||||
if (!format.equals(downstreamFormat)) {
|
if (!format.equals(downstreamFormat)) {
|
||||||
@ -271,6 +271,16 @@ import java.util.List;
|
|||||||
lastSeekPositionUs);
|
lastSeekPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean finishedReadingChunk(HlsMediaChunk chunk) {
|
||||||
|
int chunkUid = chunk.uid;
|
||||||
|
for (int i = 0; i < sampleQueues.size(); i++) {
|
||||||
|
if (groupEnabledStates[i] && sampleQueues.valueAt(i).peekSourceId() == chunkUid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceableLoader implementation
|
// SequenceableLoader implementation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -379,11 +389,21 @@ import java.util.List;
|
|||||||
// Called by the consuming thread, but only when there is no loading thread.
|
// Called by the consuming thread, but only when there is no loading thread.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates to all track outputs that they should splice in subsequently queued samples.
|
* Initializes the wrapper for loading a chunk.
|
||||||
|
*
|
||||||
|
* @param chunkUid The chunk's uid.
|
||||||
|
* @param shouldSpliceIn Whether the samples parsed from the chunk should be spliced into any
|
||||||
|
* samples already queued to the wrapper.
|
||||||
*/
|
*/
|
||||||
public void splice() {
|
public void init(int chunkUid, boolean shouldSpliceIn) {
|
||||||
|
upstreamChunkUid = chunkUid;
|
||||||
for (int i = 0; i < sampleQueues.size(); i++) {
|
for (int i = 0; i < sampleQueues.size(); i++) {
|
||||||
sampleQueues.valueAt(i).splice();
|
sampleQueues.valueAt(i).sourceId(chunkUid);
|
||||||
|
}
|
||||||
|
if (shouldSpliceIn) {
|
||||||
|
for (int i = 0; i < sampleQueues.size(); i++) {
|
||||||
|
sampleQueues.valueAt(i).splice();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,6 +416,7 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator);
|
DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator);
|
||||||
trackOutput.setUpstreamFormatChangeListener(this);
|
trackOutput.setUpstreamFormatChangeListener(this);
|
||||||
|
trackOutput.sourceId(upstreamChunkUid);
|
||||||
sampleQueues.put(id, trackOutput);
|
sampleQueues.put(id, trackOutput);
|
||||||
return trackOutput;
|
return trackOutput;
|
||||||
}
|
}
|
||||||
@ -421,7 +442,7 @@ import java.util.List;
|
|||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private void maybeFinishPrepare() {
|
private void maybeFinishPrepare() {
|
||||||
if (!sampleQueuesBuilt) {
|
if (prepared || !sampleQueuesBuilt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int sampleQueueCount = sampleQueues.size();
|
int sampleQueueCount = sampleQueues.size();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user