Commit 0c4df84e by Yannick RUI

Merge remote-tracking branch 'upstream/dev-v2' into dev-v2

# Conflicts:
#	library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java
parents 831de75f 8967dd9c
Showing with 595 additions and 365 deletions
...@@ -27,6 +27,10 @@ ...@@ -27,6 +27,10 @@
over other selection parameters. over other selection parameters.
* Remove `AnalyticsCollector.Factory`. Instances can be created directly and * Remove `AnalyticsCollector.Factory`. Instances can be created directly and
the `Player` set later using `AnalyticsCollector.setPlayer`. the `Player` set later using `AnalyticsCollector.setPlayer`.
* Add `allowAudioMixedChannelCountAdaptiveness` parameter to
`DefaultTrackSelector` to allow adaptive selections of audio tracks with
different channel counts
([#6257](https://github.com/google/ExoPlayer/issues/6257)).
### 2.10.4 ### ### 2.10.4 ###
......
...@@ -24,7 +24,6 @@ include modulePrefix + 'library-hls' ...@@ -24,7 +24,6 @@ include modulePrefix + 'library-hls'
include modulePrefix + 'library-smoothstreaming' include modulePrefix + 'library-smoothstreaming'
include modulePrefix + 'library-ui' include modulePrefix + 'library-ui'
include modulePrefix + 'testutils' include modulePrefix + 'testutils'
include modulePrefix + 'testutils-robolectric'
include modulePrefix + 'extension-ffmpeg' include modulePrefix + 'extension-ffmpeg'
include modulePrefix + 'extension-flac' include modulePrefix + 'extension-flac'
include modulePrefix + 'extension-gvr' include modulePrefix + 'extension-gvr'
...@@ -47,7 +46,6 @@ project(modulePrefix + 'library-hls').projectDir = new File(rootDir, 'library/hl ...@@ -47,7 +46,6 @@ project(modulePrefix + 'library-hls').projectDir = new File(rootDir, 'library/hl
project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming') project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming')
project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui') project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui')
project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils') project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils')
project(modulePrefix + 'testutils-robolectric').projectDir = new File(rootDir, 'testutils_robolectric')
project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg') project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg')
project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac') project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac')
project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr') project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr')
......
...@@ -37,7 +37,8 @@ dependencies { ...@@ -37,7 +37,8 @@ dependencies {
implementation project(modulePrefix + 'library-ui') implementation project(modulePrefix + 'library-ui')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -36,7 +36,8 @@ dependencies { ...@@ -36,7 +36,8 @@ dependencies {
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'library') testImplementation project(modulePrefix + 'library')
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -40,7 +40,8 @@ dependencies { ...@@ -40,7 +40,8 @@ dependencies {
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -43,7 +43,8 @@ dependencies { ...@@ -43,7 +43,8 @@ dependencies {
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
androidTestImplementation project(modulePrefix + 'testutils') androidTestImplementation project(modulePrefix + 'testutils')
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -32,11 +32,12 @@ android { ...@@ -32,11 +32,12 @@ android {
} }
dependencies { dependencies {
api 'com.google.ads.interactivemedia.v3:interactivemedia:3.11.2' api 'com.google.ads.interactivemedia.v3:interactivemedia:3.11.3'
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0' implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0'
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -40,7 +40,8 @@ android { ...@@ -40,7 +40,8 @@ android {
dependencies { dependencies {
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion
} }
......
...@@ -34,7 +34,8 @@ dependencies { ...@@ -34,7 +34,8 @@ dependencies {
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
implementation 'net.butterflytv.utils:rtmp-client:3.0.1' implementation 'net.butterflytv.utils:rtmp-client:3.0.1'
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -40,7 +40,8 @@ android { ...@@ -40,7 +40,8 @@ android {
dependencies { dependencies {
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion
androidTestImplementation 'com.google.truth:truth:' + truthVersion androidTestImplementation 'com.google.truth:truth:' + truthVersion
......
...@@ -174,8 +174,8 @@ public class LibvpxVideoRenderer extends BaseRenderer { ...@@ -174,8 +174,8 @@ public class LibvpxVideoRenderer extends BaseRenderer {
*/ */
public LibvpxVideoRenderer( public LibvpxVideoRenderer(
long allowedJoiningTimeMs, long allowedJoiningTimeMs,
Handler eventHandler, @Nullable Handler eventHandler,
VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify) { int maxDroppedFramesToNotify) {
this( this(
allowedJoiningTimeMs, allowedJoiningTimeMs,
...@@ -206,10 +206,10 @@ public class LibvpxVideoRenderer extends BaseRenderer { ...@@ -206,10 +206,10 @@ public class LibvpxVideoRenderer extends BaseRenderer {
*/ */
public LibvpxVideoRenderer( public LibvpxVideoRenderer(
long allowedJoiningTimeMs, long allowedJoiningTimeMs,
Handler eventHandler, @Nullable Handler eventHandler,
VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify, int maxDroppedFramesToNotify,
DrmSessionManager<ExoMediaCrypto> drmSessionManager, @Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys, boolean playClearSamplesWithoutKeys,
boolean disableLoopFilter) { boolean disableLoopFilter) {
this( this(
...@@ -249,10 +249,10 @@ public class LibvpxVideoRenderer extends BaseRenderer { ...@@ -249,10 +249,10 @@ public class LibvpxVideoRenderer extends BaseRenderer {
*/ */
public LibvpxVideoRenderer( public LibvpxVideoRenderer(
long allowedJoiningTimeMs, long allowedJoiningTimeMs,
Handler eventHandler, @Nullable Handler eventHandler,
VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify, int maxDroppedFramesToNotify,
DrmSessionManager<ExoMediaCrypto> drmSessionManager, @Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys, boolean playClearSamplesWithoutKeys,
boolean disableLoopFilter, boolean disableLoopFilter,
boolean enableRowMultiThreadMode, boolean enableRowMultiThreadMode,
...@@ -847,7 +847,7 @@ public class LibvpxVideoRenderer extends BaseRenderer { ...@@ -847,7 +847,7 @@ public class LibvpxVideoRenderer extends BaseRenderer {
pendingFormat = null; pendingFormat = null;
} }
inputBuffer.flip(); inputBuffer.flip();
inputBuffer.colorInfo = formatHolder.format.colorInfo; inputBuffer.colorInfo = format.colorInfo;
onQueueInputBuffer(inputBuffer); onQueueInputBuffer(inputBuffer);
decoder.queueInputBuffer(inputBuffer); decoder.queueInputBuffer(inputBuffer);
buffersInCodecCount++; buffersInCodecCount++;
......
...@@ -33,7 +33,7 @@ import java.nio.ByteBuffer; ...@@ -33,7 +33,7 @@ import java.nio.ByteBuffer;
private static final int DECODE_ERROR = 1; private static final int DECODE_ERROR = 1;
private static final int DRM_ERROR = 2; private static final int DRM_ERROR = 2;
private final ExoMediaCrypto exoMediaCrypto; @Nullable private final ExoMediaCrypto exoMediaCrypto;
private final long vpxDecContext; private final long vpxDecContext;
@C.VideoOutputMode private volatile int outputMode; @C.VideoOutputMode private volatile int outputMode;
...@@ -55,7 +55,7 @@ import java.nio.ByteBuffer; ...@@ -55,7 +55,7 @@ import java.nio.ByteBuffer;
int numInputBuffers, int numInputBuffers,
int numOutputBuffers, int numOutputBuffers,
int initialInputBufferSize, int initialInputBufferSize,
ExoMediaCrypto exoMediaCrypto, @Nullable ExoMediaCrypto exoMediaCrypto,
boolean disableLoopFilter, boolean disableLoopFilter,
boolean enableRowMultiThreadMode, boolean enableRowMultiThreadMode,
int threads) int threads)
...@@ -170,9 +170,19 @@ import java.nio.ByteBuffer; ...@@ -170,9 +170,19 @@ import java.nio.ByteBuffer;
private native long vpxClose(long context); private native long vpxClose(long context);
private native long vpxDecode(long context, ByteBuffer encoded, int length); private native long vpxDecode(long context, ByteBuffer encoded, int length);
private native long vpxSecureDecode(long context, ByteBuffer encoded, int length,
ExoMediaCrypto mediaCrypto, int inputMode, byte[] key, byte[] iv, private native long vpxSecureDecode(
int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData); long context,
ByteBuffer encoded,
int length,
@Nullable ExoMediaCrypto mediaCrypto,
int inputMode,
byte[] key,
byte[] iv,
int numSubSamples,
int[] numBytesOfClearData,
int[] numBytesOfEncryptedData);
private native int vpxGetFrame(long context, VpxOutputBuffer outputBuffer); private native int vpxGetFrame(long context, VpxOutputBuffer outputBuffer);
/** /**
......
...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.vp9; ...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.vp9;
import android.content.Context; import android.content.Context;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
import androidx.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
/** /**
...@@ -27,10 +28,10 @@ public class VpxVideoSurfaceView extends GLSurfaceView implements VpxOutputBuffe ...@@ -27,10 +28,10 @@ public class VpxVideoSurfaceView extends GLSurfaceView implements VpxOutputBuffe
private final VpxRenderer renderer; private final VpxRenderer renderer;
public VpxVideoSurfaceView(Context context) { public VpxVideoSurfaceView(Context context) {
this(context, null); this(context, /* attrs= */ null);
} }
public VpxVideoSurfaceView(Context context, AttributeSet attrs) { public VpxVideoSurfaceView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
renderer = new VpxRenderer(); renderer = new VpxRenderer();
setPreserveEGLContextOnPause(true); setPreserveEGLContextOnPause(true);
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.ext.vp9;
import com.google.android.exoplayer2.util.NonNullApi;
...@@ -42,7 +42,6 @@ android { ...@@ -42,7 +42,6 @@ android {
} }
test { test {
java.srcDirs += '../../testutils/src/main/java/' java.srcDirs += '../../testutils/src/main/java/'
java.srcDirs += '../../testutils_robolectric/src/main/java/'
} }
} }
......
...@@ -52,6 +52,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { ...@@ -52,6 +52,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
private int pendingMetadataCount; private int pendingMetadataCount;
private MetadataDecoder decoder; private MetadataDecoder decoder;
private boolean inputStreamEnded; private boolean inputStreamEnded;
private long subsampleOffsetUs;
/** /**
* @param output The output. * @param output The output.
...@@ -120,7 +121,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { ...@@ -120,7 +121,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
// If we ever need to support a metadata format where this is not the case, we'll need to // If we ever need to support a metadata format where this is not the case, we'll need to
// pass the buffer to the decoder and discard the output. // pass the buffer to the decoder and discard the output.
} else { } else {
buffer.subsampleOffsetUs = formatHolder.format.subsampleOffsetUs; buffer.subsampleOffsetUs = subsampleOffsetUs;
buffer.flip(); buffer.flip();
int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT; int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT;
Metadata metadata = decoder.decode(buffer); Metadata metadata = decoder.decode(buffer);
...@@ -130,6 +131,8 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { ...@@ -130,6 +131,8 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
pendingMetadataCount++; pendingMetadataCount++;
} }
} }
} else if (result == C.RESULT_FORMAT_READ) {
subsampleOffsetUs = formatHolder.format.subsampleOffsetUs;
} }
} }
......
...@@ -15,43 +15,34 @@ ...@@ -15,43 +15,34 @@
*/ */
package com.google.android.exoplayer2.metadata.emsg; package com.google.android.exoplayer2.metadata.emsg;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataDecoder; import com.google.android.exoplayer2.metadata.MetadataDecoder;
import com.google.android.exoplayer2.metadata.MetadataInputBuffer; import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
/** Decodes data encoded by {@link EventMessageEncoder}. */ /** Decodes data encoded by {@link EventMessageEncoder}. */
public final class EventMessageDecoder implements MetadataDecoder { public final class EventMessageDecoder implements MetadataDecoder {
private static final String TAG = "EventMessageDecoder";
@SuppressWarnings("ByteBufferBackingArray") @SuppressWarnings("ByteBufferBackingArray")
@Override @Override
public Metadata decode(MetadataInputBuffer inputBuffer) { public Metadata decode(MetadataInputBuffer inputBuffer) {
ByteBuffer buffer = inputBuffer.data; ByteBuffer buffer = inputBuffer.data;
byte[] data = buffer.array(); byte[] data = buffer.array();
int size = buffer.limit(); int size = buffer.limit();
ParsableByteArray emsgData = new ParsableByteArray(data, size); return new Metadata(decode(new ParsableByteArray(data, size)));
}
public EventMessage decode(ParsableByteArray emsgData) {
String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString()); String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString());
String value = Assertions.checkNotNull(emsgData.readNullTerminatedString()); String value = Assertions.checkNotNull(emsgData.readNullTerminatedString());
long timescale = emsgData.readUnsignedInt(); long durationMs = emsgData.readUnsignedInt();
long presentationTimeDelta = emsgData.readUnsignedInt();
if (presentationTimeDelta != 0) {
// We expect the source to have accounted for presentation_time_delta by adjusting the sample
// timestamp and zeroing the field in the sample data. Log a warning if the field is non-zero.
Log.w(TAG, "Ignoring non-zero presentation_time_delta: " + presentationTimeDelta);
}
long durationMs =
Util.scaleLargeTimestamp(emsgData.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale);
long id = emsgData.readUnsignedInt(); long id = emsgData.readUnsignedInt();
byte[] messageData = Arrays.copyOfRange(data, emsgData.getPosition(), size); byte[] messageData =
return new Metadata(new EventMessage(schemeIdUri, value, durationMs, id, messageData)); Arrays.copyOfRange(emsgData.data, emsgData.getPosition(), emsgData.limit());
return new EventMessage(schemeIdUri, value, durationMs, id, messageData);
} }
} }
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
*/ */
package com.google.android.exoplayer2.metadata.emsg; package com.google.android.exoplayer2.metadata.emsg;
import androidx.annotation.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
...@@ -40,15 +39,12 @@ public final class EventMessageEncoder { ...@@ -40,15 +39,12 @@ public final class EventMessageEncoder {
* @param eventMessage The event message to be encoded. * @param eventMessage The event message to be encoded.
* @return The serialized byte array. * @return The serialized byte array.
*/ */
@Nullable
public byte[] encode(EventMessage eventMessage) { public byte[] encode(EventMessage eventMessage) {
byteArrayOutputStream.reset(); byteArrayOutputStream.reset();
try { try {
writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri); writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri);
String nonNullValue = eventMessage.value != null ? eventMessage.value : ""; String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
writeNullTerminatedString(dataOutputStream, nonNullValue); writeNullTerminatedString(dataOutputStream, nonNullValue);
writeUnsignedInt(dataOutputStream, 1000); // timescale
writeUnsignedInt(dataOutputStream, 0); // presentation_time_delta
writeUnsignedInt(dataOutputStream, eventMessage.durationMs); writeUnsignedInt(dataOutputStream, eventMessage.durationMs);
writeUnsignedInt(dataOutputStream, eventMessage.id); writeUnsignedInt(dataOutputStream, eventMessage.id);
dataOutputStream.write(eventMessage.messageData); dataOutputStream.write(eventMessage.messageData);
......
...@@ -113,15 +113,17 @@ public interface MediaPeriod extends SequenceableLoader { ...@@ -113,15 +113,17 @@ public interface MediaPeriod extends SequenceableLoader {
* corresponding flag in {@code streamResetFlags} will be set to true. This flag will also be set * corresponding flag in {@code streamResetFlags} will be set to true. This flag will also be set
* if a new sample stream is created. * if a new sample stream is created.
* *
* <p>Note that previously received {@link TrackSelection TrackSelections} are no longer valid and * <p>Note that previously passed {@link TrackSelection TrackSelections} are no longer valid, and
* references need to be replaced even if the corresponding {@link SampleStream} is kept. * any references to them must be updated to point to the new selections.
* *
* <p>This method is only called after the period has been prepared. * <p>This method is only called after the period has been prepared.
* *
* @param selections The renderer track selections. * @param selections The renderer track selections.
* @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained * @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained
* for each selection. A {@code true} value indicates that the selection is unchanged, and * for each track selection. A {@code true} value indicates that the selection is equivalent
* that the caller does not require that the sample stream be recreated. * to the one that was previously passed, and that the caller does not require that the sample
* stream be recreated. If a retained sample stream holds any references to the track
* selection then they must be updated to point to the new selection.
* @param streams The existing sample streams, which will be updated to reflect the provided * @param streams The existing sample streams, which will be updated to reflect the provided
* selections. * selections.
* @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that * @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that
......
...@@ -55,9 +55,10 @@ public class TrackSelectionParameters implements Parcelable { ...@@ -55,9 +55,10 @@ public class TrackSelectionParameters implements Parcelable {
} }
/** /**
* See {@link TrackSelectionParameters#preferredAudioLanguage}. * Sets the preferred language for audio and forced text tracks.
* *
* @param preferredAudioLanguage Preferred audio language as an IETF BCP 47 conformant tag. * @param preferredAudioLanguage Preferred audio language as an IETF BCP 47 conformant tag, or
* {@code null} to select the default track, or the first track if there's no default.
* @return This builder. * @return This builder.
*/ */
public Builder setPreferredAudioLanguage(@Nullable String preferredAudioLanguage) { public Builder setPreferredAudioLanguage(@Nullable String preferredAudioLanguage) {
...@@ -66,9 +67,10 @@ public class TrackSelectionParameters implements Parcelable { ...@@ -66,9 +67,10 @@ public class TrackSelectionParameters implements Parcelable {
} }
/** /**
* See {@link TrackSelectionParameters#preferredTextLanguage}. * Sets the preferred language for text tracks.
* *
* @param preferredTextLanguage Preferred text language as an IETF BCP 47 conformant tag. * @param preferredTextLanguage Preferred text language as an IETF BCP 47 conformant tag, or
* {@code null} to select the default track if there is one, or no track otherwise.
* @return This builder. * @return This builder.
*/ */
public Builder setPreferredTextLanguage(@Nullable String preferredTextLanguage) { public Builder setPreferredTextLanguage(@Nullable String preferredTextLanguage) {
...@@ -88,8 +90,12 @@ public class TrackSelectionParameters implements Parcelable { ...@@ -88,8 +90,12 @@ public class TrackSelectionParameters implements Parcelable {
} }
/** /**
* See {@link TrackSelectionParameters#selectUndeterminedTextLanguage}. * Sets whether a text track with undetermined language should be selected if no track with
* {@link #setPreferredTextLanguage(String)} is available, or if the preferred language is
* unset.
* *
* @param selectUndeterminedTextLanguage Whether a text track with undetermined language should
* be selected if no preferred language track is available.
* @return This builder. * @return This builder.
*/ */
public Builder setSelectUndeterminedTextLanguage(boolean selectUndeterminedTextLanguage) { public Builder setSelectUndeterminedTextLanguage(boolean selectUndeterminedTextLanguage) {
...@@ -98,8 +104,10 @@ public class TrackSelectionParameters implements Parcelable { ...@@ -98,8 +104,10 @@ public class TrackSelectionParameters implements Parcelable {
} }
/** /**
* See {@link TrackSelectionParameters#disabledTextTrackSelectionFlags}. * Sets a bitmask of selection flags that are disabled for text track selections.
* *
* @param disabledTextTrackSelectionFlags A bitmask of {@link C.SelectionFlags} that are
* disabled for text track selections.
* @return This builder. * @return This builder.
*/ */
public Builder setDisabledTextTrackSelectionFlags( public Builder setDisabledTextTrackSelectionFlags(
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.metadata.emsg; package com.google.android.exoplayer2.metadata.emsg;
import static com.google.android.exoplayer2.testutil.TestUtil.createByteArray;
import static com.google.android.exoplayer2.testutil.TestUtil.joinByteArrays;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
...@@ -30,18 +32,19 @@ public final class EventMessageDecoderTest { ...@@ -30,18 +32,19 @@ public final class EventMessageDecoderTest {
@Test @Test
public void testDecodeEventMessage() { public void testDecodeEventMessage() {
byte[] rawEmsgBody = new byte[] { byte[] rawEmsgBody =
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test" joinByteArrays(
49, 50, 51, 0, // value = "123" createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test"
0, 0, -69, -128, // timescale = 48000 createByteArray(49, 50, 51, 0), // value = "123"
0, 0, -69, -128, // presentation_time_delta = 48000 createByteArray(0, 0, 11, 184), // event_duration_ms = 3000
0, 2, 50, -128, // event_duration = 144000 createByteArray(0, 15, 67, 211), // id = 1000403
0, 15, 67, -45, // id = 1000403 createByteArray(0, 1, 2, 3, 4)); // message_data = {0, 1, 2, 3, 4}
0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4}
EventMessageDecoder decoder = new EventMessageDecoder(); EventMessageDecoder decoder = new EventMessageDecoder();
MetadataInputBuffer buffer = new MetadataInputBuffer(); MetadataInputBuffer buffer = new MetadataInputBuffer();
buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody); buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody);
Metadata metadata = decoder.decode(buffer); Metadata metadata = decoder.decode(buffer);
assertThat(metadata.length()).isEqualTo(1); assertThat(metadata.length()).isEqualTo(1);
EventMessage eventMessage = (EventMessage) metadata.get(0); EventMessage eventMessage = (EventMessage) metadata.get(0);
assertThat(eventMessage.schemeIdUri).isEqualTo("urn:test"); assertThat(eventMessage.schemeIdUri).isEqualTo("urn:test");
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.metadata.emsg; package com.google.android.exoplayer2.metadata.emsg;
import static com.google.android.exoplayer2.testutil.TestUtil.createByteArray;
import static com.google.android.exoplayer2.testutil.TestUtil.joinByteArrays;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
...@@ -29,67 +31,52 @@ import org.junit.runner.RunWith; ...@@ -29,67 +31,52 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class EventMessageEncoderTest { public final class EventMessageEncoderTest {
private static final EventMessage DECODED_MESSAGE =
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
private static final byte[] ENCODED_MESSAGE =
joinByteArrays(
createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test"
createByteArray(49, 50, 51, 0), // value = "123"
createByteArray(0, 0, 11, 184), // event_duration_ms = 3000
createByteArray(0, 15, 67, 211), // id = 1000403
createByteArray(0, 1, 2, 3, 4)); // message_data = {0, 1, 2, 3, 4}
@Test @Test
public void testEncodeEventStream() throws IOException { public void testEncodeEventStream() throws IOException {
EventMessage eventMessage = byte[] foo = new byte[] {1, 2, 3};
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
byte[] expectedEmsgBody = byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE);
new byte[] { assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE);
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
49, 50, 51, 0, // value = "123"
0, 0, 3, -24, // timescale = 1000
0, 0, 0, 0, // presentation_time_delta = 0
0, 0, 11, -72, // event_duration = 3000
0, 15, 67, -45, // id = 1000403
0, 1, 2, 3, 4
}; // message_data = {0, 1, 2, 3, 4}
byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage);
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
} }
@Test @Test
public void testEncodeDecodeEventStream() throws IOException { public void testEncodeDecodeEventStream() throws IOException {
EventMessage expectedEmsg = byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE);
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg);
MetadataInputBuffer buffer = new MetadataInputBuffer(); MetadataInputBuffer buffer = new MetadataInputBuffer();
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray); buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
EventMessageDecoder decoder = new EventMessageDecoder(); EventMessageDecoder decoder = new EventMessageDecoder();
Metadata metadata = decoder.decode(buffer); Metadata metadata = decoder.decode(buffer);
assertThat(metadata.length()).isEqualTo(1); assertThat(metadata.length()).isEqualTo(1);
assertThat(metadata.get(0)).isEqualTo(expectedEmsg); assertThat(metadata.get(0)).isEqualTo(DECODED_MESSAGE);
} }
@Test @Test
public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException { public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException {
EventMessage eventMessage =
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
byte[] expectedEmsgBody =
new byte[] {
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
49, 50, 51, 0, // value = "123"
0, 0, 3, -24, // timescale = 1000
0, 0, 0, 0, // presentation_time_delta = 0
0, 0, 11, -72, // event_duration = 3000
0, 15, 67, -45, // id = 1000403
0, 1, 2, 3, 4
}; // message_data = {0, 1, 2, 3, 4}
EventMessage eventMessage1 = EventMessage eventMessage1 =
new EventMessage("urn:test", "123", 3000, 1000402, new byte[] {4, 3, 2, 1, 0}); new EventMessage("urn:test", "123", 3000, 1000402, new byte[] {4, 3, 2, 1, 0});
byte[] expectedEmsgBody1 = byte[] expectedEmsgBody1 =
new byte[] { joinByteArrays(
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test" createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test"
49, 50, 51, 0, // value = "123" createByteArray(49, 50, 51, 0), // value = "123"
0, 0, 3, -24, // timescale = 1000 createByteArray(0, 0, 11, 184), // event_duration_ms = 3000
0, 0, 0, 0, // presentation_time_delta = 0 createByteArray(0, 15, 67, 210), // id = 1000402
0, 0, 11, -72, // event_duration = 3000 createByteArray(4, 3, 2, 1, 0)); // message_data = {4, 3, 2, 1, 0}
0, 15, 67, -46, // id = 1000402
4, 3, 2, 1, 0
}; // message_data = {4, 3, 2, 1, 0}
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder(); EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage); byte[] encodedByteArray = eventMessageEncoder.encode(DECODED_MESSAGE);
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody); assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE);
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1); byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1);
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1); assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
} }
......
...@@ -148,6 +148,7 @@ public final class DefaultTrackSelectorTest { ...@@ -148,6 +148,7 @@ public final class DefaultTrackSelectorTest {
/* exceedAudioConstraintsIfNecessary= */ false, /* exceedAudioConstraintsIfNecessary= */ false,
/* allowAudioMixedMimeTypeAdaptiveness= */ true, /* allowAudioMixedMimeTypeAdaptiveness= */ true,
/* allowAudioMixedSampleRateAdaptiveness= */ false, /* allowAudioMixedSampleRateAdaptiveness= */ false,
/* allowAudioMixedChannelCountAdaptiveness= */ true,
// Text // Text
/* preferredTextLanguage= */ "de", /* preferredTextLanguage= */ "de",
/* selectUndeterminedTextLanguage= */ true, /* selectUndeterminedTextLanguage= */ true,
......
...@@ -41,8 +41,10 @@ android { ...@@ -41,8 +41,10 @@ android {
dependencies { dependencies {
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -60,6 +60,7 @@ import java.util.IdentityHashMap; ...@@ -60,6 +60,7 @@ import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** A DASH {@link MediaPeriod}. */ /** A DASH {@link MediaPeriod}. */
/* package */ final class DashMediaPeriod /* package */ final class DashMediaPeriod
...@@ -245,8 +246,12 @@ import java.util.regex.Pattern; ...@@ -245,8 +246,12 @@ import java.util.regex.Pattern;
} }
@Override @Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, public long selectTracks(
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { @NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections); int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections);
releaseDisabledStreams(selections, mayRetainStreamFlags, streams); releaseDisabledStreams(selections, mayRetainStreamFlags, streams);
releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex); releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex);
......
...@@ -130,7 +130,7 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -130,7 +130,7 @@ public final class DashMediaSource extends BaseMediaSource {
* @return This factory, for convenience. * @return This factory, for convenience.
* @throws IllegalStateException If one of the {@code create} methods has already been called. * @throws IllegalStateException If one of the {@code create} methods has already been called.
*/ */
public Factory setTag(Object tag) { public Factory setTag(@Nullable Object tag) {
Assertions.checkState(!isCreateCalled); Assertions.checkState(!isCreateCalled);
this.tag = tag; this.tag = tag;
return this; return this;
...@@ -430,8 +430,8 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -430,8 +430,8 @@ public final class DashMediaSource extends BaseMediaSource {
public DashMediaSource( public DashMediaSource(
DashManifest manifest, DashManifest manifest,
DashChunkSource.Factory chunkSourceFactory, DashChunkSource.Factory chunkSourceFactory,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
manifest, manifest,
chunkSourceFactory, chunkSourceFactory,
...@@ -455,8 +455,8 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -455,8 +455,8 @@ public final class DashMediaSource extends BaseMediaSource {
DashManifest manifest, DashManifest manifest,
DashChunkSource.Factory chunkSourceFactory, DashChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, int minLoadableRetryCount,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
manifest, manifest,
/* manifestUri= */ null, /* manifestUri= */ null,
...@@ -492,8 +492,8 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -492,8 +492,8 @@ public final class DashMediaSource extends BaseMediaSource {
Uri manifestUri, Uri manifestUri,
DataSource.Factory manifestDataSourceFactory, DataSource.Factory manifestDataSourceFactory,
DashChunkSource.Factory chunkSourceFactory, DashChunkSource.Factory chunkSourceFactory,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
manifestUri, manifestUri,
manifestDataSourceFactory, manifestDataSourceFactory,
...@@ -529,8 +529,8 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -529,8 +529,8 @@ public final class DashMediaSource extends BaseMediaSource {
DashChunkSource.Factory chunkSourceFactory, DashChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, int minLoadableRetryCount,
long livePresentationDelayMs, long livePresentationDelayMs,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
manifestUri, manifestUri,
manifestDataSourceFactory, manifestDataSourceFactory,
...@@ -569,8 +569,8 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -569,8 +569,8 @@ public final class DashMediaSource extends BaseMediaSource {
DashChunkSource.Factory chunkSourceFactory, DashChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, int minLoadableRetryCount,
long livePresentationDelayMs, long livePresentationDelayMs,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
/* manifest= */ null, /* manifest= */ null,
manifestUri, manifestUri,
...@@ -591,10 +591,10 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -591,10 +591,10 @@ public final class DashMediaSource extends BaseMediaSource {
} }
private DashMediaSource( private DashMediaSource(
DashManifest manifest, @Nullable DashManifest manifest,
Uri manifestUri, @Nullable Uri manifestUri,
DataSource.Factory manifestDataSourceFactory, @Nullable DataSource.Factory manifestDataSourceFactory,
ParsingLoadable.Parser<? extends DashManifest> manifestParser, @Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser,
DashChunkSource.Factory chunkSourceFactory, DashChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
DrmSessionManager<?> drmSessionManager, DrmSessionManager<?> drmSessionManager,
......
...@@ -66,7 +66,8 @@ public final class DashUtil { ...@@ -66,7 +66,8 @@ 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 @Nullable DrmInitData loadDrmInitData(DataSource dataSource, Period period) @Nullable
public static 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);
...@@ -95,7 +96,8 @@ public final class DashUtil { ...@@ -95,7 +96,8 @@ 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 @Nullable Format loadSampleFormat( @Nullable
public static Format loadSampleFormat(
DataSource dataSource, int trackType, Representation representation) DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException { throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
...@@ -116,7 +118,8 @@ public final class DashUtil { ...@@ -116,7 +118,8 @@ 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 @Nullable ChunkIndex loadChunkIndex( @Nullable
public static ChunkIndex loadChunkIndex(
DataSource dataSource, int trackType, Representation representation) DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException { throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
...@@ -138,7 +141,8 @@ public final class DashUtil { ...@@ -138,7 +141,8 @@ 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 @Nullable ChunkExtractorWrapper loadInitializationData( @Nullable
private static ChunkExtractorWrapper loadInitializationData(
DataSource dataSource, int trackType, Representation representation, boolean loadIndex) DataSource dataSource, int trackType, Representation representation, boolean loadIndex)
throws IOException, InterruptedException { throws IOException, InterruptedException {
RangedUri initializationUri = representation.getInitializationUri(); RangedUri initializationUri = representation.getInitializationUri();
...@@ -187,7 +191,8 @@ public final class DashUtil { ...@@ -187,7 +191,8 @@ public final class DashUtil {
return new ChunkExtractorWrapper(extractor, trackType, format); return new ChunkExtractorWrapper(extractor, trackType, format);
} }
private static @Nullable Representation getFirstRepresentation(Period period, int type) { @Nullable
private static 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;
...@@ -197,5 +202,4 @@ public final class DashUtil { ...@@ -197,5 +202,4 @@ public final class DashUtil {
} }
private DashUtil() {} private DashUtil() {}
} }
...@@ -67,7 +67,7 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -67,7 +67,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
private final int maxSegmentsPerLoad; private final int maxSegmentsPerLoad;
public Factory(DataSource.Factory dataSourceFactory) { public Factory(DataSource.Factory dataSourceFactory) {
this(dataSourceFactory, 1); this(dataSourceFactory, /* maxSegmentsPerLoad= */ 1);
} }
public Factory(DataSource.Factory dataSourceFactory, int maxSegmentsPerLoad) { public Factory(DataSource.Factory dataSourceFactory, int maxSegmentsPerLoad) {
...@@ -633,7 +633,7 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -633,7 +633,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
Representation representation, Representation representation,
boolean enableEventMessageTrack, boolean enableEventMessageTrack,
List<Format> closedCaptionFormats, List<Format> closedCaptionFormats,
TrackOutput playerEmsgTrackOutput) { @Nullable TrackOutput playerEmsgTrackOutput) {
this( this(
periodDurationUs, periodDurationUs,
representation, representation,
...@@ -787,7 +787,7 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -787,7 +787,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
Representation representation, Representation representation,
boolean enableEventMessageTrack, boolean enableEventMessageTrack,
List<Format> closedCaptionFormats, List<Format> closedCaptionFormats,
TrackOutput playerEmsgTrackOutput) { @Nullable TrackOutput playerEmsgTrackOutput) {
String containerMimeType = representation.format.containerMimeType; String containerMimeType = representation.format.containerMimeType;
if (mimeTypeIsRawText(containerMimeType)) { if (mimeTypeIsRawText(containerMimeType)) {
return null; return null;
......
...@@ -80,12 +80,10 @@ public class DashManifest implements FilterableManifest<DashManifest> { ...@@ -80,12 +80,10 @@ public class DashManifest implements FilterableManifest<DashManifest> {
* The {@link UtcTimingElement}, or null if not present. Defined in DVB A168:7/2016, Section * The {@link UtcTimingElement}, or null if not present. Defined in DVB A168:7/2016, Section
* 4.7.2. * 4.7.2.
*/ */
public final UtcTimingElement utcTiming; @Nullable public final UtcTimingElement utcTiming;
/** /** The location of this manifest, or null if not present. */
* The location of this manifest. @Nullable public final Uri location;
*/
public final Uri location;
/** The {@link ProgramInformation}, or null if not present. */ /** The {@link ProgramInformation}, or null if not present. */
@Nullable public final ProgramInformation programInformation; @Nullable public final ProgramInformation programInformation;
...@@ -106,8 +104,8 @@ public class DashManifest implements FilterableManifest<DashManifest> { ...@@ -106,8 +104,8 @@ public class DashManifest implements FilterableManifest<DashManifest> {
long timeShiftBufferDepthMs, long timeShiftBufferDepthMs,
long suggestedPresentationDelayMs, long suggestedPresentationDelayMs,
long publishTimeMs, long publishTimeMs,
UtcTimingElement utcTiming, @Nullable UtcTimingElement utcTiming,
Uri location, @Nullable Uri location,
List<Period> periods) { List<Period> periods) {
this( this(
availabilityStartTimeMs, availabilityStartTimeMs,
...@@ -134,8 +132,8 @@ public class DashManifest implements FilterableManifest<DashManifest> { ...@@ -134,8 +132,8 @@ public class DashManifest implements FilterableManifest<DashManifest> {
long suggestedPresentationDelayMs, long suggestedPresentationDelayMs,
long publishTimeMs, long publishTimeMs,
@Nullable ProgramInformation programInformation, @Nullable ProgramInformation programInformation,
UtcTimingElement utcTiming, @Nullable UtcTimingElement utcTiming,
Uri location, @Nullable Uri location,
List<Period> periods) { List<Period> periods) {
this.availabilityStartTimeMs = availabilityStartTimeMs; this.availabilityStartTimeMs = availabilityStartTimeMs;
this.durationMs = durationMs; this.durationMs = durationMs;
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
*/ */
package com.google.android.exoplayer2.source.dash.manifest; package com.google.android.exoplayer2.source.dash.manifest;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -24,10 +23,8 @@ import com.google.android.exoplayer2.util.Util; ...@@ -24,10 +23,8 @@ import com.google.android.exoplayer2.util.Util;
*/ */
public final class Descriptor { public final class Descriptor {
/** /** The scheme URI. */
* The scheme URI. public final String schemeIdUri;
*/
@NonNull public final String schemeIdUri;
/** /**
* The value, or null. * The value, or null.
*/ */
...@@ -42,7 +39,7 @@ public final class Descriptor { ...@@ -42,7 +39,7 @@ public final class Descriptor {
* @param value The value, or null. * @param value The value, or null.
* @param id The identifier, or null. * @param id The identifier, or null.
*/ */
public Descriptor(@NonNull String schemeIdUri, @Nullable String value, @Nullable String id) { public Descriptor(String schemeIdUri, @Nullable String value, @Nullable String id) {
this.schemeIdUri = schemeIdUri; this.schemeIdUri = schemeIdUri;
this.value = value; this.value = value;
this.id = id; this.id = id;
...@@ -63,10 +60,9 @@ public final class Descriptor { ...@@ -63,10 +60,9 @@ public final class Descriptor {
@Override @Override
public int hashCode() { public int hashCode() {
int result = (schemeIdUri != null ? schemeIdUri.hashCode() : 0); int result = schemeIdUri.hashCode();
result = 31 * result + (value != null ? value.hashCode() : 0); result = 31 * result + (value != null ? value.hashCode() : 0);
result = 31 * result + (id != null ? id.hashCode() : 0); result = 31 * result + (id != null ? id.hashCode() : 0);
return result; return result;
} }
} }
...@@ -21,22 +21,26 @@ import com.google.android.exoplayer2.util.Util; ...@@ -21,22 +21,26 @@ import com.google.android.exoplayer2.util.Util;
/** A parsed program information element. */ /** A parsed program information element. */
public class ProgramInformation { public class ProgramInformation {
/** The title for the media presentation. */ /** The title for the media presentation. */
public final String title; @Nullable public final String title;
/** Information about the original source of the media presentation. */ /** Information about the original source of the media presentation. */
public final String source; @Nullable public final String source;
/** A copyright statement for the media presentation. */ /** A copyright statement for the media presentation. */
public final String copyright; @Nullable public final String copyright;
/** A URL that provides more information about the media presentation. */ /** A URL that provides more information about the media presentation. */
public final String moreInformationURL; @Nullable public final String moreInformationURL;
/** Declares the language code(s) for this ProgramInformation. */ /** Declares the language code(s) for this ProgramInformation. */
public final String lang; @Nullable public final String lang;
public ProgramInformation( public ProgramInformation(
String title, String source, String copyright, String moreInformationURL, String lang) { @Nullable String title,
@Nullable String source,
@Nullable String copyright,
@Nullable String moreInformationURL,
@Nullable String lang) {
this.title = title; this.title = title;
this.source = source; this.source = source;
this.copyright = copyright; this.copyright = copyright;
......
...@@ -83,7 +83,7 @@ public final class RangedUri { ...@@ -83,7 +83,7 @@ public final class RangedUri {
* <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 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.
*/ */
@Nullable @Nullable
......
...@@ -16,6 +16,7 @@ ...@@ -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 androidx.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.source.dash.DashSegmentIndex; import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
...@@ -53,9 +54,7 @@ public abstract class Representation { ...@@ -53,9 +54,7 @@ public abstract class Representation {
* The offset of the presentation timestamps in the media stream relative to media time. * The offset of the presentation timestamps in the media stream relative to media time.
*/ */
public final long presentationTimeOffsetUs; public final long presentationTimeOffsetUs;
/** /** The in-band event streams in the representation. May be empty. */
* The in-band event streams in the representation. Never null, but may be empty.
*/
public final List<Descriptor> inbandEventStreams; public final List<Descriptor> inbandEventStreams;
private final RangedUri initializationUri; private final RangedUri initializationUri;
...@@ -71,7 +70,7 @@ public abstract class Representation { ...@@ -71,7 +70,7 @@ public abstract class Representation {
*/ */
public static Representation newInstance( public static Representation newInstance(
long revisionId, Format format, String baseUrl, SegmentBase segmentBase) { long revisionId, Format format, String baseUrl, SegmentBase segmentBase) {
return newInstance(revisionId, format, baseUrl, segmentBase, null); return newInstance(revisionId, format, baseUrl, segmentBase, /* inbandEventStreams= */ null);
} }
/** /**
...@@ -89,8 +88,9 @@ public abstract class Representation { ...@@ -89,8 +88,9 @@ public abstract class Representation {
Format format, Format format,
String baseUrl, String baseUrl,
SegmentBase segmentBase, SegmentBase segmentBase,
List<Descriptor> inbandEventStreams) { @Nullable List<Descriptor> inbandEventStreams) {
return newInstance(revisionId, format, baseUrl, segmentBase, inbandEventStreams, null); return newInstance(
revisionId, format, baseUrl, segmentBase, inbandEventStreams, /* cacheKey= */ null);
} }
/** /**
...@@ -110,8 +110,8 @@ public abstract class Representation { ...@@ -110,8 +110,8 @@ public abstract class Representation {
Format format, Format format,
String baseUrl, String baseUrl,
SegmentBase segmentBase, SegmentBase segmentBase,
List<Descriptor> inbandEventStreams, @Nullable List<Descriptor> inbandEventStreams,
String cacheKey) { @Nullable String cacheKey) {
if (segmentBase instanceof SingleSegmentBase) { if (segmentBase instanceof SingleSegmentBase) {
return new SingleSegmentRepresentation( return new SingleSegmentRepresentation(
revisionId, revisionId,
...@@ -135,7 +135,7 @@ public abstract class Representation { ...@@ -135,7 +135,7 @@ public abstract class Representation {
Format format, Format format,
String baseUrl, String baseUrl,
SegmentBase segmentBase, SegmentBase segmentBase,
List<Descriptor> inbandEventStreams) { @Nullable List<Descriptor> inbandEventStreams) {
this.revisionId = revisionId; this.revisionId = revisionId;
this.format = format; this.format = format;
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
...@@ -151,6 +151,7 @@ public abstract class Representation { ...@@ -151,6 +151,7 @@ public abstract class Representation {
* Returns a {@link RangedUri} defining the location of the representation's initialization data, * Returns a {@link RangedUri} defining the location of the representation's initialization data,
* or null if no initialization data exists. * or null if no initialization data exists.
*/ */
@Nullable
public RangedUri getInitializationUri() { public RangedUri getInitializationUri() {
return initializationUri; return initializationUri;
} }
...@@ -159,14 +160,15 @@ public abstract class Representation { ...@@ -159,14 +160,15 @@ public abstract class Representation {
* Returns a {@link RangedUri} defining the location of the representation's segment index, or * Returns a {@link RangedUri} defining the location of the representation's segment index, or
* null if the representation provides an index directly. * null if the representation provides an index directly.
*/ */
@Nullable
public abstract RangedUri getIndexUri(); public abstract RangedUri getIndexUri();
/** /** Returns an index if the representation provides one directly, or null otherwise. */
* Returns an index if the representation provides one directly, or null otherwise. @Nullable
*/
public abstract DashSegmentIndex getIndex(); public abstract DashSegmentIndex getIndex();
/** Returns a cache key for the representation if set, or null. */ /** Returns a cache key for the representation if set, or null. */
@Nullable
public abstract String getCacheKey(); public abstract String getCacheKey();
/** /**
...@@ -184,9 +186,9 @@ public abstract class Representation { ...@@ -184,9 +186,9 @@ public abstract class Representation {
*/ */
public final long contentLength; public final long contentLength;
private final String cacheKey; @Nullable private final String cacheKey;
private final RangedUri indexUri; @Nullable private final RangedUri indexUri;
private final SingleSegmentIndex segmentIndex; @Nullable private final SingleSegmentIndex segmentIndex;
/** /**
* @param revisionId Identifies the revision of the content. * @param revisionId Identifies the revision of the content.
...@@ -209,7 +211,7 @@ public abstract class Representation { ...@@ -209,7 +211,7 @@ public abstract class Representation {
long indexStart, long indexStart,
long indexEnd, long indexEnd,
List<Descriptor> inbandEventStreams, List<Descriptor> inbandEventStreams,
String cacheKey, @Nullable String cacheKey,
long contentLength) { long contentLength) {
RangedUri rangedUri = new RangedUri(null, initializationStart, RangedUri rangedUri = new RangedUri(null, initializationStart,
initializationEnd - initializationStart + 1); initializationEnd - initializationStart + 1);
...@@ -233,8 +235,8 @@ public abstract class Representation { ...@@ -233,8 +235,8 @@ public abstract class Representation {
Format format, Format format,
String baseUrl, String baseUrl,
SingleSegmentBase segmentBase, SingleSegmentBase segmentBase,
List<Descriptor> inbandEventStreams, @Nullable List<Descriptor> inbandEventStreams,
String cacheKey, @Nullable String cacheKey,
long contentLength) { long contentLength) {
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams); super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
this.uri = Uri.parse(baseUrl); this.uri = Uri.parse(baseUrl);
...@@ -248,16 +250,19 @@ public abstract class Representation { ...@@ -248,16 +250,19 @@ public abstract class Representation {
} }
@Override @Override
@Nullable
public RangedUri getIndexUri() { public RangedUri getIndexUri() {
return indexUri; return indexUri;
} }
@Override @Override
@Nullable
public DashSegmentIndex getIndex() { public DashSegmentIndex getIndex() {
return segmentIndex; return segmentIndex;
} }
@Override @Override
@Nullable
public String getCacheKey() { public String getCacheKey() {
return cacheKey; return cacheKey;
} }
...@@ -284,12 +289,13 @@ public abstract class Representation { ...@@ -284,12 +289,13 @@ public abstract class Representation {
Format format, Format format,
String baseUrl, String baseUrl,
MultiSegmentBase segmentBase, MultiSegmentBase segmentBase,
List<Descriptor> inbandEventStreams) { @Nullable List<Descriptor> inbandEventStreams) {
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams); super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
this.segmentBase = segmentBase; this.segmentBase = segmentBase;
} }
@Override @Override
@Nullable
public RangedUri getIndexUri() { public RangedUri getIndexUri() {
return null; return null;
} }
...@@ -300,6 +306,7 @@ public abstract class Representation { ...@@ -300,6 +306,7 @@ public abstract class Representation {
} }
@Override @Override
@Nullable
public String getCacheKey() { public String getCacheKey() {
return null; return null;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.dash.manifest; package com.google.android.exoplayer2.source.dash.manifest;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.dash.DashSegmentIndex; import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -25,7 +26,7 @@ import java.util.List; ...@@ -25,7 +26,7 @@ import java.util.List;
*/ */
public abstract class SegmentBase { public abstract class SegmentBase {
/* package */ final RangedUri initialization; /* package */ @Nullable final RangedUri initialization;
/* package */ final long timescale; /* package */ final long timescale;
/* package */ final long presentationTimeOffset; /* package */ final long presentationTimeOffset;
...@@ -36,7 +37,8 @@ public abstract class SegmentBase { ...@@ -36,7 +37,8 @@ public abstract class SegmentBase {
* @param presentationTimeOffset The presentation time offset. The value in seconds is the * @param presentationTimeOffset The presentation time offset. The value in seconds is the
* division of this value and {@code timescale}. * division of this value and {@code timescale}.
*/ */
public SegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset) { public SegmentBase(
@Nullable RangedUri initialization, long timescale, long presentationTimeOffset) {
this.initialization = initialization; this.initialization = initialization;
this.timescale = timescale; this.timescale = timescale;
this.presentationTimeOffset = presentationTimeOffset; this.presentationTimeOffset = presentationTimeOffset;
...@@ -49,6 +51,7 @@ public abstract class SegmentBase { ...@@ -49,6 +51,7 @@ public abstract class SegmentBase {
* @param representation The {@link Representation} for which initialization data is required. * @param representation The {@link Representation} for which initialization data is required.
* @return A {@link RangedUri} defining the location of the initialization data, or null. * @return A {@link RangedUri} defining the location of the initialization data, or null.
*/ */
@Nullable
public RangedUri getInitialization(Representation representation) { public RangedUri getInitialization(Representation representation) {
return initialization; return initialization;
} }
...@@ -77,19 +80,31 @@ public abstract class SegmentBase { ...@@ -77,19 +80,31 @@ public abstract class SegmentBase {
* @param indexStart The byte offset of the index data in the segment. * @param indexStart The byte offset of the index data in the segment.
* @param indexLength The length of the index data in bytes. * @param indexLength The length of the index data in bytes.
*/ */
public SingleSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset, public SingleSegmentBase(
long indexStart, long indexLength) { @Nullable RangedUri initialization,
long timescale,
long presentationTimeOffset,
long indexStart,
long indexLength) {
super(initialization, timescale, presentationTimeOffset); super(initialization, timescale, presentationTimeOffset);
this.indexStart = indexStart; this.indexStart = indexStart;
this.indexLength = indexLength; this.indexLength = indexLength;
} }
public SingleSegmentBase() { public SingleSegmentBase() {
this(null, 1, 0, 0, 0); this(
/* initialization= */ null,
/* timescale= */ 1,
/* presentationTimeOffset= */ 0,
/* indexStart= */ 0,
/* indexLength= */ 0);
} }
@Nullable
public RangedUri getIndex() { public RangedUri getIndex() {
return indexLength <= 0 ? null : new RangedUri(null, indexStart, indexLength); return indexLength <= 0
? null
: new RangedUri(/* referenceUri= */ null, indexStart, indexLength);
} }
} }
...@@ -101,7 +116,7 @@ public abstract class SegmentBase { ...@@ -101,7 +116,7 @@ public abstract class SegmentBase {
/* package */ final long startNumber; /* package */ final long startNumber;
/* package */ final long duration; /* package */ final long duration;
/* package */ final List<SegmentTimelineElement> segmentTimeline; /* package */ @Nullable final List<SegmentTimelineElement> segmentTimeline;
/** /**
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data * @param initialization A {@link RangedUri} corresponding to initialization data, if such data
...@@ -118,12 +133,12 @@ public abstract class SegmentBase { ...@@ -118,12 +133,12 @@ public abstract class SegmentBase {
* parameter. * parameter.
*/ */
public MultiSegmentBase( public MultiSegmentBase(
RangedUri initialization, @Nullable RangedUri initialization,
long timescale, long timescale,
long presentationTimeOffset, long presentationTimeOffset,
long startNumber, long startNumber,
long duration, long duration,
List<SegmentTimelineElement> segmentTimeline) { @Nullable List<SegmentTimelineElement> segmentTimeline) {
super(initialization, timescale, presentationTimeOffset); super(initialization, timescale, presentationTimeOffset);
this.startNumber = startNumber; this.startNumber = startNumber;
this.duration = duration; this.duration = duration;
...@@ -223,7 +238,7 @@ public abstract class SegmentBase { ...@@ -223,7 +238,7 @@ public abstract class SegmentBase {
*/ */
public static class SegmentList extends MultiSegmentBase { public static class SegmentList extends MultiSegmentBase {
/* package */ final List<RangedUri> mediaSegments; /* package */ @Nullable final List<RangedUri> mediaSegments;
/** /**
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data * @param initialization A {@link RangedUri} corresponding to initialization data, if such data
...@@ -246,8 +261,8 @@ public abstract class SegmentBase { ...@@ -246,8 +261,8 @@ public abstract class SegmentBase {
long presentationTimeOffset, long presentationTimeOffset,
long startNumber, long startNumber,
long duration, long duration,
List<SegmentTimelineElement> segmentTimeline, @Nullable List<SegmentTimelineElement> segmentTimeline,
List<RangedUri> mediaSegments) { @Nullable List<RangedUri> mediaSegments) {
super(initialization, timescale, presentationTimeOffset, startNumber, duration, super(initialization, timescale, presentationTimeOffset, startNumber, duration,
segmentTimeline); segmentTimeline);
this.mediaSegments = mediaSegments; this.mediaSegments = mediaSegments;
...@@ -275,8 +290,8 @@ public abstract class SegmentBase { ...@@ -275,8 +290,8 @@ public abstract class SegmentBase {
*/ */
public static class SegmentTemplate extends MultiSegmentBase { public static class SegmentTemplate extends MultiSegmentBase {
/* package */ final UrlTemplate initializationTemplate; /* package */ @Nullable final UrlTemplate initializationTemplate;
/* package */ final UrlTemplate mediaTemplate; /* package */ @Nullable final UrlTemplate mediaTemplate;
/* package */ final long endNumber; /* package */ final long endNumber;
/** /**
...@@ -308,9 +323,9 @@ public abstract class SegmentBase { ...@@ -308,9 +323,9 @@ public abstract class SegmentBase {
long startNumber, long startNumber,
long endNumber, long endNumber,
long duration, long duration,
List<SegmentTimelineElement> segmentTimeline, @Nullable List<SegmentTimelineElement> segmentTimeline,
UrlTemplate initializationTemplate, @Nullable UrlTemplate initializationTemplate,
UrlTemplate mediaTemplate) { @Nullable UrlTemplate mediaTemplate) {
super( super(
initialization, initialization,
timescale, timescale,
...@@ -324,6 +339,7 @@ public abstract class SegmentBase { ...@@ -324,6 +339,7 @@ public abstract class SegmentBase {
} }
@Override @Override
@Nullable
public RangedUri getInitialization(Representation representation) { public RangedUri getInitialization(Representation representation) {
if (initializationTemplate != null) { if (initializationTemplate != null) {
String urlString = initializationTemplate.buildUri(representation.format.id, 0, String urlString = initializationTemplate.buildUri(representation.format.id, 0,
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.dash.manifest;
import com.google.android.exoplayer2.util.NonNullApi;
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.dash.offline;
import com.google.android.exoplayer2.util.NonNullApi;
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.dash;
import com.google.android.exoplayer2.util.NonNullApi;
...@@ -41,8 +41,10 @@ android { ...@@ -41,8 +41,10 @@ android {
dependencies { dependencies {
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -105,7 +105,8 @@ import javax.crypto.spec.SecretKeySpec; ...@@ -105,7 +105,8 @@ import javax.crypto.spec.SecretKeySpec;
} }
@Override @Override
public final @Nullable Uri getUri() { @Nullable
public final Uri getUri() {
return upstream.getUri(); return upstream.getUri();
} }
......
...@@ -84,11 +84,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { ...@@ -84,11 +84,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
@Override @Override
public Result createExtractor( public Result createExtractor(
Extractor previousExtractor, @Nullable Extractor previousExtractor,
Uri uri, Uri uri,
Format format, Format format,
List<Format> muxedCaptionFormats, @Nullable List<Format> muxedCaptionFormats,
DrmInitData drmInitData, @Nullable DrmInitData drmInitData,
TimestampAdjuster timestampAdjuster, TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders, Map<String, List<String>> responseHeaders,
ExtractorInput extractorInput) ExtractorInput extractorInput)
......
...@@ -59,10 +59,8 @@ import java.util.Map; ...@@ -59,10 +59,8 @@ import java.util.Map;
clear(); clear();
} }
/** /** The chunk to be loaded next. */
* The chunk to be loaded next. @Nullable public Chunk chunk;
*/
public Chunk chunk;
/** /**
* Indicates that the end of the stream has been reached. * Indicates that the end of the stream has been reached.
...@@ -70,7 +68,7 @@ import java.util.Map; ...@@ -70,7 +68,7 @@ import java.util.Map;
public boolean endOfStream; public boolean endOfStream;
/** Indicates that the chunk source is waiting for the referred playlist to be refreshed. */ /** Indicates that the chunk source is waiting for the referred playlist to be refreshed. */
public Uri playlistUrl; @Nullable public Uri playlistUrl;
/** /**
* Clears the holder. * Clears the holder.
...@@ -138,7 +136,7 @@ import java.util.Map; ...@@ -138,7 +136,7 @@ import java.util.Map;
HlsDataSourceFactory dataSourceFactory, HlsDataSourceFactory dataSourceFactory,
@Nullable TransferListener mediaTransferListener, @Nullable TransferListener mediaTransferListener,
TimestampAdjusterProvider timestampAdjusterProvider, TimestampAdjusterProvider timestampAdjusterProvider,
List<Format> muxedCaptionFormats) { @Nullable List<Format> muxedCaptionFormats) {
this.extractorFactory = extractorFactory; this.extractorFactory = extractorFactory;
this.playlistTracker = playlistTracker; this.playlistTracker = playlistTracker;
this.playlistUrls = playlistUrls; this.playlistUrls = playlistUrls;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.hls; package com.google.android.exoplayer2.source.hls;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable;
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;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
...@@ -82,11 +83,11 @@ public interface HlsExtractorFactory { ...@@ -82,11 +83,11 @@ public interface HlsExtractorFactory {
* @throws IOException If an I/O error is encountered while sniffing. * @throws IOException If an I/O error is encountered while sniffing.
*/ */
Result createExtractor( Result createExtractor(
Extractor previousExtractor, @Nullable Extractor previousExtractor,
Uri uri, Uri uri,
Format format, Format format,
List<Format> muxedCaptionFormats, @Nullable List<Format> muxedCaptionFormats,
DrmInitData drmInitData, @Nullable DrmInitData drmInitData,
TimestampAdjuster timestampAdjuster, TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders, Map<String, List<String>> responseHeaders,
ExtractorInput sniffingExtractorInput) ExtractorInput sniffingExtractorInput)
......
...@@ -54,6 +54,7 @@ import java.util.HashSet; ...@@ -54,6 +54,7 @@ import java.util.HashSet;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** /**
* A {@link MediaPeriod} that loads an HLS stream. * A {@link MediaPeriod} that loads an HLS stream.
...@@ -249,8 +250,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper ...@@ -249,8 +250,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
} }
@Override @Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, public long selectTracks(
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { @NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
// Map each selection and stream onto a child period index. // Map each selection and stream onto a child period index.
int[] streamChildIndices = new int[selections.length]; int[] streamChildIndices = new int[selections.length];
int[] selectionChildIndices = new int[selections.length]; int[] selectionChildIndices = new int[selections.length];
......
...@@ -110,7 +110,7 @@ public final class HlsMediaSource extends BaseMediaSource ...@@ -110,7 +110,7 @@ public final class HlsMediaSource extends BaseMediaSource
* @return This factory, for convenience. * @return This factory, for convenience.
* @throws IllegalStateException If one of the {@code create} methods has already been called. * @throws IllegalStateException If one of the {@code create} methods has already been called.
*/ */
public Factory setTag(Object tag) { public Factory setTag(@Nullable Object tag) {
Assertions.checkState(!isCreateCalled); Assertions.checkState(!isCreateCalled);
this.tag = tag; this.tag = tag;
return this; return this;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.hls; package com.google.android.exoplayer2.source.hls;
import androidx.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
...@@ -49,7 +50,7 @@ public final class WebvttExtractor implements Extractor { ...@@ -49,7 +50,7 @@ public final class WebvttExtractor implements Extractor {
private static final int HEADER_MIN_LENGTH = 6 /* "WEBVTT" */; private static final int HEADER_MIN_LENGTH = 6 /* "WEBVTT" */;
private static final int HEADER_MAX_LENGTH = 3 /* optional Byte Order Mark */ + HEADER_MIN_LENGTH; private static final int HEADER_MAX_LENGTH = 3 /* optional Byte Order Mark */ + HEADER_MIN_LENGTH;
private final String language; @Nullable private final String language;
private final TimestampAdjuster timestampAdjuster; private final TimestampAdjuster timestampAdjuster;
private final ParsableByteArray sampleDataWrapper; private final ParsableByteArray sampleDataWrapper;
...@@ -58,7 +59,7 @@ public final class WebvttExtractor implements Extractor { ...@@ -58,7 +59,7 @@ public final class WebvttExtractor implements Extractor {
private byte[] sampleData; private byte[] sampleData;
private int sampleSize; private int sampleSize;
public WebvttExtractor(String language, TimestampAdjuster timestampAdjuster) { public WebvttExtractor(@Nullable String language, TimestampAdjuster timestampAdjuster) {
this.language = language; this.language = language;
this.timestampAdjuster = timestampAdjuster; this.timestampAdjuster = timestampAdjuster;
this.sampleDataWrapper = new ParsableByteArray(); this.sampleDataWrapper = new ParsableByteArray();
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.hls.offline;
import com.google.android.exoplayer2.util.NonNullApi;
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.hls;
import com.google.android.exoplayer2.util.NonNullApi;
...@@ -172,6 +172,7 @@ public final class DefaultHlsPlaylistTracker ...@@ -172,6 +172,7 @@ public final class DefaultHlsPlaylistTracker
} }
@Override @Override
@Nullable
public HlsMediaPlaylist getPlaylistSnapshot(Uri url, boolean isForPlayback) { public HlsMediaPlaylist getPlaylistSnapshot(Uri url, boolean isForPlayback) {
HlsMediaPlaylist snapshot = playlistBundles.get(url).getPlaylistSnapshot(); HlsMediaPlaylist snapshot = playlistBundles.get(url).getPlaylistSnapshot();
if (snapshot != null && isForPlayback) { if (snapshot != null && isForPlayback) {
...@@ -448,7 +449,7 @@ public final class DefaultHlsPlaylistTracker ...@@ -448,7 +449,7 @@ public final class DefaultHlsPlaylistTracker
private final Loader mediaPlaylistLoader; private final Loader mediaPlaylistLoader;
private final ParsingLoadable<HlsPlaylist> mediaPlaylistLoadable; private final ParsingLoadable<HlsPlaylist> mediaPlaylistLoadable;
private HlsMediaPlaylist playlistSnapshot; @Nullable private HlsMediaPlaylist playlistSnapshot;
private long lastSnapshotLoadMs; private long lastSnapshotLoadMs;
private long lastSnapshotChangeMs; private long lastSnapshotChangeMs;
private long earliestNextLoadTimeMs; private long earliestNextLoadTimeMs;
...@@ -467,6 +468,7 @@ public final class DefaultHlsPlaylistTracker ...@@ -467,6 +468,7 @@ public final class DefaultHlsPlaylistTracker
mediaPlaylistParser); mediaPlaylistParser);
} }
@Nullable
public HlsMediaPlaylist getPlaylistSnapshot() { public HlsMediaPlaylist getPlaylistSnapshot() {
return playlistSnapshot; return playlistSnapshot;
} }
......
...@@ -174,7 +174,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -174,7 +174,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
* The format of the audio muxed in the variants. May be null if the playlist does not declare any * The format of the audio muxed in the variants. May be null if the playlist does not declare any
* muxed audio. * muxed audio.
*/ */
public final Format muxedAudioFormat; @Nullable public final Format muxedAudioFormat;
/** /**
* The format of the closed captions declared by the playlist. May be empty if the playlist * The format of the closed captions declared by the playlist. May be empty if the playlist
* explicitly declares no captions are available, or null if the playlist does not declare any * explicitly declares no captions are available, or null if the playlist does not declare any
...@@ -208,7 +208,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -208,7 +208,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
List<Rendition> audios, List<Rendition> audios,
List<Rendition> subtitles, List<Rendition> subtitles,
List<Rendition> closedCaptions, List<Rendition> closedCaptions,
Format muxedAudioFormat, @Nullable Format muxedAudioFormat,
List<Format> muxedCaptionFormats, List<Format> muxedCaptionFormats,
boolean hasIndependentSegments, boolean hasIndependentSegments,
Map<String, String> variableDefinitions, Map<String, String> variableDefinitions,
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package com.google.android.exoplayer2.source.hls.playlist; package com.google.android.exoplayer2.source.hls.playlist;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
...@@ -95,8 +94,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist { ...@@ -95,8 +94,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
String uri, String uri,
long byterangeOffset, long byterangeOffset,
long byterangeLength, long byterangeLength,
String fullSegmentEncryptionKeyUri, @Nullable String fullSegmentEncryptionKeyUri,
String encryptionIV) { @Nullable String encryptionIV) {
this( this(
uri, uri,
/* initializationSegment= */ null, /* initializationSegment= */ null,
...@@ -154,7 +153,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { ...@@ -154,7 +153,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
} }
@Override @Override
public int compareTo(@NonNull Long relativeStartTimeUs) { public int compareTo(Long relativeStartTimeUs) {
return this.relativeStartTimeUs > relativeStartTimeUs return this.relativeStartTimeUs > relativeStartTimeUs
? 1 : (this.relativeStartTimeUs < relativeStartTimeUs ? -1 : 0); ? 1 : (this.relativeStartTimeUs < relativeStartTimeUs ? -1 : 0);
} }
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.hls.playlist;
import com.google.android.exoplayer2.util.NonNullApi;
...@@ -41,8 +41,10 @@ android { ...@@ -41,8 +41,10 @@ android {
dependencies { dependencies {
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.TransferListener; ...@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.TransferListener;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** A SmoothStreaming {@link MediaPeriod}. */ /** A SmoothStreaming {@link MediaPeriod}. */
/* package */ final class SsMediaPeriod /* package */ final class SsMediaPeriod
...@@ -120,8 +121,12 @@ import java.util.List; ...@@ -120,8 +121,12 @@ import java.util.List;
} }
@Override @Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, public long selectTracks(
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { @NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
ArrayList<ChunkSampleStream<SsChunkSource>> sampleStreamsList = new ArrayList<>(); ArrayList<ChunkSampleStream<SsChunkSource>> sampleStreamsList = new ArrayList<>();
for (int i = 0; i < selections.length; i++) { for (int i = 0; i < selections.length; i++) {
if (streams[i] != null) { if (streams[i] != null) {
......
...@@ -115,7 +115,7 @@ public final class SsMediaSource extends BaseMediaSource ...@@ -115,7 +115,7 @@ public final class SsMediaSource extends BaseMediaSource
* @return This factory, for convenience. * @return This factory, for convenience.
* @throws IllegalStateException If one of the {@code create} methods has already been called. * @throws IllegalStateException If one of the {@code create} methods has already been called.
*/ */
public Factory setTag(Object tag) { public Factory setTag(@Nullable Object tag) {
Assertions.checkState(!isCreateCalled); Assertions.checkState(!isCreateCalled);
this.tag = tag; this.tag = tag;
return this; return this;
...@@ -370,8 +370,8 @@ public final class SsMediaSource extends BaseMediaSource ...@@ -370,8 +370,8 @@ public final class SsMediaSource extends BaseMediaSource
public SsMediaSource( public SsMediaSource(
SsManifest manifest, SsManifest manifest,
SsChunkSource.Factory chunkSourceFactory, SsChunkSource.Factory chunkSourceFactory,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
manifest, manifest,
chunkSourceFactory, chunkSourceFactory,
...@@ -395,8 +395,8 @@ public final class SsMediaSource extends BaseMediaSource ...@@ -395,8 +395,8 @@ public final class SsMediaSource extends BaseMediaSource
SsManifest manifest, SsManifest manifest,
SsChunkSource.Factory chunkSourceFactory, SsChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, int minLoadableRetryCount,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
manifest, manifest,
/* manifestUri= */ null, /* manifestUri= */ null,
...@@ -431,8 +431,8 @@ public final class SsMediaSource extends BaseMediaSource ...@@ -431,8 +431,8 @@ public final class SsMediaSource extends BaseMediaSource
Uri manifestUri, Uri manifestUri,
DataSource.Factory manifestDataSourceFactory, DataSource.Factory manifestDataSourceFactory,
SsChunkSource.Factory chunkSourceFactory, SsChunkSource.Factory chunkSourceFactory,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
manifestUri, manifestUri,
manifestDataSourceFactory, manifestDataSourceFactory,
...@@ -466,8 +466,8 @@ public final class SsMediaSource extends BaseMediaSource ...@@ -466,8 +466,8 @@ public final class SsMediaSource extends BaseMediaSource
SsChunkSource.Factory chunkSourceFactory, SsChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, int minLoadableRetryCount,
long livePresentationDelayMs, long livePresentationDelayMs,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this(manifestUri, manifestDataSourceFactory, new SsManifestParser(), chunkSourceFactory, this(manifestUri, manifestDataSourceFactory, new SsManifestParser(), chunkSourceFactory,
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener); minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener);
} }
...@@ -496,8 +496,8 @@ public final class SsMediaSource extends BaseMediaSource ...@@ -496,8 +496,8 @@ public final class SsMediaSource extends BaseMediaSource
SsChunkSource.Factory chunkSourceFactory, SsChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, int minLoadableRetryCount,
long livePresentationDelayMs, long livePresentationDelayMs,
Handler eventHandler, @Nullable Handler eventHandler,
MediaSourceEventListener eventListener) { @Nullable MediaSourceEventListener eventListener) {
this( this(
/* manifest= */ null, /* manifest= */ null,
manifestUri, manifestUri,
...@@ -515,10 +515,10 @@ public final class SsMediaSource extends BaseMediaSource ...@@ -515,10 +515,10 @@ public final class SsMediaSource extends BaseMediaSource
} }
private SsMediaSource( private SsMediaSource(
SsManifest manifest, @Nullable SsManifest manifest,
Uri manifestUri, @Nullable Uri manifestUri,
DataSource.Factory manifestDataSourceFactory, @Nullable DataSource.Factory manifestDataSourceFactory,
ParsingLoadable.Parser<? extends SsManifest> manifestParser, @Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser,
SsChunkSource.Factory chunkSourceFactory, SsChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
DrmSessionManager<?> drmSessionManager, DrmSessionManager<?> drmSessionManager,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.smoothstreaming.manifest; package com.google.android.exoplayer2.source.smoothstreaming.manifest;
import android.net.Uri; import android.net.Uri;
import androidx.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.mp4.TrackEncryptionBox; import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox;
...@@ -69,7 +70,7 @@ public class SsManifest implements FilterableManifest<SsManifest> { ...@@ -69,7 +70,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
public final int maxHeight; public final int maxHeight;
public final int displayWidth; public final int displayWidth;
public final int displayHeight; public final int displayHeight;
public final String language; @Nullable public final String language;
public final Format[] formats; public final Format[] formats;
public final int chunkCount; public final int chunkCount;
...@@ -80,9 +81,20 @@ public class SsManifest implements FilterableManifest<SsManifest> { ...@@ -80,9 +81,20 @@ public class SsManifest implements FilterableManifest<SsManifest> {
private final long[] chunkStartTimesUs; private final long[] chunkStartTimesUs;
private final long lastChunkDurationUs; private final long lastChunkDurationUs;
public StreamElement(String baseUri, String chunkTemplate, int type, String subType, public StreamElement(
long timescale, String name, int maxWidth, int maxHeight, int displayWidth, String baseUri,
int displayHeight, String language, Format[] formats, List<Long> chunkStartTimes, String chunkTemplate,
int type,
String subType,
long timescale,
String name,
int maxWidth,
int maxHeight,
int displayWidth,
int displayHeight,
@Nullable String language,
Format[] formats,
List<Long> chunkStartTimes,
long lastChunkDuration) { long lastChunkDuration) {
this( this(
baseUri, baseUri,
...@@ -102,10 +114,22 @@ public class SsManifest implements FilterableManifest<SsManifest> { ...@@ -102,10 +114,22 @@ public class SsManifest implements FilterableManifest<SsManifest> {
Util.scaleLargeTimestamp(lastChunkDuration, C.MICROS_PER_SECOND, timescale)); Util.scaleLargeTimestamp(lastChunkDuration, C.MICROS_PER_SECOND, timescale));
} }
private StreamElement(String baseUri, String chunkTemplate, int type, String subType, private StreamElement(
long timescale, String name, int maxWidth, int maxHeight, int displayWidth, String baseUri,
int displayHeight, String language, Format[] formats, List<Long> chunkStartTimes, String chunkTemplate,
long[] chunkStartTimesUs, long lastChunkDurationUs) { int type,
String subType,
long timescale,
String name,
int maxWidth,
int maxHeight,
int displayWidth,
int displayHeight,
@Nullable String language,
Format[] formats,
List<Long> chunkStartTimes,
long[] chunkStartTimesUs,
long lastChunkDurationUs) {
this.baseUri = baseUri; this.baseUri = baseUri;
this.chunkTemplate = chunkTemplate; this.chunkTemplate = chunkTemplate;
this.type = type; this.type = type;
...@@ -208,7 +232,7 @@ public class SsManifest implements FilterableManifest<SsManifest> { ...@@ -208,7 +232,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
public final boolean isLive; public final boolean isLive;
/** Content protection information, or null if the content is not protected. */ /** Content protection information, or null if the content is not protected. */
public final ProtectionElement protectionElement; @Nullable public final ProtectionElement protectionElement;
/** The contained stream elements. */ /** The contained stream elements. */
public final StreamElement[] streamElements; public final StreamElement[] streamElements;
...@@ -249,7 +273,7 @@ public class SsManifest implements FilterableManifest<SsManifest> { ...@@ -249,7 +273,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
long dvrWindowLength, long dvrWindowLength,
int lookAheadCount, int lookAheadCount,
boolean isLive, boolean isLive,
ProtectionElement protectionElement, @Nullable ProtectionElement protectionElement,
StreamElement[] streamElements) { StreamElement[] streamElements) {
this( this(
majorVersion, majorVersion,
...@@ -273,7 +297,7 @@ public class SsManifest implements FilterableManifest<SsManifest> { ...@@ -273,7 +297,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
long dvrWindowLengthUs, long dvrWindowLengthUs,
int lookAheadCount, int lookAheadCount,
boolean isLive, boolean isLive,
ProtectionElement protectionElement, @Nullable ProtectionElement protectionElement,
StreamElement[] streamElements) { StreamElement[] streamElements) {
this.majorVersion = majorVersion; this.majorVersion = majorVersion;
this.minorVersion = minorVersion; this.minorVersion = minorVersion;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.smoothstreaming.manifest; package com.google.android.exoplayer2.source.smoothstreaming.manifest;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
import android.util.Pair; import android.util.Pair;
...@@ -40,6 +41,7 @@ import java.util.Collections; ...@@ -40,6 +41,7 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlPullParserFactory;
...@@ -94,10 +96,10 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> { ...@@ -94,10 +96,10 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
private final String baseUri; private final String baseUri;
private final String tag; private final String tag;
private final ElementParser parent; @Nullable private final ElementParser parent;
private final List<Pair<String, Object>> normalizedAttributes; private final List<Pair<String, @NullableType Object>> normalizedAttributes;
public ElementParser(ElementParser parent, String baseUri, String tag) { public ElementParser(@Nullable ElementParser parent, String baseUri, String tag) {
this.parent = parent; this.parent = parent;
this.baseUri = baseUri; this.baseUri = baseUri;
this.tag = tag; this.tag = tag;
...@@ -174,24 +176,25 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> { ...@@ -174,24 +176,25 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
* Stash an attribute that may be normalized at this level. In other words, an attribute that * Stash an attribute that may be normalized at this level. In other words, an attribute that
* may have been pulled up from the child elements because its value was the same in all * may have been pulled up from the child elements because its value was the same in all
* children. * children.
* <p> *
* Stashing an attribute allows child element parsers to retrieve the values of normalized * <p>Stashing an attribute allows child element parsers to retrieve the values of normalized
* attributes using {@link #getNormalizedAttribute(String)}. * attributes using {@link #getNormalizedAttribute(String)}.
* *
* @param key The name of the attribute. * @param key The name of the attribute.
* @param value The value of the attribute. * @param value The value of the attribute.
*/ */
protected final void putNormalizedAttribute(String key, Object value) { protected final void putNormalizedAttribute(String key, @Nullable Object value) {
normalizedAttributes.add(Pair.create(key, value)); normalizedAttributes.add(Pair.create(key, value));
} }
/** /**
* Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with * Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with the
* the provided name, the parent element parser will be queried, and so on up the chain. * provided name, the parent element parser will be queried, and so on up the chain.
* *
* @param key The name of the attribute. * @param key The name of the attribute.
* @return The stashed value, or null if the attribute was not be found. * @return The stashed value, or null if the attribute was not be found.
*/ */
@Nullable
protected final Object getNormalizedAttribute(String key) { protected final Object getNormalizedAttribute(String key) {
for (int i = 0; i < normalizedAttributes.size(); i++) { for (int i = 0; i < normalizedAttributes.size(); i++) {
Pair<String, Object> pair = normalizedAttributes.get(i); Pair<String, Object> pair = normalizedAttributes.get(i);
...@@ -340,7 +343,7 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> { ...@@ -340,7 +343,7 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
private long dvrWindowLength; private long dvrWindowLength;
private int lookAheadCount; private int lookAheadCount;
private boolean isLive; private boolean isLive;
private ProtectionElement protectionElement; @Nullable private ProtectionElement protectionElement;
public SmoothStreamingMediaParser(ElementParser parent, String baseUri) { public SmoothStreamingMediaParser(ElementParser parent, String baseUri) {
super(parent, baseUri, TAG); super(parent, baseUri, TAG);
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
import com.google.android.exoplayer2.util.NonNullApi;
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.smoothstreaming.offline;
import com.google.android.exoplayer2.util.NonNullApi;
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.source.smoothstreaming;
import com.google.android.exoplayer2.util.NonNullApi;
...@@ -43,7 +43,8 @@ dependencies { ...@@ -43,7 +43,8 @@ dependencies {
implementation 'androidx.media:media:1.0.1' implementation 'androidx.media:media:1.0.1'
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -39,11 +39,13 @@ android { ...@@ -39,11 +39,13 @@ android {
dependencies { dependencies {
api 'org.mockito:mockito-core:' + mockitoVersion api 'org.mockito:mockito-core:' + mockitoVersion
api 'androidx.test:core:' + androidXTestVersion
api 'androidx.test.ext:junit:' + androidXTestVersion api 'androidx.test.ext:junit:' + androidXTestVersion
api 'com.google.truth:truth:' + truthVersion api 'com.google.truth:truth:' + truthVersion
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
implementation project(modulePrefix + 'library-core') implementation project(modulePrefix + 'library-core')
implementation 'com.google.auto.value:auto-value-annotations:' + autoValueVersion implementation 'com.google.auto.value:auto-value-annotations:' + autoValueVersion
annotationProcessor 'com.google.auto.value:auto-value:' + autoValueVersion annotationProcessor 'com.google.auto.value:auto-value:' + autoValueVersion
testImplementation project(modulePrefix + 'testutils-robolectric') testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
} }
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
apply from: '../constants.gradle'
apply plugin: 'com.android.library'
android {
compileSdkVersion project.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
}
lintOptions {
// Robolectric depends on BouncyCastle, which depends on javax.naming,
// which is not part of Android.
disable 'InvalidPackage'
}
testOptions.unitTests.includeAndroidResources = true
}
dependencies {
api 'androidx.test:core:' + androidXTestVersion
api 'org.robolectric:robolectric:' + robolectricVersion
api project(modulePrefix + 'testutils')
implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:1.1.0'
annotationProcessor 'com.google.auto.service:auto-service:' + autoServiceVersion
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest package="com.google.android.exoplayer2.testutil"/>
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