use of androidx.media3.exoplayer.dash.manifest.DashManifest in project media by androidx.
the class DashMediaPeriod method updateManifest.
/**
* Updates the {@link DashManifest} and the index of this period in the manifest.
*
* @param manifest The updated manifest.
* @param periodIndex the new index of this period in the updated manifest.
*/
public void updateManifest(DashManifest manifest, int periodIndex) {
this.manifest = manifest;
this.periodIndex = periodIndex;
playerEmsgHandler.updateManifest(manifest);
if (sampleStreams != null) {
for (ChunkSampleStream<DashChunkSource> sampleStream : sampleStreams) {
sampleStream.getChunkSource().updateManifest(manifest, periodIndex);
}
callback.onContinueLoadingRequested(this);
}
eventStreams = manifest.getPeriod(periodIndex).eventStreams;
for (EventSampleStream eventSampleStream : eventSampleStreams) {
for (EventStream eventStream : eventStreams) {
if (eventStream.id().equals(eventSampleStream.eventStreamId())) {
int lastPeriodIndex = manifest.getPeriodCount() - 1;
eventSampleStream.updateEventStream(eventStream, /* eventStreamAppendable= */
manifest.dynamic && periodIndex == lastPeriodIndex);
break;
}
}
}
}
use of androidx.media3.exoplayer.dash.manifest.DashManifest in project media by androidx.
the class DashMediaSource method onManifestLoadError.
/* package */
LoadErrorAction onManifestLoadError(ParsingLoadable<DashManifest> loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error, int errorCount) {
LoadEventInfo loadEventInfo = new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, loadable.getUri(), loadable.getResponseHeaders(), elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded());
MediaLoadData mediaLoadData = new MediaLoadData(loadable.type);
LoadErrorInfo loadErrorInfo = new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
long retryDelayMs = loadErrorHandlingPolicy.getRetryDelayMsFor(loadErrorInfo);
LoadErrorAction loadErrorAction = retryDelayMs == C.TIME_UNSET ? Loader.DONT_RETRY_FATAL : Loader.createRetryAction(/* resetErrorCount= */
false, retryDelayMs);
boolean wasCanceled = !loadErrorAction.isRetry();
manifestEventDispatcher.loadError(loadEventInfo, loadable.type, error, wasCanceled);
if (wasCanceled) {
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
}
return loadErrorAction;
}
use of androidx.media3.exoplayer.dash.manifest.DashManifest in project media by androidx.
the class DashMediaSource method onManifestLoadCompleted.
// Loadable callbacks.
/* package */
void onManifestLoadCompleted(ParsingLoadable<DashManifest> loadable, long elapsedRealtimeMs, long loadDurationMs) {
LoadEventInfo loadEventInfo = new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, loadable.getUri(), loadable.getResponseHeaders(), elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded());
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
manifestEventDispatcher.loadCompleted(loadEventInfo, loadable.type);
DashManifest newManifest = loadable.getResult();
int oldPeriodCount = manifest == null ? 0 : manifest.getPeriodCount();
int removedPeriodCount = 0;
long newFirstPeriodStartTimeMs = newManifest.getPeriod(0).startMs;
while (removedPeriodCount < oldPeriodCount && manifest.getPeriod(removedPeriodCount).startMs < newFirstPeriodStartTimeMs) {
removedPeriodCount++;
}
if (newManifest.dynamic) {
boolean isManifestStale = false;
if (oldPeriodCount - removedPeriodCount > newManifest.getPeriodCount()) {
// After discarding old periods, we should never have more periods than listed in the new
// manifest. That would mean that a previously announced period is no longer advertised. If
// this condition occurs, assume that we are hitting a manifest server that is out of sync
// and
// behind.
Log.w(TAG, "Loaded out of sync manifest");
isManifestStale = true;
} else if (expiredManifestPublishTimeUs != C.TIME_UNSET && newManifest.publishTimeMs * 1000 <= expiredManifestPublishTimeUs) {
// If we receive a dynamic manifest that's older than expected (i.e. its publish time has
// expired, or it's dynamic and we know the presentation has ended), then this manifest is
// stale.
Log.w(TAG, "Loaded stale dynamic manifest: " + newManifest.publishTimeMs + ", " + expiredManifestPublishTimeUs);
isManifestStale = true;
}
if (isManifestStale) {
if (staleManifestReloadAttempt++ < loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type)) {
scheduleManifestRefresh(getManifestLoadRetryDelayMillis());
} else {
manifestFatalError = new DashManifestStaleException();
}
return;
}
staleManifestReloadAttempt = 0;
}
manifest = newManifest;
manifestLoadPending &= manifest.dynamic;
manifestLoadStartTimestampMs = elapsedRealtimeMs - loadDurationMs;
manifestLoadEndTimestampMs = elapsedRealtimeMs;
synchronized (manifestUriLock) {
// Checks whether replaceManifestUri(Uri) was called to manually replace the URI between the
// start and end of this load. If it was then isSameUriInstance evaluates to false, and we
// prefer the manual replacement to one derived from the previous request.
@SuppressWarnings("ReferenceEquality") boolean isSameUriInstance = loadable.dataSpec.uri == manifestUri;
if (isSameUriInstance) {
// Replace the manifest URI with one specified by a manifest Location element (if present),
// or with the final (possibly redirected) URI. This follows the recommendation in
// DASH-IF-IOP 4.3, section 3.2.15.3. See: https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf.
manifestUri = manifest.location != null ? manifest.location : loadable.getUri();
}
}
if (oldPeriodCount == 0) {
if (manifest.dynamic) {
if (manifest.utcTiming != null) {
resolveUtcTimingElement(manifest.utcTiming);
} else {
loadNtpTimeOffset();
}
} else {
processManifest(true);
}
} else {
firstPeriodId += removedPeriodCount;
processManifest(true);
}
}
use of androidx.media3.exoplayer.dash.manifest.DashManifest in project media by androidx.
the class DashMediaPeriodTest method getStreamKeys_isCompatibleWithDashManifestFilter.
@Test
public void getStreamKeys_isCompatibleWithDashManifestFilter() throws IOException {
// Test manifest which covers various edge cases:
// - Multiple periods.
// - Single and multiple representations per adaptation set.
// - Switch descriptors combining multiple adaptations sets.
// - Embedded track groups.
// All cases are deliberately combined in one test to catch potential indexing problems which
// only occur in combination.
DashManifest manifest = parseManifest("media/mpd/sample_mpd_stream_keys");
// Ignore embedded metadata as we don't want to select primary group just to get embedded track.
MediaPeriodAsserts.assertGetStreamKeysAndManifestFilterIntegration(DashMediaPeriodTest::createDashMediaPeriod, manifest, /* periodIndex= */
1, /* ignoredMimeType= */
"application/x-emsg");
}
use of androidx.media3.exoplayer.dash.manifest.DashManifest in project media by androidx.
the class DashMediaPeriodTest method trickPlayProperty_mergesTrackGroups.
@Test
public void trickPlayProperty_mergesTrackGroups() throws IOException {
DashManifest manifest = parseManifest("media/mpd/sample_mpd_trick_play_property");
DashMediaPeriod dashMediaPeriod = createDashMediaPeriod(manifest, 0);
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
// We expect the trick play adaptation sets to be merged with the ones to which they refer,
// retaining representations in their original order.
TrackGroupArray expectedTrackGroups = new TrackGroupArray(new TrackGroup(/* id= */
"0", adaptationSets.get(0).representations.get(0).format, adaptationSets.get(0).representations.get(1).format, adaptationSets.get(1).representations.get(0).format), new TrackGroup(/* id= */
"2", adaptationSets.get(2).representations.get(0).format, adaptationSets.get(2).representations.get(1).format, adaptationSets.get(3).representations.get(0).format));
MediaPeriodAsserts.assertTrackGroups(dashMediaPeriod, expectedTrackGroups);
}
Aggregations