mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +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.
|
over other selection parameters.
|
||||||
* Remove `AnalyticsCollector.Factory`. Instances can be created directly and
|
* Remove `AnalyticsCollector.Factory`. Instances can be created directly and
|
||||||
the `Player` set later using `AnalyticsCollector.setPlayer`.
|
the `Player` set later using `AnalyticsCollector.setPlayer`.
|
||||||
|
* Add `allowAudioMixedChannelCountAdaptiveness` parameter to
|
||||||
|
`DefaultTrackSelector` to allow adaptive selections of audio tracks with
|
||||||
|
different channel counts
|
||||||
|
([#6257](https://github.com/google/ExoPlayer/issues/6257)).
|
||||||
|
|
||||||
### 2.10.4 ###
|
### 2.10.4 ###
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ include modulePrefix + 'library-hls'
|
||||||
include modulePrefix + 'library-smoothstreaming'
|
include modulePrefix + 'library-smoothstreaming'
|
||||||
include modulePrefix + 'library-ui'
|
include modulePrefix + 'library-ui'
|
||||||
include modulePrefix + 'testutils'
|
include modulePrefix + 'testutils'
|
||||||
include modulePrefix + 'testutils-robolectric'
|
|
||||||
include modulePrefix + 'extension-ffmpeg'
|
include modulePrefix + 'extension-ffmpeg'
|
||||||
include modulePrefix + 'extension-flac'
|
include modulePrefix + 'extension-flac'
|
||||||
include modulePrefix + 'extension-gvr'
|
include modulePrefix + 'extension-gvr'
|
||||||
|
|
@ -47,7 +46,6 @@ project(modulePrefix + 'library-hls').projectDir = new File(rootDir, 'library/hl
|
||||||
project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming')
|
project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming')
|
||||||
project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui')
|
project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui')
|
||||||
project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils')
|
project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils')
|
||||||
project(modulePrefix + 'testutils-robolectric').projectDir = new File(rootDir, 'testutils_robolectric')
|
|
||||||
project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg')
|
project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg')
|
||||||
project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac')
|
project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac')
|
||||||
project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr')
|
project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr')
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ dependencies {
|
||||||
implementation project(modulePrefix + 'library-ui')
|
implementation project(modulePrefix + 'library-ui')
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ dependencies {
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
testImplementation project(modulePrefix + 'library')
|
testImplementation project(modulePrefix + 'library')
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ dependencies {
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ dependencies {
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
androidTestImplementation project(modulePrefix + 'testutils')
|
androidTestImplementation project(modulePrefix + 'testutils')
|
||||||
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
|
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,12 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api 'com.google.ads.interactivemedia.v3:interactivemedia:3.11.2'
|
api 'com.google.ads.interactivemedia.v3:interactivemedia:3.11.3'
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0'
|
implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0'
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
|
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
|
||||||
androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion
|
androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ dependencies {
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
implementation 'net.butterflytv.utils:rtmp-client:3.0.1'
|
implementation 'net.butterflytv.utils:rtmp-client:3.0.1'
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
|
androidTestImplementation 'androidx.test:runner:' + androidXTestVersion
|
||||||
androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion
|
androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion
|
||||||
androidTestImplementation 'com.google.truth:truth:' + truthVersion
|
androidTestImplementation 'com.google.truth:truth:' + truthVersion
|
||||||
|
|
|
||||||
|
|
@ -174,8 +174,8 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
*/
|
*/
|
||||||
public LibvpxVideoRenderer(
|
public LibvpxVideoRenderer(
|
||||||
long allowedJoiningTimeMs,
|
long allowedJoiningTimeMs,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
VideoRendererEventListener eventListener,
|
@Nullable VideoRendererEventListener eventListener,
|
||||||
int maxDroppedFramesToNotify) {
|
int maxDroppedFramesToNotify) {
|
||||||
this(
|
this(
|
||||||
allowedJoiningTimeMs,
|
allowedJoiningTimeMs,
|
||||||
|
|
@ -206,10 +206,10 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
*/
|
*/
|
||||||
public LibvpxVideoRenderer(
|
public LibvpxVideoRenderer(
|
||||||
long allowedJoiningTimeMs,
|
long allowedJoiningTimeMs,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
VideoRendererEventListener eventListener,
|
@Nullable VideoRendererEventListener eventListener,
|
||||||
int maxDroppedFramesToNotify,
|
int maxDroppedFramesToNotify,
|
||||||
DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
||||||
boolean playClearSamplesWithoutKeys,
|
boolean playClearSamplesWithoutKeys,
|
||||||
boolean disableLoopFilter) {
|
boolean disableLoopFilter) {
|
||||||
this(
|
this(
|
||||||
|
|
@ -249,10 +249,10 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
*/
|
*/
|
||||||
public LibvpxVideoRenderer(
|
public LibvpxVideoRenderer(
|
||||||
long allowedJoiningTimeMs,
|
long allowedJoiningTimeMs,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
VideoRendererEventListener eventListener,
|
@Nullable VideoRendererEventListener eventListener,
|
||||||
int maxDroppedFramesToNotify,
|
int maxDroppedFramesToNotify,
|
||||||
DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
||||||
boolean playClearSamplesWithoutKeys,
|
boolean playClearSamplesWithoutKeys,
|
||||||
boolean disableLoopFilter,
|
boolean disableLoopFilter,
|
||||||
boolean enableRowMultiThreadMode,
|
boolean enableRowMultiThreadMode,
|
||||||
|
|
@ -847,7 +847,7 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
pendingFormat = null;
|
pendingFormat = null;
|
||||||
}
|
}
|
||||||
inputBuffer.flip();
|
inputBuffer.flip();
|
||||||
inputBuffer.colorInfo = formatHolder.format.colorInfo;
|
inputBuffer.colorInfo = format.colorInfo;
|
||||||
onQueueInputBuffer(inputBuffer);
|
onQueueInputBuffer(inputBuffer);
|
||||||
decoder.queueInputBuffer(inputBuffer);
|
decoder.queueInputBuffer(inputBuffer);
|
||||||
buffersInCodecCount++;
|
buffersInCodecCount++;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import java.nio.ByteBuffer;
|
||||||
private static final int DECODE_ERROR = 1;
|
private static final int DECODE_ERROR = 1;
|
||||||
private static final int DRM_ERROR = 2;
|
private static final int DRM_ERROR = 2;
|
||||||
|
|
||||||
private final ExoMediaCrypto exoMediaCrypto;
|
@Nullable private final ExoMediaCrypto exoMediaCrypto;
|
||||||
private final long vpxDecContext;
|
private final long vpxDecContext;
|
||||||
|
|
||||||
@C.VideoOutputMode private volatile int outputMode;
|
@C.VideoOutputMode private volatile int outputMode;
|
||||||
|
|
@ -55,7 +55,7 @@ import java.nio.ByteBuffer;
|
||||||
int numInputBuffers,
|
int numInputBuffers,
|
||||||
int numOutputBuffers,
|
int numOutputBuffers,
|
||||||
int initialInputBufferSize,
|
int initialInputBufferSize,
|
||||||
ExoMediaCrypto exoMediaCrypto,
|
@Nullable ExoMediaCrypto exoMediaCrypto,
|
||||||
boolean disableLoopFilter,
|
boolean disableLoopFilter,
|
||||||
boolean enableRowMultiThreadMode,
|
boolean enableRowMultiThreadMode,
|
||||||
int threads)
|
int threads)
|
||||||
|
|
@ -170,9 +170,19 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
private native long vpxClose(long context);
|
private native long vpxClose(long context);
|
||||||
private native long vpxDecode(long context, ByteBuffer encoded, int length);
|
private native long vpxDecode(long context, ByteBuffer encoded, int length);
|
||||||
private native long vpxSecureDecode(long context, ByteBuffer encoded, int length,
|
|
||||||
ExoMediaCrypto mediaCrypto, int inputMode, byte[] key, byte[] iv,
|
private native long vpxSecureDecode(
|
||||||
int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData);
|
long context,
|
||||||
|
ByteBuffer encoded,
|
||||||
|
int length,
|
||||||
|
@Nullable ExoMediaCrypto mediaCrypto,
|
||||||
|
int inputMode,
|
||||||
|
byte[] key,
|
||||||
|
byte[] iv,
|
||||||
|
int numSubSamples,
|
||||||
|
int[] numBytesOfClearData,
|
||||||
|
int[] numBytesOfEncryptedData);
|
||||||
|
|
||||||
private native int vpxGetFrame(long context, VpxOutputBuffer outputBuffer);
|
private native int vpxGetFrame(long context, VpxOutputBuffer outputBuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.vp9;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.opengl.GLSurfaceView;
|
import android.opengl.GLSurfaceView;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -27,10 +28,10 @@ public class VpxVideoSurfaceView extends GLSurfaceView implements VpxOutputBuffe
|
||||||
private final VpxRenderer renderer;
|
private final VpxRenderer renderer;
|
||||||
|
|
||||||
public VpxVideoSurfaceView(Context context) {
|
public VpxVideoSurfaceView(Context context) {
|
||||||
this(context, null);
|
this(context, /* attrs= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VpxVideoSurfaceView(Context context, AttributeSet attrs) {
|
public VpxVideoSurfaceView(Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
renderer = new VpxRenderer();
|
renderer = new VpxRenderer();
|
||||||
setPreserveEGLContextOnPause(true);
|
setPreserveEGLContextOnPause(true);
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
test {
|
||||||
java.srcDirs += '../../testutils/src/main/java/'
|
java.srcDirs += '../../testutils/src/main/java/'
|
||||||
java.srcDirs += '../../testutils_robolectric/src/main/java/'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
|
||||||
private int pendingMetadataCount;
|
private int pendingMetadataCount;
|
||||||
private MetadataDecoder decoder;
|
private MetadataDecoder decoder;
|
||||||
private boolean inputStreamEnded;
|
private boolean inputStreamEnded;
|
||||||
|
private long subsampleOffsetUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param output The output.
|
* @param output The output.
|
||||||
|
|
@ -120,7 +121,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
|
||||||
// If we ever need to support a metadata format where this is not the case, we'll need to
|
// If we ever need to support a metadata format where this is not the case, we'll need to
|
||||||
// pass the buffer to the decoder and discard the output.
|
// pass the buffer to the decoder and discard the output.
|
||||||
} else {
|
} else {
|
||||||
buffer.subsampleOffsetUs = formatHolder.format.subsampleOffsetUs;
|
buffer.subsampleOffsetUs = subsampleOffsetUs;
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT;
|
int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT;
|
||||||
Metadata metadata = decoder.decode(buffer);
|
Metadata metadata = decoder.decode(buffer);
|
||||||
|
|
@ -130,6 +131,8 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
|
||||||
pendingMetadataCount++;
|
pendingMetadataCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (result == C.RESULT_FORMAT_READ) {
|
||||||
|
subsampleOffsetUs = formatHolder.format.subsampleOffsetUs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,43 +15,34 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.metadata.emsg;
|
package com.google.android.exoplayer2.metadata.emsg;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.metadata.MetadataDecoder;
|
import com.google.android.exoplayer2.metadata.MetadataDecoder;
|
||||||
import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
|
import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/** Decodes data encoded by {@link EventMessageEncoder}. */
|
/** Decodes data encoded by {@link EventMessageEncoder}. */
|
||||||
public final class EventMessageDecoder implements MetadataDecoder {
|
public final class EventMessageDecoder implements MetadataDecoder {
|
||||||
|
|
||||||
private static final String TAG = "EventMessageDecoder";
|
|
||||||
|
|
||||||
@SuppressWarnings("ByteBufferBackingArray")
|
@SuppressWarnings("ByteBufferBackingArray")
|
||||||
@Override
|
@Override
|
||||||
public Metadata decode(MetadataInputBuffer inputBuffer) {
|
public Metadata decode(MetadataInputBuffer inputBuffer) {
|
||||||
ByteBuffer buffer = inputBuffer.data;
|
ByteBuffer buffer = inputBuffer.data;
|
||||||
byte[] data = buffer.array();
|
byte[] data = buffer.array();
|
||||||
int size = buffer.limit();
|
int size = buffer.limit();
|
||||||
ParsableByteArray emsgData = new ParsableByteArray(data, size);
|
return new Metadata(decode(new ParsableByteArray(data, size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventMessage decode(ParsableByteArray emsgData) {
|
||||||
String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
||||||
String value = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
String value = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
||||||
long timescale = emsgData.readUnsignedInt();
|
long durationMs = emsgData.readUnsignedInt();
|
||||||
long presentationTimeDelta = emsgData.readUnsignedInt();
|
|
||||||
if (presentationTimeDelta != 0) {
|
|
||||||
// We expect the source to have accounted for presentation_time_delta by adjusting the sample
|
|
||||||
// timestamp and zeroing the field in the sample data. Log a warning if the field is non-zero.
|
|
||||||
Log.w(TAG, "Ignoring non-zero presentation_time_delta: " + presentationTimeDelta);
|
|
||||||
}
|
|
||||||
long durationMs =
|
|
||||||
Util.scaleLargeTimestamp(emsgData.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale);
|
|
||||||
long id = emsgData.readUnsignedInt();
|
long id = emsgData.readUnsignedInt();
|
||||||
byte[] messageData = Arrays.copyOfRange(data, emsgData.getPosition(), size);
|
byte[] messageData =
|
||||||
return new Metadata(new EventMessage(schemeIdUri, value, durationMs, id, messageData));
|
Arrays.copyOfRange(emsgData.data, emsgData.getPosition(), emsgData.limit());
|
||||||
|
return new EventMessage(schemeIdUri, value, durationMs, id, messageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.metadata.emsg;
|
package com.google.android.exoplayer2.metadata.emsg;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -40,15 +39,12 @@ public final class EventMessageEncoder {
|
||||||
* @param eventMessage The event message to be encoded.
|
* @param eventMessage The event message to be encoded.
|
||||||
* @return The serialized byte array.
|
* @return The serialized byte array.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
|
||||||
public byte[] encode(EventMessage eventMessage) {
|
public byte[] encode(EventMessage eventMessage) {
|
||||||
byteArrayOutputStream.reset();
|
byteArrayOutputStream.reset();
|
||||||
try {
|
try {
|
||||||
writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri);
|
writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri);
|
||||||
String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
|
String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
|
||||||
writeNullTerminatedString(dataOutputStream, nonNullValue);
|
writeNullTerminatedString(dataOutputStream, nonNullValue);
|
||||||
writeUnsignedInt(dataOutputStream, 1000); // timescale
|
|
||||||
writeUnsignedInt(dataOutputStream, 0); // presentation_time_delta
|
|
||||||
writeUnsignedInt(dataOutputStream, eventMessage.durationMs);
|
writeUnsignedInt(dataOutputStream, eventMessage.durationMs);
|
||||||
writeUnsignedInt(dataOutputStream, eventMessage.id);
|
writeUnsignedInt(dataOutputStream, eventMessage.id);
|
||||||
dataOutputStream.write(eventMessage.messageData);
|
dataOutputStream.write(eventMessage.messageData);
|
||||||
|
|
|
||||||
|
|
@ -113,15 +113,17 @@ public interface MediaPeriod extends SequenceableLoader {
|
||||||
* corresponding flag in {@code streamResetFlags} will be set to true. This flag will also be set
|
* corresponding flag in {@code streamResetFlags} will be set to true. This flag will also be set
|
||||||
* if a new sample stream is created.
|
* if a new sample stream is created.
|
||||||
*
|
*
|
||||||
* <p>Note that previously received {@link TrackSelection TrackSelections} are no longer valid and
|
* <p>Note that previously passed {@link TrackSelection TrackSelections} are no longer valid, and
|
||||||
* references need to be replaced even if the corresponding {@link SampleStream} is kept.
|
* any references to them must be updated to point to the new selections.
|
||||||
*
|
*
|
||||||
* <p>This method is only called after the period has been prepared.
|
* <p>This method is only called after the period has been prepared.
|
||||||
*
|
*
|
||||||
* @param selections The renderer track selections.
|
* @param selections The renderer track selections.
|
||||||
* @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained
|
* @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained
|
||||||
* for each selection. A {@code true} value indicates that the selection is unchanged, and
|
* for each track selection. A {@code true} value indicates that the selection is equivalent
|
||||||
* that the caller does not require that the sample stream be recreated.
|
* to the one that was previously passed, and that the caller does not require that the sample
|
||||||
|
* stream be recreated. If a retained sample stream holds any references to the track
|
||||||
|
* selection then they must be updated to point to the new selection.
|
||||||
* @param streams The existing sample streams, which will be updated to reflect the provided
|
* @param streams The existing sample streams, which will be updated to reflect the provided
|
||||||
* selections.
|
* selections.
|
||||||
* @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that
|
* @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
private boolean exceedAudioConstraintsIfNecessary;
|
private boolean exceedAudioConstraintsIfNecessary;
|
||||||
private boolean allowAudioMixedMimeTypeAdaptiveness;
|
private boolean allowAudioMixedMimeTypeAdaptiveness;
|
||||||
private boolean allowAudioMixedSampleRateAdaptiveness;
|
private boolean allowAudioMixedSampleRateAdaptiveness;
|
||||||
|
private boolean allowAudioMixedChannelCountAdaptiveness;
|
||||||
// General
|
// General
|
||||||
private boolean forceLowestBitrate;
|
private boolean forceLowestBitrate;
|
||||||
private boolean forceHighestSupportedBitrate;
|
private boolean forceHighestSupportedBitrate;
|
||||||
|
|
@ -227,6 +228,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary;
|
exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary;
|
||||||
allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness;
|
allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness;
|
||||||
allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness;
|
allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness;
|
||||||
|
allowAudioMixedChannelCountAdaptiveness =
|
||||||
|
initialValues.allowAudioMixedChannelCountAdaptiveness;
|
||||||
// General
|
// General
|
||||||
forceLowestBitrate = initialValues.forceLowestBitrate;
|
forceLowestBitrate = initialValues.forceLowestBitrate;
|
||||||
forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate;
|
forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate;
|
||||||
|
|
@ -258,8 +261,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#maxVideoWidth} and {@link Parameters#maxVideoHeight}.
|
* Sets the maximum allowed video width and height.
|
||||||
*
|
*
|
||||||
|
* @param maxVideoWidth Maximum allowed video width in pixels.
|
||||||
|
* @param maxVideoHeight Maximum allowed video height in pixels.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setMaxVideoSize(int maxVideoWidth, int maxVideoHeight) {
|
public ParametersBuilder setMaxVideoSize(int maxVideoWidth, int maxVideoHeight) {
|
||||||
|
|
@ -269,8 +274,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#maxVideoFrameRate}.
|
* Sets the maximum allowed video frame rate.
|
||||||
*
|
*
|
||||||
|
* @param maxVideoFrameRate Maximum allowed video frame rate in hertz.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setMaxVideoFrameRate(int maxVideoFrameRate) {
|
public ParametersBuilder setMaxVideoFrameRate(int maxVideoFrameRate) {
|
||||||
|
|
@ -279,8 +285,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#maxVideoBitrate}.
|
* Sets the maximum allowed video bitrate.
|
||||||
*
|
*
|
||||||
|
* @param maxVideoBitrate Maximum allowed video bitrate in bits per second.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setMaxVideoBitrate(int maxVideoBitrate) {
|
public ParametersBuilder setMaxVideoBitrate(int maxVideoBitrate) {
|
||||||
|
|
@ -289,8 +296,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#exceedVideoConstraintsIfNecessary}.
|
* Sets whether to exceed the {@link #setMaxVideoSize(int, int)} and {@link
|
||||||
|
* #setMaxAudioBitrate(int)} constraints when no selection can be made otherwise.
|
||||||
*
|
*
|
||||||
|
* @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no
|
||||||
|
* selection can be made otherwise.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setExceedVideoConstraintsIfNecessary(
|
public ParametersBuilder setExceedVideoConstraintsIfNecessary(
|
||||||
|
|
@ -300,8 +310,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#allowVideoMixedMimeTypeAdaptiveness}.
|
* Sets whether to allow adaptive video selections containing mixed MIME types.
|
||||||
*
|
*
|
||||||
|
* <p>Adaptations between different MIME types may not be completely seamless, in which case
|
||||||
|
* {@link #setAllowVideoNonSeamlessAdaptiveness(boolean)} also needs to be {@code true} for
|
||||||
|
* mixed MIME type selections to be made.
|
||||||
|
*
|
||||||
|
* @param allowVideoMixedMimeTypeAdaptiveness Whether to allow adaptive video selections
|
||||||
|
* containing mixed MIME types.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness(
|
public ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness(
|
||||||
|
|
@ -311,8 +327,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#allowVideoNonSeamlessAdaptiveness}.
|
* Sets whether to allow adaptive video selections where adaptation may not be completely
|
||||||
|
* seamless.
|
||||||
*
|
*
|
||||||
|
* @param allowVideoNonSeamlessAdaptiveness Whether to allow adaptive video selections where
|
||||||
|
* adaptation may not be completely seamless.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setAllowVideoNonSeamlessAdaptiveness(
|
public ParametersBuilder setAllowVideoNonSeamlessAdaptiveness(
|
||||||
|
|
@ -326,7 +345,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
* obtained from {@link Util#getPhysicalDisplaySize(Context)}.
|
* obtained from {@link Util#getPhysicalDisplaySize(Context)}.
|
||||||
*
|
*
|
||||||
* @param context Any context.
|
* @param context Any context.
|
||||||
* @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}.
|
* @param viewportOrientationMayChange Whether the viewport orientation may change during
|
||||||
|
* playback.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setViewportSizeToPhysicalDisplaySize(
|
public ParametersBuilder setViewportSizeToPhysicalDisplaySize(
|
||||||
|
|
@ -347,12 +367,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#viewportWidth}, {@link Parameters#maxVideoHeight} and {@link
|
* Sets the viewport size to constrain adaptive video selections so that only tracks suitable
|
||||||
* Parameters#viewportOrientationMayChange}.
|
* for the viewport are selected.
|
||||||
*
|
*
|
||||||
* @param viewportWidth See {@link Parameters#viewportWidth}.
|
* @param viewportWidth Viewport width in pixels.
|
||||||
* @param viewportHeight See {@link Parameters#viewportHeight}.
|
* @param viewportHeight Viewport height in pixels.
|
||||||
* @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}.
|
* @param viewportOrientationMayChange Whether the viewport orientation may change during
|
||||||
|
* playback.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setViewportSize(
|
public ParametersBuilder setViewportSize(
|
||||||
|
|
@ -372,8 +393,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#maxAudioChannelCount}.
|
* Sets the maximum allowed audio channel count.
|
||||||
*
|
*
|
||||||
|
* @param maxAudioChannelCount Maximum allowed audio channel count.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) {
|
public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) {
|
||||||
|
|
@ -382,8 +404,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#maxAudioBitrate}.
|
* Sets the maximum allowed audio bitrate.
|
||||||
*
|
*
|
||||||
|
* @param maxAudioBitrate Maximum allowed audio bitrate in bits per second.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setMaxAudioBitrate(int maxAudioBitrate) {
|
public ParametersBuilder setMaxAudioBitrate(int maxAudioBitrate) {
|
||||||
|
|
@ -392,8 +415,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#exceedAudioConstraintsIfNecessary}.
|
* Sets whether to exceed the {@link #setMaxAudioChannelCount(int)} and {@link
|
||||||
|
* #setMaxAudioBitrate(int)} constraints when no selection can be made otherwise.
|
||||||
*
|
*
|
||||||
|
* @param exceedAudioConstraintsIfNecessary Whether to exceed audio constraints when no
|
||||||
|
* selection can be made otherwise.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setExceedAudioConstraintsIfNecessary(
|
public ParametersBuilder setExceedAudioConstraintsIfNecessary(
|
||||||
|
|
@ -403,8 +429,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#allowAudioMixedMimeTypeAdaptiveness}.
|
* Sets whether to allow adaptive audio selections containing mixed MIME types.
|
||||||
*
|
*
|
||||||
|
* <p>Adaptations between different MIME types may not be completely seamless.
|
||||||
|
*
|
||||||
|
* @param allowAudioMixedMimeTypeAdaptiveness Whether to allow adaptive audio selections
|
||||||
|
* containing mixed MIME types.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness(
|
public ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness(
|
||||||
|
|
@ -414,8 +444,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#allowAudioMixedSampleRateAdaptiveness}.
|
* Sets whether to allow adaptive audio selections containing mixed sample rates.
|
||||||
*
|
*
|
||||||
|
* <p>Adaptations between different sample rates may not be completely seamless.
|
||||||
|
*
|
||||||
|
* @param allowAudioMixedSampleRateAdaptiveness Whether to allow adaptive audio selections
|
||||||
|
* containing mixed sample rates.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness(
|
public ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness(
|
||||||
|
|
@ -424,6 +458,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether to allow adaptive audio selections containing mixed channel counts.
|
||||||
|
*
|
||||||
|
* <p>Adaptations between different channel counts may not be completely seamless.
|
||||||
|
*
|
||||||
|
* @param allowAudioMixedChannelCountAdaptiveness Whether to allow adaptive audio selections
|
||||||
|
* containing mixed channel counts.
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
public ParametersBuilder setAllowAudioMixedChannelCountAdaptiveness(
|
||||||
|
boolean allowAudioMixedChannelCountAdaptiveness) {
|
||||||
|
this.allowAudioMixedChannelCountAdaptiveness = allowAudioMixedChannelCountAdaptiveness;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -454,8 +503,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
// General
|
// General
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#forceLowestBitrate}.
|
* Sets whether to force selection of the single lowest bitrate audio and video tracks that
|
||||||
|
* comply with all other constraints.
|
||||||
*
|
*
|
||||||
|
* @param forceLowestBitrate Whether to force selection of the single lowest bitrate audio and
|
||||||
|
* video tracks.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setForceLowestBitrate(boolean forceLowestBitrate) {
|
public ParametersBuilder setForceLowestBitrate(boolean forceLowestBitrate) {
|
||||||
|
|
@ -464,8 +516,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#forceHighestSupportedBitrate}.
|
* Sets whether to force selection of the highest bitrate audio and video tracks that comply
|
||||||
|
* with all other constraints.
|
||||||
*
|
*
|
||||||
|
* @param forceHighestSupportedBitrate Whether to force selection of the highest bitrate audio
|
||||||
|
* and video tracks.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setForceHighestSupportedBitrate(boolean forceHighestSupportedBitrate) {
|
public ParametersBuilder setForceHighestSupportedBitrate(boolean forceHighestSupportedBitrate) {
|
||||||
|
|
@ -491,8 +546,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#exceedRendererCapabilitiesIfNecessary}.
|
* Sets whether to exceed renderer capabilities when no selection can be made otherwise.
|
||||||
*
|
*
|
||||||
|
* <p>This parameter applies when all of the tracks available for a renderer exceed the
|
||||||
|
* renderer's reported capabilities. If the parameter is {@code true} then the lowest quality
|
||||||
|
* track will still be selected. Playback may succeed if the renderer has under-reported its
|
||||||
|
* true capabilities. If {@code false} then no track will be selected.
|
||||||
|
*
|
||||||
|
* @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no
|
||||||
|
* selection can be made otherwise.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setExceedRendererCapabilitiesIfNecessary(
|
public ParametersBuilder setExceedRendererCapabilitiesIfNecessary(
|
||||||
|
|
@ -502,7 +564,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link Parameters#tunnelingAudioSessionId}.
|
* Sets the audio session id to use when tunneling.
|
||||||
*
|
*
|
||||||
* <p>Enables or disables tunneling. To enable tunneling, pass an audio session id to use when
|
* <p>Enables or disables tunneling. To enable tunneling, pass an audio session id to use when
|
||||||
* in tunneling mode. Session ids can be generated using {@link
|
* in tunneling mode. Session ids can be generated using {@link
|
||||||
|
|
@ -512,6 +574,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*
|
*
|
||||||
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
|
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
|
||||||
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
|
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
|
||||||
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
|
public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
|
||||||
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
||||||
|
|
@ -526,6 +589,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*
|
*
|
||||||
* @param rendererIndex The renderer index.
|
* @param rendererIndex The renderer index.
|
||||||
* @param disabled Whether the renderer is disabled.
|
* @param disabled Whether the renderer is disabled.
|
||||||
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) {
|
public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) {
|
||||||
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
|
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
|
||||||
|
|
@ -562,6 +626,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
* @param rendererIndex The renderer index.
|
* @param rendererIndex The renderer index.
|
||||||
* @param groups The {@link TrackGroupArray} for which the override should be applied.
|
* @param groups The {@link TrackGroupArray} for which the override should be applied.
|
||||||
* @param override The override.
|
* @param override The override.
|
||||||
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public final ParametersBuilder setSelectionOverride(
|
public final ParametersBuilder setSelectionOverride(
|
||||||
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
|
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
|
||||||
|
|
@ -583,6 +648,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*
|
*
|
||||||
* @param rendererIndex The renderer index.
|
* @param rendererIndex The renderer index.
|
||||||
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
|
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
|
||||||
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public final ParametersBuilder clearSelectionOverride(
|
public final ParametersBuilder clearSelectionOverride(
|
||||||
int rendererIndex, TrackGroupArray groups) {
|
int rendererIndex, TrackGroupArray groups) {
|
||||||
|
|
@ -602,6 +668,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
* Clears all track selection overrides for the specified renderer.
|
* Clears all track selection overrides for the specified renderer.
|
||||||
*
|
*
|
||||||
* @param rendererIndex The renderer index.
|
* @param rendererIndex The renderer index.
|
||||||
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
|
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
|
||||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||||
|
|
@ -613,7 +680,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clears all track selection overrides for all renderers. */
|
/**
|
||||||
|
* Clears all track selection overrides for all renderers.
|
||||||
|
*
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
public final ParametersBuilder clearSelectionOverrides() {
|
public final ParametersBuilder clearSelectionOverrides() {
|
||||||
if (selectionOverrides.size() == 0) {
|
if (selectionOverrides.size() == 0) {
|
||||||
// Nothing to clear.
|
// Nothing to clear.
|
||||||
|
|
@ -646,6 +717,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
exceedAudioConstraintsIfNecessary,
|
exceedAudioConstraintsIfNecessary,
|
||||||
allowAudioMixedMimeTypeAdaptiveness,
|
allowAudioMixedMimeTypeAdaptiveness,
|
||||||
allowAudioMixedSampleRateAdaptiveness,
|
allowAudioMixedSampleRateAdaptiveness,
|
||||||
|
allowAudioMixedChannelCountAdaptiveness,
|
||||||
// Text
|
// Text
|
||||||
preferredTextLanguage,
|
preferredTextLanguage,
|
||||||
preferredRoleFlags,
|
preferredRoleFlags,
|
||||||
|
|
@ -695,8 +767,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
|
|
||||||
// Video
|
// Video
|
||||||
/**
|
/**
|
||||||
* Maximum allowed video width. The default value is {@link Integer#MAX_VALUE} (i.e. no
|
* Maximum allowed video width in pixels. The default value is {@link Integer#MAX_VALUE} (i.e.
|
||||||
* constraint).
|
* no constraint).
|
||||||
*
|
*
|
||||||
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the
|
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the
|
||||||
* region of the display within which video will be played), use ({@link #viewportWidth}, {@link
|
* region of the display within which video will be played), use ({@link #viewportWidth}, {@link
|
||||||
|
|
@ -704,8 +776,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*/
|
*/
|
||||||
public final int maxVideoWidth;
|
public final int maxVideoWidth;
|
||||||
/**
|
/**
|
||||||
* Maximum allowed video height. The default value is {@link Integer#MAX_VALUE} (i.e. no
|
* Maximum allowed video height in pixels. The default value is {@link Integer#MAX_VALUE} (i.e.
|
||||||
* constraint).
|
* no constraint).
|
||||||
*
|
*
|
||||||
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the
|
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the
|
||||||
* region of the display within which video will be played), use ({@link #viewportWidth}, {@link
|
* region of the display within which video will be played), use ({@link #viewportWidth}, {@link
|
||||||
|
|
@ -713,12 +785,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*/
|
*/
|
||||||
public final int maxVideoHeight;
|
public final int maxVideoHeight;
|
||||||
/**
|
/**
|
||||||
* Maximum allowed video frame rate. The default value is {@link Integer#MAX_VALUE} (i.e. no
|
* Maximum allowed video frame rate in hertz. The default value is {@link Integer#MAX_VALUE}
|
||||||
* constraint).
|
* (i.e. no constraint).
|
||||||
*/
|
*/
|
||||||
public final int maxVideoFrameRate;
|
public final int maxVideoFrameRate;
|
||||||
/**
|
/**
|
||||||
* Maximum video bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint).
|
* Maximum allowed video bitrate in bits per second. The default value is {@link
|
||||||
|
* Integer#MAX_VALUE} (i.e. no constraint).
|
||||||
*/
|
*/
|
||||||
public final int maxVideoBitrate;
|
public final int maxVideoBitrate;
|
||||||
/**
|
/**
|
||||||
|
|
@ -728,9 +801,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*/
|
*/
|
||||||
public final boolean exceedVideoConstraintsIfNecessary;
|
public final boolean exceedVideoConstraintsIfNecessary;
|
||||||
/**
|
/**
|
||||||
* Whether to allow adaptive video selections containing mixed mime types. Adaptations between
|
* Whether to allow adaptive video selections containing mixed MIME types. Adaptations between
|
||||||
* different mime types may not be completely seamless, in which case {@link
|
* different MIME types may not be completely seamless, in which case {@link
|
||||||
* #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed mime type
|
* #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed MIME type
|
||||||
* selections to be made. The default value is {@code false}.
|
* selections to be made. The default value is {@code false}.
|
||||||
*/
|
*/
|
||||||
public final boolean allowVideoMixedMimeTypeAdaptiveness;
|
public final boolean allowVideoMixedMimeTypeAdaptiveness;
|
||||||
|
|
@ -764,7 +837,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*/
|
*/
|
||||||
public final int maxAudioChannelCount;
|
public final int maxAudioChannelCount;
|
||||||
/**
|
/**
|
||||||
* Maximum audio bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint).
|
* Maximum allowed audio bitrate in bits per second. The default value is {@link
|
||||||
|
* Integer#MAX_VALUE} (i.e. no constraint).
|
||||||
*/
|
*/
|
||||||
public final int maxAudioBitrate;
|
public final int maxAudioBitrate;
|
||||||
/**
|
/**
|
||||||
|
|
@ -773,8 +847,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
*/
|
*/
|
||||||
public final boolean exceedAudioConstraintsIfNecessary;
|
public final boolean exceedAudioConstraintsIfNecessary;
|
||||||
/**
|
/**
|
||||||
* Whether to allow adaptive audio selections containing mixed mime types. Adaptations between
|
* Whether to allow adaptive audio selections containing mixed MIME types. Adaptations between
|
||||||
* different mime types may not be completely seamless. The default value is {@code false}.
|
* different MIME types may not be completely seamless. The default value is {@code false}.
|
||||||
*/
|
*/
|
||||||
public final boolean allowAudioMixedMimeTypeAdaptiveness;
|
public final boolean allowAudioMixedMimeTypeAdaptiveness;
|
||||||
/**
|
/**
|
||||||
|
|
@ -782,6 +856,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
* different sample rates may not be completely seamless. The default value is {@code false}.
|
* different sample rates may not be completely seamless. The default value is {@code false}.
|
||||||
*/
|
*/
|
||||||
public final boolean allowAudioMixedSampleRateAdaptiveness;
|
public final boolean allowAudioMixedSampleRateAdaptiveness;
|
||||||
|
/**
|
||||||
|
* Whether to allow adaptive audio selections containing mixed channel counts. Adaptations
|
||||||
|
* between different channel counts may not be completely seamless. The default value is {@code
|
||||||
|
* false}.
|
||||||
|
*/
|
||||||
|
public final boolean allowAudioMixedChannelCountAdaptiveness;
|
||||||
|
|
||||||
// General
|
// General
|
||||||
/**
|
/**
|
||||||
|
|
@ -842,6 +922,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
/* exceedAudioConstraintsIfNecessary= */ true,
|
/* exceedAudioConstraintsIfNecessary= */ true,
|
||||||
/* allowAudioMixedMimeTypeAdaptiveness= */ false,
|
/* allowAudioMixedMimeTypeAdaptiveness= */ false,
|
||||||
/* allowAudioMixedSampleRateAdaptiveness= */ false,
|
/* allowAudioMixedSampleRateAdaptiveness= */ false,
|
||||||
|
/* allowAudioMixedChannelCountAdaptiveness= */ false,
|
||||||
// Text
|
// Text
|
||||||
TrackSelectionParameters.DEFAULT.preferredTextLanguage,
|
TrackSelectionParameters.DEFAULT.preferredTextLanguage,
|
||||||
TrackSelectionParameters.DEFAULT.preferredRoleFlags,
|
TrackSelectionParameters.DEFAULT.preferredRoleFlags,
|
||||||
|
|
@ -875,6 +956,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
boolean exceedAudioConstraintsIfNecessary,
|
boolean exceedAudioConstraintsIfNecessary,
|
||||||
boolean allowAudioMixedMimeTypeAdaptiveness,
|
boolean allowAudioMixedMimeTypeAdaptiveness,
|
||||||
boolean allowAudioMixedSampleRateAdaptiveness,
|
boolean allowAudioMixedSampleRateAdaptiveness,
|
||||||
|
boolean allowAudioMixedChannelCountAdaptiveness,
|
||||||
// Text
|
// Text
|
||||||
@Nullable String preferredTextLanguage,
|
@Nullable String preferredTextLanguage,
|
||||||
@C.RoleFlags int preferredRoleFlags,
|
@C.RoleFlags int preferredRoleFlags,
|
||||||
|
|
@ -911,6 +993,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary;
|
this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary;
|
||||||
this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness;
|
this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness;
|
||||||
this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness;
|
this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness;
|
||||||
|
this.allowAudioMixedChannelCountAdaptiveness = allowAudioMixedChannelCountAdaptiveness;
|
||||||
// General
|
// General
|
||||||
this.forceLowestBitrate = forceLowestBitrate;
|
this.forceLowestBitrate = forceLowestBitrate;
|
||||||
this.forceHighestSupportedBitrate = forceHighestSupportedBitrate;
|
this.forceHighestSupportedBitrate = forceHighestSupportedBitrate;
|
||||||
|
|
@ -944,6 +1027,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
this.exceedAudioConstraintsIfNecessary = Util.readBoolean(in);
|
this.exceedAudioConstraintsIfNecessary = Util.readBoolean(in);
|
||||||
this.allowAudioMixedMimeTypeAdaptiveness = Util.readBoolean(in);
|
this.allowAudioMixedMimeTypeAdaptiveness = Util.readBoolean(in);
|
||||||
this.allowAudioMixedSampleRateAdaptiveness = Util.readBoolean(in);
|
this.allowAudioMixedSampleRateAdaptiveness = Util.readBoolean(in);
|
||||||
|
this.allowAudioMixedChannelCountAdaptiveness = Util.readBoolean(in);
|
||||||
// General
|
// General
|
||||||
this.forceLowestBitrate = Util.readBoolean(in);
|
this.forceLowestBitrate = Util.readBoolean(in);
|
||||||
this.forceHighestSupportedBitrate = Util.readBoolean(in);
|
this.forceHighestSupportedBitrate = Util.readBoolean(in);
|
||||||
|
|
@ -1025,6 +1109,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
&& exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary
|
&& exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary
|
||||||
&& allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness
|
&& allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness
|
||||||
&& allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness
|
&& allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness
|
||||||
|
&& allowAudioMixedChannelCountAdaptiveness
|
||||||
|
== other.allowAudioMixedChannelCountAdaptiveness
|
||||||
// General
|
// General
|
||||||
&& forceLowestBitrate == other.forceLowestBitrate
|
&& forceLowestBitrate == other.forceLowestBitrate
|
||||||
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
|
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
|
||||||
|
|
@ -1055,6 +1141,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0);
|
result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0);
|
||||||
result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0);
|
result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0);
|
||||||
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
|
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
|
||||||
|
result = 31 * result + (allowAudioMixedChannelCountAdaptiveness ? 1 : 0);
|
||||||
// General
|
// General
|
||||||
result = 31 * result + (forceLowestBitrate ? 1 : 0);
|
result = 31 * result + (forceLowestBitrate ? 1 : 0);
|
||||||
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
|
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
|
||||||
|
|
@ -1091,6 +1178,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
Util.writeBoolean(dest, exceedAudioConstraintsIfNecessary);
|
Util.writeBoolean(dest, exceedAudioConstraintsIfNecessary);
|
||||||
Util.writeBoolean(dest, allowAudioMixedMimeTypeAdaptiveness);
|
Util.writeBoolean(dest, allowAudioMixedMimeTypeAdaptiveness);
|
||||||
Util.writeBoolean(dest, allowAudioMixedSampleRateAdaptiveness);
|
Util.writeBoolean(dest, allowAudioMixedSampleRateAdaptiveness);
|
||||||
|
Util.writeBoolean(dest, allowAudioMixedChannelCountAdaptiveness);
|
||||||
// General
|
// General
|
||||||
Util.writeBoolean(dest, forceLowestBitrate);
|
Util.writeBoolean(dest, forceLowestBitrate);
|
||||||
Util.writeBoolean(dest, forceHighestSupportedBitrate);
|
Util.writeBoolean(dest, forceHighestSupportedBitrate);
|
||||||
|
|
@ -1999,7 +2087,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
formatSupports[selectedGroupIndex],
|
formatSupports[selectedGroupIndex],
|
||||||
params.maxAudioBitrate,
|
params.maxAudioBitrate,
|
||||||
params.allowAudioMixedMimeTypeAdaptiveness,
|
params.allowAudioMixedMimeTypeAdaptiveness,
|
||||||
params.allowAudioMixedSampleRateAdaptiveness);
|
params.allowAudioMixedSampleRateAdaptiveness,
|
||||||
|
params.allowAudioMixedChannelCountAdaptiveness);
|
||||||
if (adaptiveTracks.length > 0) {
|
if (adaptiveTracks.length > 0) {
|
||||||
definition = new TrackSelection.Definition(selectedGroup, adaptiveTracks);
|
definition = new TrackSelection.Definition(selectedGroup, adaptiveTracks);
|
||||||
}
|
}
|
||||||
|
|
@ -2017,7 +2106,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
int[] formatSupport,
|
int[] formatSupport,
|
||||||
int maxAudioBitrate,
|
int maxAudioBitrate,
|
||||||
boolean allowMixedMimeTypeAdaptiveness,
|
boolean allowMixedMimeTypeAdaptiveness,
|
||||||
boolean allowMixedSampleRateAdaptiveness) {
|
boolean allowMixedSampleRateAdaptiveness,
|
||||||
|
boolean allowAudioMixedChannelCountAdaptiveness) {
|
||||||
int selectedConfigurationTrackCount = 0;
|
int selectedConfigurationTrackCount = 0;
|
||||||
AudioConfigurationTuple selectedConfiguration = null;
|
AudioConfigurationTuple selectedConfiguration = null;
|
||||||
HashSet<AudioConfigurationTuple> seenConfigurationTuples = new HashSet<>();
|
HashSet<AudioConfigurationTuple> seenConfigurationTuples = new HashSet<>();
|
||||||
|
|
@ -2034,7 +2124,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
configuration,
|
configuration,
|
||||||
maxAudioBitrate,
|
maxAudioBitrate,
|
||||||
allowMixedMimeTypeAdaptiveness,
|
allowMixedMimeTypeAdaptiveness,
|
||||||
allowMixedSampleRateAdaptiveness);
|
allowMixedSampleRateAdaptiveness,
|
||||||
|
allowAudioMixedChannelCountAdaptiveness);
|
||||||
if (configurationCount > selectedConfigurationTrackCount) {
|
if (configurationCount > selectedConfigurationTrackCount) {
|
||||||
selectedConfiguration = configuration;
|
selectedConfiguration = configuration;
|
||||||
selectedConfigurationTrackCount = configurationCount;
|
selectedConfigurationTrackCount = configurationCount;
|
||||||
|
|
@ -2054,7 +2145,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
selectedConfiguration,
|
selectedConfiguration,
|
||||||
maxAudioBitrate,
|
maxAudioBitrate,
|
||||||
allowMixedMimeTypeAdaptiveness,
|
allowMixedMimeTypeAdaptiveness,
|
||||||
allowMixedSampleRateAdaptiveness)) {
|
allowMixedSampleRateAdaptiveness,
|
||||||
|
allowAudioMixedChannelCountAdaptiveness)) {
|
||||||
adaptiveIndices[index++] = i;
|
adaptiveIndices[index++] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2069,7 +2161,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
AudioConfigurationTuple configuration,
|
AudioConfigurationTuple configuration,
|
||||||
int maxAudioBitrate,
|
int maxAudioBitrate,
|
||||||
boolean allowMixedMimeTypeAdaptiveness,
|
boolean allowMixedMimeTypeAdaptiveness,
|
||||||
boolean allowMixedSampleRateAdaptiveness) {
|
boolean allowMixedSampleRateAdaptiveness,
|
||||||
|
boolean allowAudioMixedChannelCountAdaptiveness) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < group.length; i++) {
|
for (int i = 0; i < group.length; i++) {
|
||||||
if (isSupportedAdaptiveAudioTrack(
|
if (isSupportedAdaptiveAudioTrack(
|
||||||
|
|
@ -2078,7 +2171,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
configuration,
|
configuration,
|
||||||
maxAudioBitrate,
|
maxAudioBitrate,
|
||||||
allowMixedMimeTypeAdaptiveness,
|
allowMixedMimeTypeAdaptiveness,
|
||||||
allowMixedSampleRateAdaptiveness)) {
|
allowMixedSampleRateAdaptiveness,
|
||||||
|
allowAudioMixedChannelCountAdaptiveness)) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2091,11 +2185,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
AudioConfigurationTuple configuration,
|
AudioConfigurationTuple configuration,
|
||||||
int maxAudioBitrate,
|
int maxAudioBitrate,
|
||||||
boolean allowMixedMimeTypeAdaptiveness,
|
boolean allowMixedMimeTypeAdaptiveness,
|
||||||
boolean allowMixedSampleRateAdaptiveness) {
|
boolean allowMixedSampleRateAdaptiveness,
|
||||||
|
boolean allowAudioMixedChannelCountAdaptiveness) {
|
||||||
return isSupported(formatSupport, false)
|
return isSupported(formatSupport, false)
|
||||||
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= maxAudioBitrate)
|
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= maxAudioBitrate)
|
||||||
&& (format.channelCount != Format.NO_VALUE
|
&& (allowAudioMixedChannelCountAdaptiveness
|
||||||
&& format.channelCount == configuration.channelCount)
|
|| (format.channelCount != Format.NO_VALUE
|
||||||
|
&& format.channelCount == configuration.channelCount))
|
||||||
&& (allowMixedMimeTypeAdaptiveness
|
&& (allowMixedMimeTypeAdaptiveness
|
||||||
|| (format.sampleMimeType != null
|
|| (format.sampleMimeType != null
|
||||||
&& TextUtils.equals(format.sampleMimeType, configuration.mimeType)))
|
&& TextUtils.equals(format.sampleMimeType, configuration.mimeType)))
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,10 @@ public class TrackSelectionParameters implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link TrackSelectionParameters#preferredAudioLanguage}.
|
* Sets the preferred language for audio and forced text tracks.
|
||||||
*
|
*
|
||||||
* @param preferredAudioLanguage Preferred audio language as an IETF BCP 47 conformant tag.
|
* @param preferredAudioLanguage Preferred audio language as an IETF BCP 47 conformant tag, or
|
||||||
|
* {@code null} to select the default track, or the first track if there's no default.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public Builder setPreferredAudioLanguage(@Nullable String preferredAudioLanguage) {
|
public Builder setPreferredAudioLanguage(@Nullable String preferredAudioLanguage) {
|
||||||
|
|
@ -66,9 +67,10 @@ public class TrackSelectionParameters implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link TrackSelectionParameters#preferredTextLanguage}.
|
* Sets the preferred language for text tracks.
|
||||||
*
|
*
|
||||||
* @param preferredTextLanguage Preferred text language as an IETF BCP 47 conformant tag.
|
* @param preferredTextLanguage Preferred text language as an IETF BCP 47 conformant tag, or
|
||||||
|
* {@code null} to select the default track if there is one, or no track otherwise.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public Builder setPreferredTextLanguage(@Nullable String preferredTextLanguage) {
|
public Builder setPreferredTextLanguage(@Nullable String preferredTextLanguage) {
|
||||||
|
|
@ -88,8 +90,12 @@ public class TrackSelectionParameters implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link TrackSelectionParameters#selectUndeterminedTextLanguage}.
|
* Sets whether a text track with undetermined language should be selected if no track with
|
||||||
|
* {@link #setPreferredTextLanguage(String)} is available, or if the preferred language is
|
||||||
|
* unset.
|
||||||
*
|
*
|
||||||
|
* @param selectUndeterminedTextLanguage Whether a text track with undetermined language should
|
||||||
|
* be selected if no preferred language track is available.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public Builder setSelectUndeterminedTextLanguage(boolean selectUndeterminedTextLanguage) {
|
public Builder setSelectUndeterminedTextLanguage(boolean selectUndeterminedTextLanguage) {
|
||||||
|
|
@ -98,8 +104,10 @@ public class TrackSelectionParameters implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link TrackSelectionParameters#disabledTextTrackSelectionFlags}.
|
* Sets a bitmask of selection flags that are disabled for text track selections.
|
||||||
*
|
*
|
||||||
|
* @param disabledTextTrackSelectionFlags A bitmask of {@link C.SelectionFlags} that are
|
||||||
|
* disabled for text track selections.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public Builder setDisabledTextTrackSelectionFlags(
|
public Builder setDisabledTextTrackSelectionFlags(
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.metadata.emsg;
|
package com.google.android.exoplayer2.metadata.emsg;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.testutil.TestUtil.createByteArray;
|
||||||
|
import static com.google.android.exoplayer2.testutil.TestUtil.joinByteArrays;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
@ -30,18 +32,19 @@ public final class EventMessageDecoderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecodeEventMessage() {
|
public void testDecodeEventMessage() {
|
||||||
byte[] rawEmsgBody = new byte[] {
|
byte[] rawEmsgBody =
|
||||||
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
joinByteArrays(
|
||||||
49, 50, 51, 0, // value = "123"
|
createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test"
|
||||||
0, 0, -69, -128, // timescale = 48000
|
createByteArray(49, 50, 51, 0), // value = "123"
|
||||||
0, 0, -69, -128, // presentation_time_delta = 48000
|
createByteArray(0, 0, 11, 184), // event_duration_ms = 3000
|
||||||
0, 2, 50, -128, // event_duration = 144000
|
createByteArray(0, 15, 67, 211), // id = 1000403
|
||||||
0, 15, 67, -45, // id = 1000403
|
createByteArray(0, 1, 2, 3, 4)); // message_data = {0, 1, 2, 3, 4}
|
||||||
0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4}
|
|
||||||
EventMessageDecoder decoder = new EventMessageDecoder();
|
EventMessageDecoder decoder = new EventMessageDecoder();
|
||||||
MetadataInputBuffer buffer = new MetadataInputBuffer();
|
MetadataInputBuffer buffer = new MetadataInputBuffer();
|
||||||
buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody);
|
buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody);
|
||||||
|
|
||||||
Metadata metadata = decoder.decode(buffer);
|
Metadata metadata = decoder.decode(buffer);
|
||||||
|
|
||||||
assertThat(metadata.length()).isEqualTo(1);
|
assertThat(metadata.length()).isEqualTo(1);
|
||||||
EventMessage eventMessage = (EventMessage) metadata.get(0);
|
EventMessage eventMessage = (EventMessage) metadata.get(0);
|
||||||
assertThat(eventMessage.schemeIdUri).isEqualTo("urn:test");
|
assertThat(eventMessage.schemeIdUri).isEqualTo("urn:test");
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.metadata.emsg;
|
package com.google.android.exoplayer2.metadata.emsg;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.testutil.TestUtil.createByteArray;
|
||||||
|
import static com.google.android.exoplayer2.testutil.TestUtil.joinByteArrays;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
@ -29,67 +31,52 @@ import org.junit.runner.RunWith;
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public final class EventMessageEncoderTest {
|
public final class EventMessageEncoderTest {
|
||||||
|
|
||||||
|
private static final EventMessage DECODED_MESSAGE =
|
||||||
|
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
||||||
|
|
||||||
|
private static final byte[] ENCODED_MESSAGE =
|
||||||
|
joinByteArrays(
|
||||||
|
createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test"
|
||||||
|
createByteArray(49, 50, 51, 0), // value = "123"
|
||||||
|
createByteArray(0, 0, 11, 184), // event_duration_ms = 3000
|
||||||
|
createByteArray(0, 15, 67, 211), // id = 1000403
|
||||||
|
createByteArray(0, 1, 2, 3, 4)); // message_data = {0, 1, 2, 3, 4}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeEventStream() throws IOException {
|
public void testEncodeEventStream() throws IOException {
|
||||||
EventMessage eventMessage =
|
byte[] foo = new byte[] {1, 2, 3};
|
||||||
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
|
||||||
byte[] expectedEmsgBody =
|
byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE);
|
||||||
new byte[] {
|
assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE);
|
||||||
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
|
||||||
49, 50, 51, 0, // value = "123"
|
|
||||||
0, 0, 3, -24, // timescale = 1000
|
|
||||||
0, 0, 0, 0, // presentation_time_delta = 0
|
|
||||||
0, 0, 11, -72, // event_duration = 3000
|
|
||||||
0, 15, 67, -45, // id = 1000403
|
|
||||||
0, 1, 2, 3, 4
|
|
||||||
}; // message_data = {0, 1, 2, 3, 4}
|
|
||||||
byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage);
|
|
||||||
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeDecodeEventStream() throws IOException {
|
public void testEncodeDecodeEventStream() throws IOException {
|
||||||
EventMessage expectedEmsg =
|
byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE);
|
||||||
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
|
||||||
byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg);
|
|
||||||
MetadataInputBuffer buffer = new MetadataInputBuffer();
|
MetadataInputBuffer buffer = new MetadataInputBuffer();
|
||||||
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
|
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
|
||||||
|
|
||||||
EventMessageDecoder decoder = new EventMessageDecoder();
|
EventMessageDecoder decoder = new EventMessageDecoder();
|
||||||
Metadata metadata = decoder.decode(buffer);
|
Metadata metadata = decoder.decode(buffer);
|
||||||
assertThat(metadata.length()).isEqualTo(1);
|
assertThat(metadata.length()).isEqualTo(1);
|
||||||
assertThat(metadata.get(0)).isEqualTo(expectedEmsg);
|
assertThat(metadata.get(0)).isEqualTo(DECODED_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException {
|
public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException {
|
||||||
EventMessage eventMessage =
|
|
||||||
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
|
||||||
byte[] expectedEmsgBody =
|
|
||||||
new byte[] {
|
|
||||||
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
|
||||||
49, 50, 51, 0, // value = "123"
|
|
||||||
0, 0, 3, -24, // timescale = 1000
|
|
||||||
0, 0, 0, 0, // presentation_time_delta = 0
|
|
||||||
0, 0, 11, -72, // event_duration = 3000
|
|
||||||
0, 15, 67, -45, // id = 1000403
|
|
||||||
0, 1, 2, 3, 4
|
|
||||||
}; // message_data = {0, 1, 2, 3, 4}
|
|
||||||
EventMessage eventMessage1 =
|
EventMessage eventMessage1 =
|
||||||
new EventMessage("urn:test", "123", 3000, 1000402, new byte[] {4, 3, 2, 1, 0});
|
new EventMessage("urn:test", "123", 3000, 1000402, new byte[] {4, 3, 2, 1, 0});
|
||||||
byte[] expectedEmsgBody1 =
|
byte[] expectedEmsgBody1 =
|
||||||
new byte[] {
|
joinByteArrays(
|
||||||
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test"
|
||||||
49, 50, 51, 0, // value = "123"
|
createByteArray(49, 50, 51, 0), // value = "123"
|
||||||
0, 0, 3, -24, // timescale = 1000
|
createByteArray(0, 0, 11, 184), // event_duration_ms = 3000
|
||||||
0, 0, 0, 0, // presentation_time_delta = 0
|
createByteArray(0, 15, 67, 210), // id = 1000402
|
||||||
0, 0, 11, -72, // event_duration = 3000
|
createByteArray(4, 3, 2, 1, 0)); // message_data = {4, 3, 2, 1, 0}
|
||||||
0, 15, 67, -46, // id = 1000402
|
|
||||||
4, 3, 2, 1, 0
|
|
||||||
}; // message_data = {4, 3, 2, 1, 0}
|
|
||||||
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
|
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
|
||||||
byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage);
|
byte[] encodedByteArray = eventMessageEncoder.encode(DECODED_MESSAGE);
|
||||||
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
|
assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE);
|
||||||
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1);
|
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1);
|
||||||
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
|
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@ public final class DefaultTrackSelectorTest {
|
||||||
/* exceedAudioConstraintsIfNecessary= */ false,
|
/* exceedAudioConstraintsIfNecessary= */ false,
|
||||||
/* allowAudioMixedMimeTypeAdaptiveness= */ true,
|
/* allowAudioMixedMimeTypeAdaptiveness= */ true,
|
||||||
/* allowAudioMixedSampleRateAdaptiveness= */ false,
|
/* allowAudioMixedSampleRateAdaptiveness= */ false,
|
||||||
|
/* allowAudioMixedChannelCountAdaptiveness= */ true,
|
||||||
// Text
|
// Text
|
||||||
/* preferredTextLanguage= */ "de",
|
/* preferredTextLanguage= */ "de",
|
||||||
/* selectUndeterminedTextLanguage= */ true,
|
/* selectUndeterminedTextLanguage= */ true,
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,10 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
|
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/** A DASH {@link MediaPeriod}. */
|
/** A DASH {@link MediaPeriod}. */
|
||||||
/* package */ final class DashMediaPeriod
|
/* package */ final class DashMediaPeriod
|
||||||
|
|
@ -245,8 +246,12 @@ import java.util.regex.Pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
|
public long selectTracks(
|
||||||
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
|
@NullableType TrackSelection[] selections,
|
||||||
|
boolean[] mayRetainStreamFlags,
|
||||||
|
@NullableType SampleStream[] streams,
|
||||||
|
boolean[] streamResetFlags,
|
||||||
|
long positionUs) {
|
||||||
int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections);
|
int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections);
|
||||||
releaseDisabledStreams(selections, mayRetainStreamFlags, streams);
|
releaseDisabledStreams(selections, mayRetainStreamFlags, streams);
|
||||||
releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex);
|
releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex);
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
* @return This factory, for convenience.
|
* @return This factory, for convenience.
|
||||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||||
*/
|
*/
|
||||||
public Factory setTag(Object tag) {
|
public Factory setTag(@Nullable Object tag) {
|
||||||
Assertions.checkState(!isCreateCalled);
|
Assertions.checkState(!isCreateCalled);
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -430,8 +430,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
public DashMediaSource(
|
public DashMediaSource(
|
||||||
DashManifest manifest,
|
DashManifest manifest,
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
manifest,
|
manifest,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
|
|
@ -455,8 +455,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
DashManifest manifest,
|
DashManifest manifest,
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
int minLoadableRetryCount,
|
int minLoadableRetryCount,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
manifest,
|
manifest,
|
||||||
/* manifestUri= */ null,
|
/* manifestUri= */ null,
|
||||||
|
|
@ -492,8 +492,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
Uri manifestUri,
|
Uri manifestUri,
|
||||||
DataSource.Factory manifestDataSourceFactory,
|
DataSource.Factory manifestDataSourceFactory,
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
manifestUri,
|
manifestUri,
|
||||||
manifestDataSourceFactory,
|
manifestDataSourceFactory,
|
||||||
|
|
@ -529,8 +529,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
int minLoadableRetryCount,
|
int minLoadableRetryCount,
|
||||||
long livePresentationDelayMs,
|
long livePresentationDelayMs,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
manifestUri,
|
manifestUri,
|
||||||
manifestDataSourceFactory,
|
manifestDataSourceFactory,
|
||||||
|
|
@ -569,8 +569,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
int minLoadableRetryCount,
|
int minLoadableRetryCount,
|
||||||
long livePresentationDelayMs,
|
long livePresentationDelayMs,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
manifestUri,
|
manifestUri,
|
||||||
|
|
@ -591,10 +591,10 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DashMediaSource(
|
private DashMediaSource(
|
||||||
DashManifest manifest,
|
@Nullable DashManifest manifest,
|
||||||
Uri manifestUri,
|
@Nullable Uri manifestUri,
|
||||||
DataSource.Factory manifestDataSourceFactory,
|
@Nullable DataSource.Factory manifestDataSourceFactory,
|
||||||
ParsingLoadable.Parser<? extends DashManifest> manifestParser,
|
@Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser,
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||||
DrmSessionManager<?> drmSessionManager,
|
DrmSessionManager<?> drmSessionManager,
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ public final class DashUtil {
|
||||||
* @throws IOException Thrown when there is an error while loading.
|
* @throws IOException Thrown when there is an error while loading.
|
||||||
* @throws InterruptedException Thrown if the thread was interrupted.
|
* @throws InterruptedException Thrown if the thread was interrupted.
|
||||||
*/
|
*/
|
||||||
public static @Nullable DrmInitData loadDrmInitData(DataSource dataSource, Period period)
|
@Nullable
|
||||||
|
public static DrmInitData loadDrmInitData(DataSource dataSource, Period period)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
int primaryTrackType = C.TRACK_TYPE_VIDEO;
|
int primaryTrackType = C.TRACK_TYPE_VIDEO;
|
||||||
Representation representation = getFirstRepresentation(period, primaryTrackType);
|
Representation representation = getFirstRepresentation(period, primaryTrackType);
|
||||||
|
|
@ -95,7 +96,8 @@ public final class DashUtil {
|
||||||
* @throws IOException Thrown when there is an error while loading.
|
* @throws IOException Thrown when there is an error while loading.
|
||||||
* @throws InterruptedException Thrown if the thread was interrupted.
|
* @throws InterruptedException Thrown if the thread was interrupted.
|
||||||
*/
|
*/
|
||||||
public static @Nullable Format loadSampleFormat(
|
@Nullable
|
||||||
|
public static Format loadSampleFormat(
|
||||||
DataSource dataSource, int trackType, Representation representation)
|
DataSource dataSource, int trackType, Representation representation)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
|
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
|
||||||
|
|
@ -116,7 +118,8 @@ public final class DashUtil {
|
||||||
* @throws IOException Thrown when there is an error while loading.
|
* @throws IOException Thrown when there is an error while loading.
|
||||||
* @throws InterruptedException Thrown if the thread was interrupted.
|
* @throws InterruptedException Thrown if the thread was interrupted.
|
||||||
*/
|
*/
|
||||||
public static @Nullable ChunkIndex loadChunkIndex(
|
@Nullable
|
||||||
|
public static ChunkIndex loadChunkIndex(
|
||||||
DataSource dataSource, int trackType, Representation representation)
|
DataSource dataSource, int trackType, Representation representation)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
|
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
|
||||||
|
|
@ -138,7 +141,8 @@ public final class DashUtil {
|
||||||
* @throws IOException Thrown when there is an error while loading.
|
* @throws IOException Thrown when there is an error while loading.
|
||||||
* @throws InterruptedException Thrown if the thread was interrupted.
|
* @throws InterruptedException Thrown if the thread was interrupted.
|
||||||
*/
|
*/
|
||||||
private static @Nullable ChunkExtractorWrapper loadInitializationData(
|
@Nullable
|
||||||
|
private static ChunkExtractorWrapper loadInitializationData(
|
||||||
DataSource dataSource, int trackType, Representation representation, boolean loadIndex)
|
DataSource dataSource, int trackType, Representation representation, boolean loadIndex)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
RangedUri initializationUri = representation.getInitializationUri();
|
RangedUri initializationUri = representation.getInitializationUri();
|
||||||
|
|
@ -187,7 +191,8 @@ public final class DashUtil {
|
||||||
return new ChunkExtractorWrapper(extractor, trackType, format);
|
return new ChunkExtractorWrapper(extractor, trackType, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable Representation getFirstRepresentation(Period period, int type) {
|
@Nullable
|
||||||
|
private static Representation getFirstRepresentation(Period period, int type) {
|
||||||
int index = period.getAdaptationSetIndex(type);
|
int index = period.getAdaptationSetIndex(type);
|
||||||
if (index == C.INDEX_UNSET) {
|
if (index == C.INDEX_UNSET) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -197,5 +202,4 @@ public final class DashUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DashUtil() {}
|
private DashUtil() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
private final int maxSegmentsPerLoad;
|
private final int maxSegmentsPerLoad;
|
||||||
|
|
||||||
public Factory(DataSource.Factory dataSourceFactory) {
|
public Factory(DataSource.Factory dataSourceFactory) {
|
||||||
this(dataSourceFactory, 1);
|
this(dataSourceFactory, /* maxSegmentsPerLoad= */ 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Factory(DataSource.Factory dataSourceFactory, int maxSegmentsPerLoad) {
|
public Factory(DataSource.Factory dataSourceFactory, int maxSegmentsPerLoad) {
|
||||||
|
|
@ -633,7 +633,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
Representation representation,
|
Representation representation,
|
||||||
boolean enableEventMessageTrack,
|
boolean enableEventMessageTrack,
|
||||||
List<Format> closedCaptionFormats,
|
List<Format> closedCaptionFormats,
|
||||||
TrackOutput playerEmsgTrackOutput) {
|
@Nullable TrackOutput playerEmsgTrackOutput) {
|
||||||
this(
|
this(
|
||||||
periodDurationUs,
|
periodDurationUs,
|
||||||
representation,
|
representation,
|
||||||
|
|
@ -787,7 +787,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
Representation representation,
|
Representation representation,
|
||||||
boolean enableEventMessageTrack,
|
boolean enableEventMessageTrack,
|
||||||
List<Format> closedCaptionFormats,
|
List<Format> closedCaptionFormats,
|
||||||
TrackOutput playerEmsgTrackOutput) {
|
@Nullable TrackOutput playerEmsgTrackOutput) {
|
||||||
String containerMimeType = representation.format.containerMimeType;
|
String containerMimeType = representation.format.containerMimeType;
|
||||||
if (mimeTypeIsRawText(containerMimeType)) {
|
if (mimeTypeIsRawText(containerMimeType)) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -80,12 +80,10 @@ public class DashManifest implements FilterableManifest<DashManifest> {
|
||||||
* The {@link UtcTimingElement}, or null if not present. Defined in DVB A168:7/2016, Section
|
* The {@link UtcTimingElement}, or null if not present. Defined in DVB A168:7/2016, Section
|
||||||
* 4.7.2.
|
* 4.7.2.
|
||||||
*/
|
*/
|
||||||
public final UtcTimingElement utcTiming;
|
@Nullable public final UtcTimingElement utcTiming;
|
||||||
|
|
||||||
/**
|
/** The location of this manifest, or null if not present. */
|
||||||
* The location of this manifest.
|
@Nullable public final Uri location;
|
||||||
*/
|
|
||||||
public final Uri location;
|
|
||||||
|
|
||||||
/** The {@link ProgramInformation}, or null if not present. */
|
/** The {@link ProgramInformation}, or null if not present. */
|
||||||
@Nullable public final ProgramInformation programInformation;
|
@Nullable public final ProgramInformation programInformation;
|
||||||
|
|
@ -106,8 +104,8 @@ public class DashManifest implements FilterableManifest<DashManifest> {
|
||||||
long timeShiftBufferDepthMs,
|
long timeShiftBufferDepthMs,
|
||||||
long suggestedPresentationDelayMs,
|
long suggestedPresentationDelayMs,
|
||||||
long publishTimeMs,
|
long publishTimeMs,
|
||||||
UtcTimingElement utcTiming,
|
@Nullable UtcTimingElement utcTiming,
|
||||||
Uri location,
|
@Nullable Uri location,
|
||||||
List<Period> periods) {
|
List<Period> periods) {
|
||||||
this(
|
this(
|
||||||
availabilityStartTimeMs,
|
availabilityStartTimeMs,
|
||||||
|
|
@ -134,8 +132,8 @@ public class DashManifest implements FilterableManifest<DashManifest> {
|
||||||
long suggestedPresentationDelayMs,
|
long suggestedPresentationDelayMs,
|
||||||
long publishTimeMs,
|
long publishTimeMs,
|
||||||
@Nullable ProgramInformation programInformation,
|
@Nullable ProgramInformation programInformation,
|
||||||
UtcTimingElement utcTiming,
|
@Nullable UtcTimingElement utcTiming,
|
||||||
Uri location,
|
@Nullable Uri location,
|
||||||
List<Period> periods) {
|
List<Period> periods) {
|
||||||
this.availabilityStartTimeMs = availabilityStartTimeMs;
|
this.availabilityStartTimeMs = availabilityStartTimeMs;
|
||||||
this.durationMs = durationMs;
|
this.durationMs = durationMs;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package com.google.android.exoplayer2.source.dash.manifest;
|
package com.google.android.exoplayer2.source.dash.manifest;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
@ -47,6 +48,7 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
@ -189,9 +191,9 @@ public class DashManifestParser extends DefaultHandler
|
||||||
long timeShiftBufferDepthMs,
|
long timeShiftBufferDepthMs,
|
||||||
long suggestedPresentationDelayMs,
|
long suggestedPresentationDelayMs,
|
||||||
long publishTimeMs,
|
long publishTimeMs,
|
||||||
ProgramInformation programInformation,
|
@Nullable ProgramInformation programInformation,
|
||||||
UtcTimingElement utcTiming,
|
@Nullable UtcTimingElement utcTiming,
|
||||||
Uri location,
|
@Nullable Uri location,
|
||||||
List<Period> periods) {
|
List<Period> periods) {
|
||||||
return new DashManifest(
|
return new DashManifest(
|
||||||
availabilityStartTime,
|
availabilityStartTime,
|
||||||
|
|
@ -259,8 +261,9 @@ public class DashManifestParser extends DefaultHandler
|
||||||
|
|
||||||
// AdaptationSet parsing.
|
// AdaptationSet parsing.
|
||||||
|
|
||||||
protected AdaptationSet parseAdaptationSet(XmlPullParser xpp, String baseUrl,
|
protected AdaptationSet parseAdaptationSet(
|
||||||
SegmentBase segmentBase) throws XmlPullParserException, IOException {
|
XmlPullParser xpp, String baseUrl, @Nullable SegmentBase segmentBase)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET);
|
int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET);
|
||||||
int contentType = parseContentType(xpp);
|
int contentType = parseContentType(xpp);
|
||||||
|
|
||||||
|
|
@ -394,8 +397,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
* @return The scheme type and/or {@link SchemeData} parsed from the ContentProtection element.
|
* @return The scheme type and/or {@link SchemeData} parsed from the ContentProtection element.
|
||||||
* Either or both may be null, depending on the ContentProtection element being parsed.
|
* Either or both may be null, depending on the ContentProtection element being parsed.
|
||||||
*/
|
*/
|
||||||
protected Pair<String, SchemeData> parseContentProtection(XmlPullParser xpp)
|
protected Pair<@NullableType String, @NullableType SchemeData> parseContentProtection(
|
||||||
throws XmlPullParserException, IOException {
|
XmlPullParser xpp) throws XmlPullParserException, IOException {
|
||||||
String schemeType = null;
|
String schemeType = null;
|
||||||
String licenseServerUrl = null;
|
String licenseServerUrl = null;
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
|
|
@ -477,19 +480,19 @@ public class DashManifestParser extends DefaultHandler
|
||||||
protected RepresentationInfo parseRepresentation(
|
protected RepresentationInfo parseRepresentation(
|
||||||
XmlPullParser xpp,
|
XmlPullParser xpp,
|
||||||
String baseUrl,
|
String baseUrl,
|
||||||
String label,
|
@Nullable String label,
|
||||||
String adaptationSetMimeType,
|
@Nullable String adaptationSetMimeType,
|
||||||
String adaptationSetCodecs,
|
@Nullable String adaptationSetCodecs,
|
||||||
int adaptationSetWidth,
|
int adaptationSetWidth,
|
||||||
int adaptationSetHeight,
|
int adaptationSetHeight,
|
||||||
float adaptationSetFrameRate,
|
float adaptationSetFrameRate,
|
||||||
int adaptationSetAudioChannels,
|
int adaptationSetAudioChannels,
|
||||||
int adaptationSetAudioSamplingRate,
|
int adaptationSetAudioSamplingRate,
|
||||||
String adaptationSetLanguage,
|
@Nullable String adaptationSetLanguage,
|
||||||
List<Descriptor> adaptationSetRoleDescriptors,
|
List<Descriptor> adaptationSetRoleDescriptors,
|
||||||
List<Descriptor> adaptationSetAccessibilityDescriptors,
|
List<Descriptor> adaptationSetAccessibilityDescriptors,
|
||||||
List<Descriptor> adaptationSetSupplementalProperties,
|
List<Descriptor> adaptationSetSupplementalProperties,
|
||||||
SegmentBase segmentBase)
|
@Nullable SegmentBase segmentBase)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
String id = xpp.getAttributeValue(null, "id");
|
String id = xpp.getAttributeValue(null, "id");
|
||||||
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
|
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
|
||||||
|
|
@ -564,19 +567,19 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Format buildFormat(
|
protected Format buildFormat(
|
||||||
String id,
|
@Nullable String id,
|
||||||
String label,
|
@Nullable String label,
|
||||||
String containerMimeType,
|
@Nullable String containerMimeType,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
float frameRate,
|
float frameRate,
|
||||||
int audioChannels,
|
int audioChannels,
|
||||||
int audioSamplingRate,
|
int audioSamplingRate,
|
||||||
int bitrate,
|
int bitrate,
|
||||||
String language,
|
@Nullable String language,
|
||||||
List<Descriptor> roleDescriptors,
|
List<Descriptor> roleDescriptors,
|
||||||
List<Descriptor> accessibilityDescriptors,
|
List<Descriptor> accessibilityDescriptors,
|
||||||
String codecs,
|
@Nullable String codecs,
|
||||||
List<Descriptor> supplementalProperties) {
|
List<Descriptor> supplementalProperties) {
|
||||||
String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
|
String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
|
||||||
@C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors);
|
@C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors);
|
||||||
|
|
@ -650,7 +653,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
|
|
||||||
protected Representation buildRepresentation(
|
protected Representation buildRepresentation(
|
||||||
RepresentationInfo representationInfo,
|
RepresentationInfo representationInfo,
|
||||||
String extraDrmSchemeType,
|
@Nullable String extraDrmSchemeType,
|
||||||
ArrayList<SchemeData> extraDrmSchemeDatas,
|
ArrayList<SchemeData> extraDrmSchemeDatas,
|
||||||
ArrayList<Descriptor> extraInbandEventStreams) {
|
ArrayList<Descriptor> extraInbandEventStreams) {
|
||||||
Format format = representationInfo.format;
|
Format format = representationInfo.format;
|
||||||
|
|
@ -675,7 +678,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
|
|
||||||
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
||||||
|
|
||||||
protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, SingleSegmentBase parent)
|
protected SingleSegmentBase parseSegmentBase(
|
||||||
|
XmlPullParser xpp, @Nullable SingleSegmentBase parent)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
|
|
||||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||||
|
|
@ -711,7 +715,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
indexLength);
|
indexLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SegmentList parseSegmentList(XmlPullParser xpp, SegmentList parent)
|
protected SegmentList parseSegmentList(XmlPullParser xpp, @Nullable SegmentList parent)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
|
|
||||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||||
|
|
@ -756,15 +760,15 @@ public class DashManifestParser extends DefaultHandler
|
||||||
long presentationTimeOffset,
|
long presentationTimeOffset,
|
||||||
long startNumber,
|
long startNumber,
|
||||||
long duration,
|
long duration,
|
||||||
List<SegmentTimelineElement> timeline,
|
@Nullable List<SegmentTimelineElement> timeline,
|
||||||
List<RangedUri> segments) {
|
@Nullable List<RangedUri> segments) {
|
||||||
return new SegmentList(initialization, timescale, presentationTimeOffset,
|
return new SegmentList(initialization, timescale, presentationTimeOffset,
|
||||||
startNumber, duration, timeline, segments);
|
startNumber, duration, timeline, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SegmentTemplate parseSegmentTemplate(
|
protected SegmentTemplate parseSegmentTemplate(
|
||||||
XmlPullParser xpp,
|
XmlPullParser xpp,
|
||||||
SegmentTemplate parent,
|
@Nullable SegmentTemplate parent,
|
||||||
List<Descriptor> adaptationSetSupplementalProperties)
|
List<Descriptor> adaptationSetSupplementalProperties)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||||
|
|
@ -819,8 +823,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
long endNumber,
|
long endNumber,
|
||||||
long duration,
|
long duration,
|
||||||
List<SegmentTimelineElement> timeline,
|
List<SegmentTimelineElement> timeline,
|
||||||
UrlTemplate initializationTemplate,
|
@Nullable UrlTemplate initializationTemplate,
|
||||||
UrlTemplate mediaTemplate) {
|
@Nullable UrlTemplate mediaTemplate) {
|
||||||
return new SegmentTemplate(
|
return new SegmentTemplate(
|
||||||
initialization,
|
initialization,
|
||||||
timescale,
|
timescale,
|
||||||
|
|
@ -1008,8 +1012,9 @@ public class DashManifestParser extends DefaultHandler
|
||||||
return new SegmentTimelineElement(elapsedTime, duration);
|
return new SegmentTimelineElement(elapsedTime, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UrlTemplate parseUrlTemplate(XmlPullParser xpp, String name,
|
@Nullable
|
||||||
UrlTemplate defaultValue) {
|
protected UrlTemplate parseUrlTemplate(
|
||||||
|
XmlPullParser xpp, String name, @Nullable UrlTemplate defaultValue) {
|
||||||
String valueString = xpp.getAttributeValue(null, name);
|
String valueString = xpp.getAttributeValue(null, name);
|
||||||
if (valueString != null) {
|
if (valueString != null) {
|
||||||
return UrlTemplate.compile(valueString);
|
return UrlTemplate.compile(valueString);
|
||||||
|
|
@ -1126,7 +1131,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
@C.RoleFlags
|
@C.RoleFlags
|
||||||
protected int parseDashRoleSchemeValue(String value) {
|
protected int parseDashRoleSchemeValue(@Nullable String value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1159,7 +1164,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
@C.RoleFlags
|
@C.RoleFlags
|
||||||
protected int parseTvaAudioPurposeCsValue(String value) {
|
protected int parseTvaAudioPurposeCsValue(@Nullable String value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1230,7 +1235,9 @@ public class DashManifestParser extends DefaultHandler
|
||||||
* @param codecs The codecs attribute.
|
* @param codecs The codecs attribute.
|
||||||
* @return The derived sample mimeType, or null if it could not be derived.
|
* @return The derived sample mimeType, or null if it could not be derived.
|
||||||
*/
|
*/
|
||||||
private static String getSampleMimeType(String containerMimeType, String codecs) {
|
@Nullable
|
||||||
|
private static String getSampleMimeType(
|
||||||
|
@Nullable String containerMimeType, @Nullable String codecs) {
|
||||||
if (MimeTypes.isAudio(containerMimeType)) {
|
if (MimeTypes.isAudio(containerMimeType)) {
|
||||||
return MimeTypes.getAudioMediaMimeType(codecs);
|
return MimeTypes.getAudioMediaMimeType(codecs);
|
||||||
} else if (MimeTypes.isVideo(containerMimeType)) {
|
} else if (MimeTypes.isVideo(containerMimeType)) {
|
||||||
|
|
@ -1264,7 +1271,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
* @param mimeType The mimeType.
|
* @param mimeType The mimeType.
|
||||||
* @return Whether the mimeType is a text sample mimeType.
|
* @return Whether the mimeType is a text sample mimeType.
|
||||||
*/
|
*/
|
||||||
private static boolean mimeTypeIsRawText(String mimeType) {
|
private static boolean mimeTypeIsRawText(@Nullable String mimeType) {
|
||||||
return MimeTypes.isText(mimeType)
|
return MimeTypes.isText(mimeType)
|
||||||
|| MimeTypes.APPLICATION_TTML.equals(mimeType)
|
|| MimeTypes.APPLICATION_TTML.equals(mimeType)
|
||||||
|| MimeTypes.APPLICATION_MP4VTT.equals(mimeType)
|
|| MimeTypes.APPLICATION_MP4VTT.equals(mimeType)
|
||||||
|
|
@ -1273,16 +1280,18 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks two languages for consistency, returning the consistent language, or throwing an
|
* Checks two languages for consistency, returning the consistent language, or throwing an {@link
|
||||||
* {@link IllegalStateException} if the languages are inconsistent.
|
* IllegalStateException} if the languages are inconsistent.
|
||||||
* <p>
|
*
|
||||||
* Two languages are consistent if they are equal, or if one is null.
|
* <p>Two languages are consistent if they are equal, or if one is null.
|
||||||
*
|
*
|
||||||
* @param firstLanguage The first language.
|
* @param firstLanguage The first language.
|
||||||
* @param secondLanguage The second language.
|
* @param secondLanguage The second language.
|
||||||
* @return The consistent language.
|
* @return The consistent language.
|
||||||
*/
|
*/
|
||||||
private static String checkLanguageConsistency(String firstLanguage, String secondLanguage) {
|
@Nullable
|
||||||
|
private static String checkLanguageConsistency(
|
||||||
|
@Nullable String firstLanguage, @Nullable String secondLanguage) {
|
||||||
if (firstLanguage == null) {
|
if (firstLanguage == null) {
|
||||||
return secondLanguage;
|
return secondLanguage;
|
||||||
} else if (secondLanguage == null) {
|
} else if (secondLanguage == null) {
|
||||||
|
|
@ -1485,14 +1494,19 @@ public class DashManifestParser extends DefaultHandler
|
||||||
public final Format format;
|
public final Format format;
|
||||||
public final String baseUrl;
|
public final String baseUrl;
|
||||||
public final SegmentBase segmentBase;
|
public final SegmentBase segmentBase;
|
||||||
public final String drmSchemeType;
|
@Nullable public final String drmSchemeType;
|
||||||
public final ArrayList<SchemeData> drmSchemeDatas;
|
public final ArrayList<SchemeData> drmSchemeDatas;
|
||||||
public final ArrayList<Descriptor> inbandEventStreams;
|
public final ArrayList<Descriptor> inbandEventStreams;
|
||||||
public final long revisionId;
|
public final long revisionId;
|
||||||
|
|
||||||
public RepresentationInfo(Format format, String baseUrl, SegmentBase segmentBase,
|
public RepresentationInfo(
|
||||||
String drmSchemeType, ArrayList<SchemeData> drmSchemeDatas,
|
Format format,
|
||||||
ArrayList<Descriptor> inbandEventStreams, long revisionId) {
|
String baseUrl,
|
||||||
|
SegmentBase segmentBase,
|
||||||
|
@Nullable String drmSchemeType,
|
||||||
|
ArrayList<SchemeData> drmSchemeDatas,
|
||||||
|
ArrayList<Descriptor> inbandEventStreams,
|
||||||
|
long revisionId) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
this.segmentBase = segmentBase;
|
this.segmentBase = segmentBase;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.dash.manifest;
|
package com.google.android.exoplayer2.source.dash.manifest;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
|
@ -24,10 +23,8 @@ import com.google.android.exoplayer2.util.Util;
|
||||||
*/
|
*/
|
||||||
public final class Descriptor {
|
public final class Descriptor {
|
||||||
|
|
||||||
/**
|
/** The scheme URI. */
|
||||||
* The scheme URI.
|
public final String schemeIdUri;
|
||||||
*/
|
|
||||||
@NonNull public final String schemeIdUri;
|
|
||||||
/**
|
/**
|
||||||
* The value, or null.
|
* The value, or null.
|
||||||
*/
|
*/
|
||||||
|
|
@ -42,7 +39,7 @@ public final class Descriptor {
|
||||||
* @param value The value, or null.
|
* @param value The value, or null.
|
||||||
* @param id The identifier, or null.
|
* @param id The identifier, or null.
|
||||||
*/
|
*/
|
||||||
public Descriptor(@NonNull String schemeIdUri, @Nullable String value, @Nullable String id) {
|
public Descriptor(String schemeIdUri, @Nullable String value, @Nullable String id) {
|
||||||
this.schemeIdUri = schemeIdUri;
|
this.schemeIdUri = schemeIdUri;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
@ -63,10 +60,9 @@ public final class Descriptor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = (schemeIdUri != null ? schemeIdUri.hashCode() : 0);
|
int result = schemeIdUri.hashCode();
|
||||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||||
result = 31 * result + (id != null ? id.hashCode() : 0);
|
result = 31 * result + (id != null ? id.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,22 +21,26 @@ import com.google.android.exoplayer2.util.Util;
|
||||||
/** A parsed program information element. */
|
/** A parsed program information element. */
|
||||||
public class ProgramInformation {
|
public class ProgramInformation {
|
||||||
/** The title for the media presentation. */
|
/** The title for the media presentation. */
|
||||||
public final String title;
|
@Nullable public final String title;
|
||||||
|
|
||||||
/** Information about the original source of the media presentation. */
|
/** Information about the original source of the media presentation. */
|
||||||
public final String source;
|
@Nullable public final String source;
|
||||||
|
|
||||||
/** A copyright statement for the media presentation. */
|
/** A copyright statement for the media presentation. */
|
||||||
public final String copyright;
|
@Nullable public final String copyright;
|
||||||
|
|
||||||
/** A URL that provides more information about the media presentation. */
|
/** A URL that provides more information about the media presentation. */
|
||||||
public final String moreInformationURL;
|
@Nullable public final String moreInformationURL;
|
||||||
|
|
||||||
/** Declares the language code(s) for this ProgramInformation. */
|
/** Declares the language code(s) for this ProgramInformation. */
|
||||||
public final String lang;
|
@Nullable public final String lang;
|
||||||
|
|
||||||
public ProgramInformation(
|
public ProgramInformation(
|
||||||
String title, String source, String copyright, String moreInformationURL, String lang) {
|
@Nullable String title,
|
||||||
|
@Nullable String source,
|
||||||
|
@Nullable String copyright,
|
||||||
|
@Nullable String moreInformationURL,
|
||||||
|
@Nullable String lang) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.copyright = copyright;
|
this.copyright = copyright;
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ public final class RangedUri {
|
||||||
* <p>If {@code other} is null then the merge is considered unsuccessful, and null is returned.
|
* <p>If {@code other} is null then the merge is considered unsuccessful, and null is returned.
|
||||||
*
|
*
|
||||||
* @param other The {@link RangedUri} to merge.
|
* @param other The {@link RangedUri} to merge.
|
||||||
* @param baseUri The optional base Uri.
|
* @param baseUri The base Uri.
|
||||||
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise.
|
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package com.google.android.exoplayer2.source.dash.manifest;
|
package com.google.android.exoplayer2.source.dash.manifest;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
|
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
|
||||||
|
|
@ -53,9 +54,7 @@ public abstract class Representation {
|
||||||
* The offset of the presentation timestamps in the media stream relative to media time.
|
* The offset of the presentation timestamps in the media stream relative to media time.
|
||||||
*/
|
*/
|
||||||
public final long presentationTimeOffsetUs;
|
public final long presentationTimeOffsetUs;
|
||||||
/**
|
/** The in-band event streams in the representation. May be empty. */
|
||||||
* The in-band event streams in the representation. Never null, but may be empty.
|
|
||||||
*/
|
|
||||||
public final List<Descriptor> inbandEventStreams;
|
public final List<Descriptor> inbandEventStreams;
|
||||||
|
|
||||||
private final RangedUri initializationUri;
|
private final RangedUri initializationUri;
|
||||||
|
|
@ -71,7 +70,7 @@ public abstract class Representation {
|
||||||
*/
|
*/
|
||||||
public static Representation newInstance(
|
public static Representation newInstance(
|
||||||
long revisionId, Format format, String baseUrl, SegmentBase segmentBase) {
|
long revisionId, Format format, String baseUrl, SegmentBase segmentBase) {
|
||||||
return newInstance(revisionId, format, baseUrl, segmentBase, null);
|
return newInstance(revisionId, format, baseUrl, segmentBase, /* inbandEventStreams= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -89,8 +88,9 @@ public abstract class Representation {
|
||||||
Format format,
|
Format format,
|
||||||
String baseUrl,
|
String baseUrl,
|
||||||
SegmentBase segmentBase,
|
SegmentBase segmentBase,
|
||||||
List<Descriptor> inbandEventStreams) {
|
@Nullable List<Descriptor> inbandEventStreams) {
|
||||||
return newInstance(revisionId, format, baseUrl, segmentBase, inbandEventStreams, null);
|
return newInstance(
|
||||||
|
revisionId, format, baseUrl, segmentBase, inbandEventStreams, /* cacheKey= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -110,8 +110,8 @@ public abstract class Representation {
|
||||||
Format format,
|
Format format,
|
||||||
String baseUrl,
|
String baseUrl,
|
||||||
SegmentBase segmentBase,
|
SegmentBase segmentBase,
|
||||||
List<Descriptor> inbandEventStreams,
|
@Nullable List<Descriptor> inbandEventStreams,
|
||||||
String cacheKey) {
|
@Nullable String cacheKey) {
|
||||||
if (segmentBase instanceof SingleSegmentBase) {
|
if (segmentBase instanceof SingleSegmentBase) {
|
||||||
return new SingleSegmentRepresentation(
|
return new SingleSegmentRepresentation(
|
||||||
revisionId,
|
revisionId,
|
||||||
|
|
@ -135,7 +135,7 @@ public abstract class Representation {
|
||||||
Format format,
|
Format format,
|
||||||
String baseUrl,
|
String baseUrl,
|
||||||
SegmentBase segmentBase,
|
SegmentBase segmentBase,
|
||||||
List<Descriptor> inbandEventStreams) {
|
@Nullable List<Descriptor> inbandEventStreams) {
|
||||||
this.revisionId = revisionId;
|
this.revisionId = revisionId;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
|
|
@ -151,6 +151,7 @@ public abstract class Representation {
|
||||||
* Returns a {@link RangedUri} defining the location of the representation's initialization data,
|
* Returns a {@link RangedUri} defining the location of the representation's initialization data,
|
||||||
* or null if no initialization data exists.
|
* or null if no initialization data exists.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public RangedUri getInitializationUri() {
|
public RangedUri getInitializationUri() {
|
||||||
return initializationUri;
|
return initializationUri;
|
||||||
}
|
}
|
||||||
|
|
@ -159,14 +160,15 @@ public abstract class Representation {
|
||||||
* Returns a {@link RangedUri} defining the location of the representation's segment index, or
|
* Returns a {@link RangedUri} defining the location of the representation's segment index, or
|
||||||
* null if the representation provides an index directly.
|
* null if the representation provides an index directly.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public abstract RangedUri getIndexUri();
|
public abstract RangedUri getIndexUri();
|
||||||
|
|
||||||
/**
|
/** Returns an index if the representation provides one directly, or null otherwise. */
|
||||||
* Returns an index if the representation provides one directly, or null otherwise.
|
@Nullable
|
||||||
*/
|
|
||||||
public abstract DashSegmentIndex getIndex();
|
public abstract DashSegmentIndex getIndex();
|
||||||
|
|
||||||
/** Returns a cache key for the representation if set, or null. */
|
/** Returns a cache key for the representation if set, or null. */
|
||||||
|
@Nullable
|
||||||
public abstract String getCacheKey();
|
public abstract String getCacheKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -184,9 +186,9 @@ public abstract class Representation {
|
||||||
*/
|
*/
|
||||||
public final long contentLength;
|
public final long contentLength;
|
||||||
|
|
||||||
private final String cacheKey;
|
@Nullable private final String cacheKey;
|
||||||
private final RangedUri indexUri;
|
@Nullable private final RangedUri indexUri;
|
||||||
private final SingleSegmentIndex segmentIndex;
|
@Nullable private final SingleSegmentIndex segmentIndex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param revisionId Identifies the revision of the content.
|
* @param revisionId Identifies the revision of the content.
|
||||||
|
|
@ -209,7 +211,7 @@ public abstract class Representation {
|
||||||
long indexStart,
|
long indexStart,
|
||||||
long indexEnd,
|
long indexEnd,
|
||||||
List<Descriptor> inbandEventStreams,
|
List<Descriptor> inbandEventStreams,
|
||||||
String cacheKey,
|
@Nullable String cacheKey,
|
||||||
long contentLength) {
|
long contentLength) {
|
||||||
RangedUri rangedUri = new RangedUri(null, initializationStart,
|
RangedUri rangedUri = new RangedUri(null, initializationStart,
|
||||||
initializationEnd - initializationStart + 1);
|
initializationEnd - initializationStart + 1);
|
||||||
|
|
@ -233,8 +235,8 @@ public abstract class Representation {
|
||||||
Format format,
|
Format format,
|
||||||
String baseUrl,
|
String baseUrl,
|
||||||
SingleSegmentBase segmentBase,
|
SingleSegmentBase segmentBase,
|
||||||
List<Descriptor> inbandEventStreams,
|
@Nullable List<Descriptor> inbandEventStreams,
|
||||||
String cacheKey,
|
@Nullable String cacheKey,
|
||||||
long contentLength) {
|
long contentLength) {
|
||||||
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
|
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
|
||||||
this.uri = Uri.parse(baseUrl);
|
this.uri = Uri.parse(baseUrl);
|
||||||
|
|
@ -248,16 +250,19 @@ public abstract class Representation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public RangedUri getIndexUri() {
|
public RangedUri getIndexUri() {
|
||||||
return indexUri;
|
return indexUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public DashSegmentIndex getIndex() {
|
public DashSegmentIndex getIndex() {
|
||||||
return segmentIndex;
|
return segmentIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public String getCacheKey() {
|
public String getCacheKey() {
|
||||||
return cacheKey;
|
return cacheKey;
|
||||||
}
|
}
|
||||||
|
|
@ -284,12 +289,13 @@ public abstract class Representation {
|
||||||
Format format,
|
Format format,
|
||||||
String baseUrl,
|
String baseUrl,
|
||||||
MultiSegmentBase segmentBase,
|
MultiSegmentBase segmentBase,
|
||||||
List<Descriptor> inbandEventStreams) {
|
@Nullable List<Descriptor> inbandEventStreams) {
|
||||||
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
|
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
|
||||||
this.segmentBase = segmentBase;
|
this.segmentBase = segmentBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public RangedUri getIndexUri() {
|
public RangedUri getIndexUri() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +306,7 @@ public abstract class Representation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public String getCacheKey() {
|
public String getCacheKey() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.dash.manifest;
|
package com.google.android.exoplayer2.source.dash.manifest;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
|
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
@ -25,7 +26,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public abstract class SegmentBase {
|
public abstract class SegmentBase {
|
||||||
|
|
||||||
/* package */ final RangedUri initialization;
|
/* package */ @Nullable final RangedUri initialization;
|
||||||
/* package */ final long timescale;
|
/* package */ final long timescale;
|
||||||
/* package */ final long presentationTimeOffset;
|
/* package */ final long presentationTimeOffset;
|
||||||
|
|
||||||
|
|
@ -36,7 +37,8 @@ public abstract class SegmentBase {
|
||||||
* @param presentationTimeOffset The presentation time offset. The value in seconds is the
|
* @param presentationTimeOffset The presentation time offset. The value in seconds is the
|
||||||
* division of this value and {@code timescale}.
|
* division of this value and {@code timescale}.
|
||||||
*/
|
*/
|
||||||
public SegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset) {
|
public SegmentBase(
|
||||||
|
@Nullable RangedUri initialization, long timescale, long presentationTimeOffset) {
|
||||||
this.initialization = initialization;
|
this.initialization = initialization;
|
||||||
this.timescale = timescale;
|
this.timescale = timescale;
|
||||||
this.presentationTimeOffset = presentationTimeOffset;
|
this.presentationTimeOffset = presentationTimeOffset;
|
||||||
|
|
@ -49,6 +51,7 @@ public abstract class SegmentBase {
|
||||||
* @param representation The {@link Representation} for which initialization data is required.
|
* @param representation The {@link Representation} for which initialization data is required.
|
||||||
* @return A {@link RangedUri} defining the location of the initialization data, or null.
|
* @return A {@link RangedUri} defining the location of the initialization data, or null.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public RangedUri getInitialization(Representation representation) {
|
public RangedUri getInitialization(Representation representation) {
|
||||||
return initialization;
|
return initialization;
|
||||||
}
|
}
|
||||||
|
|
@ -77,19 +80,31 @@ public abstract class SegmentBase {
|
||||||
* @param indexStart The byte offset of the index data in the segment.
|
* @param indexStart The byte offset of the index data in the segment.
|
||||||
* @param indexLength The length of the index data in bytes.
|
* @param indexLength The length of the index data in bytes.
|
||||||
*/
|
*/
|
||||||
public SingleSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset,
|
public SingleSegmentBase(
|
||||||
long indexStart, long indexLength) {
|
@Nullable RangedUri initialization,
|
||||||
|
long timescale,
|
||||||
|
long presentationTimeOffset,
|
||||||
|
long indexStart,
|
||||||
|
long indexLength) {
|
||||||
super(initialization, timescale, presentationTimeOffset);
|
super(initialization, timescale, presentationTimeOffset);
|
||||||
this.indexStart = indexStart;
|
this.indexStart = indexStart;
|
||||||
this.indexLength = indexLength;
|
this.indexLength = indexLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SingleSegmentBase() {
|
public SingleSegmentBase() {
|
||||||
this(null, 1, 0, 0, 0);
|
this(
|
||||||
|
/* initialization= */ null,
|
||||||
|
/* timescale= */ 1,
|
||||||
|
/* presentationTimeOffset= */ 0,
|
||||||
|
/* indexStart= */ 0,
|
||||||
|
/* indexLength= */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public RangedUri getIndex() {
|
public RangedUri getIndex() {
|
||||||
return indexLength <= 0 ? null : new RangedUri(null, indexStart, indexLength);
|
return indexLength <= 0
|
||||||
|
? null
|
||||||
|
: new RangedUri(/* referenceUri= */ null, indexStart, indexLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +116,7 @@ public abstract class SegmentBase {
|
||||||
|
|
||||||
/* package */ final long startNumber;
|
/* package */ final long startNumber;
|
||||||
/* package */ final long duration;
|
/* package */ final long duration;
|
||||||
/* package */ final List<SegmentTimelineElement> segmentTimeline;
|
/* package */ @Nullable final List<SegmentTimelineElement> segmentTimeline;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
||||||
|
|
@ -118,12 +133,12 @@ public abstract class SegmentBase {
|
||||||
* parameter.
|
* parameter.
|
||||||
*/
|
*/
|
||||||
public MultiSegmentBase(
|
public MultiSegmentBase(
|
||||||
RangedUri initialization,
|
@Nullable RangedUri initialization,
|
||||||
long timescale,
|
long timescale,
|
||||||
long presentationTimeOffset,
|
long presentationTimeOffset,
|
||||||
long startNumber,
|
long startNumber,
|
||||||
long duration,
|
long duration,
|
||||||
List<SegmentTimelineElement> segmentTimeline) {
|
@Nullable List<SegmentTimelineElement> segmentTimeline) {
|
||||||
super(initialization, timescale, presentationTimeOffset);
|
super(initialization, timescale, presentationTimeOffset);
|
||||||
this.startNumber = startNumber;
|
this.startNumber = startNumber;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
|
|
@ -223,7 +238,7 @@ public abstract class SegmentBase {
|
||||||
*/
|
*/
|
||||||
public static class SegmentList extends MultiSegmentBase {
|
public static class SegmentList extends MultiSegmentBase {
|
||||||
|
|
||||||
/* package */ final List<RangedUri> mediaSegments;
|
/* package */ @Nullable final List<RangedUri> mediaSegments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
||||||
|
|
@ -246,8 +261,8 @@ public abstract class SegmentBase {
|
||||||
long presentationTimeOffset,
|
long presentationTimeOffset,
|
||||||
long startNumber,
|
long startNumber,
|
||||||
long duration,
|
long duration,
|
||||||
List<SegmentTimelineElement> segmentTimeline,
|
@Nullable List<SegmentTimelineElement> segmentTimeline,
|
||||||
List<RangedUri> mediaSegments) {
|
@Nullable List<RangedUri> mediaSegments) {
|
||||||
super(initialization, timescale, presentationTimeOffset, startNumber, duration,
|
super(initialization, timescale, presentationTimeOffset, startNumber, duration,
|
||||||
segmentTimeline);
|
segmentTimeline);
|
||||||
this.mediaSegments = mediaSegments;
|
this.mediaSegments = mediaSegments;
|
||||||
|
|
@ -275,8 +290,8 @@ public abstract class SegmentBase {
|
||||||
*/
|
*/
|
||||||
public static class SegmentTemplate extends MultiSegmentBase {
|
public static class SegmentTemplate extends MultiSegmentBase {
|
||||||
|
|
||||||
/* package */ final UrlTemplate initializationTemplate;
|
/* package */ @Nullable final UrlTemplate initializationTemplate;
|
||||||
/* package */ final UrlTemplate mediaTemplate;
|
/* package */ @Nullable final UrlTemplate mediaTemplate;
|
||||||
/* package */ final long endNumber;
|
/* package */ final long endNumber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -308,9 +323,9 @@ public abstract class SegmentBase {
|
||||||
long startNumber,
|
long startNumber,
|
||||||
long endNumber,
|
long endNumber,
|
||||||
long duration,
|
long duration,
|
||||||
List<SegmentTimelineElement> segmentTimeline,
|
@Nullable List<SegmentTimelineElement> segmentTimeline,
|
||||||
UrlTemplate initializationTemplate,
|
@Nullable UrlTemplate initializationTemplate,
|
||||||
UrlTemplate mediaTemplate) {
|
@Nullable UrlTemplate mediaTemplate) {
|
||||||
super(
|
super(
|
||||||
initialization,
|
initialization,
|
||||||
timescale,
|
timescale,
|
||||||
|
|
@ -324,6 +339,7 @@ public abstract class SegmentBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public RangedUri getInitialization(Representation representation) {
|
public RangedUri getInitialization(Representation representation) {
|
||||||
if (initializationTemplate != null) {
|
if (initializationTemplate != null) {
|
||||||
String urlString = initializationTemplate.buildUri(representation.format.id, 0,
|
String urlString = initializationTemplate.buildUri(representation.format.id, 0,
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
dependencies {
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
|
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,8 @@ import javax.crypto.spec.SecretKeySpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final @Nullable Uri getUri() {
|
@Nullable
|
||||||
|
public final Uri getUri() {
|
||||||
return upstream.getUri();
|
return upstream.getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result createExtractor(
|
public Result createExtractor(
|
||||||
Extractor previousExtractor,
|
@Nullable Extractor previousExtractor,
|
||||||
Uri uri,
|
Uri uri,
|
||||||
Format format,
|
Format format,
|
||||||
List<Format> muxedCaptionFormats,
|
@Nullable List<Format> muxedCaptionFormats,
|
||||||
DrmInitData drmInitData,
|
@Nullable DrmInitData drmInitData,
|
||||||
TimestampAdjuster timestampAdjuster,
|
TimestampAdjuster timestampAdjuster,
|
||||||
Map<String, List<String>> responseHeaders,
|
Map<String, List<String>> responseHeaders,
|
||||||
ExtractorInput extractorInput)
|
ExtractorInput extractorInput)
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,8 @@ import java.util.Map;
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The chunk to be loaded next. */
|
||||||
* The chunk to be loaded next.
|
@Nullable public Chunk chunk;
|
||||||
*/
|
|
||||||
public Chunk chunk;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that the end of the stream has been reached.
|
* Indicates that the end of the stream has been reached.
|
||||||
|
|
@ -70,7 +68,7 @@ import java.util.Map;
|
||||||
public boolean endOfStream;
|
public boolean endOfStream;
|
||||||
|
|
||||||
/** Indicates that the chunk source is waiting for the referred playlist to be refreshed. */
|
/** Indicates that the chunk source is waiting for the referred playlist to be refreshed. */
|
||||||
public Uri playlistUrl;
|
@Nullable public Uri playlistUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the holder.
|
* Clears the holder.
|
||||||
|
|
@ -138,7 +136,7 @@ import java.util.Map;
|
||||||
HlsDataSourceFactory dataSourceFactory,
|
HlsDataSourceFactory dataSourceFactory,
|
||||||
@Nullable TransferListener mediaTransferListener,
|
@Nullable TransferListener mediaTransferListener,
|
||||||
TimestampAdjusterProvider timestampAdjusterProvider,
|
TimestampAdjusterProvider timestampAdjusterProvider,
|
||||||
List<Format> muxedCaptionFormats) {
|
@Nullable List<Format> muxedCaptionFormats) {
|
||||||
this.extractorFactory = extractorFactory;
|
this.extractorFactory = extractorFactory;
|
||||||
this.playlistTracker = playlistTracker;
|
this.playlistTracker = playlistTracker;
|
||||||
this.playlistUrls = playlistUrls;
|
this.playlistUrls = playlistUrls;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package com.google.android.exoplayer2.source.hls;
|
package com.google.android.exoplayer2.source.hls;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||||
import com.google.android.exoplayer2.extractor.Extractor;
|
import com.google.android.exoplayer2.extractor.Extractor;
|
||||||
|
|
@ -82,11 +83,11 @@ public interface HlsExtractorFactory {
|
||||||
* @throws IOException If an I/O error is encountered while sniffing.
|
* @throws IOException If an I/O error is encountered while sniffing.
|
||||||
*/
|
*/
|
||||||
Result createExtractor(
|
Result createExtractor(
|
||||||
Extractor previousExtractor,
|
@Nullable Extractor previousExtractor,
|
||||||
Uri uri,
|
Uri uri,
|
||||||
Format format,
|
Format format,
|
||||||
List<Format> muxedCaptionFormats,
|
@Nullable List<Format> muxedCaptionFormats,
|
||||||
DrmInitData drmInitData,
|
@Nullable DrmInitData drmInitData,
|
||||||
TimestampAdjuster timestampAdjuster,
|
TimestampAdjuster timestampAdjuster,
|
||||||
Map<String, List<String>> responseHeaders,
|
Map<String, List<String>> responseHeaders,
|
||||||
ExtractorInput sniffingExtractorInput)
|
ExtractorInput sniffingExtractorInput)
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import java.util.HashSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MediaPeriod} that loads an HLS stream.
|
* A {@link MediaPeriod} that loads an HLS stream.
|
||||||
|
|
@ -249,8 +250,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
|
public long selectTracks(
|
||||||
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
|
@NullableType TrackSelection[] selections,
|
||||||
|
boolean[] mayRetainStreamFlags,
|
||||||
|
@NullableType SampleStream[] streams,
|
||||||
|
boolean[] streamResetFlags,
|
||||||
|
long positionUs) {
|
||||||
// Map each selection and stream onto a child period index.
|
// Map each selection and stream onto a child period index.
|
||||||
int[] streamChildIndices = new int[selections.length];
|
int[] streamChildIndices = new int[selections.length];
|
||||||
int[] selectionChildIndices = new int[selections.length];
|
int[] selectionChildIndices = new int[selections.length];
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||||
* @return This factory, for convenience.
|
* @return This factory, for convenience.
|
||||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||||
*/
|
*/
|
||||||
public Factory setTag(Object tag) {
|
public Factory setTag(@Nullable Object tag) {
|
||||||
Assertions.checkState(!isCreateCalled);
|
Assertions.checkState(!isCreateCalled);
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.hls;
|
package com.google.android.exoplayer2.source.hls;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
|
@ -49,7 +50,7 @@ public final class WebvttExtractor implements Extractor {
|
||||||
private static final int HEADER_MIN_LENGTH = 6 /* "WEBVTT" */;
|
private static final int HEADER_MIN_LENGTH = 6 /* "WEBVTT" */;
|
||||||
private static final int HEADER_MAX_LENGTH = 3 /* optional Byte Order Mark */ + HEADER_MIN_LENGTH;
|
private static final int HEADER_MAX_LENGTH = 3 /* optional Byte Order Mark */ + HEADER_MIN_LENGTH;
|
||||||
|
|
||||||
private final String language;
|
@Nullable private final String language;
|
||||||
private final TimestampAdjuster timestampAdjuster;
|
private final TimestampAdjuster timestampAdjuster;
|
||||||
private final ParsableByteArray sampleDataWrapper;
|
private final ParsableByteArray sampleDataWrapper;
|
||||||
|
|
||||||
|
|
@ -58,7 +59,7 @@ public final class WebvttExtractor implements Extractor {
|
||||||
private byte[] sampleData;
|
private byte[] sampleData;
|
||||||
private int sampleSize;
|
private int sampleSize;
|
||||||
|
|
||||||
public WebvttExtractor(String language, TimestampAdjuster timestampAdjuster) {
|
public WebvttExtractor(@Nullable String language, TimestampAdjuster timestampAdjuster) {
|
||||||
this.language = language;
|
this.language = language;
|
||||||
this.timestampAdjuster = timestampAdjuster;
|
this.timestampAdjuster = timestampAdjuster;
|
||||||
this.sampleDataWrapper = new ParsableByteArray();
|
this.sampleDataWrapper = new ParsableByteArray();
|
||||||
|
|
|
||||||
|
|
@ -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
|
@Override
|
||||||
|
@Nullable
|
||||||
public HlsMediaPlaylist getPlaylistSnapshot(Uri url, boolean isForPlayback) {
|
public HlsMediaPlaylist getPlaylistSnapshot(Uri url, boolean isForPlayback) {
|
||||||
HlsMediaPlaylist snapshot = playlistBundles.get(url).getPlaylistSnapshot();
|
HlsMediaPlaylist snapshot = playlistBundles.get(url).getPlaylistSnapshot();
|
||||||
if (snapshot != null && isForPlayback) {
|
if (snapshot != null && isForPlayback) {
|
||||||
|
|
@ -448,7 +449,7 @@ public final class DefaultHlsPlaylistTracker
|
||||||
private final Loader mediaPlaylistLoader;
|
private final Loader mediaPlaylistLoader;
|
||||||
private final ParsingLoadable<HlsPlaylist> mediaPlaylistLoadable;
|
private final ParsingLoadable<HlsPlaylist> mediaPlaylistLoadable;
|
||||||
|
|
||||||
private HlsMediaPlaylist playlistSnapshot;
|
@Nullable private HlsMediaPlaylist playlistSnapshot;
|
||||||
private long lastSnapshotLoadMs;
|
private long lastSnapshotLoadMs;
|
||||||
private long lastSnapshotChangeMs;
|
private long lastSnapshotChangeMs;
|
||||||
private long earliestNextLoadTimeMs;
|
private long earliestNextLoadTimeMs;
|
||||||
|
|
@ -467,6 +468,7 @@ public final class DefaultHlsPlaylistTracker
|
||||||
mediaPlaylistParser);
|
mediaPlaylistParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public HlsMediaPlaylist getPlaylistSnapshot() {
|
public HlsMediaPlaylist getPlaylistSnapshot() {
|
||||||
return playlistSnapshot;
|
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
|
* The format of the audio muxed in the variants. May be null if the playlist does not declare any
|
||||||
* muxed audio.
|
* muxed audio.
|
||||||
*/
|
*/
|
||||||
public final Format muxedAudioFormat;
|
@Nullable public final Format muxedAudioFormat;
|
||||||
/**
|
/**
|
||||||
* The format of the closed captions declared by the playlist. May be empty if the playlist
|
* The format of the closed captions declared by the playlist. May be empty if the playlist
|
||||||
* explicitly declares no captions are available, or null if the playlist does not declare any
|
* explicitly declares no captions are available, or null if the playlist does not declare any
|
||||||
|
|
@ -208,7 +208,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
|
||||||
List<Rendition> audios,
|
List<Rendition> audios,
|
||||||
List<Rendition> subtitles,
|
List<Rendition> subtitles,
|
||||||
List<Rendition> closedCaptions,
|
List<Rendition> closedCaptions,
|
||||||
Format muxedAudioFormat,
|
@Nullable Format muxedAudioFormat,
|
||||||
List<Format> muxedCaptionFormats,
|
List<Format> muxedCaptionFormats,
|
||||||
boolean hasIndependentSegments,
|
boolean hasIndependentSegments,
|
||||||
Map<String, String> variableDefinitions,
|
Map<String, String> variableDefinitions,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
package com.google.android.exoplayer2.source.hls.playlist;
|
package com.google.android.exoplayer2.source.hls.playlist;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||||
|
|
@ -95,8 +94,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
||||||
String uri,
|
String uri,
|
||||||
long byterangeOffset,
|
long byterangeOffset,
|
||||||
long byterangeLength,
|
long byterangeLength,
|
||||||
String fullSegmentEncryptionKeyUri,
|
@Nullable String fullSegmentEncryptionKeyUri,
|
||||||
String encryptionIV) {
|
@Nullable String encryptionIV) {
|
||||||
this(
|
this(
|
||||||
uri,
|
uri,
|
||||||
/* initializationSegment= */ null,
|
/* initializationSegment= */ null,
|
||||||
|
|
@ -154,7 +153,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(@NonNull Long relativeStartTimeUs) {
|
public int compareTo(Long relativeStartTimeUs) {
|
||||||
return this.relativeStartTimeUs > relativeStartTimeUs
|
return this.relativeStartTimeUs > relativeStartTimeUs
|
||||||
? 1 : (this.relativeStartTimeUs < relativeStartTimeUs ? -1 : 0);
|
? 1 : (this.relativeStartTimeUs < relativeStartTimeUs ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
dependencies {
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
|
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/** A SmoothStreaming {@link MediaPeriod}. */
|
/** A SmoothStreaming {@link MediaPeriod}. */
|
||||||
/* package */ final class SsMediaPeriod
|
/* package */ final class SsMediaPeriod
|
||||||
|
|
@ -120,8 +121,12 @@ import java.util.List;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
|
public long selectTracks(
|
||||||
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
|
@NullableType TrackSelection[] selections,
|
||||||
|
boolean[] mayRetainStreamFlags,
|
||||||
|
@NullableType SampleStream[] streams,
|
||||||
|
boolean[] streamResetFlags,
|
||||||
|
long positionUs) {
|
||||||
ArrayList<ChunkSampleStream<SsChunkSource>> sampleStreamsList = new ArrayList<>();
|
ArrayList<ChunkSampleStream<SsChunkSource>> sampleStreamsList = new ArrayList<>();
|
||||||
for (int i = 0; i < selections.length; i++) {
|
for (int i = 0; i < selections.length; i++) {
|
||||||
if (streams[i] != null) {
|
if (streams[i] != null) {
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
* @return This factory, for convenience.
|
* @return This factory, for convenience.
|
||||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||||
*/
|
*/
|
||||||
public Factory setTag(Object tag) {
|
public Factory setTag(@Nullable Object tag) {
|
||||||
Assertions.checkState(!isCreateCalled);
|
Assertions.checkState(!isCreateCalled);
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -370,8 +370,8 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
public SsMediaSource(
|
public SsMediaSource(
|
||||||
SsManifest manifest,
|
SsManifest manifest,
|
||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
manifest,
|
manifest,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
|
|
@ -395,8 +395,8 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
SsManifest manifest,
|
SsManifest manifest,
|
||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
int minLoadableRetryCount,
|
int minLoadableRetryCount,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
manifest,
|
manifest,
|
||||||
/* manifestUri= */ null,
|
/* manifestUri= */ null,
|
||||||
|
|
@ -431,8 +431,8 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
Uri manifestUri,
|
Uri manifestUri,
|
||||||
DataSource.Factory manifestDataSourceFactory,
|
DataSource.Factory manifestDataSourceFactory,
|
||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
manifestUri,
|
manifestUri,
|
||||||
manifestDataSourceFactory,
|
manifestDataSourceFactory,
|
||||||
|
|
@ -466,8 +466,8 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
int minLoadableRetryCount,
|
int minLoadableRetryCount,
|
||||||
long livePresentationDelayMs,
|
long livePresentationDelayMs,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(manifestUri, manifestDataSourceFactory, new SsManifestParser(), chunkSourceFactory,
|
this(manifestUri, manifestDataSourceFactory, new SsManifestParser(), chunkSourceFactory,
|
||||||
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener);
|
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener);
|
||||||
}
|
}
|
||||||
|
|
@ -496,8 +496,8 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
int minLoadableRetryCount,
|
int minLoadableRetryCount,
|
||||||
long livePresentationDelayMs,
|
long livePresentationDelayMs,
|
||||||
Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
@Nullable MediaSourceEventListener eventListener) {
|
||||||
this(
|
this(
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
manifestUri,
|
manifestUri,
|
||||||
|
|
@ -515,10 +515,10 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
}
|
}
|
||||||
|
|
||||||
private SsMediaSource(
|
private SsMediaSource(
|
||||||
SsManifest manifest,
|
@Nullable SsManifest manifest,
|
||||||
Uri manifestUri,
|
@Nullable Uri manifestUri,
|
||||||
DataSource.Factory manifestDataSourceFactory,
|
@Nullable DataSource.Factory manifestDataSourceFactory,
|
||||||
ParsingLoadable.Parser<? extends SsManifest> manifestParser,
|
@Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser,
|
||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||||
DrmSessionManager<?> drmSessionManager,
|
DrmSessionManager<?> drmSessionManager,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
|
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox;
|
import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox;
|
||||||
|
|
@ -69,7 +70,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
||||||
public final int maxHeight;
|
public final int maxHeight;
|
||||||
public final int displayWidth;
|
public final int displayWidth;
|
||||||
public final int displayHeight;
|
public final int displayHeight;
|
||||||
public final String language;
|
@Nullable public final String language;
|
||||||
public final Format[] formats;
|
public final Format[] formats;
|
||||||
public final int chunkCount;
|
public final int chunkCount;
|
||||||
|
|
||||||
|
|
@ -80,9 +81,20 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
||||||
private final long[] chunkStartTimesUs;
|
private final long[] chunkStartTimesUs;
|
||||||
private final long lastChunkDurationUs;
|
private final long lastChunkDurationUs;
|
||||||
|
|
||||||
public StreamElement(String baseUri, String chunkTemplate, int type, String subType,
|
public StreamElement(
|
||||||
long timescale, String name, int maxWidth, int maxHeight, int displayWidth,
|
String baseUri,
|
||||||
int displayHeight, String language, Format[] formats, List<Long> chunkStartTimes,
|
String chunkTemplate,
|
||||||
|
int type,
|
||||||
|
String subType,
|
||||||
|
long timescale,
|
||||||
|
String name,
|
||||||
|
int maxWidth,
|
||||||
|
int maxHeight,
|
||||||
|
int displayWidth,
|
||||||
|
int displayHeight,
|
||||||
|
@Nullable String language,
|
||||||
|
Format[] formats,
|
||||||
|
List<Long> chunkStartTimes,
|
||||||
long lastChunkDuration) {
|
long lastChunkDuration) {
|
||||||
this(
|
this(
|
||||||
baseUri,
|
baseUri,
|
||||||
|
|
@ -102,10 +114,22 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
||||||
Util.scaleLargeTimestamp(lastChunkDuration, C.MICROS_PER_SECOND, timescale));
|
Util.scaleLargeTimestamp(lastChunkDuration, C.MICROS_PER_SECOND, timescale));
|
||||||
}
|
}
|
||||||
|
|
||||||
private StreamElement(String baseUri, String chunkTemplate, int type, String subType,
|
private StreamElement(
|
||||||
long timescale, String name, int maxWidth, int maxHeight, int displayWidth,
|
String baseUri,
|
||||||
int displayHeight, String language, Format[] formats, List<Long> chunkStartTimes,
|
String chunkTemplate,
|
||||||
long[] chunkStartTimesUs, long lastChunkDurationUs) {
|
int type,
|
||||||
|
String subType,
|
||||||
|
long timescale,
|
||||||
|
String name,
|
||||||
|
int maxWidth,
|
||||||
|
int maxHeight,
|
||||||
|
int displayWidth,
|
||||||
|
int displayHeight,
|
||||||
|
@Nullable String language,
|
||||||
|
Format[] formats,
|
||||||
|
List<Long> chunkStartTimes,
|
||||||
|
long[] chunkStartTimesUs,
|
||||||
|
long lastChunkDurationUs) {
|
||||||
this.baseUri = baseUri;
|
this.baseUri = baseUri;
|
||||||
this.chunkTemplate = chunkTemplate;
|
this.chunkTemplate = chunkTemplate;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
@ -208,7 +232,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
||||||
public final boolean isLive;
|
public final boolean isLive;
|
||||||
|
|
||||||
/** Content protection information, or null if the content is not protected. */
|
/** Content protection information, or null if the content is not protected. */
|
||||||
public final ProtectionElement protectionElement;
|
@Nullable public final ProtectionElement protectionElement;
|
||||||
|
|
||||||
/** The contained stream elements. */
|
/** The contained stream elements. */
|
||||||
public final StreamElement[] streamElements;
|
public final StreamElement[] streamElements;
|
||||||
|
|
@ -249,7 +273,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
||||||
long dvrWindowLength,
|
long dvrWindowLength,
|
||||||
int lookAheadCount,
|
int lookAheadCount,
|
||||||
boolean isLive,
|
boolean isLive,
|
||||||
ProtectionElement protectionElement,
|
@Nullable ProtectionElement protectionElement,
|
||||||
StreamElement[] streamElements) {
|
StreamElement[] streamElements) {
|
||||||
this(
|
this(
|
||||||
majorVersion,
|
majorVersion,
|
||||||
|
|
@ -273,7 +297,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
||||||
long dvrWindowLengthUs,
|
long dvrWindowLengthUs,
|
||||||
int lookAheadCount,
|
int lookAheadCount,
|
||||||
boolean isLive,
|
boolean isLive,
|
||||||
ProtectionElement protectionElement,
|
@Nullable ProtectionElement protectionElement,
|
||||||
StreamElement[] streamElements) {
|
StreamElement[] streamElements) {
|
||||||
this.majorVersion = majorVersion;
|
this.majorVersion = majorVersion;
|
||||||
this.minorVersion = minorVersion;
|
this.minorVersion = minorVersion;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
|
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
@ -40,6 +41,7 @@ import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
import org.xmlpull.v1.XmlPullParserFactory;
|
import org.xmlpull.v1.XmlPullParserFactory;
|
||||||
|
|
@ -94,10 +96,10 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
|
||||||
private final String baseUri;
|
private final String baseUri;
|
||||||
private final String tag;
|
private final String tag;
|
||||||
|
|
||||||
private final ElementParser parent;
|
@Nullable private final ElementParser parent;
|
||||||
private final List<Pair<String, Object>> normalizedAttributes;
|
private final List<Pair<String, @NullableType Object>> normalizedAttributes;
|
||||||
|
|
||||||
public ElementParser(ElementParser parent, String baseUri, String tag) {
|
public ElementParser(@Nullable ElementParser parent, String baseUri, String tag) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.baseUri = baseUri;
|
this.baseUri = baseUri;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
|
|
@ -174,24 +176,25 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
|
||||||
* Stash an attribute that may be normalized at this level. In other words, an attribute that
|
* Stash an attribute that may be normalized at this level. In other words, an attribute that
|
||||||
* may have been pulled up from the child elements because its value was the same in all
|
* may have been pulled up from the child elements because its value was the same in all
|
||||||
* children.
|
* children.
|
||||||
* <p>
|
*
|
||||||
* Stashing an attribute allows child element parsers to retrieve the values of normalized
|
* <p>Stashing an attribute allows child element parsers to retrieve the values of normalized
|
||||||
* attributes using {@link #getNormalizedAttribute(String)}.
|
* attributes using {@link #getNormalizedAttribute(String)}.
|
||||||
*
|
*
|
||||||
* @param key The name of the attribute.
|
* @param key The name of the attribute.
|
||||||
* @param value The value of the attribute.
|
* @param value The value of the attribute.
|
||||||
*/
|
*/
|
||||||
protected final void putNormalizedAttribute(String key, Object value) {
|
protected final void putNormalizedAttribute(String key, @Nullable Object value) {
|
||||||
normalizedAttributes.add(Pair.create(key, value));
|
normalizedAttributes.add(Pair.create(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with
|
* Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with the
|
||||||
* the provided name, the parent element parser will be queried, and so on up the chain.
|
* provided name, the parent element parser will be queried, and so on up the chain.
|
||||||
*
|
*
|
||||||
* @param key The name of the attribute.
|
* @param key The name of the attribute.
|
||||||
* @return The stashed value, or null if the attribute was not be found.
|
* @return The stashed value, or null if the attribute was not be found.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
protected final Object getNormalizedAttribute(String key) {
|
protected final Object getNormalizedAttribute(String key) {
|
||||||
for (int i = 0; i < normalizedAttributes.size(); i++) {
|
for (int i = 0; i < normalizedAttributes.size(); i++) {
|
||||||
Pair<String, Object> pair = normalizedAttributes.get(i);
|
Pair<String, Object> pair = normalizedAttributes.get(i);
|
||||||
|
|
@ -340,7 +343,7 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
|
||||||
private long dvrWindowLength;
|
private long dvrWindowLength;
|
||||||
private int lookAheadCount;
|
private int lookAheadCount;
|
||||||
private boolean isLive;
|
private boolean isLive;
|
||||||
private ProtectionElement protectionElement;
|
@Nullable private ProtectionElement protectionElement;
|
||||||
|
|
||||||
public SmoothStreamingMediaParser(ElementParser parent, String baseUri) {
|
public SmoothStreamingMediaParser(ElementParser parent, String baseUri) {
|
||||||
super(parent, baseUri, TAG);
|
super(parent, baseUri, TAG);
|
||||||
|
|
|
||||||
|
|
@ -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.media:media:1.0.1'
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,13 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api 'org.mockito:mockito-core:' + mockitoVersion
|
api 'org.mockito:mockito-core:' + mockitoVersion
|
||||||
|
api 'androidx.test:core:' + androidXTestVersion
|
||||||
api 'androidx.test.ext:junit:' + androidXTestVersion
|
api 'androidx.test.ext:junit:' + androidXTestVersion
|
||||||
api 'com.google.truth:truth:' + truthVersion
|
api 'com.google.truth:truth:' + truthVersion
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
implementation 'com.google.auto.value:auto-value-annotations:' + autoValueVersion
|
implementation 'com.google.auto.value:auto-value-annotations:' + autoValueVersion
|
||||||
annotationProcessor 'com.google.auto.value:auto-value:' + autoValueVersion
|
annotationProcessor 'com.google.auto.value:auto-value:' + autoValueVersion
|
||||||
testImplementation project(modulePrefix + 'testutils-robolectric')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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