mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Make RepresentationHolder immutable.
This allows to use it as a snapshot of the representation. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=202287466
This commit is contained in:
parent
65a58ffcb5
commit
f2ce0d8981
1 changed files with 102 additions and 60 deletions
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.dash;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.support.annotation.CheckResult;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
|
@ -209,7 +210,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
List<Representation> representations = getRepresentations();
|
List<Representation> representations = getRepresentations();
|
||||||
for (int i = 0; i < representationHolders.length; i++) {
|
for (int i = 0; i < representationHolders.length; i++) {
|
||||||
Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i));
|
Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i));
|
||||||
representationHolders[i].updateRepresentation(periodDurationUs, representation);
|
representationHolders[i] =
|
||||||
|
representationHolders[i].copyWithNewRepresentation(periodDurationUs, representation);
|
||||||
}
|
}
|
||||||
} catch (BehindLiveWindowException e) {
|
} catch (BehindLiveWindowException e) {
|
||||||
fatalError = e;
|
fatalError = e;
|
||||||
|
|
@ -346,18 +348,19 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
public void onChunkLoadCompleted(Chunk chunk) {
|
public void onChunkLoadCompleted(Chunk chunk) {
|
||||||
if (chunk instanceof InitializationChunk) {
|
if (chunk instanceof InitializationChunk) {
|
||||||
InitializationChunk initializationChunk = (InitializationChunk) chunk;
|
InitializationChunk initializationChunk = (InitializationChunk) chunk;
|
||||||
RepresentationHolder representationHolder =
|
int trackIndex = trackSelection.indexOf(initializationChunk.trackFormat);
|
||||||
representationHolders[trackSelection.indexOf(initializationChunk.trackFormat)];
|
RepresentationHolder representationHolder = representationHolders[trackIndex];
|
||||||
// The null check avoids overwriting an index obtained from the manifest with one obtained
|
// The null check avoids overwriting an index obtained from the manifest with one obtained
|
||||||
// from the stream. If the manifest defines an index then the stream shouldn't, but in cases
|
// from the stream. If the manifest defines an index then the stream shouldn't, but in cases
|
||||||
// where it does we should ignore it.
|
// where it does we should ignore it.
|
||||||
if (representationHolder.segmentIndex == null) {
|
if (representationHolder.segmentIndex == null) {
|
||||||
SeekMap seekMap = representationHolder.extractorWrapper.getSeekMap();
|
SeekMap seekMap = representationHolder.extractorWrapper.getSeekMap();
|
||||||
if (seekMap != null) {
|
if (seekMap != null) {
|
||||||
representationHolder.segmentIndex =
|
representationHolders[trackIndex] =
|
||||||
new DashWrappingSegmentIndex(
|
representationHolder.copyWithNewSegmentIndex(
|
||||||
(ChunkIndex) seekMap,
|
new DashWrappingSegmentIndex(
|
||||||
representationHolder.representation.presentationTimeOffsetUs);
|
(ChunkIndex) seekMap,
|
||||||
|
representationHolder.representation.presentationTimeOffsetUs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -500,18 +503,16 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
|
|
||||||
// Protected classes.
|
// Protected classes.
|
||||||
|
|
||||||
/**
|
/** Holds information about a snapshot of a single {@link Representation}. */
|
||||||
* Holds information about a single {@link Representation}.
|
|
||||||
*/
|
|
||||||
protected static final class RepresentationHolder {
|
protected static final class RepresentationHolder {
|
||||||
|
|
||||||
/* package */ final ChunkExtractorWrapper extractorWrapper;
|
/* package */ final @Nullable ChunkExtractorWrapper extractorWrapper;
|
||||||
|
|
||||||
public Representation representation;
|
public final Representation representation;
|
||||||
public DashSegmentIndex segmentIndex;
|
public final @Nullable DashSegmentIndex segmentIndex;
|
||||||
|
|
||||||
private long periodDurationUs;
|
private final long periodDurationUs;
|
||||||
private long segmentNumShift;
|
private final long segmentNumShift;
|
||||||
|
|
||||||
/* package */ RepresentationHolder(
|
/* package */ RepresentationHolder(
|
||||||
long periodDurationUs,
|
long periodDurationUs,
|
||||||
|
|
@ -520,80 +521,86 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
boolean enableEventMessageTrack,
|
boolean enableEventMessageTrack,
|
||||||
boolean enableCea608Track,
|
boolean enableCea608Track,
|
||||||
TrackOutput playerEmsgTrackOutput) {
|
TrackOutput playerEmsgTrackOutput) {
|
||||||
this.periodDurationUs = periodDurationUs;
|
this(
|
||||||
this.representation = representation;
|
periodDurationUs,
|
||||||
String containerMimeType = representation.format.containerMimeType;
|
representation,
|
||||||
if (mimeTypeIsRawText(containerMimeType)) {
|
createExtractorWrapper(
|
||||||
extractorWrapper = null;
|
trackType,
|
||||||
} else {
|
representation,
|
||||||
Extractor extractor;
|
enableEventMessageTrack,
|
||||||
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
|
enableCea608Track,
|
||||||
extractor = new RawCcExtractor(representation.format);
|
playerEmsgTrackOutput),
|
||||||
} else if (mimeTypeIsWebm(containerMimeType)) {
|
/* segmentNumShift= */ 0,
|
||||||
extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES);
|
representation.getIndex());
|
||||||
} else {
|
|
||||||
int flags = 0;
|
|
||||||
if (enableEventMessageTrack) {
|
|
||||||
flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK;
|
|
||||||
}
|
|
||||||
// TODO: Use caption format information from the manifest if available.
|
|
||||||
List<Format> closedCaptionFormats = enableCea608Track
|
|
||||||
? Collections.singletonList(
|
|
||||||
Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, 0, null))
|
|
||||||
: Collections.<Format>emptyList();
|
|
||||||
|
|
||||||
extractor =
|
|
||||||
new FragmentedMp4Extractor(
|
|
||||||
flags, null, null, null, closedCaptionFormats, playerEmsgTrackOutput);
|
|
||||||
}
|
|
||||||
// Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream,
|
|
||||||
// as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
|
|
||||||
extractorWrapper = new ChunkExtractorWrapper(extractor, trackType, representation.format);
|
|
||||||
}
|
|
||||||
segmentIndex = representation.getIndex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void updateRepresentation(long newPeriodDurationUs,
|
private RepresentationHolder(
|
||||||
Representation newRepresentation) throws BehindLiveWindowException {
|
long periodDurationUs,
|
||||||
|
Representation representation,
|
||||||
|
@Nullable ChunkExtractorWrapper extractorWrapper,
|
||||||
|
long segmentNumShift,
|
||||||
|
@Nullable DashSegmentIndex segmentIndex) {
|
||||||
|
this.periodDurationUs = periodDurationUs;
|
||||||
|
this.representation = representation;
|
||||||
|
this.segmentNumShift = segmentNumShift;
|
||||||
|
this.extractorWrapper = extractorWrapper;
|
||||||
|
this.segmentIndex = segmentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckResult
|
||||||
|
/* package */ RepresentationHolder copyWithNewRepresentation(
|
||||||
|
long newPeriodDurationUs, Representation newRepresentation)
|
||||||
|
throws BehindLiveWindowException {
|
||||||
DashSegmentIndex oldIndex = representation.getIndex();
|
DashSegmentIndex oldIndex = representation.getIndex();
|
||||||
DashSegmentIndex newIndex = newRepresentation.getIndex();
|
DashSegmentIndex newIndex = newRepresentation.getIndex();
|
||||||
|
|
||||||
periodDurationUs = newPeriodDurationUs;
|
|
||||||
representation = newRepresentation;
|
|
||||||
if (oldIndex == null) {
|
if (oldIndex == null) {
|
||||||
// Segment numbers cannot shift if the index isn't defined by the manifest.
|
// Segment numbers cannot shift if the index isn't defined by the manifest.
|
||||||
return;
|
return new RepresentationHolder(
|
||||||
|
newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, oldIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
segmentIndex = newIndex;
|
|
||||||
if (!oldIndex.isExplicit()) {
|
if (!oldIndex.isExplicit()) {
|
||||||
// Segment numbers cannot shift if the index isn't explicit.
|
// Segment numbers cannot shift if the index isn't explicit.
|
||||||
return;
|
return new RepresentationHolder(
|
||||||
|
newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int oldIndexSegmentCount = oldIndex.getSegmentCount(periodDurationUs);
|
int oldIndexSegmentCount = oldIndex.getSegmentCount(newPeriodDurationUs);
|
||||||
if (oldIndexSegmentCount == 0) {
|
if (oldIndexSegmentCount == 0) {
|
||||||
// Segment numbers cannot shift if the old index was empty.
|
// Segment numbers cannot shift if the old index was empty.
|
||||||
return;
|
return new RepresentationHolder(
|
||||||
|
newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
long oldIndexLastSegmentNum = oldIndex.getFirstSegmentNum() + oldIndexSegmentCount - 1;
|
long oldIndexLastSegmentNum = oldIndex.getFirstSegmentNum() + oldIndexSegmentCount - 1;
|
||||||
long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum)
|
long oldIndexEndTimeUs =
|
||||||
+ oldIndex.getDurationUs(oldIndexLastSegmentNum, periodDurationUs);
|
oldIndex.getTimeUs(oldIndexLastSegmentNum)
|
||||||
|
+ oldIndex.getDurationUs(oldIndexLastSegmentNum, newPeriodDurationUs);
|
||||||
long newIndexFirstSegmentNum = newIndex.getFirstSegmentNum();
|
long newIndexFirstSegmentNum = newIndex.getFirstSegmentNum();
|
||||||
long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum);
|
long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum);
|
||||||
|
long newSegmentNumShift = segmentNumShift;
|
||||||
if (oldIndexEndTimeUs == newIndexStartTimeUs) {
|
if (oldIndexEndTimeUs == newIndexStartTimeUs) {
|
||||||
// The new index continues where the old one ended, with no overlap.
|
// The new index continues where the old one ended, with no overlap.
|
||||||
segmentNumShift += oldIndexLastSegmentNum + 1 - newIndexFirstSegmentNum;
|
newSegmentNumShift += oldIndexLastSegmentNum + 1 - newIndexFirstSegmentNum;
|
||||||
} else if (oldIndexEndTimeUs < newIndexStartTimeUs) {
|
} else if (oldIndexEndTimeUs < newIndexStartTimeUs) {
|
||||||
// There's a gap between the old index and the new one which means we've slipped behind the
|
// There's a gap between the old index and the new one which means we've slipped behind the
|
||||||
// live window and can't proceed.
|
// live window and can't proceed.
|
||||||
throw new BehindLiveWindowException();
|
throw new BehindLiveWindowException();
|
||||||
} else {
|
} else {
|
||||||
// The new index overlaps with the old one.
|
// The new index overlaps with the old one.
|
||||||
segmentNumShift += oldIndex.getSegmentNum(newIndexStartTimeUs, periodDurationUs)
|
newSegmentNumShift +=
|
||||||
- newIndexFirstSegmentNum;
|
oldIndex.getSegmentNum(newIndexStartTimeUs, newPeriodDurationUs)
|
||||||
|
- newIndexFirstSegmentNum;
|
||||||
}
|
}
|
||||||
|
return new RepresentationHolder(
|
||||||
|
newPeriodDurationUs, newRepresentation, extractorWrapper, newSegmentNumShift, newIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckResult
|
||||||
|
/* package */ RepresentationHolder copyWithNewSegmentIndex(DashSegmentIndex segmentIndex) {
|
||||||
|
return new RepresentationHolder(
|
||||||
|
periodDurationUs, representation, extractorWrapper, segmentNumShift, segmentIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getFirstSegmentNum() {
|
public long getFirstSegmentNum() {
|
||||||
|
|
@ -629,5 +636,40 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
private static boolean mimeTypeIsRawText(String mimeType) {
|
private static boolean mimeTypeIsRawText(String mimeType) {
|
||||||
return MimeTypes.isText(mimeType) || MimeTypes.APPLICATION_TTML.equals(mimeType);
|
return MimeTypes.isText(mimeType) || MimeTypes.APPLICATION_TTML.equals(mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static @Nullable ChunkExtractorWrapper createExtractorWrapper(
|
||||||
|
int trackType,
|
||||||
|
Representation representation,
|
||||||
|
boolean enableEventMessageTrack,
|
||||||
|
boolean enableCea608Track,
|
||||||
|
TrackOutput playerEmsgTrackOutput) {
|
||||||
|
String containerMimeType = representation.format.containerMimeType;
|
||||||
|
if (mimeTypeIsRawText(containerMimeType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Extractor extractor;
|
||||||
|
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
|
||||||
|
extractor = new RawCcExtractor(representation.format);
|
||||||
|
} else if (mimeTypeIsWebm(containerMimeType)) {
|
||||||
|
extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES);
|
||||||
|
} else {
|
||||||
|
int flags = 0;
|
||||||
|
if (enableEventMessageTrack) {
|
||||||
|
flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK;
|
||||||
|
}
|
||||||
|
// TODO: Use caption format information from the manifest if available.
|
||||||
|
List<Format> closedCaptionFormats =
|
||||||
|
enableCea608Track
|
||||||
|
? Collections.singletonList(
|
||||||
|
Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, 0, null))
|
||||||
|
: Collections.emptyList();
|
||||||
|
extractor =
|
||||||
|
new FragmentedMp4Extractor(
|
||||||
|
flags, null, null, null, closedCaptionFormats, playerEmsgTrackOutput);
|
||||||
|
}
|
||||||
|
// Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream,
|
||||||
|
// as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
|
||||||
|
return new ChunkExtractorWrapper(extractor, trackType, representation.format);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue