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
This commit is contained in:
tonihei 2018-05-02 08:47:52 -07:00 committed by Oliver Woodman
parent c466fabb1c
commit 7799e8fd5e
19 changed files with 363 additions and 184 deletions

View File

@ -2,6 +2,7 @@
### dev-v2 (not yet released) ### ### 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 * Optimize seeking in FMP4 by enabling seeking to the nearest sync sample within
a fragment. This benefits standalone FMP4 playbacks, DASH and SmoothStreaming. a fragment. This benefits standalone FMP4 playbacks, DASH and SmoothStreaming.
* Moved initial bitrate estimate from `AdaptiveTrackSelection` to * Moved initial bitrate estimate from `AdaptiveTrackSelection` to

View File

@ -31,6 +31,7 @@ project.ext {
junitVersion = '4.12' junitVersion = '4.12'
truthVersion = '0.39' truthVersion = '0.39'
robolectricVersion = '3.7.1' robolectricVersion = '3.7.1'
checkerframeworkVersion = '2.5.0'
modulePrefix = ':' modulePrefix = ':'
if (gradle.ext.has('exoplayerModulePrefix')) { if (gradle.ext.has('exoplayerModulePrefix')) {
modulePrefix += gradle.ext.exoplayerModulePrefix modulePrefix += gradle.ext.exoplayerModulePrefix

View File

@ -46,6 +46,7 @@ android {
dependencies { dependencies {
implementation 'com.android.support:support-annotations:' + supportLibraryVersion implementation 'com.android.support:support-annotations:' + supportLibraryVersion
implementation 'org.checkerframework:checker-qual:' + checkerframeworkVersion
androidTestImplementation 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestImplementation 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestImplementation 'com.google.truth:truth:' + truthVersion androidTestImplementation 'com.google.truth:truth:' + truthVersion

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
@ -43,29 +44,21 @@ public final class Format implements Parcelable {
*/ */
public static final long OFFSET_SAMPLE_RELATIVE = Long.MAX_VALUE; public static final long OFFSET_SAMPLE_RELATIVE = Long.MAX_VALUE;
/** /** An identifier for the format, or null if unknown or not applicable. */
* An identifier for the format, or null if unknown or not applicable. public final @Nullable String id;
*/
public final String id;
/** /**
* The average bandwidth in bits per second, or {@link #NO_VALUE} if unknown or not applicable. * The average bandwidth in bits per second, or {@link #NO_VALUE} if unknown or not applicable.
*/ */
public final int bitrate; public final int bitrate;
/** /** Codecs of the format as described in RFC 6381, or null if unknown or not applicable. */
* Codecs of the format as described in RFC 6381, or null if unknown or not applicable. public final @Nullable String codecs;
*/ /** Metadata, or null if unknown or not applicable. */
public final String codecs; public final @Nullable Metadata metadata;
/**
* Metadata, or null if unknown or not applicable.
*/
public final Metadata metadata;
// Container specific. // Container specific.
/** /** The mime type of the container, or null if unknown or not applicable. */
* The mime type of the container, or null if unknown or not applicable. public final @Nullable String containerMimeType;
*/
public final String containerMimeType;
// Elementary stream specific. // Elementary stream specific.
@ -73,7 +66,7 @@ public final class Format implements Parcelable {
* The mime type of the elementary stream (i.e. the individual samples), or null if unknown or not * The mime type of the elementary stream (i.e. the individual samples), or null if unknown or not
* applicable. * applicable.
*/ */
public final String sampleMimeType; public final @Nullable String sampleMimeType;
/** /**
* The maximum size of a buffer of data (typically one sample), or {@link #NO_VALUE} if unknown or * The maximum size of a buffer of data (typically one sample), or {@link #NO_VALUE} if unknown or
* not applicable. * not applicable.
@ -84,10 +77,8 @@ public final class Format implements Parcelable {
* if initialization data is not required. * if initialization data is not required.
*/ */
public final List<byte[]> initializationData; public final List<byte[]> initializationData;
/** /** DRM initialization data if the stream is protected, or null otherwise. */
* DRM initialization data if the stream is protected, or null otherwise. public final @Nullable DrmInitData drmInitData;
*/
public final DrmInitData drmInitData;
// Video specific. // Video specific.
@ -117,14 +108,10 @@ public final class Format implements Parcelable {
*/ */
@C.StereoMode @C.StereoMode
public final int stereoMode; public final int stereoMode;
/** /** The projection data for 360/VR video, or null if not applicable. */
* The projection data for 360/VR video, or null if not applicable. public final @Nullable byte[] projectionData;
*/ /** The color metadata associated with the video, helps with accurate color reproduction. */
public final byte[] projectionData; public final @Nullable ColorInfo colorInfo;
/**
* The color metadata associated with the video, helps with accurate color reproduction.
*/
public final ColorInfo colorInfo;
// Audio specific. // Audio specific.
@ -171,10 +158,8 @@ public final class Format implements Parcelable {
@C.SelectionFlags @C.SelectionFlags
public final int selectionFlags; public final int selectionFlags;
/** /** The language, or null if unknown or not applicable. */
* The language, or null if unknown or not applicable. public final @Nullable String language;
*/
public final String language;
/** /**
* The Accessibility channel, or {@link #NO_VALUE} if not known or applicable. * The Accessibility channel, or {@link #NO_VALUE} if not known or applicable.
@ -186,36 +171,72 @@ public final class Format implements Parcelable {
// Video. // Video.
public static Format createVideoContainerFormat(String id, String containerMimeType, public static Format createVideoContainerFormat(
String sampleMimeType, String codecs, int bitrate, int width, int height, @Nullable String id,
float frameRate, List<byte[]> initializationData, @C.SelectionFlags int selectionFlags) { @Nullable String containerMimeType,
String sampleMimeType,
String codecs,
int bitrate,
int width,
int height,
float frameRate,
List<byte[]> initializationData,
@C.SelectionFlags int selectionFlags) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, width, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, width,
height, frameRate, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, height, frameRate, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, selectionFlags, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, NO_VALUE, NO_VALUE, selectionFlags, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE,
initializationData, null, null); initializationData, null, null);
} }
public static Format createVideoSampleFormat(String id, String sampleMimeType, String codecs, public static Format createVideoSampleFormat(
int bitrate, int maxInputSize, int width, int height, float frameRate, @Nullable String id,
List<byte[]> initializationData, DrmInitData drmInitData) { @Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
int maxInputSize,
int width,
int height,
float frameRate,
List<byte[]> initializationData,
@Nullable DrmInitData drmInitData) {
return createVideoSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, width, return createVideoSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, width,
height, frameRate, initializationData, NO_VALUE, NO_VALUE, drmInitData); height, frameRate, initializationData, NO_VALUE, NO_VALUE, drmInitData);
} }
public static Format createVideoSampleFormat(String id, String sampleMimeType, String codecs, public static Format createVideoSampleFormat(
int bitrate, int maxInputSize, int width, int height, float frameRate, @Nullable String id,
List<byte[]> initializationData, int rotationDegrees, float pixelWidthHeightRatio, @Nullable String sampleMimeType,
DrmInitData drmInitData) { @Nullable String codecs,
int bitrate,
int maxInputSize,
int width,
int height,
float frameRate,
List<byte[]> initializationData,
int rotationDegrees,
float pixelWidthHeightRatio,
@Nullable DrmInitData drmInitData) {
return createVideoSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, width, return createVideoSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, width,
height, frameRate, initializationData, rotationDegrees, pixelWidthHeightRatio, null, height, frameRate, initializationData, rotationDegrees, pixelWidthHeightRatio, null,
NO_VALUE, null, drmInitData); NO_VALUE, null, drmInitData);
} }
public static Format createVideoSampleFormat(String id, String sampleMimeType, String codecs, public static Format createVideoSampleFormat(
int bitrate, int maxInputSize, int width, int height, float frameRate, @Nullable String id,
List<byte[]> initializationData, int rotationDegrees, float pixelWidthHeightRatio, @Nullable String sampleMimeType,
byte[] projectionData, @C.StereoMode int stereoMode, ColorInfo colorInfo, @Nullable String codecs,
DrmInitData drmInitData) { int bitrate,
int maxInputSize,
int width,
int height,
float frameRate,
List<byte[]> initializationData,
int rotationDegrees,
float pixelWidthHeightRatio,
byte[] projectionData,
@C.StereoMode int stereoMode,
@Nullable ColorInfo colorInfo,
@Nullable DrmInitData drmInitData) {
return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, width, height, return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, width, height,
frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode,
colorInfo, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, 0, null, NO_VALUE, colorInfo, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, 0, null, NO_VALUE,
@ -224,37 +245,73 @@ public final class Format implements Parcelable {
// Audio. // Audio.
public static Format createAudioContainerFormat(String id, String containerMimeType, public static Format createAudioContainerFormat(
String sampleMimeType, String codecs, int bitrate, int channelCount, int sampleRate, @Nullable String id,
List<byte[]> initializationData, @C.SelectionFlags int selectionFlags, String language) { @Nullable String containerMimeType,
@Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
int channelCount,
int sampleRate,
List<byte[]> initializationData,
@C.SelectionFlags int selectionFlags,
@Nullable String language) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, channelCount, sampleRate, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, channelCount, sampleRate,
NO_VALUE, NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, NO_VALUE, NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE,
initializationData, null, null); initializationData, null, null);
} }
public static Format createAudioSampleFormat(String id, String sampleMimeType, String codecs, public static Format createAudioSampleFormat(
int bitrate, int maxInputSize, int channelCount, int sampleRate, @Nullable String id,
List<byte[]> initializationData, DrmInitData drmInitData, @Nullable String sampleMimeType,
@C.SelectionFlags int selectionFlags, String language) { @Nullable String codecs,
int bitrate,
int maxInputSize,
int channelCount,
int sampleRate,
List<byte[]> initializationData,
@Nullable DrmInitData drmInitData,
@C.SelectionFlags int selectionFlags,
@Nullable String language) {
return createAudioSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount, return createAudioSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount,
sampleRate, NO_VALUE, initializationData, drmInitData, selectionFlags, language); sampleRate, NO_VALUE, initializationData, drmInitData, selectionFlags, language);
} }
public static Format createAudioSampleFormat(String id, String sampleMimeType, String codecs, public static Format createAudioSampleFormat(
int bitrate, int maxInputSize, int channelCount, int sampleRate, @Nullable String id,
@C.PcmEncoding int pcmEncoding, List<byte[]> initializationData, DrmInitData drmInitData, @Nullable String sampleMimeType,
@C.SelectionFlags int selectionFlags, String language) { @Nullable String codecs,
int bitrate,
int maxInputSize,
int channelCount,
int sampleRate,
@C.PcmEncoding int pcmEncoding,
List<byte[]> initializationData,
@Nullable DrmInitData drmInitData,
@C.SelectionFlags int selectionFlags,
@Nullable String language) {
return createAudioSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount, return createAudioSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount,
sampleRate, pcmEncoding, NO_VALUE, NO_VALUE, initializationData, drmInitData, sampleRate, pcmEncoding, NO_VALUE, NO_VALUE, initializationData, drmInitData,
selectionFlags, language, null); selectionFlags, language, null);
} }
public static Format createAudioSampleFormat(String id, String sampleMimeType, String codecs, public static Format createAudioSampleFormat(
int bitrate, int maxInputSize, int channelCount, int sampleRate, @Nullable String id,
@C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, @Nullable String sampleMimeType,
List<byte[]> initializationData, DrmInitData drmInitData, @Nullable String codecs,
@C.SelectionFlags int selectionFlags, String language, Metadata metadata) { int bitrate,
int maxInputSize,
int channelCount,
int sampleRate,
@C.PcmEncoding int pcmEncoding,
int encoderDelay,
int encoderPadding,
List<byte[]> initializationData,
@Nullable DrmInitData drmInitData,
@C.SelectionFlags int selectionFlags,
@Nullable String language,
@Nullable Metadata metadata) {
return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, NO_VALUE, NO_VALUE, return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, channelCount, sampleRate, pcmEncoding, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, channelCount, sampleRate, pcmEncoding,
encoderDelay, encoderPadding, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, encoderDelay, encoderPadding, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE,
@ -263,50 +320,87 @@ public final class Format implements Parcelable {
// Text. // Text.
public static Format createTextContainerFormat(String id, String containerMimeType, public static Format createTextContainerFormat(
String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String id,
String language) { @Nullable String containerMimeType,
@Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
@C.SelectionFlags int selectionFlags,
@Nullable String language) {
return createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs, bitrate, return createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs, bitrate,
selectionFlags, language, NO_VALUE); selectionFlags, language, NO_VALUE);
} }
public static Format createTextContainerFormat(String id, String containerMimeType, public static Format createTextContainerFormat(
String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String id,
String language, int accessibilityChannel) { @Nullable String containerMimeType,
@Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
@C.SelectionFlags int selectionFlags,
@Nullable String language,
int accessibilityChannel) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, selectionFlags, language, accessibilityChannel, NO_VALUE, NO_VALUE, NO_VALUE, selectionFlags, language, accessibilityChannel,
OFFSET_SAMPLE_RELATIVE, null, null, null); OFFSET_SAMPLE_RELATIVE, null, null, null);
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, public static Format createTextSampleFormat(
@C.SelectionFlags int selectionFlags, String language) { @Nullable String id,
String sampleMimeType,
@C.SelectionFlags int selectionFlags,
@Nullable String language) {
return createTextSampleFormat(id, sampleMimeType, selectionFlags, language, null); return createTextSampleFormat(id, sampleMimeType, selectionFlags, language, null);
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, public static Format createTextSampleFormat(
@C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData) { @Nullable String id,
String sampleMimeType,
@C.SelectionFlags int selectionFlags,
@Nullable String language,
@Nullable DrmInitData drmInitData) {
return createTextSampleFormat(id, sampleMimeType, null, NO_VALUE, selectionFlags, language, return createTextSampleFormat(id, sampleMimeType, null, NO_VALUE, selectionFlags, language,
NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.<byte[]>emptyList()); NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.<byte[]>emptyList());
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(
int bitrate, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel, @Nullable String id,
DrmInitData drmInitData) { @Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
@C.SelectionFlags int selectionFlags,
@Nullable String language,
int accessibilityChannel,
@Nullable DrmInitData drmInitData) {
return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language,
accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.<byte[]>emptyList()); accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.<byte[]>emptyList());
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(
int bitrate, @C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData, @Nullable String id,
@Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
@C.SelectionFlags int selectionFlags,
@Nullable String language,
@Nullable DrmInitData drmInitData,
long subsampleOffsetUs) { long subsampleOffsetUs) {
return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language,
NO_VALUE, drmInitData, subsampleOffsetUs, Collections.<byte[]>emptyList()); NO_VALUE, drmInitData, subsampleOffsetUs, Collections.<byte[]>emptyList());
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(
int bitrate, @C.SelectionFlags int selectionFlags, String language, @Nullable String id,
int accessibilityChannel, DrmInitData drmInitData, long subsampleOffsetUs, @Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
@C.SelectionFlags int selectionFlags,
@Nullable String language,
int accessibilityChannel,
@Nullable DrmInitData drmInitData,
long subsampleOffsetUs,
List<byte[]> initializationData) { List<byte[]> initializationData) {
return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
@ -317,14 +411,14 @@ public final class Format implements Parcelable {
// Image. // Image.
public static Format createImageSampleFormat( public static Format createImageSampleFormat(
String id, @Nullable String id,
String sampleMimeType, @Nullable String sampleMimeType,
String codecs, @Nullable String codecs,
int bitrate, int bitrate,
@C.SelectionFlags int selectionFlags, @C.SelectionFlags int selectionFlags,
List<byte[]> initializationData, List<byte[]> initializationData,
String language, @Nullable String language,
DrmInitData drmInitData) { @Nullable DrmInitData drmInitData) {
return new Format( return new Format(
id, id,
null, null,
@ -356,36 +450,65 @@ public final class Format implements Parcelable {
// Generic. // Generic.
public static Format createContainerFormat(String id, String containerMimeType, public static Format createContainerFormat(
String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String id,
String language) { @Nullable String containerMimeType,
@Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
@C.SelectionFlags int selectionFlags,
@Nullable String language) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, null, NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, null,
null); null);
} }
public static Format createSampleFormat(String id, String sampleMimeType, public static Format createSampleFormat(
long subsampleOffsetUs) { @Nullable String id, @Nullable String sampleMimeType, long subsampleOffsetUs) {
return new Format(id, null, sampleMimeType, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, return new Format(id, null, sampleMimeType, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, 0, null, NO_VALUE, subsampleOffsetUs, null, null, null); NO_VALUE, 0, null, NO_VALUE, subsampleOffsetUs, null, null, null);
} }
public static Format createSampleFormat(String id, String sampleMimeType, String codecs, public static Format createSampleFormat(
int bitrate, DrmInitData drmInitData) { @Nullable String id,
@Nullable String sampleMimeType,
@Nullable String codecs,
int bitrate,
@Nullable DrmInitData drmInitData) {
return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, drmInitData, null); NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, drmInitData, null);
} }
/* package */ Format(String id, String containerMimeType, String sampleMimeType, String codecs, /* package */ Format(
int bitrate, int maxInputSize, int width, int height, float frameRate, int rotationDegrees, @Nullable String id,
float pixelWidthHeightRatio, byte[] projectionData, @C.StereoMode int stereoMode, @Nullable String containerMimeType,
ColorInfo colorInfo, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, @Nullable String sampleMimeType,
int encoderDelay, int encoderPadding, @C.SelectionFlags int selectionFlags, String language, @Nullable String codecs,
int accessibilityChannel, long subsampleOffsetUs, List<byte[]> initializationData, int bitrate,
DrmInitData drmInitData, Metadata metadata) { int maxInputSize,
int width,
int height,
float frameRate,
int rotationDegrees,
float pixelWidthHeightRatio,
@Nullable byte[] projectionData,
@C.StereoMode int stereoMode,
@Nullable ColorInfo colorInfo,
int channelCount,
int sampleRate,
@C.PcmEncoding int pcmEncoding,
int encoderDelay,
int encoderPadding,
@C.SelectionFlags int selectionFlags,
@Nullable String language,
int accessibilityChannel,
long subsampleOffsetUs,
@Nullable List<byte[]> initializationData,
@Nullable DrmInitData drmInitData,
@Nullable Metadata metadata) {
this.id = id; this.id = id;
this.containerMimeType = containerMimeType; this.containerMimeType = containerMimeType;
this.sampleMimeType = sampleMimeType; this.sampleMimeType = sampleMimeType;
@ -468,14 +591,14 @@ public final class Format implements Parcelable {
} }
public Format copyWithContainerInfo( public Format copyWithContainerInfo(
String id, @Nullable String id,
String sampleMimeType, @Nullable String sampleMimeType,
String codecs, @Nullable String codecs,
int bitrate, int bitrate,
int width, int width,
int height, int height,
@C.SelectionFlags int selectionFlags, @C.SelectionFlags int selectionFlags,
String language) { @Nullable String language) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width,
height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode,
colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
@ -512,7 +635,7 @@ public final class Format implements Parcelable {
drmInitData, metadata); drmInitData, metadata);
} }
public Format copyWithDrmInitData(DrmInitData drmInitData) { public Format copyWithDrmInitData(@Nullable DrmInitData drmInitData) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width,
height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode,
colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
@ -520,7 +643,7 @@ public final class Format implements Parcelable {
drmInitData, metadata); drmInitData, metadata);
} }
public Format copyWithMetadata(Metadata metadata) { public Format copyWithMetadata(@Nullable Metadata metadata) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width,
height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode,
colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
@ -574,7 +697,7 @@ public final class Format implements Parcelable {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(@Nullable Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
} }

View File

@ -121,11 +121,11 @@ public final class FragmentedMp4Extractor implements Extractor {
// Workarounds. // Workarounds.
@Flags private final int flags; @Flags private final int flags;
private final Track sideloadedTrack; private final @Nullable Track sideloadedTrack;
// Sideloaded data. // Sideloaded data.
private final List<Format> closedCaptionFormats; private final List<Format> closedCaptionFormats;
private final DrmInitData sideloadedDrmInitData; private final @Nullable DrmInitData sideloadedDrmInitData;
// Track-linked data bundle, accessible as a whole through trackID. // Track-linked data bundle, accessible as a whole through trackID.
private final SparseArray<TrackBundle> trackBundles; private final SparseArray<TrackBundle> trackBundles;
@ -136,7 +136,7 @@ public final class FragmentedMp4Extractor implements Extractor {
private final ParsableByteArray nalBuffer; private final ParsableByteArray nalBuffer;
// Adjusts sample timestamps. // Adjusts sample timestamps.
private final TimestampAdjuster timestampAdjuster; private final @Nullable TimestampAdjuster timestampAdjuster;
// Parser state. // Parser state.
private final ParsableByteArray atomHeader; private final ParsableByteArray atomHeader;
@ -185,20 +185,23 @@ public final class FragmentedMp4Extractor implements Extractor {
* @param flags Flags that control the extractor's behavior. * @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. * @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); this(flags, timestampAdjuster, null, null);
} }
/** /**
* @param flags Flags that control the extractor's behavior. * @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. * @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor * @param sideloadedTrack Sideloaded track information, in the case that the extractor will not
* will not receive a moov box in the input data. Null if a moov box is expected. * 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 * @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the
* pssh boxes (if present) will be used. * pssh boxes (if present) will be used.
*/ */
public FragmentedMp4Extractor(@Flags int flags, TimestampAdjuster timestampAdjuster, public FragmentedMp4Extractor(
Track sideloadedTrack, DrmInitData sideloadedDrmInitData) { @Flags int flags,
@Nullable TimestampAdjuster timestampAdjuster,
@Nullable Track sideloadedTrack,
@Nullable DrmInitData sideloadedDrmInitData) {
this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData, this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData,
Collections.<Format>emptyList()); Collections.<Format>emptyList());
} }
@ -206,15 +209,19 @@ public final class FragmentedMp4Extractor implements Extractor {
/** /**
* @param flags Flags that control the extractor's behavior. * @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. * @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor * @param sideloadedTrack Sideloaded track information, in the case that the extractor will not
* will not receive a moov box in the input data. Null if a moov box is expected. * 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 * @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the
* pssh boxes (if present) will be used. * pssh boxes (if present) will be used.
* @param closedCaptionFormats For tracks that contain SEI messages, the formats of the closed * @param closedCaptionFormats For tracks that contain SEI messages, the formats of the closed
* caption channels to expose. * caption channels to expose.
*/ */
public FragmentedMp4Extractor(@Flags int flags, TimestampAdjuster timestampAdjuster, public FragmentedMp4Extractor(
Track sideloadedTrack, DrmInitData sideloadedDrmInitData, List<Format> closedCaptionFormats) { @Flags int flags,
@Nullable TimestampAdjuster timestampAdjuster,
@Nullable Track sideloadedTrack,
@Nullable DrmInitData sideloadedDrmInitData,
List<Format> closedCaptionFormats) {
this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData, this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData,
closedCaptionFormats, null); closedCaptionFormats, null);
} }
@ -222,8 +229,8 @@ public final class FragmentedMp4Extractor implements Extractor {
/** /**
* @param flags Flags that control the extractor's behavior. * @param flags Flags that control the extractor's behavior.
* @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. * @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed.
* @param sideloadedTrack Sideloaded track information, in the case that the extractor * @param sideloadedTrack Sideloaded track information, in the case that the extractor will not
* will not receive a moov box in the input data. Null if a moov box is expected. * 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 * @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the
* pssh boxes (if present) will be used. * pssh boxes (if present) will be used.
* @param closedCaptionFormats For tracks that contain SEI messages, the formats of the closed * @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 * 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. * handling of emsg messages for players is not required.
*/ */
public FragmentedMp4Extractor(@Flags int flags, TimestampAdjuster timestampAdjuster, public FragmentedMp4Extractor(
Track sideloadedTrack, DrmInitData sideloadedDrmInitData, List<Format> closedCaptionFormats, @Flags int flags,
@Nullable TimestampAdjuster timestampAdjuster,
@Nullable Track sideloadedTrack,
@Nullable DrmInitData sideloadedDrmInitData,
List<Format> closedCaptionFormats,
@Nullable TrackOutput additionalEmsgTrackOutput) { @Nullable TrackOutput additionalEmsgTrackOutput) {
this.flags = flags | (sideloadedTrack != null ? FLAG_SIDELOADED : 0); this.flags = flags | (sideloadedTrack != null ? FLAG_SIDELOADED : 0);
this.timestampAdjuster = timestampAdjuster; this.timestampAdjuster = timestampAdjuster;

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.extractor.mp4; package com.google.android.exoplayer2.extractor.mp4;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -36,7 +37,7 @@ public final class PsshAtomUtil {
* @param data The scheme specific data. * @param data The scheme specific data.
* @return The PSSH atom. * @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); return buildPsshAtom(systemId, null, data);
} }
@ -48,7 +49,8 @@ public final class PsshAtomUtil {
* @param data The scheme specific data. * @param data The scheme specific data.
* @return The PSSH atom. * @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; boolean buildV1Atom = keyIds != null;
int dataLength = data != null ? data.length : 0; int dataLength = data != null ? data.length : 0;
int psshBoxLength = Atom.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength; 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. * 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. * @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 * @return The parsed UUID. Null if the input is not a valid PSSH atom, or if the PSSH atom has an
* an unsupported version. * unsupported version.
*/ */
public static UUID parseUuid(byte[] atom) { public static @Nullable UUID parseUuid(byte[] atom) {
PsshAtom parsedAtom = parsePsshAtom(atom); PsshAtom parsedAtom = parsePsshAtom(atom);
if (parsedAtom == null) { if (parsedAtom == null) {
return 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. * 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. * 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. * @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 * @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. * 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); PsshAtom parsedAtom = parsePsshAtom(atom);
if (parsedAtom == null) { if (parsedAtom == null) {
return null; return null;
@ -140,7 +142,7 @@ public final class PsshAtomUtil {
* has an unsupported version. * has an unsupported version.
*/ */
// TODO: Support parsing of the key ids for version 1 PSSH atoms. // 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); ParsableByteArray atomData = new ParsableByteArray(atom);
if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) { if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) {
// Data too short. // Data too short.

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.chunk; package com.google.android.exoplayer2.source.chunk;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.upstream.DataSource; 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 * Optional data associated with the selection of the track to which this chunk belongs. Null if
* the chunk does not belong to a track. * 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 * 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. * being loaded does not contain media samples.
@ -75,8 +76,15 @@ public abstract class Chunk implements Loadable {
* @param startTimeUs See {@link #startTimeUs}. * @param startTimeUs See {@link #startTimeUs}.
* @param endTimeUs See {@link #endTimeUs}. * @param endTimeUs See {@link #endTimeUs}.
*/ */
public Chunk(DataSource dataSource, DataSpec dataSpec, int type, Format trackFormat, public Chunk(
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs) { DataSource dataSource,
DataSpec dataSpec,
int type,
Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
long startTimeUs,
long endTimeUs) {
this.dataSource = Assertions.checkNotNull(dataSource); this.dataSource = Assertions.checkNotNull(dataSource);
this.dataSpec = Assertions.checkNotNull(dataSpec); this.dataSpec = Assertions.checkNotNull(dataSpec);
this.type = type; this.type = type;

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.chunk; package com.google.android.exoplayer2.source.chunk;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
@ -44,8 +45,12 @@ public final class InitializationChunk extends Chunk {
* @param trackSelectionData See {@link #trackSelectionData}. * @param trackSelectionData See {@link #trackSelectionData}.
* @param extractorWrapper A wrapped extractor to use for parsing the initialization data. * @param extractorWrapper A wrapped extractor to use for parsing the initialization data.
*/ */
public InitializationChunk(DataSource dataSource, DataSpec dataSpec, Format trackFormat, public InitializationChunk(
int trackSelectionReason, Object trackSelectionData, DataSource dataSource,
DataSpec dataSpec,
Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
ChunkExtractorWrapper extractorWrapper) { ChunkExtractorWrapper extractorWrapper) {
super(dataSource, dataSpec, C.DATA_TYPE_MEDIA_INITIALIZATION, trackFormat, trackSelectionReason, super(dataSource, dataSpec, C.DATA_TYPE_MEDIA_INITIALIZATION, trackFormat, trackSelectionReason,
trackSelectionData, C.TIME_UNSET, C.TIME_UNSET); trackSelectionData, C.TIME_UNSET, C.TIME_UNSET);

View File

@ -16,8 +16,10 @@
package com.google.android.exoplayer2.util; package com.google.android.exoplayer2.util;
import android.os.Looper; import android.os.Looper;
import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
/** /**
* Provides methods for asserting the truth of expressions and properties. * 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. * @return The non-null reference that was validated.
* @throws NullPointerException If {@code reference} is null. * @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) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
@ -119,7 +122,8 @@ public final class Assertions {
* @return The non-null reference that was validated. * @return The non-null reference that was validated.
* @throws NullPointerException If {@code reference} is null. * @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) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) {
throw new NullPointerException(String.valueOf(errorMessage)); throw new NullPointerException(String.valueOf(errorMessage));
} }
@ -133,7 +137,8 @@ public final class Assertions {
* @return The non-null, non-empty string that was validated. * @return The non-null, non-empty string that was validated.
* @throws IllegalArgumentException If {@code string} is null or 0-length. * @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)) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@ -149,7 +154,8 @@ public final class Assertions {
* @return The non-null, non-empty string that was validated. * @return The non-null, non-empty string that was validated.
* @throws IllegalArgumentException If {@code string} is null or 0-length. * @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)) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) {
throw new IllegalArgumentException(String.valueOf(errorMessage)); throw new IllegalArgumentException(String.valueOf(errorMessage));
} }

View File

@ -134,14 +134,13 @@ public final class MimeTypes {
return BASE_TYPE_APPLICATION.equals(getTopLevelType(mimeType)); return BASE_TYPE_APPLICATION.equals(getTopLevelType(mimeType));
} }
/** /**
* Derives a video sample mimeType from a codecs attribute. * Derives a video sample mimeType from a codecs attribute.
* *
* @param codecs The codecs attribute. * @param codecs The codecs attribute.
* @return The derived video mimeType, or null if it could not be derived. * @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) { if (codecs == null) {
return null; return null;
} }
@ -161,7 +160,7 @@ public final class MimeTypes {
* @param codecs The codecs attribute. * @param codecs The codecs attribute.
* @return The derived audio mimeType, or null if it could not be derived. * @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) { if (codecs == null) {
return null; return null;
} }
@ -181,7 +180,7 @@ public final class MimeTypes {
* @param codec The codec identifier to derive. * @param codec The codec identifier to derive.
* @return The mimeType, or null if it could not be derived. * @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) { if (codec == null) {
return null; return null;
} }
@ -345,7 +344,7 @@ public final class MimeTypes {
* @param mimeType The mimeType whose top-level type is required. * @param mimeType The mimeType whose top-level type is required.
* @return The top-level type, or null if the mimeType is null. * @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) { if (mimeType == null) {
return null; return null;
} }

View File

@ -29,6 +29,7 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Display; import android.view.Display;
@ -190,7 +191,7 @@ public final class Util {
* @param o2 The second object. * @param o2 The second object.
* @return {@code o1 == null ? o2 == null : o1.equals(o2)}. * @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); return o1 == null ? o2 == null : o1.equals(o2);
} }
@ -224,6 +225,20 @@ public final class Util {
list.subList(fromIndex, toIndex).clear(); list.subList(fromIndex, toIndex).clear();
} }
/**
* 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. * Instantiates a new single threaded executor whose thread has the specified name.
* *

View File

@ -34,6 +34,8 @@ android {
dependencies { dependencies {
implementation project(modulePrefix + 'library-core') 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 implementation 'com.android.support:support-annotations:' + supportLibraryVersion
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils-robolectric')
} }

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.dash; package com.google.android.exoplayer2.source.dash;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.drm.DrmInitData; 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 IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted. * @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 { throws IOException, InterruptedException {
int primaryTrackType = C.TRACK_TYPE_VIDEO; int primaryTrackType = C.TRACK_TYPE_VIDEO;
Representation representation = getFirstRepresentation(period, primaryTrackType); 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}. * 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 dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the * @param trackType The type of the representation. Typically one of the {@link
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to. * @param representation The representation which initialization chunk belongs to.
* @return the sample {@link Format} of the given representation. * @return the sample {@link Format} of the given representation.
* @throws IOException Thrown when there is an error while loading. * @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted. * @throws InterruptedException Thrown if the thread was interrupted.
*/ */
public static Format loadSampleFormat(DataSource dataSource, int trackType, public static @Nullable Format loadSampleFormat(
Representation representation) throws IOException, InterruptedException { DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
representation, false); representation, false);
return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0]; return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0];
@ -106,28 +108,29 @@ public final class DashUtil {
* ChunkIndex}. * ChunkIndex}.
* *
* @param dataSource The source from which the data should be loaded. * @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the * @param trackType The type of the representation. Typically one of the {@link
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to. * @param representation The representation which initialization chunk belongs to.
* @return The {@link ChunkIndex} of the given representation, or null if no initialization or * @return The {@link ChunkIndex} of the given representation, or null if no initialization or
* index data exists. * index data exists.
* @throws IOException Thrown when there is an error while loading. * @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted. * @throws InterruptedException Thrown if the thread was interrupted.
*/ */
public static ChunkIndex loadChunkIndex(DataSource dataSource, int trackType, public static @Nullable ChunkIndex loadChunkIndex(
Representation representation) throws IOException, InterruptedException { DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
representation, true); representation, true);
return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap(); return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap();
} }
/** /**
* Loads initialization data for the {@code representation} and optionally index data then * Loads initialization data for the {@code representation} and optionally index data then returns
* returns a {@link ChunkExtractorWrapper} which contains the output. * a {@link ChunkExtractorWrapper} which contains the output.
* *
* @param dataSource The source from which the data should be loaded. * @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the * @param trackType The type of the representation. Typically one of the {@link
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to. * @param representation The representation which initialization chunk belongs to.
* @param loadIndex Whether to load index data too. * @param loadIndex Whether to load index data too.
* @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no * @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 IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted. * @throws InterruptedException Thrown if the thread was interrupted.
*/ */
private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, int trackType, private static @Nullable ChunkExtractorWrapper loadInitializationData(
Representation representation, boolean loadIndex) throws IOException, InterruptedException { DataSource dataSource, int trackType, Representation representation, boolean loadIndex)
throws IOException, InterruptedException {
RangedUri initializationUri = representation.getInitializationUri(); RangedUri initializationUri = representation.getInitializationUri();
if (initializationUri == null) { if (initializationUri == null) {
return null; return null;
@ -181,7 +185,7 @@ public final class DashUtil {
return new ChunkExtractorWrapper(extractor, trackType, format); 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); int index = period.getAdaptationSetIndex(type);
if (index == C.INDEX_UNSET) { if (index == C.INDEX_UNSET) {
return null; return null;

View File

@ -45,8 +45,10 @@ import java.io.IOException;
EventSampleStream(EventStream eventStream, Format upstreamFormat, boolean eventStreamUpdatable) { EventSampleStream(EventStream eventStream, Format upstreamFormat, boolean eventStreamUpdatable) {
this.upstreamFormat = upstreamFormat; this.upstreamFormat = upstreamFormat;
this.eventStream = eventStream;
eventMessageEncoder = new EventMessageEncoder(); eventMessageEncoder = new EventMessageEncoder();
pendingSeekPositionUs = C.TIME_UNSET; pendingSeekPositionUs = C.TIME_UNSET;
eventTimesUs = eventStream.presentationTimesUs;
updateEventStream(eventStream, eventStreamUpdatable); updateEventStream(eventStream, eventStreamUpdatable);
} }

View File

@ -100,6 +100,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
* messages that generate DASH media source events. * messages that generate DASH media source events.
* @param allocator An {@link Allocator} from which allocations can be obtained. * @param allocator An {@link Allocator} from which allocations can be obtained.
*/ */
@SuppressWarnings("nullness")
public PlayerEmsgHandler( public PlayerEmsgHandler(
DashManifest manifest, PlayerEmsgCallback playerEmsgCallback, Allocator allocator) { DashManifest manifest, PlayerEmsgCallback playerEmsgCallback, Allocator allocator) {
this.manifest = manifest; this.manifest = manifest;
@ -237,11 +238,10 @@ public final class PlayerEmsgHandler implements Handler.Callback {
// Internal methods. // Internal methods.
private void handleManifestExpiredMessage(long eventTimeUs, long manifestPublishTimeMsInEmsg) { private void handleManifestExpiredMessage(long eventTimeUs, long manifestPublishTimeMsInEmsg) {
if (!manifestPublishTimeToExpiryTimeUs.containsKey(manifestPublishTimeMsInEmsg)) { Long previousExpiryTimeUs = manifestPublishTimeToExpiryTimeUs.get(manifestPublishTimeMsInEmsg);
if (previousExpiryTimeUs == null) {
manifestPublishTimeToExpiryTimeUs.put(manifestPublishTimeMsInEmsg, eventTimeUs); manifestPublishTimeToExpiryTimeUs.put(manifestPublishTimeMsInEmsg, eventTimeUs);
} else { } else {
long previousExpiryTimeUs =
manifestPublishTimeToExpiryTimeUs.get(manifestPublishTimeMsInEmsg);
if (previousExpiryTimeUs > eventTimeUs) { if (previousExpiryTimeUs > eventTimeUs) {
manifestPublishTimeToExpiryTimeUs.put(manifestPublishTimeMsInEmsg, eventTimeUs); manifestPublishTimeToExpiryTimeUs.put(manifestPublishTimeMsInEmsg, eventTimeUs);
} }
@ -253,10 +253,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
notifySourceMediaPresentationEnded(); notifySourceMediaPresentationEnded();
} }
private Map.Entry<Long, Long> ceilingExpiryEntryForPublishTime(long publishTimeMs) { private @Nullable Map.Entry<Long, Long> ceilingExpiryEntryForPublishTime(long publishTimeMs) {
if (manifestPublishTimeToExpiryTimeUs.isEmpty()) {
return null;
}
return manifestPublishTimeToExpiryTimeUs.ceilingEntry(publishTimeMs); return manifestPublishTimeToExpiryTimeUs.ceilingEntry(publishTimeMs);
} }

View File

@ -49,7 +49,7 @@ public final class Descriptor {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(@Nullable Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
} }

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.dash.manifest; package com.google.android.exoplayer2.source.dash.manifest;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.UriUtil; 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 * @param length The length of the range, or {@link C#LENGTH_UNSET} to indicate that the range is
* unbounded. * unbounded.
*/ */
public RangedUri(String referenceUri, long start, long length) { public RangedUri(@Nullable String referenceUri, long start, long length) {
this.referenceUri = referenceUri == null ? "" : referenceUri; this.referenceUri = referenceUri == null ? "" : referenceUri;
this.start = start; this.start = start;
this.length = length; 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. * 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 * <p>A merge is successful if both instances define the same {@link Uri} after resolution with
* base uri, and if one starts the byte after the other ends, forming a contiguous region with * the base uri, and if one starts the byte after the other ends, forming a contiguous region with
* no overlap. * 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 other The {@link RangedUri} to merge.
* @param baseUri The optional base Uri. * @param baseUri The optional base Uri.
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise. * @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); final String resolvedUri = resolveUriString(baseUri);
if (other == null || !resolvedUri.equals(other.resolveUriString(baseUri))) { if (other == null || !resolvedUri.equals(other.resolveUriString(baseUri))) {
return null; return null;
@ -113,7 +114,7 @@ public final class RangedUri {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(@Nullable Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
} }

View File

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.dash.manifest;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/** /**
* Uniquely identifies a {@link Representation} in a {@link DashManifest}. * Uniquely identifies a {@link Representation} in a {@link DashManifest}.
@ -81,7 +82,7 @@ public final class RepresentationKey implements Parcelable, Comparable<Represent
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(@Nullable Object o) {
if (this == o) { if (this == o) {
return true; return true;
} }

View File

@ -151,7 +151,7 @@ public final class DashDownloader extends SegmentDownloader<DashManifest, Repres
out.add(new Segment(startTimeUs, dataSpec)); out.add(new Segment(startTimeUs, dataSpec));
} }
private static DashSegmentIndex getSegmentIndex( private static @Nullable DashSegmentIndex getSegmentIndex(
DataSource dataSource, int trackType, Representation representation) DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException { throws IOException, InterruptedException {
DashSegmentIndex index = representation.getIndex(); DashSegmentIndex index = representation.getIndex();