Skip to content

Commit

Permalink
Correctly use "current-manifest-live" v.s. "stream-is-live"
Browse files Browse the repository at this point in the history
When a live stream ends, what typically happens is that the manifest
is refreshed and the refreshed version is not marked as live/dynamic.
When this happens we:

1. Don't want the duration of the track to change.
2. Still want to consider the possibility that we may have fallen behind
   the live window.
3. Don't want to allow futher manifest refreshes.

This change uses the right thing in the right place.
  • Loading branch information
ojw28 committed Sep 10, 2015
1 parent 143a4de commit 4a29be4
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public NoAdaptationSetException(String message) {
private final long liveEdgeLatencyUs;
private final long elapsedRealtimeOffsetUs;
private final long[] availableRangeValues;
private final boolean live;

private MediaPresentationDescription currentManifest;
private ExposedTrack enabledTrack;
Expand Down Expand Up @@ -260,7 +261,8 @@ dataSource, adaptiveFormatEvaluator, new SystemClock(), liveEdgeLatencyMs * 1000
this.evaluation = new Evaluation();
this.availableRangeValues = new long[2];
periodHolders = new SparseArray<>();
tracks = new ArrayList<ExposedTrack>();
tracks = new ArrayList<>();
live = initialManifest.dynamic;
}

