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 735 additions and 409 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
......
...@@ -177,6 +177,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -177,6 +177,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private boolean exceedAudioConstraintsIfNecessary; private boolean exceedAudioConstraintsIfNecessary;
private boolean allowAudioMixedMimeTypeAdaptiveness; private boolean allowAudioMixedMimeTypeAdaptiveness;
private boolean allowAudioMixedSampleRateAdaptiveness; private boolean allowAudioMixedSampleRateAdaptiveness;
private boolean allowAudioMixedChannelCountAdaptiveness;
// General // General
private boolean forceLowestBitrate; private boolean forceLowestBitrate;
private boolean forceHighestSupportedBitrate; private boolean forceHighestSupportedBitrate;
...@@ -227,6 +228,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -227,6 +228,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary; exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary;
allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness; allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness;
allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness; allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness;
allowAudioMixedChannelCountAdaptiveness =
initialValues.allowAudioMixedChannelCountAdaptiveness;
// General // General
forceLowestBitrate = initialValues.forceLowestBitrate; forceLowestBitrate = initialValues.forceLowestBitrate;
forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate; forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate;
...@@ -258,8 +261,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -258,8 +261,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#maxVideoWidth} and {@link Parameters#maxVideoHeight}. * Sets the maximum allowed video width and height.
* *
* @param maxVideoWidth Maximum allowed video width in pixels.
* @param maxVideoHeight Maximum allowed video height in pixels.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setMaxVideoSize(int maxVideoWidth, int maxVideoHeight) { public ParametersBuilder setMaxVideoSize(int maxVideoWidth, int maxVideoHeight) {
...@@ -269,8 +274,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -269,8 +274,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#maxVideoFrameRate}. * Sets the maximum allowed video frame rate.
* *
* @param maxVideoFrameRate Maximum allowed video frame rate in hertz.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setMaxVideoFrameRate(int maxVideoFrameRate) { public ParametersBuilder setMaxVideoFrameRate(int maxVideoFrameRate) {
...@@ -279,8 +285,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -279,8 +285,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#maxVideoBitrate}. * Sets the maximum allowed video bitrate.
* *
* @param maxVideoBitrate Maximum allowed video bitrate in bits per second.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setMaxVideoBitrate(int maxVideoBitrate) { public ParametersBuilder setMaxVideoBitrate(int maxVideoBitrate) {
...@@ -289,8 +296,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -289,8 +296,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#exceedVideoConstraintsIfNecessary}. * Sets whether to exceed the {@link #setMaxVideoSize(int, int)} and {@link
* #setMaxAudioBitrate(int)} constraints when no selection can be made otherwise.
* *
* @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no
* selection can be made otherwise.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setExceedVideoConstraintsIfNecessary( public ParametersBuilder setExceedVideoConstraintsIfNecessary(
...@@ -300,8 +310,14 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -300,8 +310,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#allowVideoMixedMimeTypeAdaptiveness}. * Sets whether to allow adaptive video selections containing mixed MIME types.
* *
* <p>Adaptations between different MIME types may not be completely seamless, in which case
* {@link #setAllowVideoNonSeamlessAdaptiveness(boolean)} also needs to be {@code true} for
* mixed MIME type selections to be made.
*
* @param allowVideoMixedMimeTypeAdaptiveness Whether to allow adaptive video selections
* containing mixed MIME types.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness( public ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness(
...@@ -311,8 +327,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -311,8 +327,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#allowVideoNonSeamlessAdaptiveness}. * Sets whether to allow adaptive video selections where adaptation may not be completely
* seamless.
* *
* @param allowVideoNonSeamlessAdaptiveness Whether to allow adaptive video selections where
* adaptation may not be completely seamless.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setAllowVideoNonSeamlessAdaptiveness( public ParametersBuilder setAllowVideoNonSeamlessAdaptiveness(
...@@ -326,7 +345,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -326,7 +345,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* obtained from {@link Util#getPhysicalDisplaySize(Context)}. * obtained from {@link Util#getPhysicalDisplaySize(Context)}.
* *
* @param context Any context. * @param context Any context.
* @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}. * @param viewportOrientationMayChange Whether the viewport orientation may change during
* playback.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setViewportSizeToPhysicalDisplaySize( public ParametersBuilder setViewportSizeToPhysicalDisplaySize(
...@@ -347,12 +367,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -347,12 +367,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#viewportWidth}, {@link Parameters#maxVideoHeight} and {@link * Sets the viewport size to constrain adaptive video selections so that only tracks suitable
* Parameters#viewportOrientationMayChange}. * for the viewport are selected.
* *
* @param viewportWidth See {@link Parameters#viewportWidth}. * @param viewportWidth Viewport width in pixels.
* @param viewportHeight See {@link Parameters#viewportHeight}. * @param viewportHeight Viewport height in pixels.
* @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}. * @param viewportOrientationMayChange Whether the viewport orientation may change during
* playback.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setViewportSize( public ParametersBuilder setViewportSize(
...@@ -372,8 +393,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -372,8 +393,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#maxAudioChannelCount}. * Sets the maximum allowed audio channel count.
* *
* @param maxAudioChannelCount Maximum allowed audio channel count.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) { public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) {
...@@ -382,8 +404,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -382,8 +404,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#maxAudioBitrate}. * Sets the maximum allowed audio bitrate.
* *
* @param maxAudioBitrate Maximum allowed audio bitrate in bits per second.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setMaxAudioBitrate(int maxAudioBitrate) { public ParametersBuilder setMaxAudioBitrate(int maxAudioBitrate) {
...@@ -392,8 +415,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -392,8 +415,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#exceedAudioConstraintsIfNecessary}. * Sets whether to exceed the {@link #setMaxAudioChannelCount(int)} and {@link
* #setMaxAudioBitrate(int)} constraints when no selection can be made otherwise.
* *
* @param exceedAudioConstraintsIfNecessary Whether to exceed audio constraints when no
* selection can be made otherwise.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setExceedAudioConstraintsIfNecessary( public ParametersBuilder setExceedAudioConstraintsIfNecessary(
...@@ -403,8 +429,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -403,8 +429,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#allowAudioMixedMimeTypeAdaptiveness}. * Sets whether to allow adaptive audio selections containing mixed MIME types.
*
* <p>Adaptations between different MIME types may not be completely seamless.
* *
* @param allowAudioMixedMimeTypeAdaptiveness Whether to allow adaptive audio selections
* containing mixed MIME types.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness( public ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness(
...@@ -414,8 +444,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -414,8 +444,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#allowAudioMixedSampleRateAdaptiveness}. * Sets whether to allow adaptive audio selections containing mixed sample rates.
* *
* <p>Adaptations between different sample rates may not be completely seamless.
*
* @param allowAudioMixedSampleRateAdaptiveness Whether to allow adaptive audio selections
* containing mixed sample rates.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness( public ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness(
...@@ -424,6 +458,21 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -424,6 +458,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
/**
* Sets whether to allow adaptive audio selections containing mixed channel counts.
*
* <p>Adaptations between different channel counts may not be completely seamless.
*
* @param allowAudioMixedChannelCountAdaptiveness Whether to allow adaptive audio selections
* containing mixed channel counts.
* @return This builder.
*/
public ParametersBuilder setAllowAudioMixedChannelCountAdaptiveness(
boolean allowAudioMixedChannelCountAdaptiveness) {
this.allowAudioMixedChannelCountAdaptiveness = allowAudioMixedChannelCountAdaptiveness;
return this;
}
// Text // Text
@Override @Override
...@@ -454,8 +503,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -454,8 +503,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
/** /**
* See {@link Parameters#forceLowestBitrate}. * Sets whether to force selection of the single lowest bitrate audio and video tracks that
* comply with all other constraints.
* *
* @param forceLowestBitrate Whether to force selection of the single lowest bitrate audio and
* video tracks.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setForceLowestBitrate(boolean forceLowestBitrate) { public ParametersBuilder setForceLowestBitrate(boolean forceLowestBitrate) {
...@@ -464,8 +516,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -464,8 +516,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#forceHighestSupportedBitrate}. * Sets whether to force selection of the highest bitrate audio and video tracks that comply
* with all other constraints.
* *
* @param forceHighestSupportedBitrate Whether to force selection of the highest bitrate audio
* and video tracks.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setForceHighestSupportedBitrate(boolean forceHighestSupportedBitrate) { public ParametersBuilder setForceHighestSupportedBitrate(boolean forceHighestSupportedBitrate) {
...@@ -491,8 +546,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -491,8 +546,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#exceedRendererCapabilitiesIfNecessary}. * Sets whether to exceed renderer capabilities when no selection can be made otherwise.
*
* <p>This parameter applies when all of the tracks available for a renderer exceed the
* renderer's reported capabilities. If the parameter is {@code true} then the lowest quality
* track will still be selected. Playback may succeed if the renderer has under-reported its
* true capabilities. If {@code false} then no track will be selected.
* *
* @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no
* selection can be made otherwise.
* @return This builder. * @return This builder.
*/ */
public ParametersBuilder setExceedRendererCapabilitiesIfNecessary( public ParametersBuilder setExceedRendererCapabilitiesIfNecessary(
...@@ -502,7 +564,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -502,7 +564,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#tunnelingAudioSessionId}. * Sets the audio session id to use when tunneling.
* *
* <p>Enables or disables tunneling. To enable tunneling, pass an audio session id to use when * <p>Enables or disables tunneling. To enable tunneling, pass an audio session id to use when
* in tunneling mode. Session ids can be generated using {@link * in tunneling mode. Session ids can be generated using {@link
...@@ -512,6 +574,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -512,6 +574,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* *
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link * @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling. * C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
* @return This builder.
*/ */
public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) { public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
this.tunnelingAudioSessionId = tunnelingAudioSessionId; this.tunnelingAudioSessionId = tunnelingAudioSessionId;
...@@ -526,6 +589,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -526,6 +589,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* *
* @param rendererIndex The renderer index. * @param rendererIndex The renderer index.
* @param disabled Whether the renderer is disabled. * @param disabled Whether the renderer is disabled.
* @return This builder.
*/ */
public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) { public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) {
if (rendererDisabledFlags.get(rendererIndex) == disabled) { if (rendererDisabledFlags.get(rendererIndex) == disabled) {
...@@ -562,6 +626,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -562,6 +626,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param rendererIndex The renderer index. * @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be applied. * @param groups The {@link TrackGroupArray} for which the override should be applied.
* @param override The override. * @param override The override.
* @return This builder.
*/ */
public final ParametersBuilder setSelectionOverride( public final ParametersBuilder setSelectionOverride(
int rendererIndex, TrackGroupArray groups, SelectionOverride override) { int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
...@@ -583,6 +648,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -583,6 +648,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* *
* @param rendererIndex The renderer index. * @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be cleared. * @param groups The {@link TrackGroupArray} for which the override should be cleared.
* @return This builder.
*/ */
public final ParametersBuilder clearSelectionOverride( public final ParametersBuilder clearSelectionOverride(
int rendererIndex, TrackGroupArray groups) { int rendererIndex, TrackGroupArray groups) {
...@@ -602,6 +668,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -602,6 +668,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* Clears all track selection overrides for the specified renderer. * Clears all track selection overrides for the specified renderer.
* *
* @param rendererIndex The renderer index. * @param rendererIndex The renderer index.
* @return This builder.
*/ */
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) { public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex); Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
...@@ -613,7 +680,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -613,7 +680,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
/** Clears all track selection overrides for all renderers. */ /**
* Clears all track selection overrides for all renderers.
*
* @return This builder.
*/
public final ParametersBuilder clearSelectionOverrides() { public final ParametersBuilder clearSelectionOverrides() {
if (selectionOverrides.size() == 0) { if (selectionOverrides.size() == 0) {
// Nothing to clear. // Nothing to clear.
...@@ -646,6 +717,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -646,6 +717,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
exceedAudioConstraintsIfNecessary, exceedAudioConstraintsIfNecessary,
allowAudioMixedMimeTypeAdaptiveness, allowAudioMixedMimeTypeAdaptiveness,
allowAudioMixedSampleRateAdaptiveness, allowAudioMixedSampleRateAdaptiveness,
allowAudioMixedChannelCountAdaptiveness,
// Text // Text
preferredTextLanguage, preferredTextLanguage,
preferredRoleFlags, preferredRoleFlags,
...@@ -695,8 +767,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -695,8 +767,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Video // Video
/** /**
* Maximum allowed video width. The default value is {@link Integer#MAX_VALUE} (i.e. no * Maximum allowed video width in pixels. The default value is {@link Integer#MAX_VALUE} (i.e.
* constraint). * no constraint).
* *
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the * <p>To constrain adaptive video track selections to be suitable for a given viewport (the
* region of the display within which video will be played), use ({@link #viewportWidth}, {@link * region of the display within which video will be played), use ({@link #viewportWidth}, {@link
...@@ -704,8 +776,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -704,8 +776,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
public final int maxVideoWidth; public final int maxVideoWidth;
/** /**
* Maximum allowed video height. The default value is {@link Integer#MAX_VALUE} (i.e. no * Maximum allowed video height in pixels. The default value is {@link Integer#MAX_VALUE} (i.e.
* constraint). * no constraint).
* *
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the * <p>To constrain adaptive video track selections to be suitable for a given viewport (the
* region of the display within which video will be played), use ({@link #viewportWidth}, {@link * region of the display within which video will be played), use ({@link #viewportWidth}, {@link
...@@ -713,12 +785,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -713,12 +785,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
public final int maxVideoHeight; public final int maxVideoHeight;
/** /**
* Maximum allowed video frame rate. The default value is {@link Integer#MAX_VALUE} (i.e. no * Maximum allowed video frame rate in hertz. The default value is {@link Integer#MAX_VALUE}
* constraint). * (i.e. no constraint).
*/ */
public final int maxVideoFrameRate; public final int maxVideoFrameRate;
/** /**
* Maximum video bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint). * Maximum allowed video bitrate in bits per second. The default value is {@link
* Integer#MAX_VALUE} (i.e. no constraint).
*/ */
public final int maxVideoBitrate; public final int maxVideoBitrate;
/** /**
...@@ -728,9 +801,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -728,9 +801,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
public final boolean exceedVideoConstraintsIfNecessary; public final boolean exceedVideoConstraintsIfNecessary;
/** /**
* Whether to allow adaptive video selections containing mixed mime types. Adaptations between * Whether to allow adaptive video selections containing mixed MIME types. Adaptations between
* different mime types may not be completely seamless, in which case {@link * different MIME types may not be completely seamless, in which case {@link
* #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed mime type * #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed MIME type
* selections to be made. The default value is {@code false}. * selections to be made. The default value is {@code false}.
*/ */
public final boolean allowVideoMixedMimeTypeAdaptiveness; public final boolean allowVideoMixedMimeTypeAdaptiveness;
...@@ -764,7 +837,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -764,7 +837,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
public final int maxAudioChannelCount; public final int maxAudioChannelCount;
/** /**
* Maximum audio bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint). * Maximum allowed audio bitrate in bits per second. The default value is {@link
* Integer#MAX_VALUE} (i.e. no constraint).
*/ */
public final int maxAudioBitrate; public final int maxAudioBitrate;
/** /**
...@@ -773,8 +847,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -773,8 +847,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
public final boolean exceedAudioConstraintsIfNecessary; public final boolean exceedAudioConstraintsIfNecessary;
/** /**
* Whether to allow adaptive audio selections containing mixed mime types. Adaptations between * Whether to allow adaptive audio selections containing mixed MIME types. Adaptations between
* different mime types may not be completely seamless. The default value is {@code false}. * different MIME types may not be completely seamless. The default value is {@code false}.
*/ */
public final boolean allowAudioMixedMimeTypeAdaptiveness; public final boolean allowAudioMixedMimeTypeAdaptiveness;
/** /**
...@@ -782,6 +856,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -782,6 +856,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* different sample rates may not be completely seamless. The default value is {@code false}. * different sample rates may not be completely seamless. The default value is {@code false}.
*/ */
public final boolean allowAudioMixedSampleRateAdaptiveness; public final boolean allowAudioMixedSampleRateAdaptiveness;
/**
* Whether to allow adaptive audio selections containing mixed channel counts. Adaptations
* between different channel counts may not be completely seamless. The default value is {@code
* false}.
*/
public final boolean allowAudioMixedChannelCountAdaptiveness;
// General // General
/** /**
...@@ -842,6 +922,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -842,6 +922,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
/* exceedAudioConstraintsIfNecessary= */ true, /* exceedAudioConstraintsIfNecessary= */ true,
/* allowAudioMixedMimeTypeAdaptiveness= */ false, /* allowAudioMixedMimeTypeAdaptiveness= */ false,
/* allowAudioMixedSampleRateAdaptiveness= */ false, /* allowAudioMixedSampleRateAdaptiveness= */ false,
/* allowAudioMixedChannelCountAdaptiveness= */ false,
// Text // Text
TrackSelectionParameters.DEFAULT.preferredTextLanguage, TrackSelectionParameters.DEFAULT.preferredTextLanguage,
TrackSelectionParameters.DEFAULT.preferredRoleFlags, TrackSelectionParameters.DEFAULT.preferredRoleFlags,
...@@ -875,6 +956,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -875,6 +956,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
boolean exceedAudioConstraintsIfNecessary, boolean exceedAudioConstraintsIfNecessary,
boolean allowAudioMixedMimeTypeAdaptiveness, boolean allowAudioMixedMimeTypeAdaptiveness,
boolean allowAudioMixedSampleRateAdaptiveness, boolean allowAudioMixedSampleRateAdaptiveness,
boolean allowAudioMixedChannelCountAdaptiveness,
// Text // Text
@Nullable String preferredTextLanguage, @Nullable String preferredTextLanguage,
@C.RoleFlags int preferredRoleFlags, @C.RoleFlags int preferredRoleFlags,
...@@ -911,6 +993,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -911,6 +993,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary; this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary;
this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness; this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness;
this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness; this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness;
this.allowAudioMixedChannelCountAdaptiveness = allowAudioMixedChannelCountAdaptiveness;
// General // General
this.forceLowestBitrate = forceLowestBitrate; this.forceLowestBitrate = forceLowestBitrate;
this.forceHighestSupportedBitrate = forceHighestSupportedBitrate; this.forceHighestSupportedBitrate = forceHighestSupportedBitrate;
...@@ -944,6 +1027,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -944,6 +1027,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.exceedAudioConstraintsIfNecessary = Util.readBoolean(in); this.exceedAudioConstraintsIfNecessary = Util.readBoolean(in);
this.allowAudioMixedMimeTypeAdaptiveness = Util.readBoolean(in); this.allowAudioMixedMimeTypeAdaptiveness = Util.readBoolean(in);
this.allowAudioMixedSampleRateAdaptiveness = Util.readBoolean(in); this.allowAudioMixedSampleRateAdaptiveness = Util.readBoolean(in);
this.allowAudioMixedChannelCountAdaptiveness = Util.readBoolean(in);
// General // General
this.forceLowestBitrate = Util.readBoolean(in); this.forceLowestBitrate = Util.readBoolean(in);
this.forceHighestSupportedBitrate = Util.readBoolean(in); this.forceHighestSupportedBitrate = Util.readBoolean(in);
...@@ -1025,6 +1109,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1025,6 +1109,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary && exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary
&& allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness && allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness
&& allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness && allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness
&& allowAudioMixedChannelCountAdaptiveness
== other.allowAudioMixedChannelCountAdaptiveness
// General // General
&& forceLowestBitrate == other.forceLowestBitrate && forceLowestBitrate == other.forceLowestBitrate
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate && forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
...@@ -1055,6 +1141,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1055,6 +1141,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0); result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0); result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0);
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0); result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
result = 31 * result + (allowAudioMixedChannelCountAdaptiveness ? 1 : 0);
// General // General
result = 31 * result + (forceLowestBitrate ? 1 : 0); result = 31 * result + (forceLowestBitrate ? 1 : 0);
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0); result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
...@@ -1091,6 +1178,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1091,6 +1178,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
Util.writeBoolean(dest, exceedAudioConstraintsIfNecessary); Util.writeBoolean(dest, exceedAudioConstraintsIfNecessary);
Util.writeBoolean(dest, allowAudioMixedMimeTypeAdaptiveness); Util.writeBoolean(dest, allowAudioMixedMimeTypeAdaptiveness);
Util.writeBoolean(dest, allowAudioMixedSampleRateAdaptiveness); Util.writeBoolean(dest, allowAudioMixedSampleRateAdaptiveness);
Util.writeBoolean(dest, allowAudioMixedChannelCountAdaptiveness);
// General // General
Util.writeBoolean(dest, forceLowestBitrate); Util.writeBoolean(dest, forceLowestBitrate);
Util.writeBoolean(dest, forceHighestSupportedBitrate); Util.writeBoolean(dest, forceHighestSupportedBitrate);
...@@ -1999,7 +2087,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1999,7 +2087,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
formatSupports[selectedGroupIndex], formatSupports[selectedGroupIndex],
params.maxAudioBitrate, params.maxAudioBitrate,
params.allowAudioMixedMimeTypeAdaptiveness, params.allowAudioMixedMimeTypeAdaptiveness,
params.allowAudioMixedSampleRateAdaptiveness); params.allowAudioMixedSampleRateAdaptiveness,
params.allowAudioMixedChannelCountAdaptiveness);
if (adaptiveTracks.length > 0) { if (adaptiveTracks.length > 0) {
definition = new TrackSelection.Definition(selectedGroup, adaptiveTracks); definition = new TrackSelection.Definition(selectedGroup, adaptiveTracks);
} }
...@@ -2017,7 +2106,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -2017,7 +2106,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int[] formatSupport, int[] formatSupport,
int maxAudioBitrate, int maxAudioBitrate,
boolean allowMixedMimeTypeAdaptiveness, boolean allowMixedMimeTypeAdaptiveness,
boolean allowMixedSampleRateAdaptiveness) { boolean allowMixedSampleRateAdaptiveness,
boolean allowAudioMixedChannelCountAdaptiveness) {
int selectedConfigurationTrackCount = 0; int selectedConfigurationTrackCount = 0;
AudioConfigurationTuple selectedConfiguration = null; AudioConfigurationTuple selectedConfiguration = null;
HashSet<AudioConfigurationTuple> seenConfigurationTuples = new HashSet<>(); HashSet<AudioConfigurationTuple> seenConfigurationTuples = new HashSet<>();
...@@ -2034,7 +2124,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -2034,7 +2124,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
configuration, configuration,
maxAudioBitrate, maxAudioBitrate,
allowMixedMimeTypeAdaptiveness, allowMixedMimeTypeAdaptiveness,
allowMixedSampleRateAdaptiveness); allowMixedSampleRateAdaptiveness,
allowAudioMixedChannelCountAdaptiveness);
if (configurationCount > selectedConfigurationTrackCount) { if (configurationCount > selectedConfigurationTrackCount) {
selectedConfiguration = configuration; selectedConfiguration = configuration;
selectedConfigurationTrackCount = configurationCount; selectedConfigurationTrackCount = configurationCount;
...@@ -2054,7 +2145,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -2054,7 +2145,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
selectedConfiguration, selectedConfiguration,
maxAudioBitrate, maxAudioBitrate,
allowMixedMimeTypeAdaptiveness, allowMixedMimeTypeAdaptiveness,
allowMixedSampleRateAdaptiveness)) { allowMixedSampleRateAdaptiveness,
allowAudioMixedChannelCountAdaptiveness)) {
adaptiveIndices[index++] = i; adaptiveIndices[index++] = i;
} }
} }
...@@ -2069,7 +2161,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -2069,7 +2161,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
AudioConfigurationTuple configuration, AudioConfigurationTuple configuration,
int maxAudioBitrate, int maxAudioBitrate,
boolean allowMixedMimeTypeAdaptiveness, boolean allowMixedMimeTypeAdaptiveness,
boolean allowMixedSampleRateAdaptiveness) { boolean allowMixedSampleRateAdaptiveness,
boolean allowAudioMixedChannelCountAdaptiveness) {
int count = 0; int count = 0;
for (int i = 0; i < group.length; i++) { for (int i = 0; i < group.length; i++) {
if (isSupportedAdaptiveAudioTrack( if (isSupportedAdaptiveAudioTrack(
...@@ -2078,7 +2171,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -2078,7 +2171,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
configuration, configuration,
maxAudioBitrate, maxAudioBitrate,
allowMixedMimeTypeAdaptiveness, allowMixedMimeTypeAdaptiveness,
allowMixedSampleRateAdaptiveness)) { allowMixedSampleRateAdaptiveness,
allowAudioMixedChannelCountAdaptiveness)) {
count++; count++;
} }
} }
...@@ -2091,11 +2185,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -2091,11 +2185,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
AudioConfigurationTuple configuration, AudioConfigurationTuple configuration,
int maxAudioBitrate, int maxAudioBitrate,
boolean allowMixedMimeTypeAdaptiveness, boolean allowMixedMimeTypeAdaptiveness,
boolean allowMixedSampleRateAdaptiveness) { boolean allowMixedSampleRateAdaptiveness,
boolean allowAudioMixedChannelCountAdaptiveness) {
return isSupported(formatSupport, false) return isSupported(formatSupport, false)
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= maxAudioBitrate) && (format.bitrate == Format.NO_VALUE || format.bitrate <= maxAudioBitrate)
&& (format.channelCount != Format.NO_VALUE && (allowAudioMixedChannelCountAdaptiveness
&& format.channelCount == configuration.channelCount) || (format.channelCount != Format.NO_VALUE
&& format.channelCount == configuration.channelCount))
&& (allowMixedMimeTypeAdaptiveness && (allowMixedMimeTypeAdaptiveness
|| (format.sampleMimeType != null || (format.sampleMimeType != null
&& TextUtils.equals(format.sampleMimeType, configuration.mimeType))) && TextUtils.equals(format.sampleMimeType, configuration.mimeType)))
......
...@@ -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;
......
...@@ -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 android.text.TextUtils; import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
import android.util.Pair; import android.util.Pair;
...@@ -47,6 +48,7 @@ import java.util.List; ...@@ -47,6 +48,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
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;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
...@@ -189,9 +191,9 @@ public class DashManifestParser extends DefaultHandler ...@@ -189,9 +191,9 @@ public class DashManifestParser extends DefaultHandler
long timeShiftBufferDepthMs, long timeShiftBufferDepthMs,
long suggestedPresentationDelayMs, long suggestedPresentationDelayMs,
long publishTimeMs, long publishTimeMs,
ProgramInformation programInformation, @Nullable ProgramInformation programInformation,
UtcTimingElement utcTiming, @Nullable UtcTimingElement utcTiming,
Uri location, @Nullable Uri location,
List<Period> periods) { List<Period> periods) {
return new DashManifest( return new DashManifest(
availabilityStartTime, availabilityStartTime,
...@@ -259,8 +261,9 @@ public class DashManifestParser extends DefaultHandler ...@@ -259,8 +261,9 @@ public class DashManifestParser extends DefaultHandler
// AdaptationSet parsing. // AdaptationSet parsing.
protected AdaptationSet parseAdaptationSet(XmlPullParser xpp, String baseUrl, protected AdaptationSet parseAdaptationSet(
SegmentBase segmentBase) throws XmlPullParserException, IOException { XmlPullParser xpp, String baseUrl, @Nullable SegmentBase segmentBase)
throws XmlPullParserException, IOException {
int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET); int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET);
int contentType = parseContentType(xpp); int contentType = parseContentType(xpp);
...@@ -394,8 +397,8 @@ public class DashManifestParser extends DefaultHandler ...@@ -394,8 +397,8 @@ public class DashManifestParser extends DefaultHandler
* @return The scheme type and/or {@link SchemeData} parsed from the ContentProtection element. * @return The scheme type and/or {@link SchemeData} parsed from the ContentProtection element.
* Either or both may be null, depending on the ContentProtection element being parsed. * Either or both may be null, depending on the ContentProtection element being parsed.
*/ */
protected Pair<String, SchemeData> parseContentProtection(XmlPullParser xpp) protected Pair<@NullableType String, @NullableType SchemeData> parseContentProtection(
throws XmlPullParserException, IOException { XmlPullParser xpp) throws XmlPullParserException, IOException {
String schemeType = null; String schemeType = null;
String licenseServerUrl = null; String licenseServerUrl = null;
byte[] data = null; byte[] data = null;
...@@ -477,19 +480,19 @@ public class DashManifestParser extends DefaultHandler ...@@ -477,19 +480,19 @@ public class DashManifestParser extends DefaultHandler
protected RepresentationInfo parseRepresentation( protected RepresentationInfo parseRepresentation(
XmlPullParser xpp, XmlPullParser xpp,
String baseUrl, String baseUrl,
String label, @Nullable String label,
String adaptationSetMimeType, @Nullable String adaptationSetMimeType,
String adaptationSetCodecs, @Nullable String adaptationSetCodecs,
int adaptationSetWidth, int adaptationSetWidth,
int adaptationSetHeight, int adaptationSetHeight,
float adaptationSetFrameRate, float adaptationSetFrameRate,
int adaptationSetAudioChannels, int adaptationSetAudioChannels,
int adaptationSetAudioSamplingRate, int adaptationSetAudioSamplingRate,
String adaptationSetLanguage, @Nullable String adaptationSetLanguage,
List<Descriptor> adaptationSetRoleDescriptors, List<Descriptor> adaptationSetRoleDescriptors,
List<Descriptor> adaptationSetAccessibilityDescriptors, List<Descriptor> adaptationSetAccessibilityDescriptors,
List<Descriptor> adaptationSetSupplementalProperties, List<Descriptor> adaptationSetSupplementalProperties,
SegmentBase segmentBase) @Nullable SegmentBase segmentBase)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id"); String id = xpp.getAttributeValue(null, "id");
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
...@@ -564,19 +567,19 @@ public class DashManifestParser extends DefaultHandler ...@@ -564,19 +567,19 @@ public class DashManifestParser extends DefaultHandler
} }
protected Format buildFormat( protected Format buildFormat(
String id, @Nullable String id,
String label, @Nullable String label,
String containerMimeType, @Nullable String containerMimeType,
int width, int width,
int height, int height,
float frameRate, float frameRate,
int audioChannels, int audioChannels,
int audioSamplingRate, int audioSamplingRate,
int bitrate, int bitrate,
String language, @Nullable String language,
List<Descriptor> roleDescriptors, List<Descriptor> roleDescriptors,
List<Descriptor> accessibilityDescriptors, List<Descriptor> accessibilityDescriptors,
String codecs, @Nullable String codecs,
List<Descriptor> supplementalProperties) { List<Descriptor> supplementalProperties) {
String sampleMimeType = getSampleMimeType(containerMimeType, codecs); String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
@C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors); @C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors);
...@@ -650,7 +653,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -650,7 +653,7 @@ public class DashManifestParser extends DefaultHandler
protected Representation buildRepresentation( protected Representation buildRepresentation(
RepresentationInfo representationInfo, RepresentationInfo representationInfo,
String extraDrmSchemeType, @Nullable String extraDrmSchemeType,
ArrayList<SchemeData> extraDrmSchemeDatas, ArrayList<SchemeData> extraDrmSchemeDatas,
ArrayList<Descriptor> extraInbandEventStreams) { ArrayList<Descriptor> extraInbandEventStreams) {
Format format = representationInfo.format; Format format = representationInfo.format;
...@@ -675,7 +678,8 @@ public class DashManifestParser extends DefaultHandler ...@@ -675,7 +678,8 @@ public class DashManifestParser extends DefaultHandler
// SegmentBase, SegmentList and SegmentTemplate parsing. // SegmentBase, SegmentList and SegmentTemplate parsing.
protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, SingleSegmentBase parent) protected SingleSegmentBase parseSegmentBase(
XmlPullParser xpp, @Nullable SingleSegmentBase parent)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
...@@ -711,7 +715,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -711,7 +715,7 @@ public class DashManifestParser extends DefaultHandler
indexLength); indexLength);
} }
protected SegmentList parseSegmentList(XmlPullParser xpp, SegmentList parent) protected SegmentList parseSegmentList(XmlPullParser xpp, @Nullable SegmentList parent)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
...@@ -756,15 +760,15 @@ public class DashManifestParser extends DefaultHandler ...@@ -756,15 +760,15 @@ public class DashManifestParser extends DefaultHandler
long presentationTimeOffset, long presentationTimeOffset,
long startNumber, long startNumber,
long duration, long duration,
List<SegmentTimelineElement> timeline, @Nullable List<SegmentTimelineElement> timeline,
List<RangedUri> segments) { @Nullable List<RangedUri> segments) {
return new SegmentList(initialization, timescale, presentationTimeOffset, return new SegmentList(initialization, timescale, presentationTimeOffset,
startNumber, duration, timeline, segments); startNumber, duration, timeline, segments);
} }
protected SegmentTemplate parseSegmentTemplate( protected SegmentTemplate parseSegmentTemplate(
XmlPullParser xpp, XmlPullParser xpp,
SegmentTemplate parent, @Nullable SegmentTemplate parent,
List<Descriptor> adaptationSetSupplementalProperties) List<Descriptor> adaptationSetSupplementalProperties)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
...@@ -819,8 +823,8 @@ public class DashManifestParser extends DefaultHandler ...@@ -819,8 +823,8 @@ public class DashManifestParser extends DefaultHandler
long endNumber, long endNumber,
long duration, long duration,
List<SegmentTimelineElement> timeline, List<SegmentTimelineElement> timeline,
UrlTemplate initializationTemplate, @Nullable UrlTemplate initializationTemplate,
UrlTemplate mediaTemplate) { @Nullable UrlTemplate mediaTemplate) {
return new SegmentTemplate( return new SegmentTemplate(
initialization, initialization,
timescale, timescale,
...@@ -1008,8 +1012,9 @@ public class DashManifestParser extends DefaultHandler ...@@ -1008,8 +1012,9 @@ public class DashManifestParser extends DefaultHandler
return new SegmentTimelineElement(elapsedTime, duration); return new SegmentTimelineElement(elapsedTime, duration);
} }
protected UrlTemplate parseUrlTemplate(XmlPullParser xpp, String name, @Nullable
UrlTemplate defaultValue) { protected UrlTemplate parseUrlTemplate(
XmlPullParser xpp, String name, @Nullable UrlTemplate defaultValue) {
String valueString = xpp.getAttributeValue(null, name); String valueString = xpp.getAttributeValue(null, name);
if (valueString != null) { if (valueString != null) {
return UrlTemplate.compile(valueString); return UrlTemplate.compile(valueString);
...@@ -1126,7 +1131,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -1126,7 +1131,7 @@ public class DashManifestParser extends DefaultHandler
} }
@C.RoleFlags @C.RoleFlags
protected int parseDashRoleSchemeValue(String value) { protected int parseDashRoleSchemeValue(@Nullable String value) {
if (value == null) { if (value == null) {
return 0; return 0;
} }
...@@ -1159,7 +1164,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -1159,7 +1164,7 @@ public class DashManifestParser extends DefaultHandler
} }
@C.RoleFlags @C.RoleFlags
protected int parseTvaAudioPurposeCsValue(String value) { protected int parseTvaAudioPurposeCsValue(@Nullable String value) {
if (value == null) { if (value == null) {
return 0; return 0;
} }
...@@ -1230,7 +1235,9 @@ public class DashManifestParser extends DefaultHandler ...@@ -1230,7 +1235,9 @@ public class DashManifestParser extends DefaultHandler
* @param codecs The codecs attribute. * @param codecs The codecs attribute.
* @return The derived sample mimeType, or null if it could not be derived. * @return The derived sample mimeType, or null if it could not be derived.
*/ */
private static String getSampleMimeType(String containerMimeType, String codecs) { @Nullable
private static String getSampleMimeType(
@Nullable String containerMimeType, @Nullable String codecs) {
if (MimeTypes.isAudio(containerMimeType)) { if (MimeTypes.isAudio(containerMimeType)) {
return MimeTypes.getAudioMediaMimeType(codecs); return MimeTypes.getAudioMediaMimeType(codecs);
} else if (MimeTypes.isVideo(containerMimeType)) { } else if (MimeTypes.isVideo(containerMimeType)) {
...@@ -1264,7 +1271,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -1264,7 +1271,7 @@ public class DashManifestParser extends DefaultHandler
* @param mimeType The mimeType. * @param mimeType The mimeType.
* @return Whether the mimeType is a text sample mimeType. * @return Whether the mimeType is a text sample mimeType.
*/ */
private static boolean mimeTypeIsRawText(String mimeType) { private static boolean mimeTypeIsRawText(@Nullable String mimeType) {
return MimeTypes.isText(mimeType) return MimeTypes.isText(mimeType)
|| MimeTypes.APPLICATION_TTML.equals(mimeType) || MimeTypes.APPLICATION_TTML.equals(mimeType)
|| MimeTypes.APPLICATION_MP4VTT.equals(mimeType) || MimeTypes.APPLICATION_MP4VTT.equals(mimeType)
...@@ -1273,16 +1280,18 @@ public class DashManifestParser extends DefaultHandler ...@@ -1273,16 +1280,18 @@ public class DashManifestParser extends DefaultHandler
} }
/** /**
* Checks two languages for consistency, returning the consistent language, or throwing an * Checks two languages for consistency, returning the consistent language, or throwing an {@link
* {@link IllegalStateException} if the languages are inconsistent. * IllegalStateException} if the languages are inconsistent.
* <p> *
* Two languages are consistent if they are equal, or if one is null. * <p>Two languages are consistent if they are equal, or if one is null.
* *
* @param firstLanguage The first language. * @param firstLanguage The first language.
* @param secondLanguage The second language. * @param secondLanguage The second language.
* @return The consistent language. * @return The consistent language.
*/ */
private static String checkLanguageConsistency(String firstLanguage, String secondLanguage) { @Nullable
private static String checkLanguageConsistency(
@Nullable String firstLanguage, @Nullable String secondLanguage) {
if (firstLanguage == null) { if (firstLanguage == null) {
return secondLanguage; return secondLanguage;
} else if (secondLanguage == null) { } else if (secondLanguage == null) {
...@@ -1485,14 +1494,19 @@ public class DashManifestParser extends DefaultHandler ...@@ -1485,14 +1494,19 @@ public class DashManifestParser extends DefaultHandler
public final Format format; public final Format format;
public final String baseUrl; public final String baseUrl;
public final SegmentBase segmentBase; public final SegmentBase segmentBase;
public final String drmSchemeType; @Nullable public final String drmSchemeType;
public final ArrayList<SchemeData> drmSchemeDatas; public final ArrayList<SchemeData> drmSchemeDatas;
public final ArrayList<Descriptor> inbandEventStreams; public final ArrayList<Descriptor> inbandEventStreams;
public final long revisionId; public final long revisionId;
public RepresentationInfo(Format format, String baseUrl, SegmentBase segmentBase, public RepresentationInfo(
String drmSchemeType, ArrayList<SchemeData> drmSchemeDatas, Format format,
ArrayList<Descriptor> inbandEventStreams, long revisionId) { String baseUrl,
SegmentBase segmentBase,
@Nullable String drmSchemeType,
ArrayList<SchemeData> drmSchemeDatas,
ArrayList<Descriptor> inbandEventStreams,
long revisionId) {
this.format = format; this.format = format;
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.segmentBase = segmentBase; this.segmentBase = segmentBase;
......
...@@ -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