mirror of
https://github.com/samsonjs/media.git
synced 2026-03-29 10:05:48 +00:00
Merge remote-tracking branch 'upstream/dev-v2' into dev-v2
# Conflicts: # library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java
This commit is contained in:
commit
0c4df84eaa
79 changed files with 735 additions and 409 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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
private boolean exceedAudioConstraintsIfNecessary;
|
||||
private boolean allowAudioMixedMimeTypeAdaptiveness;
|
||||
private boolean allowAudioMixedSampleRateAdaptiveness;
|
||||
private boolean allowAudioMixedChannelCountAdaptiveness;
|
||||
// General
|
||||
private boolean forceLowestBitrate;
|
||||
private boolean forceHighestSupportedBitrate;
|
||||
|
|
@ -227,6 +228,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary;
|
||||
allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness;
|
||||
allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness;
|
||||
allowAudioMixedChannelCountAdaptiveness =
|
||||
initialValues.allowAudioMixedChannelCountAdaptiveness;
|
||||
// General
|
||||
forceLowestBitrate = initialValues.forceLowestBitrate;
|
||||
forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate;
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setMaxVideoSize(int maxVideoWidth, int maxVideoHeight) {
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setMaxVideoFrameRate(int maxVideoFrameRate) {
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setMaxVideoBitrate(int maxVideoBitrate) {
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setExceedVideoConstraintsIfNecessary(
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness(
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setAllowVideoNonSeamlessAdaptiveness(
|
||||
|
|
@ -326,7 +345,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
* obtained from {@link Util#getPhysicalDisplaySize(Context)}.
|
||||
*
|
||||
* @param context Any context.
|
||||
* @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}.
|
||||
* @param viewportOrientationMayChange Whether the viewport orientation may change during
|
||||
* playback.
|
||||
* @return This builder.
|
||||
*/
|
||||
public ParametersBuilder setViewportSizeToPhysicalDisplaySize(
|
||||
|
|
@ -347,12 +367,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
}
|
||||
|
||||
/**
|
||||
* See {@link Parameters#viewportWidth}, {@link Parameters#maxVideoHeight} and {@link
|
||||
* Parameters#viewportOrientationMayChange}.
|
||||
* Sets the viewport size to constrain adaptive video selections so that only tracks suitable
|
||||
* for the viewport are selected.
|
||||
*
|
||||
* @param viewportWidth See {@link Parameters#viewportWidth}.
|
||||
* @param viewportHeight See {@link Parameters#viewportHeight}.
|
||||
* @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}.
|
||||
* @param viewportWidth Viewport width in pixels.
|
||||
* @param viewportHeight Viewport height in pixels.
|
||||
* @param viewportOrientationMayChange Whether the viewport orientation may change during
|
||||
* playback.
|
||||
* @return This builder.
|
||||
*/
|
||||
public ParametersBuilder setViewportSize(
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) {
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setMaxAudioBitrate(int maxAudioBitrate) {
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setExceedAudioConstraintsIfNecessary(
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness(
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness(
|
||||
|
|
@ -424,6 +458,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
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
|
||||
|
||||
@Override
|
||||
|
|
@ -454,8 +503,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
// 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.
|
||||
*/
|
||||
public ParametersBuilder setForceLowestBitrate(boolean forceLowestBitrate) {
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setForceHighestSupportedBitrate(boolean forceHighestSupportedBitrate) {
|
||||
|
|
@ -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.
|
||||
*/
|
||||
public ParametersBuilder setExceedRendererCapabilitiesIfNecessary(
|
||||
|
|
@ -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
|
||||
* in tunneling mode. Session ids can be generated using {@link
|
||||
|
|
@ -512,6 +574,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*
|
||||
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
|
||||
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
|
||||
* @return This builder.
|
||||
*/
|
||||
public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
|
||||
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
||||
|
|
@ -526,6 +589,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param disabled Whether the renderer is disabled.
|
||||
* @return This builder.
|
||||
*/
|
||||
public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) {
|
||||
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
|
||||
|
|
@ -562,6 +626,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray} for which the override should be applied.
|
||||
* @param override The override.
|
||||
* @return This builder.
|
||||
*/
|
||||
public final ParametersBuilder setSelectionOverride(
|
||||
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
|
||||
|
|
@ -583,6 +648,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
|
||||
* @return This builder.
|
||||
*/
|
||||
public final ParametersBuilder clearSelectionOverride(
|
||||
int rendererIndex, TrackGroupArray groups) {
|
||||
|
|
@ -602,6 +668,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
* Clears all track selection overrides for the specified renderer.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @return This builder.
|
||||
*/
|
||||
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
|
|
@ -613,7 +680,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
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() {
|
||||
if (selectionOverrides.size() == 0) {
|
||||
// Nothing to clear.
|
||||
|
|
@ -646,6 +717,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
exceedAudioConstraintsIfNecessary,
|
||||
allowAudioMixedMimeTypeAdaptiveness,
|
||||
allowAudioMixedSampleRateAdaptiveness,
|
||||
allowAudioMixedChannelCountAdaptiveness,
|
||||
// Text
|
||||
preferredTextLanguage,
|
||||
preferredRoleFlags,
|
||||
|
|
@ -695,8 +767,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
|
||||
// Video
|
||||
/**
|
||||
* Maximum allowed video width. The default value is {@link Integer#MAX_VALUE} (i.e. no
|
||||
* constraint).
|
||||
* Maximum allowed video width in pixels. The default value is {@link Integer#MAX_VALUE} (i.e.
|
||||
* no constraint).
|
||||
*
|
||||
* <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
|
||||
|
|
@ -704,8 +776,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
public final int maxVideoWidth;
|
||||
/**
|
||||
* Maximum allowed video height. The default value is {@link Integer#MAX_VALUE} (i.e. no
|
||||
* constraint).
|
||||
* Maximum allowed video height in pixels. The default value is {@link Integer#MAX_VALUE} (i.e.
|
||||
* no constraint).
|
||||
*
|
||||
* <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
|
||||
|
|
@ -713,12 +785,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
public final int maxVideoHeight;
|
||||
/**
|
||||
* Maximum allowed video frame rate. The default value is {@link Integer#MAX_VALUE} (i.e. no
|
||||
* constraint).
|
||||
* Maximum allowed video frame rate in hertz. The default value is {@link Integer#MAX_VALUE}
|
||||
* (i.e. no constraint).
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
|
|
@ -728,9 +801,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
public final boolean exceedVideoConstraintsIfNecessary;
|
||||
/**
|
||||
* Whether to allow adaptive video selections containing mixed mime types. Adaptations between
|
||||
* different mime types may not be completely seamless, in which case {@link
|
||||
* #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed mime type
|
||||
* Whether to allow adaptive video selections containing mixed MIME types. Adaptations between
|
||||
* different MIME types may not be completely seamless, in which case {@link
|
||||
* #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed MIME type
|
||||
* selections to be made. The default value is {@code false}.
|
||||
*/
|
||||
public final boolean allowVideoMixedMimeTypeAdaptiveness;
|
||||
|
|
@ -764,7 +837,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
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;
|
||||
/**
|
||||
|
|
@ -773,8 +847,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
public final boolean exceedAudioConstraintsIfNecessary;
|
||||
/**
|
||||
* 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}.
|
||||
* 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}.
|
||||
*/
|
||||
public final boolean allowAudioMixedMimeTypeAdaptiveness;
|
||||
/**
|
||||
|
|
@ -782,6 +856,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
* different sample rates may not be completely seamless. The default value is {@code false}.
|
||||
*/
|
||||
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
|
||||
/**
|
||||
|
|
@ -842,6 +922,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
/* exceedAudioConstraintsIfNecessary= */ true,
|
||||
/* allowAudioMixedMimeTypeAdaptiveness= */ false,
|
||||
/* allowAudioMixedSampleRateAdaptiveness= */ false,
|
||||
/* allowAudioMixedChannelCountAdaptiveness= */ false,
|
||||
// Text
|
||||
TrackSelectionParameters.DEFAULT.preferredTextLanguage,
|
||||
TrackSelectionParameters.DEFAULT.preferredRoleFlags,
|
||||
|
|
@ -875,6 +956,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
boolean exceedAudioConstraintsIfNecessary,
|
||||
boolean allowAudioMixedMimeTypeAdaptiveness,
|
||||
boolean allowAudioMixedSampleRateAdaptiveness,
|
||||
boolean allowAudioMixedChannelCountAdaptiveness,
|
||||
// Text
|
||||
@Nullable String preferredTextLanguage,
|
||||
@C.RoleFlags int preferredRoleFlags,
|
||||
|
|
@ -911,6 +993,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary;
|
||||
this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness;
|
||||
this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness;
|
||||
this.allowAudioMixedChannelCountAdaptiveness = allowAudioMixedChannelCountAdaptiveness;
|
||||
// General
|
||||
this.forceLowestBitrate = forceLowestBitrate;
|
||||
this.forceHighestSupportedBitrate = forceHighestSupportedBitrate;
|
||||
|
|
@ -944,6 +1027,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
this.exceedAudioConstraintsIfNecessary = Util.readBoolean(in);
|
||||
this.allowAudioMixedMimeTypeAdaptiveness = Util.readBoolean(in);
|
||||
this.allowAudioMixedSampleRateAdaptiveness = Util.readBoolean(in);
|
||||
this.allowAudioMixedChannelCountAdaptiveness = Util.readBoolean(in);
|
||||
// General
|
||||
this.forceLowestBitrate = Util.readBoolean(in);
|
||||
this.forceHighestSupportedBitrate = Util.readBoolean(in);
|
||||
|
|
@ -1025,6 +1109,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
&& exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary
|
||||
&& allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness
|
||||
&& allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness
|
||||
&& allowAudioMixedChannelCountAdaptiveness
|
||||
== other.allowAudioMixedChannelCountAdaptiveness
|
||||
// General
|
||||
&& forceLowestBitrate == other.forceLowestBitrate
|
||||
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
|
||||
|
|
@ -1055,6 +1141,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0);
|
||||
result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0);
|
||||
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
|
||||
result = 31 * result + (allowAudioMixedChannelCountAdaptiveness ? 1 : 0);
|
||||
// General
|
||||
result = 31 * result + (forceLowestBitrate ? 1 : 0);
|
||||
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
|
||||
|
|
@ -1091,6 +1178,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
Util.writeBoolean(dest, exceedAudioConstraintsIfNecessary);
|
||||
Util.writeBoolean(dest, allowAudioMixedMimeTypeAdaptiveness);
|
||||
Util.writeBoolean(dest, allowAudioMixedSampleRateAdaptiveness);
|
||||
Util.writeBoolean(dest, allowAudioMixedChannelCountAdaptiveness);
|
||||
// General
|
||||
Util.writeBoolean(dest, forceLowestBitrate);
|
||||
Util.writeBoolean(dest, forceHighestSupportedBitrate);
|
||||
|
|
@ -1999,7 +2087,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
formatSupports[selectedGroupIndex],
|
||||
params.maxAudioBitrate,
|
||||
params.allowAudioMixedMimeTypeAdaptiveness,
|
||||
params.allowAudioMixedSampleRateAdaptiveness);
|
||||
params.allowAudioMixedSampleRateAdaptiveness,
|
||||
params.allowAudioMixedChannelCountAdaptiveness);
|
||||
if (adaptiveTracks.length > 0) {
|
||||
definition = new TrackSelection.Definition(selectedGroup, adaptiveTracks);
|
||||
}
|
||||
|
|
@ -2017,7 +2106,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
int[] formatSupport,
|
||||
int maxAudioBitrate,
|
||||
boolean allowMixedMimeTypeAdaptiveness,
|
||||
boolean allowMixedSampleRateAdaptiveness) {
|
||||
boolean allowMixedSampleRateAdaptiveness,
|
||||
boolean allowAudioMixedChannelCountAdaptiveness) {
|
||||
int selectedConfigurationTrackCount = 0;
|
||||
AudioConfigurationTuple selectedConfiguration = null;
|
||||
HashSet<AudioConfigurationTuple> seenConfigurationTuples = new HashSet<>();
|
||||
|
|
@ -2034,7 +2124,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
configuration,
|
||||
maxAudioBitrate,
|
||||
allowMixedMimeTypeAdaptiveness,
|
||||
allowMixedSampleRateAdaptiveness);
|
||||
allowMixedSampleRateAdaptiveness,
|
||||
allowAudioMixedChannelCountAdaptiveness);
|
||||
if (configurationCount > selectedConfigurationTrackCount) {
|
||||
selectedConfiguration = configuration;
|
||||
selectedConfigurationTrackCount = configurationCount;
|
||||
|
|
@ -2054,7 +2145,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
selectedConfiguration,
|
||||
maxAudioBitrate,
|
||||
allowMixedMimeTypeAdaptiveness,
|
||||
allowMixedSampleRateAdaptiveness)) {
|
||||
allowMixedSampleRateAdaptiveness,
|
||||
allowAudioMixedChannelCountAdaptiveness)) {
|
||||
adaptiveIndices[index++] = i;
|
||||
}
|
||||
}
|
||||
|
|
@ -2069,7 +2161,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
AudioConfigurationTuple configuration,
|
||||
int maxAudioBitrate,
|
||||
boolean allowMixedMimeTypeAdaptiveness,
|
||||
boolean allowMixedSampleRateAdaptiveness) {
|
||||
boolean allowMixedSampleRateAdaptiveness,
|
||||
boolean allowAudioMixedChannelCountAdaptiveness) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < group.length; i++) {
|
||||
if (isSupportedAdaptiveAudioTrack(
|
||||
|
|
@ -2078,7 +2171,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
configuration,
|
||||
maxAudioBitrate,
|
||||
allowMixedMimeTypeAdaptiveness,
|
||||
allowMixedSampleRateAdaptiveness)) {
|
||||
allowMixedSampleRateAdaptiveness,
|
||||
allowAudioMixedChannelCountAdaptiveness)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
|
@ -2091,11 +2185,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
AudioConfigurationTuple configuration,
|
||||
int maxAudioBitrate,
|
||||
boolean allowMixedMimeTypeAdaptiveness,
|
||||
boolean allowMixedSampleRateAdaptiveness) {
|
||||
boolean allowMixedSampleRateAdaptiveness,
|
||||
boolean allowAudioMixedChannelCountAdaptiveness) {
|
||||
return isSupported(formatSupport, false)
|
||||
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= maxAudioBitrate)
|
||||
&& (format.channelCount != Format.NO_VALUE
|
||||
&& format.channelCount == configuration.channelCount)
|
||||
&& (allowAudioMixedChannelCountAdaptiveness
|
||||
|| (format.channelCount != Format.NO_VALUE
|
||||
&& format.channelCount == configuration.channelCount))
|
||||
&& (allowMixedMimeTypeAdaptiveness
|
||||
|| (format.sampleMimeType != null
|
||||
&& TextUtils.equals(format.sampleMimeType, configuration.mimeType)))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer2.source.dash.manifest;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Pair;
|
||||
|
|
@ -47,6 +48,7 @@ import java.util.List;
|
|||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
|
@ -189,9 +191,9 @@ public class DashManifestParser extends DefaultHandler
|
|||
long timeShiftBufferDepthMs,
|
||||
long suggestedPresentationDelayMs,
|
||||
long publishTimeMs,
|
||||
ProgramInformation programInformation,
|
||||
UtcTimingElement utcTiming,
|
||||
Uri location,
|
||||
@Nullable ProgramInformation programInformation,
|
||||
@Nullable UtcTimingElement utcTiming,
|
||||
@Nullable Uri location,
|
||||
List<Period> periods) {
|
||||
return new DashManifest(
|
||||
availabilityStartTime,
|
||||
|
|
@ -259,8 +261,9 @@ public class DashManifestParser extends DefaultHandler
|
|||
|
||||
// AdaptationSet parsing.
|
||||
|
||||
protected AdaptationSet parseAdaptationSet(XmlPullParser xpp, String baseUrl,
|
||||
SegmentBase segmentBase) throws XmlPullParserException, IOException {
|
||||
protected AdaptationSet parseAdaptationSet(
|
||||
XmlPullParser xpp, String baseUrl, @Nullable SegmentBase segmentBase)
|
||||
throws XmlPullParserException, IOException {
|
||||
int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET);
|
||||
int contentType = parseContentType(xpp);
|
||||
|
||||
|
|
@ -394,8 +397,8 @@ public class DashManifestParser extends DefaultHandler
|
|||
* @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.
|
||||
*/
|
||||
protected Pair<String, SchemeData> parseContentProtection(XmlPullParser xpp)
|
||||
throws XmlPullParserException, IOException {
|
||||
protected Pair<@NullableType String, @NullableType SchemeData> parseContentProtection(
|
||||
XmlPullParser xpp) throws XmlPullParserException, IOException {
|
||||
String schemeType = null;
|
||||
String licenseServerUrl = null;
|
||||
byte[] data = null;
|
||||
|
|
@ -477,19 +480,19 @@ public class DashManifestParser extends DefaultHandler
|
|||
protected RepresentationInfo parseRepresentation(
|
||||
XmlPullParser xpp,
|
||||
String baseUrl,
|
||||
String label,
|
||||
String adaptationSetMimeType,
|
||||
String adaptationSetCodecs,
|
||||
@Nullable String label,
|
||||
@Nullable String adaptationSetMimeType,
|
||||
@Nullable String adaptationSetCodecs,
|
||||
int adaptationSetWidth,
|
||||
int adaptationSetHeight,
|
||||
float adaptationSetFrameRate,
|
||||
int adaptationSetAudioChannels,
|
||||
int adaptationSetAudioSamplingRate,
|
||||
String adaptationSetLanguage,
|
||||
@Nullable String adaptationSetLanguage,
|
||||
List<Descriptor> adaptationSetRoleDescriptors,
|
||||
List<Descriptor> adaptationSetAccessibilityDescriptors,
|
||||
List<Descriptor> adaptationSetSupplementalProperties,
|
||||
SegmentBase segmentBase)
|
||||
@Nullable SegmentBase segmentBase)
|
||||
throws XmlPullParserException, IOException {
|
||||
String id = xpp.getAttributeValue(null, "id");
|
||||
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
|
||||
|
|
@ -564,19 +567,19 @@ public class DashManifestParser extends DefaultHandler
|
|||
}
|
||||
|
||||
protected Format buildFormat(
|
||||
String id,
|
||||
String label,
|
||||
String containerMimeType,
|
||||
@Nullable String id,
|
||||
@Nullable String label,
|
||||
@Nullable String containerMimeType,
|
||||
int width,
|
||||
int height,
|
||||
float frameRate,
|
||||
int audioChannels,
|
||||
int audioSamplingRate,
|
||||
int bitrate,
|
||||
String language,
|
||||
@Nullable String language,
|
||||
List<Descriptor> roleDescriptors,
|
||||
List<Descriptor> accessibilityDescriptors,
|
||||
String codecs,
|
||||
@Nullable String codecs,
|
||||
List<Descriptor> supplementalProperties) {
|
||||
String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
|
||||
@C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors);
|
||||
|
|
@ -650,7 +653,7 @@ public class DashManifestParser extends DefaultHandler
|
|||
|
||||
protected Representation buildRepresentation(
|
||||
RepresentationInfo representationInfo,
|
||||
String extraDrmSchemeType,
|
||||
@Nullable String extraDrmSchemeType,
|
||||
ArrayList<SchemeData> extraDrmSchemeDatas,
|
||||
ArrayList<Descriptor> extraInbandEventStreams) {
|
||||
Format format = representationInfo.format;
|
||||
|
|
@ -675,7 +678,8 @@ public class DashManifestParser extends DefaultHandler
|
|||
|
||||
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
||||
|
||||
protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, SingleSegmentBase parent)
|
||||
protected SingleSegmentBase parseSegmentBase(
|
||||
XmlPullParser xpp, @Nullable SingleSegmentBase parent)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||
|
|
@ -711,7 +715,7 @@ public class DashManifestParser extends DefaultHandler
|
|||
indexLength);
|
||||
}
|
||||
|
||||
protected SegmentList parseSegmentList(XmlPullParser xpp, SegmentList parent)
|
||||
protected SegmentList parseSegmentList(XmlPullParser xpp, @Nullable SegmentList parent)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||
|
|
@ -756,15 +760,15 @@ public class DashManifestParser extends DefaultHandler
|
|||
long presentationTimeOffset,
|
||||
long startNumber,
|
||||
long duration,
|
||||
List<SegmentTimelineElement> timeline,
|
||||
List<RangedUri> segments) {
|
||||
@Nullable List<SegmentTimelineElement> timeline,
|
||||
@Nullable List<RangedUri> segments) {
|
||||
return new SegmentList(initialization, timescale, presentationTimeOffset,
|
||||
startNumber, duration, timeline, segments);
|
||||
}
|
||||
|
||||
protected SegmentTemplate parseSegmentTemplate(
|
||||
XmlPullParser xpp,
|
||||
SegmentTemplate parent,
|
||||
@Nullable SegmentTemplate parent,
|
||||
List<Descriptor> adaptationSetSupplementalProperties)
|
||||
throws XmlPullParserException, IOException {
|
||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||
|
|
@ -819,8 +823,8 @@ public class DashManifestParser extends DefaultHandler
|
|||
long endNumber,
|
||||
long duration,
|
||||
List<SegmentTimelineElement> timeline,
|
||||
UrlTemplate initializationTemplate,
|
||||
UrlTemplate mediaTemplate) {
|
||||
@Nullable UrlTemplate initializationTemplate,
|
||||
@Nullable UrlTemplate mediaTemplate) {
|
||||
return new SegmentTemplate(
|
||||
initialization,
|
||||
timescale,
|
||||
|
|
@ -1008,8 +1012,9 @@ public class DashManifestParser extends DefaultHandler
|
|||
return new SegmentTimelineElement(elapsedTime, duration);
|
||||
}
|
||||
|
||||
protected UrlTemplate parseUrlTemplate(XmlPullParser xpp, String name,
|
||||
UrlTemplate defaultValue) {
|
||||
@Nullable
|
||||
protected UrlTemplate parseUrlTemplate(
|
||||
XmlPullParser xpp, String name, @Nullable UrlTemplate defaultValue) {
|
||||
String valueString = xpp.getAttributeValue(null, name);
|
||||
if (valueString != null) {
|
||||
return UrlTemplate.compile(valueString);
|
||||
|
|
@ -1126,7 +1131,7 @@ public class DashManifestParser extends DefaultHandler
|
|||
}
|
||||
|
||||
@C.RoleFlags
|
||||
protected int parseDashRoleSchemeValue(String value) {
|
||||
protected int parseDashRoleSchemeValue(@Nullable String value) {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1159,7 +1164,7 @@ public class DashManifestParser extends DefaultHandler
|
|||
}
|
||||
|
||||
@C.RoleFlags
|
||||
protected int parseTvaAudioPurposeCsValue(String value) {
|
||||
protected int parseTvaAudioPurposeCsValue(@Nullable String value) {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1230,7 +1235,9 @@ public class DashManifestParser extends DefaultHandler
|
|||
* @param codecs The codecs attribute.
|
||||
* @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)) {
|
||||
return MimeTypes.getAudioMediaMimeType(codecs);
|
||||
} else if (MimeTypes.isVideo(containerMimeType)) {
|
||||
|
|
@ -1264,7 +1271,7 @@ public class DashManifestParser extends DefaultHandler
|
|||
* @param mimeType The 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)
|
||||
|| MimeTypes.APPLICATION_TTML.equals(mimeType)
|
||||
|| MimeTypes.APPLICATION_MP4VTT.equals(mimeType)
|
||||
|
|
@ -1273,16 +1280,18 @@ public class DashManifestParser extends DefaultHandler
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks two languages for consistency, returning the consistent language, or throwing an
|
||||
* {@link IllegalStateException} if the languages are inconsistent.
|
||||
* <p>
|
||||
* Two languages are consistent if they are equal, or if one is null.
|
||||
* Checks two languages for consistency, returning the consistent language, or throwing an {@link
|
||||
* IllegalStateException} if the languages are inconsistent.
|
||||
*
|
||||
* <p>Two languages are consistent if they are equal, or if one is null.
|
||||
*
|
||||
* @param firstLanguage The first language.
|
||||
* @param secondLanguage The second 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) {
|
||||
return secondLanguage;
|
||||
} else if (secondLanguage == null) {
|
||||
|
|
@ -1485,14 +1494,19 @@ public class DashManifestParser extends DefaultHandler
|
|||
public final Format format;
|
||||
public final String baseUrl;
|
||||
public final SegmentBase segmentBase;
|
||||
public final String drmSchemeType;
|
||||
@Nullable public final String drmSchemeType;
|
||||
public final ArrayList<SchemeData> drmSchemeDatas;
|
||||
public final ArrayList<Descriptor> inbandEventStreams;
|
||||
public final long revisionId;
|
||||
|
||||
public RepresentationInfo(Format format, String baseUrl, SegmentBase segmentBase,
|
||||
String drmSchemeType, ArrayList<SchemeData> drmSchemeDatas,
|
||||
ArrayList<Descriptor> inbandEventStreams, long revisionId) {
|
||||
public RepresentationInfo(
|
||||
Format format,
|
||||
String baseUrl,
|
||||
SegmentBase segmentBase,
|
||||
@Nullable String drmSchemeType,
|
||||
ArrayList<SchemeData> drmSchemeDatas,
|
||||
ArrayList<Descriptor> inbandEventStreams,
|
||||
long revisionId) {
|
||||
this.format = format;
|
||||
this.baseUrl = baseUrl;
|
||||
this.segmentBase = segmentBase;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
// 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
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<?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"/>
|
||||
Loading…
Reference in a new issue