Commit 0c4df84e by Yannick RUI

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

# Conflicts:
#	library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java
parents 831de75f 8967dd9c
Showing with 595 additions and 365 deletions
......@@ -27,6 +27,10 @@
over other selection parameters.
* Remove `AnalyticsCollector.Factory`. Instances can be created directly and
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 ###
......
......@@ -24,7 +24,6 @@ include modulePrefix + 'library-hls'
include modulePrefix + 'library-smoothstreaming'
include modulePrefix + 'library-ui'
include modulePrefix + 'testutils'
include modulePrefix + 'testutils-robolectric'
include modulePrefix + 'extension-ffmpeg'
include modulePrefix + 'extension-flac'
include modulePrefix + 'extension-gvr'
......@@ -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-ui').projectDir = new File(rootDir, 'library/ui')
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-flac').projectDir = new File(rootDir, 'extensions/flac')
project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr')
......
......@@ -37,7 +37,8 @@ dependencies {
implementation project(modulePrefix + 'library-ui')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -36,7 +36,8 @@ dependencies {
implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'library')
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -40,7 +40,8 @@ dependencies {
implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -43,7 +43,8 @@ dependencies {
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
androidTestImplementation project(modulePrefix + 'testutils')
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -32,11 +32,12 @@ android {
}
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 'androidx.annotation:annotation:1.1.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 {
......
......@@ -40,7 +40,8 @@ android {
dependencies {
implementation project(modulePrefix + 'library-core')
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.ext:junit:' + androidXTestVersion
}
......
......@@ -34,7 +34,8 @@ dependencies {
implementation project(modulePrefix + 'library-core')
implementation 'net.butterflytv.utils:rtmp-client:3.0.1'
implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -40,7 +40,8 @@ android {
dependencies {
implementation project(modulePrefix + 'library-core')
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.ext:junit:' + androidXTestVersion
androidTestImplementation 'com.google.truth:truth:' + truthVersion
......
......@@ -174,8 +174,8 @@ public class LibvpxVideoRenderer extends BaseRenderer {
*/
public LibvpxVideoRenderer(
long allowedJoiningTimeMs,
Handler eventHandler,
VideoRendererEventListener eventListener,
@Nullable Handler eventHandler,
@Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify) {
this(
allowedJoiningTimeMs,
......@@ -206,10 +206,10 @@ public class LibvpxVideoRenderer extends BaseRenderer {
*/
public LibvpxVideoRenderer(
long allowedJoiningTimeMs,
Handler eventHandler,
VideoRendererEventListener eventListener,
@Nullable Handler eventHandler,
@Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify,
DrmSessionManager<ExoMediaCrypto> drmSessionManager,
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys,
boolean disableLoopFilter) {
this(
......@@ -249,10 +249,10 @@ public class LibvpxVideoRenderer extends BaseRenderer {
*/
public LibvpxVideoRenderer(
long allowedJoiningTimeMs,
Handler eventHandler,
VideoRendererEventListener eventListener,
@Nullable Handler eventHandler,
@Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify,
DrmSessionManager<ExoMediaCrypto> drmSessionManager,
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys,
boolean disableLoopFilter,
boolean enableRowMultiThreadMode,
......@@ -847,7 +847,7 @@ public class LibvpxVideoRenderer extends BaseRenderer {
pendingFormat = null;
}
inputBuffer.flip();
inputBuffer.colorInfo = formatHolder.format.colorInfo;
inputBuffer.colorInfo = format.colorInfo;
onQueueInputBuffer(inputBuffer);
decoder.queueInputBuffer(inputBuffer);
buffersInCodecCount++;
......
......@@ -33,7 +33,7 @@ import java.nio.ByteBuffer;
private static final int DECODE_ERROR = 1;
private static final int DRM_ERROR = 2;
private final ExoMediaCrypto exoMediaCrypto;
@Nullable private final ExoMediaCrypto exoMediaCrypto;
private final long vpxDecContext;
@C.VideoOutputMode private volatile int outputMode;
......@@ -55,7 +55,7 @@ import java.nio.ByteBuffer;
int numInputBuffers,
int numOutputBuffers,
int initialInputBufferSize,
ExoMediaCrypto exoMediaCrypto,
@Nullable ExoMediaCrypto exoMediaCrypto,
boolean disableLoopFilter,
boolean enableRowMultiThreadMode,
int threads)
......@@ -170,9 +170,19 @@ import java.nio.ByteBuffer;
private native long vpxClose(long context);
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,
int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData);
private native long vpxSecureDecode(
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);
/**
......
......@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.vp9;
import android.content.Context;
import android.opengl.GLSurfaceView;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
/**
......@@ -27,10 +28,10 @@ public class VpxVideoSurfaceView extends GLSurfaceView implements VpxOutputBuffe
private final VpxRenderer renderer;
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);
renderer = new VpxRenderer();
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 {
}
test {
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 {
private int pendingMetadataCount;
private MetadataDecoder decoder;
private boolean inputStreamEnded;
private long subsampleOffsetUs;
/**
* @param output The output.
......@@ -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
// pass the buffer to the decoder and discard the output.
} else {
buffer.subsampleOffsetUs = formatHolder.format.subsampleOffsetUs;
buffer.subsampleOffsetUs = subsampleOffsetUs;
buffer.flip();
int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT;
Metadata metadata = decoder.decode(buffer);
......@@ -130,6 +131,8 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
pendingMetadataCount++;
}
}
} else if (result == C.RESULT_FORMAT_READ) {
subsampleOffsetUs = formatHolder.format.subsampleOffsetUs;
}
}
......
......@@ -15,43 +15,34 @@
*/
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.MetadataDecoder;
import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
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.Util;
import java.nio.ByteBuffer;
import java.util.Arrays;
/** Decodes data encoded by {@link EventMessageEncoder}. */
public final class EventMessageDecoder implements MetadataDecoder {
private static final String TAG = "EventMessageDecoder";
@SuppressWarnings("ByteBufferBackingArray")
@Override
public Metadata decode(MetadataInputBuffer inputBuffer) {
ByteBuffer buffer = inputBuffer.data;
byte[] data = buffer.array();
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 value = Assertions.checkNotNull(emsgData.readNullTerminatedString());
long timescale = 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 durationMs = emsgData.readUnsignedInt();
long id = emsgData.readUnsignedInt();
byte[] messageData = Arrays.copyOfRange(data, emsgData.getPosition(), size);
return new Metadata(new EventMessage(schemeIdUri, value, durationMs, id, messageData));
byte[] messageData =
Arrays.copyOfRange(emsgData.data, emsgData.getPosition(), emsgData.limit());
return new EventMessage(schemeIdUri, value, durationMs, id, messageData);
}
}
......@@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer2.metadata.emsg;
import androidx.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
......@@ -40,15 +39,12 @@ public final class EventMessageEncoder {
* @param eventMessage The event message to be encoded.
* @return The serialized byte array.
*/
@Nullable
public byte[] encode(EventMessage eventMessage) {
byteArrayOutputStream.reset();
try {
writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri);
String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
writeNullTerminatedString(dataOutputStream, nonNullValue);
writeUnsignedInt(dataOutputStream, 1000); // timescale
writeUnsignedInt(dataOutputStream, 0); // presentation_time_delta
writeUnsignedInt(dataOutputStream, eventMessage.durationMs);
writeUnsignedInt(dataOutputStream, eventMessage.id);
dataOutputStream.write(eventMessage.messageData);
......
......@@ -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
* if a new sample stream is created.
*
* <p>Note that previously received {@link TrackSelection TrackSelections} are no longer valid and
* references need to be replaced even if the corresponding {@link SampleStream} is kept.
* <p>Note that previously passed {@link TrackSelection TrackSelections} are no longer valid, and
* 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.
*
* @param selections The renderer track selections.
* @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
* that the caller does not require that the sample stream be recreated.
* for each track selection. A {@code true} value indicates that the selection is equivalent
* 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
* selections.
* @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that
......
......@@ -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.
*/
public Builder setPreferredAudioLanguage(@Nullable String preferredAudioLanguage) {
......@@ -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.
*/
public Builder setPreferredTextLanguage(@Nullable String preferredTextLanguage) {
......@@ -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.
*/
public Builder setSelectUndeterminedTextLanguage(boolean selectUndeterminedTextLanguage) {
......@@ -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.
*/
public Builder setDisabledTextTrackSelectionFlags(
......
......@@ -15,6 +15,8 @@
*/
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 androidx.test.ext.junit.runners.AndroidJUnit4;
......@@ -30,18 +32,19 @@ public final class EventMessageDecoderTest {
@Test
public void testDecodeEventMessage() {
byte[] rawEmsgBody = new byte[] {
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
49, 50, 51, 0, // value = "123"
0, 0, -69, -128, // timescale = 48000
0, 0, -69, -128, // presentation_time_delta = 48000
0, 2, 50, -128, // event_duration = 144000
0, 15, 67, -45, // id = 1000403
0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4}
byte[] rawEmsgBody =
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}
EventMessageDecoder decoder = new EventMessageDecoder();
MetadataInputBuffer buffer = new MetadataInputBuffer();
buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody);
Metadata metadata = decoder.decode(buffer);
assertThat(metadata.length()).isEqualTo(1);
EventMessage eventMessage = (EventMessage) metadata.get(0);
assertThat(eventMessage.schemeIdUri).isEqualTo("urn:test");
......
......@@ -15,6 +15,8 @@
*/
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 androidx.test.ext.junit.runners.AndroidJUnit4;
......@@ -29,67 +31,52 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
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
public void testEncodeEventStream() 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}
byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage);
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
byte[] foo = new byte[] {1, 2, 3};
byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE);
assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE);
}
@Test
public void testEncodeDecodeEventStream() throws IOException {
EventMessage expectedEmsg =
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg);
byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE);
MetadataInputBuffer buffer = new MetadataInputBuffer();
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
EventMessageDecoder decoder = new EventMessageDecoder();
Metadata metadata = decoder.decode(buffer);
assertThat(metadata.length()).isEqualTo(1);
assertThat(metadata.get(0)).isEqualTo(expectedEmsg);
assertThat(metadata.get(0)).isEqualTo(DECODED_MESSAGE);
}
@Test
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 =
new EventMessage("urn:test", "123", 3000, 1000402, new byte[] {4, 3, 2, 1, 0});
byte[] expectedEmsgBody1 =
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, -46, // id = 1000402
4, 3, 2, 1, 0
}; // message_data = {4, 3, 2, 1, 0}
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, 210), // id = 1000402
createByteArray(4, 3, 2, 1, 0)); // message_data = {4, 3, 2, 1, 0}
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage);
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
byte[] encodedByteArray = eventMessageEncoder.encode(DECODED_MESSAGE);
assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE);
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1);
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
}
......
......@@ -148,6 +148,7 @@ public final class DefaultTrackSelectorTest {
/* exceedAudioConstraintsIfNecessary= */ false,
/* allowAudioMixedMimeTypeAdaptiveness= */ true,
/* allowAudioMixedSampleRateAdaptiveness= */ false,
/* allowAudioMixedChannelCountAdaptiveness= */ true,
// Text
/* preferredTextLanguage= */ "de",
/* selectUndeterminedTextLanguage= */ true,
......
......@@ -41,8 +41,10 @@ android {
dependencies {
implementation project(modulePrefix + 'library-core')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -60,6 +60,7 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** A DASH {@link MediaPeriod}. */
/* package */ final class DashMediaPeriod
......@@ -245,8 +246,12 @@ import java.util.regex.Pattern;
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
public long selectTracks(
@NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections);
releaseDisabledStreams(selections, mayRetainStreamFlags, streams);
releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex);
......
......@@ -130,7 +130,7 @@ public final class DashMediaSource extends BaseMediaSource {
* @return This factory, for convenience.
* @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);
this.tag = tag;
return this;
......@@ -430,8 +430,8 @@ public final class DashMediaSource extends BaseMediaSource {
public DashMediaSource(
DashManifest manifest,
DashChunkSource.Factory chunkSourceFactory,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
manifest,
chunkSourceFactory,
......@@ -455,8 +455,8 @@ public final class DashMediaSource extends BaseMediaSource {
DashManifest manifest,
DashChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
manifest,
/* manifestUri= */ null,
......@@ -492,8 +492,8 @@ public final class DashMediaSource extends BaseMediaSource {
Uri manifestUri,
DataSource.Factory manifestDataSourceFactory,
DashChunkSource.Factory chunkSourceFactory,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
manifestUri,
manifestDataSourceFactory,
......@@ -529,8 +529,8 @@ public final class DashMediaSource extends BaseMediaSource {
DashChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount,
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
manifestUri,
manifestDataSourceFactory,
......@@ -569,8 +569,8 @@ public final class DashMediaSource extends BaseMediaSource {
DashChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount,
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
/* manifest= */ null,
manifestUri,
......@@ -591,10 +591,10 @@ public final class DashMediaSource extends BaseMediaSource {
}
private DashMediaSource(
DashManifest manifest,
Uri manifestUri,
DataSource.Factory manifestDataSourceFactory,
ParsingLoadable.Parser<? extends DashManifest> manifestParser,
@Nullable DashManifest manifest,
@Nullable Uri manifestUri,
@Nullable DataSource.Factory manifestDataSourceFactory,
@Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser,
DashChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
DrmSessionManager<?> drmSessionManager,
......
......@@ -66,7 +66,8 @@ public final class DashUtil {
* @throws IOException Thrown when there is an error while loading.
* @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 {
int primaryTrackType = C.TRACK_TYPE_VIDEO;
Representation representation = getFirstRepresentation(period, primaryTrackType);
......@@ -95,7 +96,8 @@ public final class DashUtil {
* @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted.
*/
public static @Nullable Format loadSampleFormat(
@Nullable
public static Format loadSampleFormat(
DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
......@@ -116,7 +118,8 @@ public final class DashUtil {
* @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted.
*/
public static @Nullable ChunkIndex loadChunkIndex(
@Nullable
public static ChunkIndex loadChunkIndex(
DataSource dataSource, int trackType, Representation representation)
throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
......@@ -138,7 +141,8 @@ public final class DashUtil {
* @throws IOException Thrown when there is an error while loading.
* @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)
throws IOException, InterruptedException {
RangedUri initializationUri = representation.getInitializationUri();
......@@ -187,7 +191,8 @@ public final class DashUtil {
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);
if (index == C.INDEX_UNSET) {
return null;
......@@ -197,5 +202,4 @@ public final class DashUtil {
}
private DashUtil() {}
}
......@@ -67,7 +67,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
private final int maxSegmentsPerLoad;
public Factory(DataSource.Factory dataSourceFactory) {
this(dataSourceFactory, 1);
this(dataSourceFactory, /* maxSegmentsPerLoad= */ 1);
}
public Factory(DataSource.Factory dataSourceFactory, int maxSegmentsPerLoad) {
......@@ -633,7 +633,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
Representation representation,
boolean enableEventMessageTrack,
List<Format> closedCaptionFormats,
TrackOutput playerEmsgTrackOutput) {
@Nullable TrackOutput playerEmsgTrackOutput) {
this(
periodDurationUs,
representation,
......@@ -787,7 +787,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
Representation representation,
boolean enableEventMessageTrack,
List<Format> closedCaptionFormats,
TrackOutput playerEmsgTrackOutput) {
@Nullable TrackOutput playerEmsgTrackOutput) {
String containerMimeType = representation.format.containerMimeType;
if (mimeTypeIsRawText(containerMimeType)) {
return null;
......
......@@ -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
* 4.7.2.
*/
public final UtcTimingElement utcTiming;
@Nullable public final UtcTimingElement utcTiming;
/**
* The location of this manifest.
*/
public final Uri location;
/** The location of this manifest, or null if not present. */
@Nullable public final Uri location;
/** The {@link ProgramInformation}, or null if not present. */
@Nullable public final ProgramInformation programInformation;
......@@ -106,8 +104,8 @@ public class DashManifest implements FilterableManifest<DashManifest> {
long timeShiftBufferDepthMs,
long suggestedPresentationDelayMs,
long publishTimeMs,
UtcTimingElement utcTiming,
Uri location,
@Nullable UtcTimingElement utcTiming,
@Nullable Uri location,
List<Period> periods) {
this(
availabilityStartTimeMs,
......@@ -134,8 +132,8 @@ public class DashManifest implements FilterableManifest<DashManifest> {
long suggestedPresentationDelayMs,
long publishTimeMs,
@Nullable ProgramInformation programInformation,
UtcTimingElement utcTiming,
Uri location,
@Nullable UtcTimingElement utcTiming,
@Nullable Uri location,
List<Period> periods) {
this.availabilityStartTimeMs = availabilityStartTimeMs;
this.durationMs = durationMs;
......
......@@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer2.source.dash.manifest;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Util;
......@@ -24,10 +23,8 @@ import com.google.android.exoplayer2.util.Util;
*/
public final class Descriptor {
/**
* The scheme URI.
*/
@NonNull public final String schemeIdUri;
/** The scheme URI. */
public final String schemeIdUri;
/**
* The value, or null.
*/
......@@ -42,7 +39,7 @@ public final class Descriptor {
* @param value The value, 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.value = value;
this.id = id;
......@@ -63,10 +60,9 @@ public final class Descriptor {
@Override
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 + (id != null ? id.hashCode() : 0);
return result;
}
}
......@@ -21,22 +21,26 @@ import com.google.android.exoplayer2.util.Util;
/** A parsed program information element. */
public class ProgramInformation {
/** The title for the media presentation. */
public final String title;
@Nullable public final String title;
/** 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. */
public final String copyright;
@Nullable public final String copyright;
/** 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. */
public final String lang;
@Nullable public final String lang;
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.source = source;
this.copyright = copyright;
......
......@@ -83,7 +83,7 @@ public final class RangedUri {
* <p>If {@code other} is null then the merge is considered unsuccessful, and null is returned.
*
* @param other The {@link RangedUri} to merge.
* @param baseUri The optional base Uri.
* @param baseUri The base Uri.
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise.
*/
@Nullable
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.dash.manifest;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
......@@ -53,9 +54,7 @@ public abstract class Representation {
* The offset of the presentation timestamps in the media stream relative to media time.
*/
public final long presentationTimeOffsetUs;
/**
* The in-band event streams in the representation. Never null, but may be empty.
*/
/** The in-band event streams in the representation. May be empty. */
public final List<Descriptor> inbandEventStreams;
private final RangedUri initializationUri;
......@@ -71,7 +70,7 @@ public abstract class Representation {
*/
public static Representation newInstance(
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 {
Format format,
String baseUrl,
SegmentBase segmentBase,
List<Descriptor> inbandEventStreams) {
return newInstance(revisionId, format, baseUrl, segmentBase, inbandEventStreams, null);
@Nullable List<Descriptor> inbandEventStreams) {
return newInstance(
revisionId, format, baseUrl, segmentBase, inbandEventStreams, /* cacheKey= */ null);
}
/**
......@@ -110,8 +110,8 @@ public abstract class Representation {
Format format,
String baseUrl,
SegmentBase segmentBase,
List<Descriptor> inbandEventStreams,
String cacheKey) {
@Nullable List<Descriptor> inbandEventStreams,
@Nullable String cacheKey) {
if (segmentBase instanceof SingleSegmentBase) {
return new SingleSegmentRepresentation(
revisionId,
......@@ -135,7 +135,7 @@ public abstract class Representation {
Format format,
String baseUrl,
SegmentBase segmentBase,
List<Descriptor> inbandEventStreams) {
@Nullable List<Descriptor> inbandEventStreams) {
this.revisionId = revisionId;
this.format = format;
this.baseUrl = baseUrl;
......@@ -151,6 +151,7 @@ public abstract class Representation {
* Returns a {@link RangedUri} defining the location of the representation's initialization data,
* or null if no initialization data exists.
*/
@Nullable
public RangedUri getInitializationUri() {
return initializationUri;
}
......@@ -159,14 +160,15 @@ public abstract class Representation {
* Returns a {@link RangedUri} defining the location of the representation's segment index, or
* null if the representation provides an index directly.
*/
@Nullable
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();
/** Returns a cache key for the representation if set, or null. */
@Nullable
public abstract String getCacheKey();
/**
......@@ -184,9 +186,9 @@ public abstract class Representation {
*/
public final long contentLength;
private final String cacheKey;
private final RangedUri indexUri;
private final SingleSegmentIndex segmentIndex;
@Nullable private final String cacheKey;
@Nullable private final RangedUri indexUri;
@Nullable private final SingleSegmentIndex segmentIndex;
/**
* @param revisionId Identifies the revision of the content.
......@@ -209,7 +211,7 @@ public abstract class Representation {
long indexStart,
long indexEnd,
List<Descriptor> inbandEventStreams,
String cacheKey,
@Nullable String cacheKey,
long contentLength) {
RangedUri rangedUri = new RangedUri(null, initializationStart,
initializationEnd - initializationStart + 1);
......@@ -233,8 +235,8 @@ public abstract class Representation {
Format format,
String baseUrl,
SingleSegmentBase segmentBase,
List<Descriptor> inbandEventStreams,
String cacheKey,
@Nullable List<Descriptor> inbandEventStreams,
@Nullable String cacheKey,
long contentLength) {
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
this.uri = Uri.parse(baseUrl);
......@@ -248,16 +250,19 @@ public abstract class Representation {
}
@Override
@Nullable
public RangedUri getIndexUri() {
return indexUri;
}
@Override
@Nullable
public DashSegmentIndex getIndex() {
return segmentIndex;
}
@Override
@Nullable
public String getCacheKey() {
return cacheKey;
}
......@@ -284,12 +289,13 @@ public abstract class Representation {
Format format,
String baseUrl,
MultiSegmentBase segmentBase,
List<Descriptor> inbandEventStreams) {
@Nullable List<Descriptor> inbandEventStreams) {
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
this.segmentBase = segmentBase;
}
@Override
@Nullable
public RangedUri getIndexUri() {
return null;
}
......@@ -300,6 +306,7 @@ public abstract class Representation {
}
@Override
@Nullable
public String getCacheKey() {
return null;
}
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source.dash.manifest;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
import com.google.android.exoplayer2.util.Util;
......@@ -25,7 +26,7 @@ import java.util.List;
*/
public abstract class SegmentBase {
/* package */ final RangedUri initialization;
/* package */ @Nullable final RangedUri initialization;
/* package */ final long timescale;
/* package */ final long presentationTimeOffset;
......@@ -36,7 +37,8 @@ public abstract class SegmentBase {
* @param presentationTimeOffset The presentation time offset. The value in seconds is the
* 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.timescale = timescale;
this.presentationTimeOffset = presentationTimeOffset;
......@@ -49,6 +51,7 @@ public abstract class SegmentBase {
* @param representation The {@link Representation} for which initialization data is required.
* @return A {@link RangedUri} defining the location of the initialization data, or null.
*/
@Nullable
public RangedUri getInitialization(Representation representation) {
return initialization;
}
......@@ -77,19 +80,31 @@ public abstract class SegmentBase {
* @param indexStart The byte offset of the index data in the segment.
* @param indexLength The length of the index data in bytes.
*/
public SingleSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset,
long indexStart, long indexLength) {
public SingleSegmentBase(
@Nullable RangedUri initialization,
long timescale,
long presentationTimeOffset,
long indexStart,
long indexLength) {
super(initialization, timescale, presentationTimeOffset);
this.indexStart = indexStart;
this.indexLength = indexLength;
}
public SingleSegmentBase() {
this(null, 1, 0, 0, 0);
this(
/* initialization= */ null,
/* timescale= */ 1,
/* presentationTimeOffset= */ 0,
/* indexStart= */ 0,
/* indexLength= */ 0);
}
@Nullable
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 {
/* package */ final long startNumber;
/* 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
......@@ -118,12 +133,12 @@ public abstract class SegmentBase {
* parameter.
*/
public MultiSegmentBase(
RangedUri initialization,
@Nullable RangedUri initialization,
long timescale,
long presentationTimeOffset,
long startNumber,
long duration,
List<SegmentTimelineElement> segmentTimeline) {
@Nullable List<SegmentTimelineElement> segmentTimeline) {
super(initialization, timescale, presentationTimeOffset);
this.startNumber = startNumber;
this.duration = duration;
......@@ -223,7 +238,7 @@ public abstract class SegmentBase {
*/
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
......@@ -246,8 +261,8 @@ public abstract class SegmentBase {
long presentationTimeOffset,
long startNumber,
long duration,
List<SegmentTimelineElement> segmentTimeline,
List<RangedUri> mediaSegments) {
@Nullable List<SegmentTimelineElement> segmentTimeline,
@Nullable List<RangedUri> mediaSegments) {
super(initialization, timescale, presentationTimeOffset, startNumber, duration,
segmentTimeline);
this.mediaSegments = mediaSegments;
......@@ -275,8 +290,8 @@ public abstract class SegmentBase {
*/
public static class SegmentTemplate extends MultiSegmentBase {
/* package */ final UrlTemplate initializationTemplate;
/* package */ final UrlTemplate mediaTemplate;
/* package */ @Nullable final UrlTemplate initializationTemplate;
/* package */ @Nullable final UrlTemplate mediaTemplate;
/* package */ final long endNumber;
/**
......@@ -308,9 +323,9 @@ public abstract class SegmentBase {
long startNumber,
long endNumber,
long duration,
List<SegmentTimelineElement> segmentTimeline,
UrlTemplate initializationTemplate,
UrlTemplate mediaTemplate) {
@Nullable List<SegmentTimelineElement> segmentTimeline,
@Nullable UrlTemplate initializationTemplate,
@Nullable UrlTemplate mediaTemplate) {
super(
initialization,
timescale,
......@@ -324,6 +339,7 @@ public abstract class SegmentBase {
}
@Override
@Nullable
public RangedUri getInitialization(Representation representation) {
if (initializationTemplate != null) {
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 {
dependencies {
implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
implementation project(modulePrefix + 'library-core')
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -105,7 +105,8 @@ import javax.crypto.spec.SecretKeySpec;
}
@Override
public final @Nullable Uri getUri() {
@Nullable
public final Uri getUri() {
return upstream.getUri();
}
......
......@@ -84,11 +84,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
@Override
public Result createExtractor(
Extractor previousExtractor,
@Nullable Extractor previousExtractor,
Uri uri,
Format format,
List<Format> muxedCaptionFormats,
DrmInitData drmInitData,
@Nullable List<Format> muxedCaptionFormats,
@Nullable DrmInitData drmInitData,
TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders,
ExtractorInput extractorInput)
......
......@@ -59,10 +59,8 @@ import java.util.Map;
clear();
}
/**
* The chunk to be loaded next.
*/
public Chunk chunk;
/** The chunk to be loaded next. */
@Nullable public Chunk chunk;
/**
* Indicates that the end of the stream has been reached.
......@@ -70,7 +68,7 @@ import java.util.Map;
public boolean endOfStream;
/** Indicates that the chunk source is waiting for the referred playlist to be refreshed. */
public Uri playlistUrl;
@Nullable public Uri playlistUrl;
/**
* Clears the holder.
......@@ -138,7 +136,7 @@ import java.util.Map;
HlsDataSourceFactory dataSourceFactory,
@Nullable TransferListener mediaTransferListener,
TimestampAdjusterProvider timestampAdjusterProvider,
List<Format> muxedCaptionFormats) {
@Nullable List<Format> muxedCaptionFormats) {
this.extractorFactory = extractorFactory;
this.playlistTracker = playlistTracker;
this.playlistUrls = playlistUrls;
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.hls;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.extractor.Extractor;
......@@ -82,11 +83,11 @@ public interface HlsExtractorFactory {
* @throws IOException If an I/O error is encountered while sniffing.
*/
Result createExtractor(
Extractor previousExtractor,
@Nullable Extractor previousExtractor,
Uri uri,
Format format,
List<Format> muxedCaptionFormats,
DrmInitData drmInitData,
@Nullable List<Format> muxedCaptionFormats,
@Nullable DrmInitData drmInitData,
TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders,
ExtractorInput sniffingExtractorInput)
......
......@@ -54,6 +54,7 @@ import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* A {@link MediaPeriod} that loads an HLS stream.
......@@ -249,8 +250,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
public long selectTracks(
@NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
// Map each selection and stream onto a child period index.
int[] streamChildIndices = new int[selections.length];
int[] selectionChildIndices = new int[selections.length];
......
......@@ -110,7 +110,7 @@ public final class HlsMediaSource extends BaseMediaSource
* @return This factory, for convenience.
* @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);
this.tag = tag;
return this;
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source.hls;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
......@@ -49,7 +50,7 @@ public final class WebvttExtractor implements Extractor {
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 final String language;
@Nullable private final String language;
private final TimestampAdjuster timestampAdjuster;
private final ParsableByteArray sampleDataWrapper;
......@@ -58,7 +59,7 @@ public final class WebvttExtractor implements Extractor {
private byte[] sampleData;
private int sampleSize;
public WebvttExtractor(String language, TimestampAdjuster timestampAdjuster) {
public WebvttExtractor(@Nullable String language, TimestampAdjuster timestampAdjuster) {
this.language = language;
this.timestampAdjuster = timestampAdjuster;
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
}
@Override
@Nullable
public HlsMediaPlaylist getPlaylistSnapshot(Uri url, boolean isForPlayback) {
HlsMediaPlaylist snapshot = playlistBundles.get(url).getPlaylistSnapshot();
if (snapshot != null && isForPlayback) {
......@@ -448,7 +449,7 @@ public final class DefaultHlsPlaylistTracker
private final Loader mediaPlaylistLoader;
private final ParsingLoadable<HlsPlaylist> mediaPlaylistLoadable;
private HlsMediaPlaylist playlistSnapshot;
@Nullable private HlsMediaPlaylist playlistSnapshot;
private long lastSnapshotLoadMs;
private long lastSnapshotChangeMs;
private long earliestNextLoadTimeMs;
......@@ -467,6 +468,7 @@ public final class DefaultHlsPlaylistTracker
mediaPlaylistParser);
}
@Nullable
public HlsMediaPlaylist getPlaylistSnapshot() {
return playlistSnapshot;
}
......
......@@ -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
* 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
* 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 {
List<Rendition> audios,
List<Rendition> subtitles,
List<Rendition> closedCaptions,
Format muxedAudioFormat,
@Nullable Format muxedAudioFormat,
List<Format> muxedCaptionFormats,
boolean hasIndependentSegments,
Map<String, String> variableDefinitions,
......
......@@ -16,7 +16,6 @@
package com.google.android.exoplayer2.source.hls.playlist;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData;
......@@ -95,8 +94,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
String uri,
long byterangeOffset,
long byterangeLength,
String fullSegmentEncryptionKeyUri,
String encryptionIV) {
@Nullable String fullSegmentEncryptionKeyUri,
@Nullable String encryptionIV) {
this(
uri,
/* initializationSegment= */ null,
......@@ -154,7 +153,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
}
@Override
public int compareTo(@NonNull Long relativeStartTimeUs) {
public int compareTo(Long relativeStartTimeUs) {
return this.relativeStartTimeUs > relativeStartTimeUs
? 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 {
dependencies {
implementation project(modulePrefix + 'library-core')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
implementation 'androidx.annotation:annotation:1.1.0'
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.TransferListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** A SmoothStreaming {@link MediaPeriod}. */
/* package */ final class SsMediaPeriod
......@@ -120,8 +121,12 @@ import java.util.List;
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
public long selectTracks(
@NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
ArrayList<ChunkSampleStream<SsChunkSource>> sampleStreamsList = new ArrayList<>();
for (int i = 0; i < selections.length; i++) {
if (streams[i] != null) {
......
......@@ -115,7 +115,7 @@ public final class SsMediaSource extends BaseMediaSource
* @return This factory, for convenience.
* @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);
this.tag = tag;
return this;
......@@ -370,8 +370,8 @@ public final class SsMediaSource extends BaseMediaSource
public SsMediaSource(
SsManifest manifest,
SsChunkSource.Factory chunkSourceFactory,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
manifest,
chunkSourceFactory,
......@@ -395,8 +395,8 @@ public final class SsMediaSource extends BaseMediaSource
SsManifest manifest,
SsChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
manifest,
/* manifestUri= */ null,
......@@ -431,8 +431,8 @@ public final class SsMediaSource extends BaseMediaSource
Uri manifestUri,
DataSource.Factory manifestDataSourceFactory,
SsChunkSource.Factory chunkSourceFactory,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
manifestUri,
manifestDataSourceFactory,
......@@ -466,8 +466,8 @@ public final class SsMediaSource extends BaseMediaSource
SsChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount,
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(manifestUri, manifestDataSourceFactory, new SsManifestParser(), chunkSourceFactory,
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener);
}
......@@ -496,8 +496,8 @@ public final class SsMediaSource extends BaseMediaSource
SsChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount,
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
this(
/* manifest= */ null,
manifestUri,
......@@ -515,10 +515,10 @@ public final class SsMediaSource extends BaseMediaSource
}
private SsMediaSource(
SsManifest manifest,
Uri manifestUri,
DataSource.Factory manifestDataSourceFactory,
ParsingLoadable.Parser<? extends SsManifest> manifestParser,
@Nullable SsManifest manifest,
@Nullable Uri manifestUri,
@Nullable DataSource.Factory manifestDataSourceFactory,
@Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser,
SsChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
DrmSessionManager<?> drmSessionManager,
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox;
......@@ -69,7 +70,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
public final int maxHeight;
public final int displayWidth;
public final int displayHeight;
public final String language;
@Nullable public final String language;
public final Format[] formats;
public final int chunkCount;
......@@ -80,9 +81,20 @@ public class SsManifest implements FilterableManifest<SsManifest> {
private final long[] chunkStartTimesUs;
private final long lastChunkDurationUs;
public StreamElement(String baseUri, String chunkTemplate, int type, String subType,
long timescale, String name, int maxWidth, int maxHeight, int displayWidth,
int displayHeight, String language, Format[] formats, List<Long> chunkStartTimes,
public StreamElement(
String baseUri,
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) {
this(
baseUri,
......@@ -102,10 +114,22 @@ public class SsManifest implements FilterableManifest<SsManifest> {
Util.scaleLargeTimestamp(lastChunkDuration, C.MICROS_PER_SECOND, timescale));
}
private StreamElement(String baseUri, String chunkTemplate, int type, String subType,
long timescale, String name, int maxWidth, int maxHeight, int displayWidth,
int displayHeight, String language, Format[] formats, List<Long> chunkStartTimes,
long[] chunkStartTimesUs, long lastChunkDurationUs) {
private StreamElement(
String baseUri,
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[] chunkStartTimesUs,
long lastChunkDurationUs) {
this.baseUri = baseUri;
this.chunkTemplate = chunkTemplate;
this.type = type;
......@@ -208,7 +232,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
public final boolean isLive;
/** Content protection information, or null if the content is not protected. */
public final ProtectionElement protectionElement;
@Nullable public final ProtectionElement protectionElement;
/** The contained stream elements. */
public final StreamElement[] streamElements;
......@@ -249,7 +273,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
long dvrWindowLength,
int lookAheadCount,
boolean isLive,
ProtectionElement protectionElement,
@Nullable ProtectionElement protectionElement,
StreamElement[] streamElements) {
this(
majorVersion,
......@@ -273,7 +297,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
long dvrWindowLengthUs,
int lookAheadCount,
boolean isLive,
ProtectionElement protectionElement,
@Nullable ProtectionElement protectionElement,
StreamElement[] streamElements) {
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
import android.net.Uri;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Pair;
......@@ -40,6 +41,7 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
......@@ -94,10 +96,10 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
private final String baseUri;
private final String tag;
private final ElementParser parent;
private final List<Pair<String, Object>> normalizedAttributes;
@Nullable private final ElementParser parent;
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.baseUri = baseUri;
this.tag = tag;
......@@ -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
* may have been pulled up from the child elements because its value was the same in all
* 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)}.
*
* @param key The name 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));
}
/**
* Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with
* the provided name, the parent element parser will be queried, and so on up the chain.
* Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with the
* provided name, the parent element parser will be queried, and so on up the chain.
*
* @param key The name of the attribute.
* @return The stashed value, or null if the attribute was not be found.
*/
@Nullable
protected final Object getNormalizedAttribute(String key) {
for (int i = 0; i < normalizedAttributes.size(); i++) {
Pair<String, Object> pair = normalizedAttributes.get(i);
......@@ -340,7 +343,7 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
private long dvrWindowLength;
private int lookAheadCount;
private boolean isLive;
private ProtectionElement protectionElement;
@Nullable private ProtectionElement protectionElement;
public SmoothStreamingMediaParser(ElementParser parent, String baseUri) {
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 {
implementation 'androidx.media:media:1.0.1'
implementation 'androidx.annotation:annotation:1.1.0'
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
testImplementation project(modulePrefix + 'testutils-robolectric')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}
ext {
......
......@@ -39,11 +39,13 @@ android {
dependencies {
api 'org.mockito:mockito-core:' + mockitoVersion
api 'androidx.test:core:' + androidXTestVersion
api 'androidx.test.ext:junit:' + androidXTestVersion
api 'com.google.truth:truth:' + truthVersion
implementation 'androidx.annotation:annotation:1.1.0'
implementation project(modulePrefix + 'library-core')
implementation 'com.google.auto.value:auto-value-annotations:' + 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