// ChunkSource implementation.
Expand Down Expand Up @@ -375,7 +377,7 @@ public final void getChunkOperation(List<? extends MediaChunk> queue, long seekP

availableRange.getCurrentBoundsUs(availableRangeValues);
if (queue.isEmpty()) {
if (currentManifest.dynamic) {
if (live) {
if (startAtLiveEdge) {
// We want live streams to start at the live edge instead of the beginning of the
// manifest
Expand Down Expand Up @@ -403,18 +405,16 @@ public final void getChunkOperation(List<? extends MediaChunk> queue, long seekP
return;
}

if (currentManifest.dynamic) {
long nextSegmentStartTimeUs = previous.endTimeUs;
if (nextSegmentStartTimeUs < availableRangeValues[0]) {
// This is before the first chunk in the current manifest.
fatalError = new BehindLiveWindowException();
return;
} else if (nextSegmentStartTimeUs >= availableRangeValues[1]) {
// This chunk is beyond the last chunk in the current manifest. If the index is bounded
// we'll need to wait until it's refreshed. If it's unbounded we just need to wait for a
// while before attempting to load the chunk.
return;
}
long nextSegmentStartTimeUs = previous.endTimeUs;
if (live && nextSegmentStartTimeUs < availableRangeValues[0]) {
// This is before the first chunk in the current manifest.
fatalError = new BehindLiveWindowException();
return;
} else if (currentManifest.dynamic && nextSegmentStartTimeUs >= availableRangeValues[1]) {
// This chunk is beyond the last chunk in the current manifest. If the index is bounded
// we'll need to wait until it's refreshed. If it's unbounded we just need to wait for a
// while before attempting to load the chunk.
return;
}

startingNewPeriod = false;
Expand Down Expand Up @@ -545,7 +545,7 @@ public void adaptiveTrack(MediaPresentationDescription manifest, int periodIndex
representationFormats[i] = format;
}
Arrays.sort(representationFormats, new DecreasingBandwidthComparator());
long trackDurationUs = manifest.dynamic ? C.UNKNOWN_TIME_US : manifest.duration * 1000;
long trackDurationUs = live ? C.UNKNOWN_TIME_US : manifest.duration * 1000;
String mediaMimeType = getMediaMimeType(maxHeightRepresentationFormat);
if (mediaMimeType == null) {
Log.w(TAG, "Skipped adaptive track (unknown media mime type)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ public HlsChunkSource(DataSource dataSource, String playlistUrl, HlsPlaylist pla
}

public long getDurationUs() {
return live ? C.UNKNOWN_TIME_US : durationUs;
return durationUs;
}

/**
Expand Down Expand Up @@ -551,7 +551,7 @@ private void setMediaPlaylist(int variantIndex, HlsMediaPlaylist mediaPlaylist)
variantLastPlaylistLoadTimesMs[variantIndex] = SystemClock.elapsedRealtime();
variantPlaylists[variantIndex] = mediaPlaylist;
live |= mediaPlaylist.live;
durationUs = mediaPlaylist.durationUs;
durationUs = live ? C.UNKNOWN_TIME_US : mediaPlaylist.durationUs;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.google.android.exoplayer.smoothstreaming;

import com.google.android.exoplayer.BehindLiveWindowException;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.chunk.Chunk;
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper;
Expand Down Expand Up @@ -69,6 +70,7 @@ public class SmoothStreamingChunkSource implements ChunkSource,
private final ManifestFetcher<SmoothStreamingManifest> manifestFetcher;
private final DrmInitData.Mapped drmInitData;
private final FormatEvaluator adaptiveFormatEvaluator;
private final boolean live;

// The tracks exposed by this source.
private final ArrayList<ExposedTrack> tracks;
Expand All @@ -80,7 +82,7 @@ public class SmoothStreamingChunkSource implements ChunkSource,
private boolean prepareCalled;
private SmoothStreamingManifest currentManifest;
private int currentManifestChunkOffset;
private boolean currentManifestFinished;
private boolean needManifestRefresh;
private ExposedTrack enabledTrack;
private IOException fatalError;

Expand Down Expand Up @@ -135,6 +137,7 @@ private SmoothStreamingChunkSource(ManifestFetcher<SmoothStreamingManifest> mani
tracks = new ArrayList<>();
extractorWrappers = new SparseArray<>();
mediaFormats = new SparseArray<>();
live = initialManifest.isLive;

ProtectionElement protectionElement = initialManifest.protectionElement;
if (protectionElement != null) {
Expand Down Expand Up @@ -221,10 +224,10 @@ public void continueBuffering(long playbackPositionUs) {
}
}
currentManifest = newManifest;
currentManifestFinished = false;
needManifestRefresh = false;
}

if (currentManifestFinished && (SystemClock.elapsedRealtime()
if (needManifestRefresh && (SystemClock.elapsedRealtime()
> manifestFetcher.getManifestLoadStartTimestamp() + MINIMUM_MANIFEST_REFRESH_PERIOD_MS)) {
manifestFetcher.requestRefresh();
}
Expand Down Expand Up @@ -265,14 +268,15 @@ public final void getChunkOperation(List<? extends MediaChunk> queue, long seekP

StreamElement streamElement = currentManifest.streamElements[enabledTrack.elementIndex];
if (streamElement.chunkCount == 0) {
// The manifest is currently empty for this stream.
currentManifestFinished = true;
if (currentManifest.isLive) {
needManifestRefresh = true;
}
return;
}

int chunkIndex;
if (queue.isEmpty()) {
if (currentManifest.isLive) {
if (live) {
seekPositionUs = getLiveSeekPosition(currentManifest, liveEdgeLatencyUs);
}
chunkIndex = streamElement.getChunkIndex(seekPositionUs);
Expand All @@ -281,19 +285,19 @@ public final void getChunkOperation(List<? extends MediaChunk> queue, long seekP
chunkIndex = previous.isLastChunk ? -1 : previous.chunkIndex + 1 - currentManifestChunkOffset;
}

if (currentManifest.isLive) {
if (chunkIndex < 0) {
// This is before the first chunk in the current manifest.
fatalError = new BehindLiveWindowException();
return;
} else if (chunkIndex >= streamElement.chunkCount) {
if (live && chunkIndex < 0) {
// This is before the first chunk in the current manifest.
fatalError = new BehindLiveWindowException();
return;
} else if (currentManifest.isLive) {
if (chunkIndex >= streamElement.chunkCount) {
// This is beyond the last chunk in the current manifest.
currentManifestFinished = true;
needManifestRefresh = true;
return;
} else if (chunkIndex == streamElement.chunkCount - 1) {
// This is the last chunk in the current manifest. Mark the manifest as being finished,
// but continue to return the final chunk.
currentManifestFinished = true;
needManifestRefresh = true;
}
}

Expand Down Expand Up @@ -388,7 +392,7 @@ private MediaFormat initManifestTrack(SmoothStreamingManifest manifest, int elem
}

// Build the media format.
long durationUs = manifest.durationUs;
long durationUs = live ? C.UNKNOWN_TIME_US : manifest.durationUs;
StreamElement element = manifest.streamElements[elementIndex];
Format format = element.tracks[trackIndex].format;
byte[][] csdArray = element.tracks[trackIndex].csd;
Expand Down

0 comments on commit 4a29be4

Please sign in to comment.