Add TrackSelectionUtil getBitratesUsingPastInfo
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=220066159
This commit is contained in:
parent
894bac6173
commit
0afd9c17e6
@ -17,8 +17,12 @@ package com.google.android.exoplayer2.trackselection;
|
|||||||
|
|
||||||
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.MediaChunk;
|
||||||
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.MediaChunkListIterator;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/** Track selection related utility methods. */
|
/** Track selection related utility methods. */
|
||||||
public final class TrackSelectionUtil {
|
public final class TrackSelectionUtil {
|
||||||
@ -58,10 +62,11 @@ public final class TrackSelectionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns average bitrate values for a set of tracks whose upcoming media chunk iterators and
|
* Returns bitrate values for a set of tracks whose upcoming media chunk iterators and formats are
|
||||||
* formats are given. If an average bitrate can't be calculated, an estimation is calculated using
|
* given.
|
||||||
* average bitrate of another track and the ratio of the bitrate values defined in the formats of
|
*
|
||||||
* the two tracks.
|
* <p>If an average bitrate can't be calculated, an estimation is calculated using average bitrate
|
||||||
|
* of another track and the ratio of the bitrate values defined in the formats of the two tracks.
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
@ -72,7 +77,7 @@ public final class TrackSelectionUtil {
|
|||||||
* 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)
|
||||||
*/
|
*/
|
||||||
public static int[] getAverageBitrates(
|
public static int[] getBitratesUsingFutureInfo(
|
||||||
MediaChunkIterator[] iterators, Format[] formats, long maxDurationUs) {
|
MediaChunkIterator[] iterators, Format[] formats, long maxDurationUs) {
|
||||||
int trackCount = iterators.length;
|
int trackCount = iterators.length;
|
||||||
Assertions.checkArgument(trackCount == formats.length);
|
Assertions.checkArgument(trackCount == formats.length);
|
||||||
@ -102,26 +107,82 @@ public final class TrackSelectionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needEstimateBitrate && canEstimateBitrate) {
|
if (needEstimateBitrate && canEstimateBitrate) {
|
||||||
for (int i = 0; i < trackCount; i++) {
|
estimateBitrates(bitrates, formats, formatBitrates, bitrateRatios);
|
||||||
if (bitrates[i] == Format.NO_VALUE) {
|
|
||||||
int formatBitrate = formats[i].bitrate;
|
|
||||||
if (formatBitrate != Format.NO_VALUE) {
|
|
||||||
int closestFormat = findClosestBitrateFormat(formatBitrate, formatBitrates);
|
|
||||||
bitrates[i] = (int) (bitrateRatios[closestFormat] * formatBitrate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bitrates;
|
return bitrates;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int findClosestBitrateFormat(int formatBitrate, int[] formatBitrates) {
|
/**
|
||||||
|
* Returns bitrate values for a set of tracks whose formats are given, using the given queue of
|
||||||
|
* already buffered {@link MediaChunk} instances.
|
||||||
|
*
|
||||||
|
* @param queue The queue of already buffered {@link MediaChunk} instances. Must not be modified.
|
||||||
|
* @param formats The track formats.
|
||||||
|
* @param maxDurationUs Maximum duration of chunks to be included in average bitrate values, in
|
||||||
|
* microseconds.
|
||||||
|
* @return Bitrate values for the tracks. If for a track, a bitrate value can't be calculated,
|
||||||
|
* {@link Format#NO_VALUE} is set.
|
||||||
|
* @see #getBitratesUsingFutureInfo(MediaChunkIterator[], Format[], long)
|
||||||
|
*/
|
||||||
|
public static int[] getBitratesUsingPastInfo(
|
||||||
|
List<? extends MediaChunk> queue, Format[] formats, long maxDurationUs) {
|
||||||
|
int[] bitrates = new int[formats.length];
|
||||||
|
Arrays.fill(bitrates, Format.NO_VALUE);
|
||||||
|
int queueAverageBitrate = getAverageQueueBitrate(queue, maxDurationUs);
|
||||||
|
if (queueAverageBitrate == Format.NO_VALUE) {
|
||||||
|
return bitrates;
|
||||||
|
}
|
||||||
|
int queueFormatBitrate = queue.get(queue.size() - 1).trackFormat.bitrate;
|
||||||
|
if (queueFormatBitrate != Format.NO_VALUE) {
|
||||||
|
float queueBitrateRatio = ((float) queueAverageBitrate) / queueFormatBitrate;
|
||||||
|
estimateBitrates(
|
||||||
|
bitrates, formats, new int[] {queueFormatBitrate}, new float[] {queueBitrateRatio});
|
||||||
|
}
|
||||||
|
return bitrates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getAverageQueueBitrate(List<? extends MediaChunk> queue, long maxDurationUs) {
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
return Format.NO_VALUE;
|
||||||
|
}
|
||||||
|
MediaChunkListIterator iterator =
|
||||||
|
new MediaChunkListIterator(getSingleFormatSubQueue(queue), /* reverseOrder= */ true);
|
||||||
|
return getAverageBitrate(iterator, maxDurationUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<? extends MediaChunk> getSingleFormatSubQueue(
|
||||||
|
List<? extends MediaChunk> queue) {
|
||||||
|
Format queueFormat = queue.get(queue.size() - 1).trackFormat;
|
||||||
|
int queueSize = queue.size();
|
||||||
|
for (int i = queueSize - 2; i >= 0; i--) {
|
||||||
|
if (!queue.get(i).trackFormat.equals(queueFormat)) {
|
||||||
|
return queue.subList(i + 1, queueSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void estimateBitrates(
|
||||||
|
int[] bitrates, Format[] formats, int[] formatBitrates, float[] bitrateRatios) {
|
||||||
|
for (int i = 0; i < bitrates.length; i++) {
|
||||||
|
if (bitrates[i] == Format.NO_VALUE) {
|
||||||
|
int formatBitrate = formats[i].bitrate;
|
||||||
|
if (formatBitrate != Format.NO_VALUE) {
|
||||||
|
int closestFormat = getClosestBitrateIndex(formatBitrate, formatBitrates);
|
||||||
|
bitrates[i] = (int) (bitrateRatios[closestFormat] * formatBitrate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getClosestBitrateIndex(int formatBitrate, int[] formatBitrates) {
|
||||||
int closestDistance = Integer.MAX_VALUE;
|
int closestDistance = Integer.MAX_VALUE;
|
||||||
int closestFormat = C.INDEX_UNSET;
|
int closestFormat = C.INDEX_UNSET;
|
||||||
for (int j = 0; j < formatBitrates.length; j++) {
|
for (int j = 0; j < formatBitrates.length; j++) {
|
||||||
if (formatBitrates[j] != Format.NO_VALUE) {
|
if (formatBitrates[j] != Format.NO_VALUE) {
|
||||||
int distance = Math.abs(formatBitrates[j] - formatBitrate);
|
int distance = Math.abs(formatBitrates[j] - formatBitrate);
|
||||||
if (distance < closestDistance) {
|
if (distance < closestDistance) {
|
||||||
|
closestDistance = distance;
|
||||||
closestFormat = j;
|
closestFormat = j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,14 @@ package com.google.android.exoplayer2.trackselection;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
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.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.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@ -96,11 +98,12 @@ 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);
|
FakeIterator iterator = new FakeIterator(chunkTimeBoundariesSec, chunkLengths);
|
||||||
|
|
||||||
assertThat(TrackSelectionUtil.getAverageBitrate(iterator, 30 * C.MICROS_PER_SECOND))
|
long maxDurationUs = 30 * C.MICROS_PER_SECOND;
|
||||||
.isEqualTo(12);
|
int averageBitrate = TrackSelectionUtil.getAverageBitrate(iterator, maxDurationUs);
|
||||||
|
|
||||||
|
assertThat(averageBitrate).isEqualTo(12);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -115,26 +118,26 @@ public class TrackSelectionUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAverageBitrates_noIterator_returnsEmptyArray() {
|
public void getBitratesUsingFutureInfo_noIterator_returnsEmptyArray() {
|
||||||
assertThat(
|
assertThat(
|
||||||
TrackSelectionUtil.getAverageBitrates(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[0], new Format[0], MAX_DURATION_US))
|
new MediaChunkIterator[0], new Format[0], MAX_DURATION_US))
|
||||||
.hasLength(0);
|
.hasLength(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAverageBitrates_emptyIterator_returnsNoValue() {
|
public void getBitratesUsingFutureInfo_emptyIterator_returnsNoValue() {
|
||||||
int[] averageBitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getAverageBitrates(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {MediaChunkIterator.EMPTY},
|
new MediaChunkIterator[] {MediaChunkIterator.EMPTY},
|
||||||
new Format[] {createFormatWithBitrate(10)},
|
new Format[] {createFormatWithBitrate(10)},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US);
|
||||||
|
|
||||||
assertThat(averageBitrates).asList().containsExactly(Format.NO_VALUE);
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAverageBitrates_twoTracks_returnsAverageChunkBitrates() {
|
public void getBitratesUsingFutureInfo_twoTracksZeroMaxDuration_returnsNoValue() {
|
||||||
FakeIterator iterator1 =
|
FakeIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
||||||
@ -143,35 +146,62 @@ public class TrackSelectionUtilTest {
|
|||||||
/* 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[] averageBitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getAverageBitrates(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
|
new Format[] {createFormatWithBitrate(10), createFormatWithBitrate(20)},
|
||||||
|
/* maxDurationUs= */ 0);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE, Format.NO_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingFutureInfo_twoTracks_returnsBitrates() {
|
||||||
|
FakeIterator iterator1 =
|
||||||
|
new FakeIterator(
|
||||||
|
/* chunkTimeBoundariesSec= */ new long[] {0, 10}, /* chunkLengths= */ new long[] {10});
|
||||||
|
FakeIterator iterator2 =
|
||||||
|
new FakeIterator(
|
||||||
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5, 15, 30},
|
||||||
|
/* chunkLengths= */ new long[] {10, 20, 30});
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
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);
|
||||||
|
|
||||||
assertThat(averageBitrates).asList().containsExactly(8, 16).inOrder();
|
assertThat(bitrates).asList().containsExactly(8, 16).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAverageBitrates_oneEmptyIteratorOneWithChunks_returnsEstimationForEmpty() {
|
public void getBitratesUsingFutureInfo_emptyIterator_returnsEstimationUsingClosest() {
|
||||||
FakeIterator iterator1 =
|
FakeIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeIterator(
|
||||||
/* 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 =
|
||||||
|
new FakeIterator(
|
||||||
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {50});
|
||||||
|
Format format3 = createFormatWithBitrate(25);
|
||||||
|
FakeIterator iterator4 =
|
||||||
|
new FakeIterator(
|
||||||
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {20});
|
||||||
|
Format format4 = createFormatWithBitrate(30);
|
||||||
|
|
||||||
int[] averageBitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getAverageBitrates(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2},
|
new MediaChunkIterator[] {iterator1, iterator2, iterator3, iterator4},
|
||||||
new Format[] {format1, format2},
|
new Format[] {format1, format2, format3, format4},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US);
|
||||||
|
|
||||||
assertThat(averageBitrates).asList().containsExactly(16, 32).inOrder();
|
assertThat(bitrates).asList().containsExactly(16, 64, 80, 32).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAverageBitrates_formatWithoutBitrate_returnsNoValueForEmpty() {
|
public void getBitratesUsingFutureInfo_formatWithoutBitrate_returnsNoValueForEmpty() {
|
||||||
FakeIterator iterator1 =
|
FakeIterator iterator1 =
|
||||||
new FakeIterator(
|
new FakeIterator(
|
||||||
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {10});
|
/* chunkTimeBoundariesSec= */ new long[] {0, 5}, /* chunkLengths= */ new long[] {10});
|
||||||
@ -179,16 +209,212 @@ public class TrackSelectionUtilTest {
|
|||||||
MediaChunkIterator iterator2 = MediaChunkIterator.EMPTY;
|
MediaChunkIterator iterator2 = MediaChunkIterator.EMPTY;
|
||||||
Format format2 = createFormatWithBitrate(Format.NO_VALUE);
|
Format format2 = createFormatWithBitrate(Format.NO_VALUE);
|
||||||
|
|
||||||
int[] averageBitrates =
|
int[] bitrates =
|
||||||
TrackSelectionUtil.getAverageBitrates(
|
TrackSelectionUtil.getBitratesUsingFutureInfo(
|
||||||
new MediaChunkIterator[] {iterator1, iterator2},
|
new MediaChunkIterator[] {iterator1, iterator2},
|
||||||
new Format[] {format1, format2},
|
new Format[] {format1, format2},
|
||||||
MAX_DURATION_US);
|
MAX_DURATION_US);
|
||||||
|
|
||||||
assertThat(averageBitrates).asList().containsExactly(16, Format.NO_VALUE).inOrder();
|
assertThat(bitrates).asList().containsExactly(16, Format.NO_VALUE).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_noFormat_returnsEmptyArray() {
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(
|
||||||
|
createFormatWithBitrate(10),
|
||||||
|
/* length= */ 10,
|
||||||
|
/* startTimeSec= */ 0,
|
||||||
|
/* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk), new Format[0], MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).hasLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_emptyQueue_returnsNoValue() {
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.emptyList(), new Format[] {createFormatWithBitrate(10)}, MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_oneChunkFormatNoBitrate_returnsNoValue() {
|
||||||
|
Format format = createFormatWithBitrate(Format.NO_VALUE);
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(format, /* length= */ 10, /* startTimeSec= */ 0, /* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk), new Format[] {format}, MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_oneChunkNoLength_returnsNoValue() {
|
||||||
|
Format format = createFormatWithBitrate(10);
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(
|
||||||
|
format, /* length= */ C.LENGTH_UNSET, /* startTimeSec= */ 0, /* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk), new Format[] {format}, MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_oneChunkWithSameFormat_returnsBitrates() {
|
||||||
|
Format format = createFormatWithBitrate(10);
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(format, /* length= */ 10, /* startTimeSec= */ 0, /* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk), new Format[] {format}, MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(8).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_zeroMaxDuration_returnsNoValue() {
|
||||||
|
Format format = createFormatWithBitrate(10);
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(format, /* length= */ 10, /* startTimeSec= */ 0, /* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk), new Format[] {format}, /* maxDurationUs= */ 0);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_multipleChunkWithSameFormat_returnsAverageBitrate() {
|
||||||
|
Format format = createFormatWithBitrate(10);
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(format, /* length= */ 10, /* startTimeSec= */ 0, /* endTimeSec= */ 10);
|
||||||
|
FakeMediaChunk chunk2 =
|
||||||
|
createChunk(format, /* length= */ 20, /* startTimeSec= */ 10, /* endTimeSec= */ 20);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Arrays.asList(chunk, chunk2), new Format[] {format}, MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(12).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_oneChunkWithDifferentFormat_returnsEstimationBitrate() {
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(
|
||||||
|
createFormatWithBitrate(10),
|
||||||
|
/* length= */ 10,
|
||||||
|
/* startTimeSec= */ 0,
|
||||||
|
/* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {createFormatWithBitrate(20)},
|
||||||
|
MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(16).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_trackFormatNoBitrate_returnsNoValue() {
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(
|
||||||
|
createFormatWithBitrate(10),
|
||||||
|
/* length= */ 10,
|
||||||
|
/* startTimeSec= */ 0,
|
||||||
|
/* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {createFormatWithBitrate(Format.NO_VALUE)},
|
||||||
|
MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(Format.NO_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBitratesUsingPastInfo_multipleTracks_returnsBitrates() {
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(
|
||||||
|
createFormatWithBitrate(10),
|
||||||
|
/* length= */ 10,
|
||||||
|
/* startTimeSec= */ 0,
|
||||||
|
/* endTimeSec= */ 10);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Collections.singletonList(chunk),
|
||||||
|
new Format[] {createFormatWithBitrate(20), createFormatWithBitrate(30)},
|
||||||
|
MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(16, 24).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
getBitratesUsingPastInfo_multipleChunkExceedingMaxDuration_returnsAverageUntilMaxDuration() {
|
||||||
|
Format format = createFormatWithBitrate(10);
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(format, /* length= */ 10, /* startTimeSec= */ 0, /* endTimeSec= */ 20);
|
||||||
|
FakeMediaChunk chunk2 =
|
||||||
|
createChunk(format, /* length= */ 40, /* startTimeSec= */ 20, /* endTimeSec= */ 40);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Arrays.asList(chunk, chunk2),
|
||||||
|
new Format[] {format},
|
||||||
|
/* maxDurationUs= */ 30 * C.MICROS_PER_SECOND);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(12).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
getBitratesUsingPastInfo_chunksWithDifferentFormats_returnsChunkAverageBitrateForLastFormat() {
|
||||||
|
FakeMediaChunk chunk =
|
||||||
|
createChunk(
|
||||||
|
createFormatWithBitrate(10),
|
||||||
|
/* length= */ 10,
|
||||||
|
/* startTimeSec= */ 0,
|
||||||
|
/* endTimeSec= */ 10);
|
||||||
|
FakeMediaChunk chunk2 =
|
||||||
|
createChunk(
|
||||||
|
createFormatWithBitrate(20),
|
||||||
|
/* length= */ 40,
|
||||||
|
/* startTimeSec= */ 10,
|
||||||
|
/* endTimeSec= */ 20);
|
||||||
|
|
||||||
|
int[] bitrates =
|
||||||
|
TrackSelectionUtil.getBitratesUsingPastInfo(
|
||||||
|
Arrays.asList(chunk, chunk2),
|
||||||
|
new Format[] {createFormatWithBitrate(10)},
|
||||||
|
MAX_DURATION_US);
|
||||||
|
|
||||||
|
assertThat(bitrates).asList().containsExactly(16).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FakeMediaChunk createChunk(
|
||||||
|
Format format, int length, int startTimeSec, int endTimeSec) {
|
||||||
|
DataSpec dataSpec = new DataSpec(Uri.EMPTY, 0, length, null, 0);
|
||||||
|
return new FakeMediaChunk(
|
||||||
|
dataSpec, format, startTimeSec * C.MICROS_PER_SECOND, endTimeSec * C.MICROS_PER_SECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static Format createFormatWithBitrate(int bitrate) {
|
private static Format createFormatWithBitrate(int bitrate) {
|
||||||
return Format.createSampleFormat(null, null, null, bitrate, null);
|
return Format.createSampleFormat(null, null, null, bitrate, null);
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,13 @@ public final class FakeMediaChunk extends MediaChunk {
|
|||||||
private static final DataSource DATA_SOURCE = new DefaultHttpDataSource("TEST_AGENT", null);
|
private static final DataSource DATA_SOURCE = new DefaultHttpDataSource("TEST_AGENT", null);
|
||||||
|
|
||||||
public FakeMediaChunk(Format trackFormat, long startTimeUs, long endTimeUs) {
|
public FakeMediaChunk(Format trackFormat, long startTimeUs, long endTimeUs) {
|
||||||
|
this(new DataSpec(Uri.EMPTY), trackFormat, startTimeUs, endTimeUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FakeMediaChunk(DataSpec dataSpec, Format trackFormat, long startTimeUs, long endTimeUs) {
|
||||||
super(
|
super(
|
||||||
DATA_SOURCE,
|
DATA_SOURCE,
|
||||||
new DataSpec(Uri.EMPTY),
|
dataSpec,
|
||||||
trackFormat,
|
trackFormat,
|
||||||
C.SELECTION_REASON_ADAPTIVE,
|
C.SELECTION_REASON_ADAPTIVE,
|
||||||
/* trackSelectionData= */ null,
|
/* trackSelectionData= */ null,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user