Commit 7799e8fd by tonihei Committed by Oliver Woodman

Add dependency on nullness annotations and add missing annotations for DASH.

This includes only the (hopefully) non-debatable changes for the DASH module
and all needed changes for call into the core library.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=195097791
parent c466fabb
......@@ -2,6 +2,7 @@
### dev-v2 (not yet released) ###
* Added dependency on checkerframework annotations for static code analysis.
* Optimize seeking in FMP4 by enabling seeking to the nearest sync sample within
a fragment. This benefits standalone FMP4 playbacks, DASH and SmoothStreaming.
* Moved initial bitrate estimate from `AdaptiveTrackSelection` to
......
......@@ -31,6 +31,7 @@ project.ext {
junitVersion = '4.12'
truthVersion = '0.39'
robolectricVersion = '3.7.1'
checkerframeworkVersion = '2.5.0'
modulePrefix = ':'
if (gradle.ext.has('exoplayerModulePrefix')) {
modulePrefix += gradle.ext.exoplayerModulePrefix
......
......@@ -46,6 +46,7 @@ android {
dependencies {
implementation 'com.android.support:support-annotations:' + supportLibraryVersion
implementation 'org.checkerframework:checker-qual:' + checkerframeworkVersion
androidTestImplementation 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestImplementation 'com.google.truth:truth:' + truthVersion
......
......@@ -121,11 +121,11 @@ public final class FragmentedMp4Extractor implements Extractor {
// Workarounds.
@Flags private final int flags;
private final Track sideloadedTrack;
private final @Nullable Track sideloadedTrack;
// Sideloaded data.
private final List<Format> closedCaptionFormats;
private final DrmInitData sideloadedDrmInitData;
private final @Nullable DrmInitData sideloadedDrmInitData;
// Track-linked data bundle, accessible as a whole through trackID.
private final SparseArray<TrackBundle> trackBundles;
......@@ -136,7 +136,7 @@ public final class FragmentedMp4Extractor implements Extractor {
private final ParsableByteArray nalBuffer;
// Adjusts sample timestamps.
private final TimestampAdjuster timestampAdjuster;
private final @Nullable TimestampAdjuster timestampAdjuster;
// Parser state.
private final ParsableByteArray atomHeader;
......@@ -185,20 +185,23 @@ public final class FragmentedMp4Extractor implements Extractor {
* @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed.
*/
public FragmentedMp4Extractor(@Flags int flags, TimestampAdjuster timestampAdjuster) {
public FragmentedMp4Extractor(@Flags int flags, @Nullable TimestampAdjuster timestampAdjuster) {
this(flags, timestampAdjuster, null, null);
}
/**
* @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor
* will not receive a moov box in the input data. Null if a moov box is expected.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor will not
* receive a moov box in the input data. Null if a moov box is expected.
* @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the
* pssh boxes (if present) will be used.
*/
public FragmentedMp4Extractor(@Flags int flags, TimestampAdjuster timestampAdjuster,
Track sideloadedTrack, DrmInitData sideloadedDrmInitData) {
public FragmentedMp4Extractor(
@Flags int flags,
@Nullable TimestampAdjuster timestampAdjuster,
@Nullable Track sideloadedTrack,
@Nullable DrmInitData sideloadedDrmInitData) {
this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData,
Collections.<Format>emptyList());
}
......@@ -206,15 +209,19 @@ public final class FragmentedMp4Extractor implements Extractor {
/**
* @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor
* will not receive a moov box in the input data. Null if a moov box is expected.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor will not
* receive a moov box in the input data. Null if a moov box is expected.
* @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the
* pssh boxes (if present) will be used.
* @param closedCaptionFormats For tracks that contain SEI messages, the formats of the closed
* caption channels to expose.
*/
public FragmentedMp4Extractor(@Flags int flags, TimestampAdjuster timestampAdjuster,
Track sideloadedTrack, DrmInitData sideloadedDrmInitData, List<Format> closedCaptionFormats) {
public FragmentedMp4Extractor(
@Flags int flags,
@Nullable TimestampAdjuster timestampAdjuster,
@Nullable Track sideloadedTrack,
@Nullable DrmInitData sideloadedDrmInitData,
List<Format> closedCaptionFormats) {
this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData,
closedCaptionFormats, null);
}
......@@ -222,8 +229,8 @@ public final class FragmentedMp4Extractor implements Extractor {
/**
* @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor
* will not receive a moov box in the input data. Null if a moov box is expected.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor will not
* receive a moov box in the input data. Null if a moov box is expected.
* @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the
* pssh boxes (if present) will be used.
* @param closedCaptionFormats For tracks that contain SEI messages, the formats of the closed
......@@ -232,8 +239,12 @@ public final class FragmentedMp4Extractor implements Extractor {
* targeting the player, even if {@link #FLAG_ENABLE_EMSG_TRACK} is not set. Null if special
* handling of emsg messages for players is not required.
*/
public FragmentedMp4Extractor(@Flags int flags, TimestampAdjuster timestampAdjuster,
Track sideloadedTrack, DrmInitData sideloadedDrmInitData, List<Format> closedCaptionFormats,
public FragmentedMp4Extractor(
@Flags int flags,
@Nullable TimestampAdjuster timestampAdjuster,
@Nullable Track sideloadedTrack,
@Nullable DrmInitData sideloadedDrmInitData,
List<Format> closedCaptionFormats,
@Nullable TrackOutput additionalEmsgTrackOutput) {
this.flags = flags | (sideloadedTrack != null ? FLAG_SIDELOADED : 0);
this.timestampAdjuster = timestampAdjuster;
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.extractor.mp4;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.nio.ByteBuffer;
......@@ -36,7 +37,7 @@ public final class PsshAtomUtil {
* @param data The scheme specific data.
* @return The PSSH atom.
*/
public static byte[] buildPsshAtom(UUID systemId, byte[] data) {
public static byte[] buildPsshAtom(UUID systemId, @Nullable byte[] data) {
return buildPsshAtom(systemId, null, data);
}
......@@ -48,7 +49,8 @@ public final class PsshAtomUtil {
* @param data The scheme specific data.
* @return The PSSH atom.
*/
public static byte[] buildPsshAtom(UUID systemId, UUID[] keyIds, byte[] data) {
public static byte[] buildPsshAtom(
UUID systemId, @Nullable UUID[] keyIds, @Nullable byte[] data) {
boolean buildV1Atom = keyIds != null;
int dataLength = data != null ? data.length : 0;
int psshBoxLength = Atom.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength;
......@@ -77,14 +79,14 @@ public final class PsshAtomUtil {
/**
* Parses the UUID from a PSSH atom. Version 0 and 1 PSSH atoms are supported.
* <p>
* The UUID is only parsed if the data is a valid PSSH atom.
*
* <p>The UUID is only parsed if the data is a valid PSSH atom.
*
* @param atom The atom to parse.
* @return The parsed UUID. Null if the input is not a valid PSSH atom, or if the PSSH atom has
* an unsupported version.
* @return The parsed UUID. Null if the input is not a valid PSSH atom, or if the PSSH atom has an
* unsupported version.
*/
public static UUID parseUuid(byte[] atom) {
public static @Nullable UUID parseUuid(byte[] atom) {
PsshAtom parsedAtom = parsePsshAtom(atom);
if (parsedAtom == null) {
return null;
......@@ -111,8 +113,8 @@ public final class PsshAtomUtil {
/**
* Parses the scheme specific data from a PSSH atom. Version 0 and 1 PSSH atoms are supported.
* <p>
* The scheme specific data is only parsed if the data is a valid PSSH atom matching the given
*
* <p>The scheme specific data is only parsed if the data is a valid PSSH atom matching the given
* UUID, or if the data is a valid PSSH atom of any type in the case that the passed UUID is null.
*
* @param atom The atom to parse.
......@@ -120,7 +122,7 @@ public final class PsshAtomUtil {
* @return The parsed scheme specific data. Null if the input is not a valid PSSH atom, or if the
* PSSH atom has an unsupported version, or if the PSSH atom does not match the passed UUID.
*/
public static byte[] parseSchemeSpecificData(byte[] atom, UUID uuid) {
public static @Nullable byte[] parseSchemeSpecificData(byte[] atom, UUID uuid) {
PsshAtom parsedAtom = parsePsshAtom(atom);
if (parsedAtom == null) {
return null;
......@@ -140,7 +142,7 @@ public final class PsshAtomUtil {
* has an unsupported version.
*/
// TODO: Support parsing of the key ids for version 1 PSSH atoms.
private static PsshAtom parsePsshAtom(byte[] atom) {
private static @Nullable PsshAtom parsePsshAtom(byte[] atom) {
ParsableByteArray atomData = new ParsableByteArray(atom);
if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) {
// Data too short.
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source.chunk;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.upstream.DataSource;
......@@ -51,7 +52,7 @@ public abstract class Chunk implements Loadable {
* Optional data associated with the selection of the track to which this chunk belongs. Null if
* the chunk does not belong to a track.
*/
public final Object trackSelectionData;
public final @Nullable Object trackSelectionData;
/**
* The start time of the media contained by the chunk, or {@link C#TIME_UNSET} if the data
* being loaded does not contain media samples.
......@@ -75,8 +76,15 @@ public abstract class Chunk implements Loadable {
* @param startTimeUs See {@link #startTimeUs}.
* @param endTimeUs See {@link #endTimeUs}.
*/
public Chunk(DataSource dataSource, DataSpec dataSpec, int type, Format trackFormat,
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs) {
public Chunk(
DataSource dataSource,
DataSpec dataSpec,
int type,
Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
long startTimeUs,
long endTimeUs) {
this.dataSource = Assertions.checkNotNull(dataSource);
this.dataSpec = Assertions.checkNotNull(dataSpec);
this.type = type;
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source.chunk;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
......@@ -44,8 +45,12 @@ public final class InitializationChunk extends Chunk {
* @param trackSelectionData See {@link #trackSelectionData}.
* @param extractorWrapper A wrapped extractor to use for parsing the initialization data.
*/
public InitializationChunk(DataSource dataSource, DataSpec dataSpec, Format trackFormat,
int trackSelectionReason, Object trackSelectionData,
public InitializationChunk(
DataSource dataSource,
DataSpec dataSpec,
Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
ChunkExtractorWrapper extractorWrapper) {
super(dataSource, dataSpec, C.DATA_TYPE_MEDIA_INITIALIZATION, trackFormat, trackSelectionReason,
trackSelectionData, C.TIME_UNSET, C.TIME_UNSET);
......
......@@ -16,8 +16,10 @@
package com.google.android.exoplayer2.util;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
/**
* Provides methods for asserting the truth of expressions and properties.
......@@ -102,7 +104,8 @@ public final class Assertions {
* @return The non-null reference that was validated.
* @throws NullPointerException If {@code reference} is null.
*/
public static <T> T checkNotNull(T reference) {
@EnsuresNonNull({"#1"})
public static <T> T checkNotNull(@Nullable T reference) {
if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) {
throw new NullPointerException();
}
......@@ -119,7 +122,8 @@ public final class Assertions {
* @return The non-null reference that was validated.
* @throws NullPointerException If {@code reference} is null.
*/
public static <T> T checkNotNull(T reference, Object errorMessage) {
@EnsuresNonNull({"#1"})
public static <T> T checkNotNull(@Nullable T reference, Object errorMessage) {
if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
......@@ -133,7 +137,8 @@ public final class Assertions {
* @return The non-null, non-empty string that was validated.
* @throws IllegalArgumentException If {@code string} is null or 0-length.
*/
public static String checkNotEmpty(String string) {
@EnsuresNonNull({"#1"})
public static String checkNotEmpty(@Nullable String string) {
if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) {
throw new IllegalArgumentException();
}
......@@ -149,7 +154,8 @@ public final class Assertions {
* @return The non-null, non-empty string that was validated.
* @throws IllegalArgumentException If {@code string} is null or 0-length.
*/
public static String checkNotEmpty(String string, Object errorMessage) {
@EnsuresNonNull({"#1"})
public static String checkNotEmpty(@Nullable String string, Object errorMessage) {
if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
}
......
......@@ -134,14 +134,13 @@ public final class MimeTypes {
return BASE_TYPE_APPLICATION.equals(getTopLevelType(mimeType));
}
/**
* Derives a video sample mimeType from a codecs attribute.
*
* @param codecs The codecs attribute.
* @return The derived video mimeType, or null if it could not be derived.
*/
public static String getVideoMediaMimeType(String codecs) {
public static @Nullable String getVideoMediaMimeType(@Nullable String codecs) {
if (codecs == null) {
return null;
}
......@@ -161,7 +160,7 @@ public final class MimeTypes {
* @param codecs The codecs attribute.
* @return The derived audio mimeType, or null if it could not be derived.
*/
public static String getAudioMediaMimeType(String codecs) {
public static @Nullable String getAudioMediaMimeType(@Nullable String codecs) {
if (codecs == null) {
return null;
}
......@@ -181,7 +180,7 @@ public final class MimeTypes {
* @param codec The codec identifier to derive.
* @return The mimeType, or null if it could not be derived.
*/
public static String getMediaMimeType(String codec) {
public static @Nullable String getMediaMimeType(@Nullable String codec) {
if (codec == null) {
return null;
}
......@@ -345,7 +344,7 @@ public final class MimeTypes {
* @param mimeType The mimeType whose top-level type is required.
* @return The top-level type, or null if the mimeType is null.
*/
private static String getTopLevelType(String mimeType) {
private static @Nullable String getTopLevelType(@Nullable String mimeType) {
if (mimeType == null) {
return null;
}
......
......@@ -29,6 +29,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Parcel;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
......@@ -190,7 +191,7 @@ public final class Util {
* @param o2 The second object.
* @return {@code o1 == null ? o2 == null : o1.equals(o2)}.
*/
public static boolean areEqual(Object o1, Object o2) {
public static boolean areEqual(@Nullable Object o1, @Nullable Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
......@@ -225,6 +226,20 @@ public final class Util {
}
/**
* Copies and optionally truncates an array. Prevents null array elements created by {@link
* Arrays#copyOf(Object[], int)} by ensuring the new length does not exceed the current length.
*
* @param input The input array.
* @param length The output array length. Must be less or equal to the length of the input array.
* @return The copied array.
*/
@SuppressWarnings("nullness:assignment.type.incompatible")
public static <T> T[] nullSafeArrayCopy(T[] input, int length) {
Assertions.checkArgument(length <= input.length);
return Arrays.copyOf(input, length);
}
/**
* Instantiates a new single threaded executor whose thread has the specified name.
*
* @param threadName The name of the thread.
......
......@@ -34,6 +34,8 @@ android {
dependencies {
implementation project(modulePrefix + 'library-core')
implementation 'org.checkerframework:checker-qual:' + checkerframeworkVersion
implementation 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
implementation 'com.android.support:support-annotations:' + supportLibraryVersion
testImplementation project(modulePrefix + 'testutils-robolectric')
}
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.dash;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.drm.DrmInitData;
......@@ -65,7 +66,7 @@ public final class DashUtil {
* @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted.
*/
public static DrmInitData loadDrmInitData(DataSource dataSource, Period period)
public static @Nullable DrmInitData loadDrmInitData(DataSource dataSource, Period period)
throws IOException, InterruptedException {
int primaryTrackType = C.TRACK_TYPE_VIDEO;
Representation representation = getFirstRepresentation(period, primaryTrackType);
......@@ -87,15 +88,16 @@ public final class DashUtil {
* Loads initialization data for the {@code representation} and returns the sample {@link Format}.
*
* @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param trackType The type of the representation. Typically one of the {@link
* com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to.
* @return the sample {@link Format} of the given representation.
* @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted.
*/
public static Format loadSampleFormat(DataSource dataSource, int trackType,
Representation representation) throws IOException, InterruptedException {
public static @Nullable Format loadSampleFormat(
DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
representation, false);
return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0];
......@@ -106,28 +108,29 @@ public final class DashUtil {
* ChunkIndex}.
*
* @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param trackType The type of the representation. Typically one of the {@link
* com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to.
* @return The {@link ChunkIndex} of the given representation, or null if no initialization or
* index data exists.
* @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted.
*/
public static ChunkIndex loadChunkIndex(DataSource dataSource, int trackType,
Representation representation) throws IOException, InterruptedException {
public static @Nullable ChunkIndex loadChunkIndex(
DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
representation, true);
return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap();
}
/**
* Loads initialization data for the {@code representation} and optionally index data then
* returns a {@link ChunkExtractorWrapper} which contains the output.
* Loads initialization data for the {@code representation} and optionally index data then returns
* a {@link ChunkExtractorWrapper} which contains the output.
*
* @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param trackType The type of the representation. Typically one of the {@link
* com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to.
* @param loadIndex Whether to load index data too.
* @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no
......@@ -135,8 +138,9 @@ public final class DashUtil {
* @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted.
*/
private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, int trackType,
Representation representation, boolean loadIndex) throws IOException, InterruptedException {
private static @Nullable ChunkExtractorWrapper loadInitializationData(
DataSource dataSource, int trackType, Representation representation, boolean loadIndex)
throws IOException, InterruptedException {
RangedUri initializationUri = representation.getInitializationUri();
if (initializationUri == null) {
return null;
......@@ -181,7 +185,7 @@ public final class DashUtil {
return new ChunkExtractorWrapper(extractor, trackType, format);
}
private static Representation getFirstRepresentation(Period period, int type) {
private static @Nullable Representation getFirstRepresentation(Period period, int type) {
int index = period.getAdaptationSetIndex(type);
if (index == C.INDEX_UNSET) {
return null;
......
......@@ -45,8 +45,10 @@ import java.io.IOException;
EventSampleStream(EventStream eventStream, Format upstreamFormat, boolean eventStreamUpdatable) {
this.upstreamFormat = upstreamFormat;
this.eventStream = eventStream;
eventMessageEncoder = new EventMessageEncoder();
pendingSeekPositionUs = C.TIME_UNSET;
eventTimesUs = eventStream.presentationTimesUs;
updateEventStream(eventStream, eventStreamUpdatable);
}
......
......@@ -100,6 +100,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
* messages that generate DASH media source events.
* @param allocator An {@link Allocator} from which allocations can be obtained.
*/
@SuppressWarnings("nullness")
public PlayerEmsgHandler(
DashManifest manifest, PlayerEmsgCallback playerEmsgCallback, Allocator allocator) {
this.manifest = manifest;
......@@ -237,11 +238,10 @@ public final class PlayerEmsgHandler implements Handler.Callback {
// Internal methods.
private void handleManifestExpiredMessage(long eventTimeUs, long manifestPublishTimeMsInEmsg) {
if (!manifestPublishTimeToExpiryTimeUs.containsKey(manifestPublishTimeMsInEmsg)) {
Long previousExpiryTimeUs = manifestPublishTimeToExpiryTimeUs.get(manifestPublishTimeMsInEmsg);
if (previousExpiryTimeUs == null) {
manifestPublishTimeToExpiryTimeUs.put(manifestPublishTimeMsInEmsg, eventTimeUs);
} else {
long previousExpiryTimeUs =
manifestPublishTimeToExpiryTimeUs.get(manifestPublishTimeMsInEmsg);
if (previousExpiryTimeUs > eventTimeUs) {
manifestPublishTimeToExpiryTimeUs.put(manifestPublishTimeMsInEmsg, eventTimeUs);
}
......@@ -253,10 +253,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
notifySourceMediaPresentationEnded();
}
private Map.Entry<Long, Long> ceilingExpiryEntryForPublishTime(long publishTimeMs) {
if (manifestPublishTimeToExpiryTimeUs.isEmpty()) {
return null;
}
private @Nullable Map.Entry<Long, Long> ceilingExpiryEntryForPublishTime(long publishTimeMs) {
return manifestPublishTimeToExpiryTimeUs.ceilingEntry(publishTimeMs);
}
......
......@@ -49,7 +49,7 @@ public final class Descriptor {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.dash.manifest;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.UriUtil;
......@@ -46,7 +47,7 @@ public final class RangedUri {
* @param length The length of the range, or {@link C#LENGTH_UNSET} to indicate that the range is
* unbounded.
*/
public RangedUri(String referenceUri, long start, long length) {
public RangedUri(@Nullable String referenceUri, long start, long length) {
this.referenceUri = referenceUri == null ? "" : referenceUri;
this.start = start;
this.length = length;
......@@ -74,18 +75,18 @@ public final class RangedUri {
/**
* Attempts to merge this {@link RangedUri} with another and an optional common base uri.
* <p>
* A merge is successful if both instances define the same {@link Uri} after resolution with the
* base uri, and if one starts the byte after the other ends, forming a contiguous region with
*
* <p>A merge is successful if both instances define the same {@link Uri} after resolution with
* the base uri, and if one starts the byte after the other ends, forming a contiguous region with
* no overlap.
* <p>
* If {@code other} is null then the merge is considered unsuccessful, and null is returned.
*
* <p>If {@code other} is null then the merge is considered unsuccessful, and null is returned.
*
* @param other The {@link RangedUri} to merge.
* @param baseUri The optional base Uri.
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise.
*/
public RangedUri attemptMerge(RangedUri other, String baseUri) {
public @Nullable RangedUri attemptMerge(@Nullable RangedUri other, String baseUri) {
final String resolvedUri = resolveUriString(baseUri);
if (other == null || !resolvedUri.equals(other.resolveUriString(baseUri))) {
return null;
......@@ -113,7 +114,7 @@ public final class RangedUri {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
......
......@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.dash.manifest;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* Uniquely identifies a {@link Representation} in a {@link DashManifest}.
......@@ -81,7 +82,7 @@ public final class RepresentationKey implements Parcelable, Comparable<Represent
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
......
......@@ -151,7 +151,7 @@ public final class DashDownloader extends SegmentDownloader<DashManifest, Repres
out.add(new Segment(startTimeUs, dataSpec));
}
private static DashSegmentIndex getSegmentIndex(
private static @Nullable DashSegmentIndex getSegmentIndex(
DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException {
DashSegmentIndex index = representation.getIndex();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment