Add TrackBitrateEstimator and WindowedTrackBitrateEstimator
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=220529628
This commit is contained in:
parent
f895be6b1f
commit
158bc1edac
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Estimates track bitrate values. */
|
||||||
|
public interface TrackBitrateEstimator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TrackBitrateEstimator} that returns the bitrate values defined in the track formats.
|
||||||
|
*/
|
||||||
|
TrackBitrateEstimator DEFAULT =
|
||||||
|
(formats, queue, iterators, bitrates) ->
|
||||||
|
TrackSelectionUtil.getFormatBitrates(formats, bitrates);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns bitrate values for a set of tracks whose formats are given.
|
||||||
|
*
|
||||||
|
* @param formats The track formats.
|
||||||
|
* @param queue The queue of already buffered {@link MediaChunk} instances. Must not be modified.
|
||||||
|
* @param iterators An array of {@link MediaChunkIterator}s providing information about the
|
||||||
|
* sequence of upcoming media chunks for each track.
|
||||||
|
* @param bitrates An array into which the bitrate values will be written. If non-null, this array
|
||||||
|
* is the one that will be returned.
|
||||||
|
* @return Bitrate values for the tracks. As long as the format of a track has set bitrate, a
|
||||||
|
* bitrate value is set in the returned array. Otherwise it might be set to {@link
|
||||||
|
* Format#NO_VALUE}.
|
||||||
|
*/
|
||||||
|
int[] getBitrates(
|
||||||
|
Format[] formats,
|
||||||
|
List<? extends MediaChunk> queue,
|
||||||
|
MediaChunkIterator[] iterators,
|
||||||
|
@Nullable int[] bitrates);
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.trackselection;
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
@ -74,20 +75,25 @@ public final class TrackSelectionUtil {
|
|||||||
* @param formats The track formats.
|
* @param formats The track formats.
|
||||||
* @param maxDurationUs Maximum duration of chunks to be included in average bitrate values, in
|
* @param maxDurationUs Maximum duration of chunks to be included in average bitrate values, in
|
||||||
* microseconds.
|
* microseconds.
|
||||||
|
* @param bitrates If not null, stores bitrate values in this array.
|
||||||
* @return Average bitrate values for the tracks. If for a track, an average bitrate or an
|
* @return Average bitrate values for the tracks. If for a track, an average bitrate or an
|
||||||
* estimation can't be calculated, {@link Format#NO_VALUE} is set.
|
* estimation can't be calculated, {@link Format#NO_VALUE} is set.
|
||||||
* @see #getAverageBitrate(MediaChunkIterator, long)
|
* @see #getAverageBitrate(MediaChunkIterator, long)
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
/* package */ static int[] getBitratesUsingFutureInfo(
|
/* package */ static int[] getBitratesUsingFutureInfo(
|
||||||
MediaChunkIterator[] iterators, Format[] formats, long maxDurationUs) {
|
MediaChunkIterator[] iterators,
|
||||||
|
Format[] formats,
|
||||||
|
long maxDurationUs,
|
||||||
|
@Nullable int[] bitrates) {
|
||||||
int trackCount = iterators.length;
|
int trackCount = iterators.length;
|
||||||
Assertions.checkArgument(trackCount == formats.length);
|
Assertions.checkArgument(trackCount == formats.length);
|
||||||
if (trackCount == 0) {
|
if (trackCount == 0) {
|
||||||
return new int[0];
|
return new int[0];
|
||||||
}
|
}
|
||||||
|
if (bitrates == null) {
|
||||||
int[] bitrates = new int[trackCount];
|
bitrates = new int[trackCount];
|
||||||
|
}
|
||||||
if (maxDurationUs == 0) {
|
if (maxDurationUs == 0) {
|
||||||
Arrays.fill(bitrates, Format.NO_VALUE);
|
Arrays.fill(bitrates, Format.NO_VALUE);
|
||||||
return bitrates;
|
return bitrates;
|
||||||
@ -127,15 +133,22 @@ public final class TrackSelectionUtil {
|
|||||||
* @param formats The track formats.
|
* @param formats The track formats.
|
||||||
* @param maxDurationUs Maximum duration of chunks to be included in average bitrate values, in
|
* @param maxDurationUs Maximum duration of chunks to be included in average bitrate values, in
|
||||||
* microseconds.
|
* microseconds.
|
||||||
|
* @param bitrates If not null, calculates bitrate values only for indexes set to Format.NO_VALUE
|
||||||
|
* and stores result in this array.
|
||||||
* @return Bitrate values for the tracks. If for a track, a bitrate value can't be calculated,
|
* @return Bitrate values for the tracks. If for a track, a bitrate value can't be calculated,
|
||||||
* {@link Format#NO_VALUE} is set.
|
* {@link Format#NO_VALUE} is set.
|
||||||
* @see #getBitratesUsingFutureInfo(MediaChunkIterator[], Format[], long)
|
* @see #getBitratesUsingFutureInfo(MediaChunkIterator[], Format[], long, int[])
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
/* package */ static int[] getBitratesUsingPastInfo(
|
/* package */ static int[] getBitratesUsingPastInfo(
|
||||||
List<? extends MediaChunk> queue, Format[] formats, long maxDurationUs) {
|
List<? extends MediaChunk> queue,
|
||||||
int[] bitrates = new int[formats.length];
|
Format[] formats,
|
||||||
Arrays.fill(bitrates, Format.NO_VALUE);
|
long maxDurationUs,
|
||||||
|
@Nullable int[] bitrates) {
|
||||||
|
if (bitrates == null) {
|
||||||
|
bitrates = new int[formats.length];
|
||||||
|
Arrays.fill(bitrates, Format.NO_VALUE);
|
||||||
|
}
|
||||||
if (maxDurationUs == 0) {
|
if (maxDurationUs == 0) {
|
||||||
return bitrates;
|
return bitrates;
|
||||||
}
|
}
|
||||||
@ -156,40 +169,58 @@ public final class TrackSelectionUtil {
|
|||||||
* Returns bitrate values for a set of tracks whose formats are given, using the given upcoming
|
* Returns bitrate values for a set of tracks whose formats are given, using the given upcoming
|
||||||
* media chunk iterators and the queue of already buffered {@link MediaChunk}s.
|
* media chunk iterators and the queue of already buffered {@link MediaChunk}s.
|
||||||
*
|
*
|
||||||
|
* @param formats The track formats.
|
||||||
|
* @param queue The queue of already buffered {@link MediaChunk}s. Must not be modified.
|
||||||
|
* @param maxPastDurationUs Maximum duration of past chunks to be included in average bitrate
|
||||||
|
* values, in microseconds.
|
||||||
* @param iterators An array of {@link MediaChunkIterator}s providing information about the
|
* @param iterators An array of {@link MediaChunkIterator}s providing information about the
|
||||||
* sequence of upcoming media chunks for each track.
|
* sequence of upcoming media chunks for each track.
|
||||||
* @param queue The queue of already buffered {@link MediaChunk}s. Must not be modified.
|
|
||||||
* @param formats The track formats.
|
|
||||||
* @param maxFutureDurationUs Maximum duration of future chunks to be included in average bitrate
|
* @param maxFutureDurationUs Maximum duration of future chunks to be included in average bitrate
|
||||||
* values, in microseconds.
|
* values, in microseconds.
|
||||||
* @param maxPastDurationUs Maximum duration of past chunks to be included in average bitrate
|
|
||||||
* values, in microseconds.
|
|
||||||
* @param useFormatBitrateAsLowerBound Whether to return the estimated bitrate only if it's higher
|
* @param useFormatBitrateAsLowerBound Whether to return the estimated bitrate only if it's higher
|
||||||
* than the bitrate of the track's format.
|
* than the bitrate of the track's format.
|
||||||
* @return Bitrate values for the tracks. If for a track, a bitrate value can't be calculated,
|
* @param bitrates An array into which the bitrate values will be written. If non-null, this array
|
||||||
* {@link Format#NO_VALUE} is set.
|
* is the one that will be returned.
|
||||||
|
* @return Bitrate values for the tracks. As long as the format of a track has set bitrate, a
|
||||||
|
* bitrate value is set in the returned array. Otherwise it might be set to {@link
|
||||||
|
* Format#NO_VALUE}.
|
||||||
*/
|
*/
|
||||||
public static int[] getBitratesUsingPastAndFutureInfo(
|
public static int[] getBitratesUsingPastAndFutureInfo(
|
||||||
MediaChunkIterator[] iterators,
|
|
||||||
List<? extends MediaChunk> queue,
|
|
||||||
Format[] formats,
|
Format[] formats,
|
||||||
long maxFutureDurationUs,
|
List<? extends MediaChunk> queue,
|
||||||
long maxPastDurationUs,
|
long maxPastDurationUs,
|
||||||
boolean useFormatBitrateAsLowerBound) {
|
MediaChunkIterator[] iterators,
|
||||||
int[] bitrates = getBitratesUsingFutureInfo(iterators, formats, maxFutureDurationUs);
|
long maxFutureDurationUs,
|
||||||
int[] bitratesUsingPastInfo = getBitratesUsingPastInfo(queue, formats, maxPastDurationUs);
|
boolean useFormatBitrateAsLowerBound,
|
||||||
|
@Nullable int[] bitrates) {
|
||||||
|
bitrates = getBitratesUsingFutureInfo(iterators, formats, maxFutureDurationUs, bitrates);
|
||||||
|
getBitratesUsingPastInfo(queue, formats, maxPastDurationUs, bitrates);
|
||||||
for (int i = 0; i < bitrates.length; i++) {
|
for (int i = 0; i < bitrates.length; i++) {
|
||||||
int bitrate = bitrates[i];
|
int bitrate = bitrates[i];
|
||||||
if (bitrate == Format.NO_VALUE) {
|
|
||||||
bitrate = bitratesUsingPastInfo[i];
|
|
||||||
}
|
|
||||||
if (bitrate == Format.NO_VALUE
|
if (bitrate == Format.NO_VALUE
|
||||||
|| (useFormatBitrateAsLowerBound
|
|| (useFormatBitrateAsLowerBound
|
||||||
&& formats[i].bitrate != Format.NO_VALUE
|
&& formats[i].bitrate != Format.NO_VALUE
|
||||||
&& bitrate < formats[i].bitrate)) {
|
&& bitrate < formats[i].bitrate)) {
|
||||||
bitrate = formats[i].bitrate;
|
bitrates[i] = formats[i].bitrate;
|
||||||
}
|
}
|
||||||
bitrates[i] = bitrate;
|
}
|
||||||
|
return bitrates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing {@link Format#bitrate} values for given each format in order.
|
||||||
|
*
|
||||||
|
* @param formats The format array to copy {@link Format#bitrate} values.
|
||||||
|
* @param bitrates If not null, stores bitrate values in this array.
|
||||||
|
* @return An array containing {@link Format#bitrate} values for given each format in order.
|
||||||
|
*/
|
||||||
|
public static int[] getFormatBitrates(Format[] formats, @Nullable int[] bitrates) {
|
||||||
|
int trackCount = formats.length;
|
||||||
|
if (bitrates == null) {
|
||||||
|
bitrates = new int[trackCount];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < trackCount; i++) {
|
||||||
|
bitrates[i] = formats[i].bitrate;
|
||||||
}
|
}
|
||||||
return bitrates;
|
return bitrates;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** A {@link TrackBitrateEstimator} which derives estimates from a window of time. */
|
||||||
|
public final class WindowedTrackBitrateEstimator implements TrackBitrateEstimator {
|
||||||
|
|
||||||
|
private final long maxFutureDurationUs;
|
||||||
|
private final long maxPastDurationUs;
|
||||||
|
private final boolean useFormatBitrateAsLowerBound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param maxFutureDurationUs Maximum duration of future chunks to be included in average bitrate
|
||||||
|
* values, in microseconds.
|
||||||
|
* @param maxPastDurationUs Maximum duration of past chunks to be included in average bitrate
|
||||||
|
* values, in microseconds.
|
||||||
|
* @param useFormatBitrateAsLowerBound Whether to return the estimated bitrate only if it's higher
|
||||||
|
* than the bitrate of the track's format.
|
||||||
|
*/
|
||||||
|
public WindowedTrackBitrateEstimator(
|
||||||
|
long maxFutureDurationUs, long maxPastDurationUs, boolean useFormatBitrateAsLowerBound) {
|
||||||
|
this.maxFutureDurationUs = maxFutureDurationUs;
|
||||||
|
this.maxPastDurationUs = maxPastDurationUs;
|
||||||
|
this.useFormatBitrateAsLowerBound = useFormatBitrateAsLowerBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getBitrates(
|
||||||
|
Format[] formats,
|
||||||
|
List<? extends MediaChunk> queue,
|
||||||
|
MediaChunkIterator[] iterators,
|
||||||
|
@Nullable int[] bitrates) {
|
||||||
|
if (maxFutureDurationUs > 0 || maxPastDurationUs > 0) {
|
||||||
|
return TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
||||||
|
formats,
|
||||||
|
queue,
|
||||||
|
maxPastDurationUs,
|
||||||
|
iterators,
|
||||||
|
maxFutureDurationUs,
|
||||||
|
useFormatBitrateAsLowerBound,
|
||||||
|
bitrates);
|
||||||
|
}
|
||||||
|
return TrackSelectionUtil.getFormatBitrates(formats, bitrates);
|
||||||
|
}
|
||||||
|
}
|
@ -20,9 +20,9 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
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.chunk.BaseMediaChunkIterator;
|
|
||||||
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
||||||
import com.google.android.exoplayer2.testutil.FakeMediaChunk;
|
import com.google.android.exoplayer2.testutil.FakeMediaChunk;
|
||||||
|
import com.google.android.exoplayer2.testutil.FakeMediaChunkIterator;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -47,7 +47,8 @@ public class TrackSelectionUtilTest {
|
|||||||
long[] chunkTimeBoundariesSec = {12, 17};
|
long[] chunkTimeBoundariesSec = {12, 17};
|
||||||
long[] chunkLengths = {10};
|
long[] chunkLengths = {10};
|
||||||
|
|
||||||
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
FakeMediaChunkIterator iterator =
|
||||||
|
new FakeMediaChunkIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(16);
|
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(16);
|
||||||
}
|
}
|
||||||
@ -57,7 +58,8 @@ public class TrackSelectionUtilTest {
|
|||||||
long[] chunkTimeBoundariesSec = {0, 5, 10};
|
long[] chunkTimeBoundariesSec = {0, 5, 10};
|
||||||
long[] chunkLengths = {10, 20};
|
long[] chunkLengths = {10, 20};
|
||||||
|
|
||||||
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
FakeMediaChunkIterator iterator =
|
||||||
|
new FakeMediaChunkIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(24);
|
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(24);
|
||||||
}
|
}
|
||||||
@ -67,7 +69,8 @@ public class TrackSelectionUtilTest {
|
|||||||
long[] chunkTimeBoundariesSec = {0, 5, 15, 30};
|
long[] chunkTimeBoundariesSec = {0, 5, 15, 30};
|
||||||
long[] chunkLengths = {10, 20, 30};
|
long[] chunkLengths = {10, 20, 30};
|
||||||
|
|
||||||
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
FakeMediaChunkIterator iterator =
|
||||||
|
new FakeMediaChunkIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(16);
|
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(16);
|
||||||
}
|
}
|
||||||
@ -77,7 +80,8 @@ public class TrackSelectionUtilTest {
|
|||||||
long[] chunkTimeBoundariesSec = {0, 5, 15, 30};
|
long[] chunkTimeBoundariesSec = {0, 5, 15, 30};
|
||||||
long[] chunkLengths = {C.LENGTH_UNSET, 20, 30};
|
long[] chunkLengths = {C.LENGTH_UNSET, 20, 30};
|
||||||
|
|
||||||
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
FakeMediaChunkIterator iterator =
|
||||||
|
new FakeMediaChunkIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US))
|
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US))
|
||||||
.isEqualTo(Format.NO_VALUE);
|
.isEqualTo(Format.NO_VALUE);
|
||||||
@ -88,7 +92,8 @@ public class TrackSelectionUtilTest {
|
|||||||
long[] chunkTimeBoundariesSec = {0, 5, 15, 30};
|
long[] chunkTimeBoundariesSec = {0, 5, 15, 30};
|
||||||
long[] chunkLengths = {10, C.LENGTH_UNSET, 30};
|
long[] chunkLengths = {10, C.LENGTH_UNSET, 30};
|
||||||
|
|
||||||
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
FakeMediaChunkIterator iterator =
|
||||||
|
new FakeMediaChunkIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(16);
|
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, MAX_DURATION_US)).isEqualTo(16);
|
||||||
}
|
}
|
||||||
@ -98,7 +103,8 @@ public class TrackSelectionUtilTest {
|
|||||||
getAverageBitrate_chunksExceedingMaxDuration_returnsAverageChunkBitrateUpToMaxDuration() {
|
getAverageBitrate_chunksExceedingMaxDuration_returnsAverageChunkBitrateUpToMaxDuration() {
|
||||||
long[] chunkTimeBoundariesSec = {0, 5, 15, 45, 50};
|
long[] chunkTimeBoundariesSec = {0, 5, 15, 45, 50};
|
||||||
long[] chunkLengths = {10, 20, 30, 100};
|
long[] chunkLengths = {10, 20, 30, 100};
|
||||||
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
FakeMediaChunkIterator iterator =
|
||||||
|
new FakeMediaChunkIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
long maxDurationUs = 30 * C.MICROS_PER_SECOND;
|
long maxDurationUs = 30 * C.MICROS_PER_SECOND;
|
||||||
int averageBitrate = TrackSelectionUtil.getAverageBitrate(iterator, maxDurationUs);
|
int averageBitrate = TrackSelectionUtil.getAverageBitrate(iterator, maxDurationUs);
|
||||||
@ -111,7 +117,8 @@ public class TrackSelectionUtilTest {
|
|||||||
long[] chunkTimeBoundariesSec = {0, 5, 10};
|
long[] chunkTimeBoundariesSec = {0, 5, 10};
|
||||||
long[] chunkLengths = {10, 20};
|
long[] chunkLengths = {10, 20};
|
||||||
|
|
||||||
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
FakeMediaChunkIterator iterator =
|
||||||
|
new FakeMediaChunkIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, /* maxDurationUs= */ 0))
|
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, /* maxDurationUs= */ 0))
|
||||||
.isEqualTo(Format.NO_VALUE);
|
.isEqualTo(Format.NO_VALUE);
|
||||||
@ -121,7 +128,7 @@ public class TrackSelectionUtilTest {
|
|||||||
public void getBitratesUsingFutureInfo_noIterator_returnsEmptyArray() {
|
public void getBitratesUsingFutureInfo_noIterator_returnsEmptyArray() {
|
||||||
assertThat(
|
assertThat(
|
||||||
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[0], new Format[0], MAX_DURATION_US))
|
new MediaChunkIterator[0], new Format[0], MAX_DURATION_US, /* bitrates= */ null))
|
||||||
.hasLength(0);
|
.hasLength(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,18 +138,19 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {MediaChunkIterator.EMPTY},
|
new MediaChunkIterator[] {MediaChunkIterator.EMPTY},
|
||||||
new Format[] {createFormatWithBitrate(10)},
|
new Format[] {createFormatWithBitrate(10)},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBitratesUsingFutureInfo_twoTracksZeroMaxDuration_returnsNoValue() {
|
public void getBitratesUsingFutureInfo_twoTracksZeroMaxDuration_returnsNoValue() {
|
||||||
FakeIterator iterator1 =
|
FakeMediaChunkIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
||||||
FakeIterator iterator2 =
|
FakeMediaChunkIterator iterator2 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
||||||
/* chunkLengths= */ new long[] {10, 20, 30});
|
/* chunkLengths= */ new long[] {10, 20, 30});
|
||||||
|
|
||||||
@ -150,18 +158,19 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2},
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
||||||
/* maxDurationUs= */ 0);
|
/* maxDurationUs= */ 0,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE, Format.NO_VALUE);
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE, Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBitratesUsingFutureInfo_twoTracks_returnsBitrates() {
|
public void getBitratesUsingFutureInfo_twoTracks_returnsBitrates() {
|
||||||
FakeIterator iterator1 =
|
FakeMediaChunkIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
||||||
FakeIterator iterator2 =
|
FakeMediaChunkIterator iterator2 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
||||||
/* chunkLengths= */ new long[] {10, 20, 30});
|
/* chunkLengths= */ new long[] {10, 20, 30});
|
||||||
|
|
||||||
@ -169,25 +178,47 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2},
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingFutureInfo_bitratesArrayGiven_returnsTheSameArray() {
|
||||||
|
FakeMediaChunkIterator iterator1 =
|
||||||
|
new FakeMediaChunkIterator(
|
||||||
|
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
||||||
|
FakeMediaChunkIterator iterator2 =
|
||||||
|
new FakeMediaChunkIterator(
|
||||||
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
||||||
|
/* chunkLengths= */ new long[] {10, 20, 30});
|
||||||
|
|
||||||
|
int[] bitratesArrayToUse = new int[2];
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
|
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
||||||
|
MAX_DURATION_US,
|
||||||
|
bitratesArrayToUse);
|
||||||
|
|
||||||
|
assertThat(bitrates).isSameAs(bitratesArrayToUse);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBitratesUsingFutureInfo_emptyIterator_returnsEstimationUsingClosest() {
|
public void getBitratesUsingFutureInfo_emptyIterator_returnsEstimationUsingClosest() {
|
||||||
FakeIterator iterator1 =
|
FakeMediaChunkIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {10});
|
||||||
Format format1 = createFormatWithBitrate(10);
|
Format format1 = createFormatWithBitrate(10);
|
||||||
MediaChunkIterator iterator2 = MediaChunkIterator.EMPTY;
|
MediaChunkIterator iterator2 = MediaChunkIterator.EMPTY;
|
||||||
Format format2 = createFormatWithBitrate(20);
|
Format format2 = createFormatWithBitrate(20);
|
||||||
FakeIterator iterator3 =
|
FakeMediaChunkIterator iterator3 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {50});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {50});
|
||||||
Format format3 = createFormatWithBitrate(25);
|
Format format3 = createFormatWithBitrate(25);
|
||||||
FakeIterator iterator4 =
|
FakeMediaChunkIterator iterator4 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {20});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {20});
|
||||||
Format format4 = createFormatWithBitrate(30);
|
Format format4 = createFormatWithBitrate(30);
|
||||||
|
|
||||||
@ -195,15 +226,16 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2, iterator3, iterator4},
|
new MediaChunkIterator[] {iterator1, iterator2, iterator3, iterator4},
|
||||||
new Format[] {format1, format2, format3, format4},
|
new Format[] {format1, format2, format3, format4},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(16, 64, 80, 32).inOrder();
|
assertThat(bitrates).asList().containsExactly(16, 64, 80, 32).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBitratesUsingFutureInfo_formatWithoutBitrate_returnsNoValueForEmpty() {
|
public void getBitratesUsingFutureInfo_formatWithoutBitrate_returnsNoValueForEmpty() {
|
||||||
FakeIterator iterator1 =
|
FakeMediaChunkIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {10});
|
||||||
Format format1 = createFormatWithBitrate(10);
|
Format format1 = createFormatWithBitrate(10);
|
||||||
MediaChunkIterator iterator2 = MediaChunkIterator.EMPTY;
|
MediaChunkIterator iterator2 = MediaChunkIterator.EMPTY;
|
||||||
@ -213,7 +245,8 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2},
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
new Format[] {format1, format2},
|
new Format[] {format1, format2},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(16, Format.NO_VALUE).inOrder();
|
assertThat(bitrates).asList().containsExactly(16, Format.NO_VALUE).inOrder();
|
||||||
}
|
}
|
||||||
@ -229,7 +262,7 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk), new Format[0], MAX_DURATION_US);
|
Collections.singletonList(chunk), new Format[0], MAX_DURATION_US, /* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).hasLength(0);
|
assertThat(bitrates).hasLength(0);
|
||||||
}
|
}
|
||||||
@ -238,7 +271,10 @@ public class TrackSelectionUtilTest {
|
|||||||
public void getBitratesUsingPastInfo_emptyQueue_returnsNoValue() {
|
public void getBitratesUsingPastInfo_emptyQueue_returnsNoValue() {
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.emptyList(), new Format[] {createFormatWithBitrate(10)}, MAX_DURATION_US);
|
Collections.emptyList(),
|
||||||
|
new Format[] {createFormatWithBitrate(10)},
|
||||||
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
@ -251,7 +287,10 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk), new Format[] {format}, MAX_DURATION_US);
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {format},
|
||||||
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
@ -265,7 +304,10 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk), new Format[] {format}, MAX_DURATION_US);
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {format},
|
||||||
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
@ -278,7 +320,10 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk), new Format[] {format}, MAX_DURATION_US);
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {format},
|
||||||
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(8).inOrder();
|
assertThat(bitrates).asList().containsExactly(8).inOrder();
|
||||||
}
|
}
|
||||||
@ -291,7 +336,10 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk), new Format[] {format}, /* maxDurationUs= */ 0);
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {format},
|
||||||
|
/* maxDurationUs= */ 0,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE).inOrder();
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE).inOrder();
|
||||||
}
|
}
|
||||||
@ -306,7 +354,10 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Arrays.asList(chunk, chunk2), new Format[] {format}, MAX_DURATION_US);
|
Arrays.asList(chunk, chunk2),
|
||||||
|
new Format[] {format},
|
||||||
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(12).inOrder();
|
assertThat(bitrates).asList().containsExactly(12).inOrder();
|
||||||
}
|
}
|
||||||
@ -324,7 +375,8 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk),
|
Collections.singletonList(chunk),
|
||||||
new Format[] {createFormatWithBitrate(20)},
|
new Format[] {createFormatWithBitrate(20)},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(16).inOrder();
|
assertThat(bitrates).asList().containsExactly(16).inOrder();
|
||||||
}
|
}
|
||||||
@ -342,7 +394,8 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk),
|
Collections.singletonList(chunk),
|
||||||
new Format[] {createFormatWithBitrate(Format.NO_VALUE)},
|
new Format[] {createFormatWithBitrate(Format.NO_VALUE)},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
@ -360,11 +413,32 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Collections.singletonList(chunk),
|
Collections.singletonList(chunk),
|
||||||
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(16, 24).inOrder();
|
assertThat(bitrates).asList().containsExactly(16, 24).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_bitratesArrayGiven_returnsTheSameArray() {
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(
|
||||||
|
createFormatWithBitrate(10),
|
||||||
|
/* length= */ 10,
|
||||||
|
/* startTimeSec= */ 0,
|
||||||
|
/* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitratesArrayToUse = new int[2];
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
||||||
|
MAX_DURATION_US,
|
||||||
|
bitratesArrayToUse);
|
||||||
|
|
||||||
|
assertThat(bitrates).isSameAs(bitratesArrayToUse);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
getBitratesUsingPastInfo_multipleChunkExceedingMaxDuration_returnsAverageUntilMaxDuration() {
|
getBitratesUsingPastInfo_multipleChunkExceedingMaxDuration_returnsAverageUntilMaxDuration() {
|
||||||
@ -378,7 +452,8 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Arrays.asList(chunk, chunk2),
|
Arrays.asList(chunk, chunk2),
|
||||||
new Format[] {format},
|
new Format[] {format},
|
||||||
/* maxDurationUs= */ 30 * C.MICROS_PER_SECOND);
|
/* maxDurationUs= */ 30 * C.MICROS_PER_SECOND,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(12).inOrder();
|
assertThat(bitrates).asList().containsExactly(12).inOrder();
|
||||||
}
|
}
|
||||||
@ -403,29 +478,31 @@ public class TrackSelectionUtilTest {
|
|||||||
TrackSelectionUtil.getBitratesUsingPastInfo(
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
Arrays.asList(chunk, chunk2),
|
Arrays.asList(chunk, chunk2),
|
||||||
new Format[] {createFormatWithBitrate(10)},
|
new Format[] {createFormatWithBitrate(10)},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(16).inOrder();
|
assertThat(bitrates).asList().containsExactly(16).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBitratesUsingPastAndFutureInfo_noPastInfo_returnsBitratesUsingOnlyFutureInfo() {
|
public void getBitratesUsingPastAndFutureInfo_noPastInfo_returnsBitratesUsingOnlyFutureInfo() {
|
||||||
FakeIterator iterator1 =
|
FakeMediaChunkIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
||||||
FakeIterator iterator2 =
|
FakeMediaChunkIterator iterator2 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
||||||
/* chunkLengths= */ new long[] {10, 20, 30});
|
/* chunkLengths= */ new long[] {10, 20, 30});
|
||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2},
|
|
||||||
Collections.emptyList(),
|
|
||||||
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
||||||
|
Collections.emptyList(),
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
/* useFormatBitrateAsLowerBound= */ false);
|
/* useFormatBitrateAsLowerBound= */ false,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
||||||
}
|
}
|
||||||
@ -441,12 +518,13 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
||||||
new MediaChunkIterator[] {MediaChunkIterator.EMPTY, MediaChunkIterator.EMPTY},
|
|
||||||
Collections.singletonList(chunk),
|
|
||||||
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
|
new MediaChunkIterator[] {MediaChunkIterator.EMPTY, MediaChunkIterator.EMPTY},
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
/* useFormatBitrateAsLowerBound= */ false);
|
/* useFormatBitrateAsLowerBound= */ false,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(16, 24).inOrder();
|
assertThat(bitrates).asList().containsExactly(16, 24).inOrder();
|
||||||
}
|
}
|
||||||
@ -460,22 +538,23 @@ public class TrackSelectionUtilTest {
|
|||||||
/* length= */ 10,
|
/* length= */ 10,
|
||||||
/* startTimeSec= */ 0,
|
/* startTimeSec= */ 0,
|
||||||
/* endTimeSec= */ 10);
|
/* endTimeSec= */ 10);
|
||||||
FakeIterator iterator1 =
|
FakeMediaChunkIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
||||||
FakeIterator iterator2 =
|
FakeMediaChunkIterator iterator2 =
|
||||||
new FakeIterator(
|
new FakeMediaChunkIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
||||||
/* chunkLengths= */ new long[] {10, 20, 30});
|
/* chunkLengths= */ new long[] {10, 20, 30});
|
||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2},
|
|
||||||
Collections.singletonList(chunk),
|
|
||||||
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
/* useFormatBitrateAsLowerBound= */ false);
|
/* useFormatBitrateAsLowerBound= */ false,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
||||||
}
|
}
|
||||||
@ -484,12 +563,13 @@ public class TrackSelectionUtilTest {
|
|||||||
public void getBitratesUsingPastAndFutureInfo_noPastAndFutureInfo_returnsBitratesOfFormats() {
|
public void getBitratesUsingPastAndFutureInfo_noPastAndFutureInfo_returnsBitratesOfFormats() {
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
||||||
new MediaChunkIterator[] {MediaChunkIterator.EMPTY, MediaChunkIterator.EMPTY},
|
|
||||||
Collections.emptyList(),
|
|
||||||
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
||||||
|
Collections.emptyList(),
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
|
new MediaChunkIterator[] {MediaChunkIterator.EMPTY, MediaChunkIterator.EMPTY},
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
/* useFormatBitrateAsLowerBound= */ false);
|
/* useFormatBitrateAsLowerBound= */ false,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(10, 20).inOrder();
|
assertThat(bitrates).asList().containsExactly(10, 20).inOrder();
|
||||||
}
|
}
|
||||||
@ -506,58 +586,32 @@ public class TrackSelectionUtilTest {
|
|||||||
|
|
||||||
int[] bitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
TrackSelectionUtil.getBitratesUsingPastAndFutureInfo(
|
||||||
new MediaChunkIterator[] {MediaChunkIterator.EMPTY, MediaChunkIterator.EMPTY},
|
|
||||||
Collections.singletonList(chunk),
|
|
||||||
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
|
new MediaChunkIterator[] {MediaChunkIterator.EMPTY, MediaChunkIterator.EMPTY},
|
||||||
MAX_DURATION_US,
|
MAX_DURATION_US,
|
||||||
/* useFormatBitrateAsLowerBound= */ true);
|
/* useFormatBitrateAsLowerBound= */ true,
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
assertThat(bitrates).asList().containsExactly(20, 30).inOrder();
|
assertThat(bitrates).asList().containsExactly(20, 30).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FakeMediaChunk createChunk(
|
private static FakeMediaChunk createChunk(
|
||||||
Format format, int length, int startTimeSec, int endTimeSec) {
|
Format format, int length, int startTimeSec, int endTimeSec) {
|
||||||
DataSpec dataSpec = new DataSpec(Uri.EMPTY, 0, length, null, 0);
|
DataSpec dataSpec =
|
||||||
|
new DataSpec(
|
||||||
|
Uri.EMPTY, /* absoluteStreamPosition= */ 0, length, /* key= */ null, /* flags= */ 0);
|
||||||
return new FakeMediaChunk(
|
return new FakeMediaChunk(
|
||||||
dataSpec, format, startTimeSec * C.MICROS_PER_SECOND, endTimeSec * C.MICROS_PER_SECOND);
|
dataSpec, format, startTimeSec * C.MICROS_PER_SECOND, endTimeSec * C.MICROS_PER_SECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Format createFormatWithBitrate(int bitrate) {
|
private static Format createFormatWithBitrate(int bitrate) {
|
||||||
return Format.createSampleFormat(null, null, null, bitrate, null);
|
return Format.createSampleFormat(
|
||||||
}
|
/* id= */ null,
|
||||||
|
/* sampleMimeType= */ null,
|
||||||
private static final class FakeIterator extends BaseMediaChunkIterator {
|
/* codecs= */ null,
|
||||||
|
bitrate,
|
||||||
private final long[] chunkTimeBoundariesSec;
|
/* drmInitData= */ null);
|
||||||
private final long[] chunkLengths;
|
|
||||||
|
|
||||||
public FakeIterator(long[] chunkTimeBoundariesSec, long[] chunkLengths) {
|
|
||||||
super(/* fromIndex= */ 0, /* toIndex= */ chunkTimeBoundariesSec.length - 2);
|
|
||||||
this.chunkTimeBoundariesSec = chunkTimeBoundariesSec;
|
|
||||||
this.chunkLengths = chunkLengths;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataSpec getDataSpec() {
|
|
||||||
checkInBounds();
|
|
||||||
return new DataSpec(
|
|
||||||
Uri.EMPTY,
|
|
||||||
/* absoluteStreamPosition= */ 0,
|
|
||||||
chunkLengths[(int) getCurrentIndex()],
|
|
||||||
/* key= */ null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getChunkStartTimeUs() {
|
|
||||||
checkInBounds();
|
|
||||||
return chunkTimeBoundariesSec[(int) getCurrentIndex()] * C.MICROS_PER_SECOND;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getChunkEndTimeUs() {
|
|
||||||
checkInBounds();
|
|
||||||
return chunkTimeBoundariesSec[(int) getCurrentIndex() + 1] * C.MICROS_PER_SECOND;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
||||||
|
import com.google.android.exoplayer2.testutil.FakeMediaChunk;
|
||||||
|
import com.google.android.exoplayer2.testutil.FakeMediaChunkIterator;
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
/** {@link WindowedTrackBitrateEstimator} tests. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class WindowedTrackBitrateEstimatorTest {
|
||||||
|
|
||||||
|
private static final long MAX_DURATION_US = 30 * C.MICROS_PER_SECOND;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitrates_zeroMaxDuration_returnsFormatBitrates() {
|
||||||
|
WindowedTrackBitrateEstimator estimator =
|
||||||
|
new WindowedTrackBitrateEstimator(
|
||||||
|
/* maxFutureDurationUs= */ 0,
|
||||||
|
/* maxPastDurationUs= */ 0,
|
||||||
|
/* useFormatBitrateAsLowerBound= */ false);
|
||||||
|
MediaChunk chunk = createMediaChunk(/* formatBitrate= */ 5, /* actualBitrate= */ 10);
|
||||||
|
MediaChunkIterator iterator1 = createMediaChunkIteratorWithBitrate(8);
|
||||||
|
MediaChunkIterator iterator2 = createMediaChunkIteratorWithBitrate(16);
|
||||||
|
Format format1 = createFormatWithBitrate(10);
|
||||||
|
Format format2 = createFormatWithBitrate(20);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
estimator.getBitrates(
|
||||||
|
new Format[] {format1, format2},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(10, 20).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitrates_futureMaxDurationSet_returnsEstimateUsingFutureChunks() {
|
||||||
|
WindowedTrackBitrateEstimator estimator =
|
||||||
|
new WindowedTrackBitrateEstimator(
|
||||||
|
MAX_DURATION_US, /* maxPastDurationUs= */ 0, /* useFormatBitrateAsLowerBound= */ false);
|
||||||
|
MediaChunk chunk = createMediaChunk(/* formatBitrate= */ 5, /* actualBitrate= */ 10);
|
||||||
|
MediaChunkIterator iterator1 = createMediaChunkIteratorWithBitrate(8);
|
||||||
|
MediaChunkIterator iterator2 = createMediaChunkIteratorWithBitrate(16);
|
||||||
|
Format format1 = createFormatWithBitrate(10);
|
||||||
|
Format format2 = createFormatWithBitrate(20);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
estimator.getBitrates(
|
||||||
|
new Format[] {format1, format2},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitrates_pastMaxDurationSet_returnsEstimateUsingPastChunks() {
|
||||||
|
WindowedTrackBitrateEstimator estimator =
|
||||||
|
new WindowedTrackBitrateEstimator(
|
||||||
|
/* maxFutureDurationUs= */ 0,
|
||||||
|
MAX_DURATION_US,
|
||||||
|
/* useFormatBitrateAsLowerBound= */ false);
|
||||||
|
MediaChunk chunk = createMediaChunk(/* formatBitrate= */ 5, /* actualBitrate= */ 10);
|
||||||
|
MediaChunkIterator iterator1 = createMediaChunkIteratorWithBitrate(8);
|
||||||
|
MediaChunkIterator iterator2 = createMediaChunkIteratorWithBitrate(16);
|
||||||
|
Format format1 = createFormatWithBitrate(10);
|
||||||
|
Format format2 = createFormatWithBitrate(20);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
estimator.getBitrates(
|
||||||
|
new Format[] {format1, format2},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(16, 32).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
getBitrates_useFormatBitrateAsLowerBoundSetTrue_returnsEstimateIfOnlyHigherThanFormat() {
|
||||||
|
WindowedTrackBitrateEstimator estimator =
|
||||||
|
new WindowedTrackBitrateEstimator(
|
||||||
|
MAX_DURATION_US, MAX_DURATION_US, /* useFormatBitrateAsLowerBound= */ true);
|
||||||
|
MediaChunk chunk = createMediaChunk(/* formatBitrate= */ 5, /* actualBitrate= */ 10);
|
||||||
|
MediaChunkIterator iterator1 = createMediaChunkIteratorWithBitrate(80);
|
||||||
|
MediaChunkIterator iterator2 = createMediaChunkIteratorWithBitrate(16);
|
||||||
|
Format format1 = createFormatWithBitrate(10);
|
||||||
|
Format format2 = createFormatWithBitrate(20);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
estimator.getBitrates(
|
||||||
|
new Format[] {format1, format2},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
|
/* bitrates= */ null);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(80, 20).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitrates_bitratesArrayGiven_returnsTheSameArray() {
|
||||||
|
WindowedTrackBitrateEstimator estimator =
|
||||||
|
new WindowedTrackBitrateEstimator(
|
||||||
|
MAX_DURATION_US, MAX_DURATION_US, /* useFormatBitrateAsLowerBound= */ true);
|
||||||
|
MediaChunk chunk = createMediaChunk(/* formatBitrate= */ 5, /* actualBitrate= */ 10);
|
||||||
|
MediaChunkIterator iterator1 = createMediaChunkIteratorWithBitrate(8);
|
||||||
|
MediaChunkIterator iterator2 = createMediaChunkIteratorWithBitrate(16);
|
||||||
|
Format format1 = createFormatWithBitrate(10);
|
||||||
|
Format format2 = createFormatWithBitrate(20);
|
||||||
|
|
||||||
|
int[] bitratesArrayToUse = new int[2];
|
||||||
|
int[] bitrates =
|
||||||
|
estimator.getBitrates(
|
||||||
|
new Format[] {format1, format2},
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
|
bitratesArrayToUse);
|
||||||
|
|
||||||
|
assertThat(bitrates).isSameAs(bitratesArrayToUse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MediaChunk createMediaChunk(int formatBitrate, int actualBitrate) {
|
||||||
|
int length = actualBitrate / C.BITS_PER_BYTE;
|
||||||
|
DataSpec dataSpec =
|
||||||
|
new DataSpec(
|
||||||
|
Uri.EMPTY, /* absoluteStreamPosition= */ 0, length, /* key= */ null, /* flags= */ 0);
|
||||||
|
Format format = createFormatWithBitrate(formatBitrate);
|
||||||
|
return new FakeMediaChunk(
|
||||||
|
dataSpec, format, /* startTimeUs= */ 0L, /* endTimeUs= */ C.MICROS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Format createFormatWithBitrate(int bitrate) {
|
||||||
|
return Format.createSampleFormat(
|
||||||
|
/* id= */ null,
|
||||||
|
/* sampleMimeType= */ null,
|
||||||
|
/* codecs= */ null,
|
||||||
|
bitrate,
|
||||||
|
/* drmInitData= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MediaChunkIterator createMediaChunkIteratorWithBitrate(int bitrate) {
|
||||||
|
return new FakeMediaChunkIterator(
|
||||||
|
/* chunkTimeBoundariesSec= */ new long[] {0, 1},
|
||||||
|
/* chunkLengths= */ new long[] {bitrate / C.BITS_PER_BYTE});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator;
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
|
||||||
|
/** Fake {@link com.google.android.exoplayer2.source.chunk.MediaChunkIterator}. */
|
||||||
|
public final class FakeMediaChunkIterator extends BaseMediaChunkIterator {
|
||||||
|
|
||||||
|
private final long[] chunkTimeBoundariesSec;
|
||||||
|
private final long[] chunkLengths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a fake {@link com.google.android.exoplayer2.source.chunk.MediaChunkIterator}.
|
||||||
|
*
|
||||||
|
* @param chunkTimeBoundariesSec An array containing the time boundaries where one chunk ends and
|
||||||
|
* the next one starts. The first value is the start time of the first chunk and the last
|
||||||
|
* value is the end time of the last chunk. The array should be of length (chunk-count + 1).
|
||||||
|
* @param chunkLengths An array which contains the length of each chunk, should be of length
|
||||||
|
* (chunk-count).
|
||||||
|
*/
|
||||||
|
public FakeMediaChunkIterator(long[] chunkTimeBoundariesSec, long[] chunkLengths) {
|
||||||
|
super(/* fromIndex= */ 0, /* toIndex= */ chunkTimeBoundariesSec.length - 2);
|
||||||
|
this.chunkTimeBoundariesSec = chunkTimeBoundariesSec;
|
||||||
|
this.chunkLengths = chunkLengths;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSpec getDataSpec() {
|
||||||
|
checkInBounds();
|
||||||
|
return new DataSpec(
|
||||||
|
Uri.EMPTY,
|
||||||
|
/* absoluteStreamPosition= */ 0,
|
||||||
|
chunkLengths[(int) getCurrentIndex()],
|
||||||
|
/* key= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getChunkStartTimeUs() {
|
||||||
|
checkInBounds();
|
||||||
|
return chunkTimeBoundariesSec[(int) getCurrentIndex()] * C.MICROS_PER_SECOND;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getChunkEndTimeUs() {
|
||||||
|
checkInBounds();
|
||||||
|
return chunkTimeBoundariesSec[(int) getCurrentIndex() + 1] * C.MICROS_PER_SECOND;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user