use of androidx.media3.exoplayer.dash.manifest.BaseUrl in project media by androidx.
the class DashManifestParser method parsePeriod.
protected Pair<Period, Long> parsePeriod(XmlPullParser xpp, List<BaseUrl> parentBaseUrls, long defaultStartMs, long baseUrlAvailabilityTimeOffsetUs, long availabilityStartTimeMs, long timeShiftBufferDepthMs, boolean dvbProfileDeclared) throws XmlPullParserException, IOException {
@Nullable String id = xpp.getAttributeValue(null, "id");
long startMs = parseDuration(xpp, "start", defaultStartMs);
long periodStartUnixTimeMs = availabilityStartTimeMs != C.TIME_UNSET ? availabilityStartTimeMs + startMs : C.TIME_UNSET;
long durationMs = parseDuration(xpp, "duration", C.TIME_UNSET);
@Nullable SegmentBase segmentBase = null;
@Nullable Descriptor assetIdentifier = null;
List<AdaptationSet> adaptationSets = new ArrayList<>();
List<EventStream> eventStreams = new ArrayList<>();
ArrayList<BaseUrl> baseUrls = new ArrayList<>();
boolean seenFirstBaseUrl = false;
long segmentBaseAvailabilityTimeOffsetUs = C.TIME_UNSET;
do {
xpp.next();
if (XmlPullParserUtil.isStartTag(xpp, "BaseURL")) {
if (!seenFirstBaseUrl) {
baseUrlAvailabilityTimeOffsetUs = parseAvailabilityTimeOffsetUs(xpp, baseUrlAvailabilityTimeOffsetUs);
seenFirstBaseUrl = true;
}
baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls, dvbProfileDeclared));
} else if (XmlPullParserUtil.isStartTag(xpp, "AdaptationSet")) {
adaptationSets.add(parseAdaptationSet(xpp, !baseUrls.isEmpty() ? baseUrls : parentBaseUrls, segmentBase, durationMs, baseUrlAvailabilityTimeOffsetUs, segmentBaseAvailabilityTimeOffsetUs, periodStartUnixTimeMs, timeShiftBufferDepthMs, dvbProfileDeclared));
} else if (XmlPullParserUtil.isStartTag(xpp, "EventStream")) {
eventStreams.add(parseEventStream(xpp));
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
segmentBase = parseSegmentBase(xpp, /* parent= */
null);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
segmentBaseAvailabilityTimeOffsetUs = parseAvailabilityTimeOffsetUs(xpp, /* parentAvailabilityTimeOffsetUs= */
C.TIME_UNSET);
segmentBase = parseSegmentList(xpp, /* parent= */
null, periodStartUnixTimeMs, durationMs, baseUrlAvailabilityTimeOffsetUs, segmentBaseAvailabilityTimeOffsetUs, timeShiftBufferDepthMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBaseAvailabilityTimeOffsetUs = parseAvailabilityTimeOffsetUs(xpp, /* parentAvailabilityTimeOffsetUs= */
C.TIME_UNSET);
segmentBase = parseSegmentTemplate(xpp, /* parent= */
null, ImmutableList.of(), periodStartUnixTimeMs, durationMs, baseUrlAvailabilityTimeOffsetUs, segmentBaseAvailabilityTimeOffsetUs, timeShiftBufferDepthMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "AssetIdentifier")) {
assetIdentifier = parseDescriptor(xpp, "AssetIdentifier");
} else {
maybeSkipTag(xpp);
}
} while (!XmlPullParserUtil.isEndTag(xpp, "Period"));
return Pair.create(buildPeriod(id, startMs, adaptationSets, eventStreams, assetIdentifier), durationMs);
}
use of androidx.media3.exoplayer.dash.manifest.BaseUrl in project media by androidx.
the class DashDownloader method addSegmentsForAdaptationSet.
private void addSegmentsForAdaptationSet(DataSource dataSource, AdaptationSet adaptationSet, long periodStartUs, long periodDurationUs, boolean removing, ArrayList<Segment> out) throws IOException, InterruptedException {
for (int i = 0; i < adaptationSet.representations.size(); i++) {
Representation representation = adaptationSet.representations.get(i);
DashSegmentIndex index;
try {
index = getSegmentIndex(dataSource, adaptationSet.type, representation, removing);
if (index == null) {
// Loading succeeded but there was no index.
throw new DownloadException("Missing segment index");
}
} catch (IOException e) {
if (!removing) {
throw e;
}
// Generating an incomplete segment list is allowed. Advance to the next representation.
continue;
}
long segmentCount = index.getSegmentCount(periodDurationUs);
if (segmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
throw new DownloadException("Unbounded segment index");
}
String baseUrl = castNonNull(baseUrlExclusionList.selectBaseUrl(representation.baseUrls)).url;
@Nullable RangedUri initializationUri = representation.getInitializationUri();
if (initializationUri != null) {
out.add(createSegment(representation, baseUrl, periodStartUs, initializationUri));
}
@Nullable RangedUri indexUri = representation.getIndexUri();
if (indexUri != null) {
out.add(createSegment(representation, baseUrl, periodStartUs, indexUri));
}
long firstSegmentNum = index.getFirstSegmentNum();
long lastSegmentNum = firstSegmentNum + segmentCount - 1;
for (long j = firstSegmentNum; j <= lastSegmentNum; j++) {
out.add(createSegment(representation, baseUrl, periodStartUs + index.getTimeUs(j), index.getSegmentUrl(j)));
}
}
}
use of androidx.media3.exoplayer.dash.manifest.BaseUrl in project media by androidx.
the class BaseUrlExclusionList method selectBaseUrl.
/**
* Selects the base URL to use from the given list.
*
* <p>The list is reduced by service location and priority of base URLs that have been passed to
* {@link #exclude(BaseUrl, long)}. The base URL to use is then selected from the remaining base
* URLs by priority and weight.
*
* @param baseUrls The list of {@link BaseUrl base URLs} to select from.
* @return The selected base URL after exclusion or null if all elements have been excluded.
*/
@Nullable
public BaseUrl selectBaseUrl(List<BaseUrl> baseUrls) {
List<BaseUrl> includedBaseUrls = applyExclusions(baseUrls);
if (includedBaseUrls.size() < 2) {
return Iterables.getFirst(includedBaseUrls, /* defaultValue= */
null);
}
// Sort by priority and service location to make the sort order of the candidates deterministic.
Collections.sort(includedBaseUrls, BaseUrlExclusionList::compareBaseUrl);
// Get candidates of the lowest priority from the head of the sorted list.
List<Pair<String, Integer>> candidateKeys = new ArrayList<>();
int lowestPriority = includedBaseUrls.get(0).priority;
for (int i = 0; i < includedBaseUrls.size(); i++) {
BaseUrl baseUrl = includedBaseUrls.get(i);
if (lowestPriority != baseUrl.priority) {
if (candidateKeys.size() == 1) {
// Only a single candidate of lowest priority; no choice.
return includedBaseUrls.get(0);
}
break;
}
candidateKeys.add(new Pair<>(baseUrl.serviceLocation, baseUrl.weight));
}
// Check whether selection has already been taken.
@Nullable BaseUrl baseUrl = selectionsTaken.get(candidateKeys);
if (baseUrl == null) {
// Weighted random selection from multiple candidates of the same priority.
baseUrl = selectWeighted(includedBaseUrls.subList(0, candidateKeys.size()));
// Remember the selection taken for later.
selectionsTaken.put(candidateKeys, baseUrl);
}
return baseUrl;
}
use of androidx.media3.exoplayer.dash.manifest.BaseUrl in project media by androidx.
the class BaseUrlExclusionList method selectWeighted.
private BaseUrl selectWeighted(List<BaseUrl> candidates) {
int totalWeight = 0;
for (int i = 0; i < candidates.size(); i++) {
totalWeight += candidates.get(i).weight;
}
int randomChoice = random.nextInt(/* bound= */
totalWeight);
totalWeight = 0;
for (int i = 0; i < candidates.size(); i++) {
BaseUrl baseUrl = candidates.get(i);
totalWeight += baseUrl.weight;
if (randomChoice < totalWeight) {
return baseUrl;
}
}
return Iterables.getLast(candidates);
}
use of androidx.media3.exoplayer.dash.manifest.BaseUrl in project media by androidx.
the class BaseUrlExclusionList method applyExclusions.
// Internal methods.
private List<BaseUrl> applyExclusions(List<BaseUrl> baseUrls) {
long nowMs = SystemClock.elapsedRealtime();
removeExpiredExclusions(nowMs, excludedServiceLocations);
removeExpiredExclusions(nowMs, excludedPriorities);
List<BaseUrl> includedBaseUrls = new ArrayList<>();
for (int i = 0; i < baseUrls.size(); i++) {
BaseUrl baseUrl = baseUrls.get(i);
if (!excludedServiceLocations.containsKey(baseUrl.serviceLocation) && !excludedPriorities.containsKey(baseUrl.priority)) {
includedBaseUrls.add(baseUrl);
}
}
return includedBaseUrls;
}
Aggregations