Skip to content

Commit

Permalink
Refactor #6.5: Restore DASH UTC timing element support.
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=121002218
  • Loading branch information
ojw28 committed Jun 15, 2016
1 parent 0841d04 commit 23cb953
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;

import android.os.SystemClock;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
Expand All @@ -62,6 +64,7 @@ public class DashChunkSource implements ChunkSource {
private final boolean[] adaptiveFormatBlacklistFlags;
private final DataSource dataSource;
private final FormatEvaluator adaptiveFormatEvaluator;
private final long elapsedRealtimeOffsetUs;
private final Evaluation evaluation;

private MediaPresentationDescription manifest;
Expand All @@ -77,15 +80,19 @@ public class DashChunkSource implements ChunkSource {
* @param tracks The indices of the selected tracks within the adaptation set.
* @param dataSource A {@link DataSource} suitable for loading the media data.
* @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats.
* @param elapsedRealtimeOffsetMs If known, an estimate of the instantaneous difference between
* server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified
* as the server's unix time minus the local elapsed time. It unknown, set to 0.
*/
public DashChunkSource(MediaPresentationDescription manifest, int adaptationSetIndex,
TrackGroup trackGroup, int[] tracks, DataSource dataSource,
FormatEvaluator adaptiveFormatEvaluator) {
FormatEvaluator adaptiveFormatEvaluator, long elapsedRealtimeOffsetMs) {
this.manifest = manifest;
this.adaptationSetIndex = adaptationSetIndex;
this.trackGroup = trackGroup;
this.dataSource = dataSource;
this.adaptiveFormatEvaluator = adaptiveFormatEvaluator;
this.elapsedRealtimeOffsetUs = elapsedRealtimeOffsetMs * 1000;
this.evaluation = new Evaluation();

Period period = manifest.getPeriod(0);
Expand Down Expand Up @@ -197,9 +204,7 @@ public final void getNextChunk(MediaChunk previous, long playbackPositionUs, Chu
return;
}

// TODO[REFACTOR]: Bring back UTC timing element support.
long nowUs = System.currentTimeMillis() * 1000;

long nowUs = getNowUnixTimeUs();
int firstAvailableSegmentNum = representationHolder.getFirstSegmentNum();
int lastAvailableSegmentNum = representationHolder.getLastSegmentNum();
boolean indexUnbounded = lastAvailableSegmentNum == DashSegmentIndex.INDEX_UNBOUNDED;
Expand Down Expand Up @@ -278,6 +283,14 @@ public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) {

// Private methods.

private long getNowUnixTimeUs() {
if (elapsedRealtimeOffsetUs != 0) {
return (SystemClock.elapsedRealtime() * 1000) + elapsedRealtimeOffsetUs;
} else {
return System.currentTimeMillis() * 1000;
}
}

private Chunk newInitializationChunk(RangedUri initializationUri, RangedUri indexUri,
Representation representation, ChunkExtractorWrapper extractor, DataSource dataSource,
int trigger) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,20 @@
import com.google.android.exoplayer.dash.mpd.MediaPresentationDescriptionParser;
import com.google.android.exoplayer.dash.mpd.Period;
import com.google.android.exoplayer.dash.mpd.Representation;
import com.google.android.exoplayer.dash.mpd.UtcTimingElement;
import com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver;
import com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver.UtcTimingCallback;
import com.google.android.exoplayer.upstream.BandwidthMeter;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.Util;

import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;

import java.io.IOException;
Expand All @@ -53,7 +56,9 @@
/**
* A {@link SampleSource} for DASH media.
*/
public final class DashSampleSource implements SampleSource {
public final class DashSampleSource implements SampleSource, UtcTimingCallback {

private static final String TAG = "DashSampleSource";

private final ManifestFetcher<MediaPresentationDescription> manifestFetcher;
private final DataSourceFactory dataSourceFactory;
Expand All @@ -63,8 +68,10 @@ public final class DashSampleSource implements SampleSource {
private final LoadControl loadControl;

private boolean prepared;
private boolean released;
private long durationUs;
private MediaPresentationDescription currentManifest;
private long elapsedRealtimeOffset;
private MediaPresentationDescription manifest;
private TrackGroupArray trackGroups;
private int[] trackGroupAdaptationSetIndices;
private boolean pendingReset;
Expand Down Expand Up @@ -96,20 +103,24 @@ public boolean prepare(long positionUs) throws IOException {
return true;
}

if (currentManifest == null) {
currentManifest = manifestFetcher.getManifest();
if (currentManifest == null) {
if (manifest == null) {
manifest = manifestFetcher.getManifest();
if (manifest == null) {
manifestFetcher.maybeThrowError();
manifestFetcher.requestRefresh();
return false;
}
durationUs = manifest.dynamic ? C.UNSET_TIME_US : manifest.duration * 1000;
buildTrackGroups(manifest);
if (manifest.utcTiming != null) {
UtcTimingElementResolver.resolveTimingElement(dataSourceFactory.createDataSource(),
manifest.utcTiming, manifestFetcher.getManifestLoadCompleteTimestamp(), this);
} else {
prepared = true;
}
}

durationUs = currentManifest.dynamic ? C.UNSET_TIME_US : currentManifest.duration * 1000;
buildTrackGroups(currentManifest);

prepared = true;
return true;
return prepared;
}

@Override
Expand All @@ -125,8 +136,6 @@ public TrackGroupArray getTrackGroups() {
@Override
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
List<TrackSelection> newSelections, long positionUs) {
Assertions.checkState(prepared);

int newEnabledSourceCount = trackStreams.length + newSelections.size() - oldStreams.size();
DashChunkSource[] newChunkSources = new DashChunkSource[newEnabledSourceCount];
ChunkTrackStream[] newTrackStreams = new ChunkTrackStream[newEnabledSourceCount];
Expand Down Expand Up @@ -161,16 +170,16 @@ public TrackStream[] selectTracks(List<TrackStream> oldStreams,

@Override
public void continueBuffering(long positionUs) {
if (currentManifest.dynamic) {
if (manifest.dynamic) {
MediaPresentationDescription newManifest = manifestFetcher.getManifest();
if (newManifest != currentManifest) {
currentManifest = newManifest;
if (newManifest != manifest) {
manifest = newManifest;
for (DashChunkSource chunkSource : chunkSources) {
chunkSource.updateManifest(newManifest);
}
}

long minUpdatePeriod = currentManifest.minUpdatePeriod;
long minUpdatePeriod = manifest.minUpdatePeriod;
if (minUpdatePeriod == 0) {
// TODO: This is a temporary hack to avoid constantly refreshing the MPD in cases where
// minUpdatePeriod is set to 0. In such cases we shouldn't refresh unless there is explicit
Expand Down Expand Up @@ -233,6 +242,28 @@ public void release() {
for (ChunkTrackStream trackStream : trackStreams) {
trackStream.release();
}
released = true;
}

// UtcTimingCallback implementation.

@Override
public void onTimestampResolved(UtcTimingElement utcTiming, long elapsedRealtimeOffset) {
if (released) {
return;
}
this.elapsedRealtimeOffset = elapsedRealtimeOffset;
prepared = true;
}

@Override
public void onTimestampError(UtcTimingElement utcTiming, IOException e) {
if (released) {
return;
}
Log.e(TAG, "Failed to resolve UtcTiming element [" + utcTiming + "]", e);
// Be optimistic and continue in the hope that the device clock is correct.
prepared = true;
}

// Internal methods.
Expand Down Expand Up @@ -271,13 +302,14 @@ private Pair<DashChunkSource, ChunkTrackStream> buildTrackStream(TrackSelection
FormatEvaluator adaptiveEvaluator = selectedTracks.length > 1
? new AdaptiveEvaluator(bandwidthMeter) : null;
int adaptationSetIndex = trackGroupAdaptationSetIndices[selection.group];
AdaptationSet adaptationSet = currentManifest.getPeriod(0).adaptationSets.get(
AdaptationSet adaptationSet = manifest.getPeriod(0).adaptationSets.get(
adaptationSetIndex);
int adaptationSetType = adaptationSet.type;
int bufferSize = Util.getDefaultBufferSize(adaptationSetType);
DataSource dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
DashChunkSource chunkSource = new DashChunkSource(currentManifest, adaptationSetIndex,
trackGroups.get(selection.group), selectedTracks, dataSource, adaptiveEvaluator);
DashChunkSource chunkSource = new DashChunkSource(manifest, adaptationSetIndex,
trackGroups.get(selection.group), selectedTracks, dataSource, adaptiveEvaluator,
elapsedRealtimeOffset);
ChunkTrackStream trackStream = new ChunkTrackStream(chunkSource, loadControl, bufferSize,
positionUs, eventHandler, eventListener, adaptationSetType);
return Pair.create(chunkSource, trackStream);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;
Expand Down Expand Up @@ -67,7 +66,6 @@ public final class SmoothStreamingSampleSource implements SampleSource {
private final LoadControl loadControl;
private final ManifestFetcher<SmoothStreamingManifest> manifestFetcher;

private boolean prepared;
private long durationUs;
private SmoothStreamingManifest currentManifest;
private TrackEncryptionBox[] trackEncryptionBoxes;
Expand Down Expand Up @@ -102,22 +100,20 @@ public SmoothStreamingSampleSource(Uri uri, DataSourceFactory dataSourceFactory,

@Override
public boolean prepare(long positionUs) throws IOException {
if (prepared) {
if (currentManifest != null) {
// Already prepared.
return true;
}

currentManifest = manifestFetcher.getManifest();
if (currentManifest == null) {
currentManifest = manifestFetcher.getManifest();
if (currentManifest == null) {
manifestFetcher.maybeThrowError();
manifestFetcher.requestRefresh();
return false;
}
manifestFetcher.maybeThrowError();
manifestFetcher.requestRefresh();
return false;
}

durationUs = currentManifest.durationUs;
buildTrackGroups(currentManifest);

ProtectionElement protectionElement = currentManifest.protectionElement;
if (protectionElement != null) {
byte[] keyId = getProtectionElementKeyId(protectionElement.data);
Expand All @@ -127,8 +123,6 @@ public boolean prepare(long positionUs) throws IOException {
drmInitData.put(protectionElement.uuid,
new SchemeInitData(MimeTypes.VIDEO_MP4, protectionElement.data));
}

prepared = true;
return true;
}

Expand All @@ -145,8 +139,6 @@ public TrackGroupArray getTrackGroups() {
@Override
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
List<TrackSelection> newSelections, long positionUs) {
Assertions.checkState(prepared);

int newEnabledSourceCount = trackStreams.length + newSelections.size() - oldStreams.size();
SmoothStreamingChunkSource[] newChunkSources =
new SmoothStreamingChunkSource[newEnabledSourceCount];
Expand Down

0 comments on commit 23cb953

Please sign in to comment.