Make IndexSeekMap dynamic, allowing seek points to be added later

PiperOrigin-RevId: 660324829
This commit is contained in:
rohks 2024-08-07 03:55:31 -07:00 committed by Copybara-Service
parent 5dac58995a
commit a087f82fa8
2 changed files with 51 additions and 16 deletions

View File

@ -15,6 +15,8 @@
*/ */
package androidx.media3.common.util; package androidx.media3.common.util;
import static java.lang.Math.max;
import java.util.Arrays; import java.util.Arrays;
/** An append-only, auto-growing {@code long[]}. */ /** An append-only, auto-growing {@code long[]}. */
@ -49,6 +51,20 @@ public final class LongArray {
values[size++] = value; values[size++] = value;
} }
/**
* Appends all elements of the specified array.
*
* @param values The array whose elements are to be added.
*/
public void addAll(long[] values) {
int newSize = size + values.length;
if (newSize > this.values.length) {
this.values = Arrays.copyOf(this.values, max(this.values.length * 2, newSize));
}
System.arraycopy(values, 0, this.values, size, values.length);
size = newSize;
}
/** /**
* Returns the value at a specified index. * Returns the value at a specified index.
* *

View File

@ -19,6 +19,7 @@ package androidx.media3.extractor;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.LongArray;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
@ -29,10 +30,9 @@ import androidx.media3.common.util.Util;
@UnstableApi @UnstableApi
public final class IndexSeekMap implements SeekMap { public final class IndexSeekMap implements SeekMap {
private final long[] positions; private final LongArray positions;
private final long[] timesUs; private final LongArray timesUs;
private final long durationUs; private final long durationUs;
private final boolean isSeekable;
/** /**
* Creates an instance. * Creates an instance.
@ -44,23 +44,24 @@ public final class IndexSeekMap implements SeekMap {
public IndexSeekMap(long[] positions, long[] timesUs, long durationUs) { public IndexSeekMap(long[] positions, long[] timesUs, long durationUs) {
checkArgument(positions.length == timesUs.length); checkArgument(positions.length == timesUs.length);
int length = timesUs.length; int length = timesUs.length;
isSeekable = length > 0; if (length > 0 && timesUs[0] > 0) {
if (isSeekable && timesUs[0] > 0) {
// Add (position = 0, timeUs = 0) as first entry. // Add (position = 0, timeUs = 0) as first entry.
this.positions = new long[length + 1]; this.positions = new LongArray(length + 1);
this.timesUs = new long[length + 1]; this.timesUs = new LongArray(length + 1);
System.arraycopy(positions, 0, this.positions, 1, length); this.positions.add(0L);
System.arraycopy(timesUs, 0, this.timesUs, 1, length); this.timesUs.add(0L);
} else { } else {
this.positions = positions; this.positions = new LongArray(length);
this.timesUs = timesUs; this.timesUs = new LongArray(length);
} }
this.positions.addAll(positions);
this.timesUs.addAll(timesUs);
this.durationUs = durationUs; this.durationUs = durationUs;
} }
@Override @Override
public boolean isSeekable() { public boolean isSeekable() {
return isSeekable; return timesUs.size() > 0;
} }
@Override @Override
@ -70,18 +71,36 @@ public final class IndexSeekMap implements SeekMap {
@Override @Override
public SeekMap.SeekPoints getSeekPoints(long timeUs) { public SeekMap.SeekPoints getSeekPoints(long timeUs) {
if (!isSeekable) { if (timesUs.size() == 0) {
return new SeekMap.SeekPoints(SeekPoint.START); return new SeekMap.SeekPoints(SeekPoint.START);
} }
int targetIndex = int targetIndex =
Util.binarySearchFloor(timesUs, timeUs, /* inclusive= */ true, /* stayInBounds= */ true); Util.binarySearchFloor(timesUs, timeUs, /* inclusive= */ true, /* stayInBounds= */ true);
SeekPoint leftSeekPoint = new SeekPoint(timesUs[targetIndex], positions[targetIndex]); SeekPoint leftSeekPoint = new SeekPoint(timesUs.get(targetIndex), positions.get(targetIndex));
if (leftSeekPoint.timeUs == timeUs || targetIndex == timesUs.length - 1) { if (leftSeekPoint.timeUs == timeUs || targetIndex == timesUs.size() - 1) {
return new SeekMap.SeekPoints(leftSeekPoint); return new SeekMap.SeekPoints(leftSeekPoint);
} else { } else {
SeekPoint rightSeekPoint = SeekPoint rightSeekPoint =
new SeekPoint(timesUs[targetIndex + 1], positions[targetIndex + 1]); new SeekPoint(timesUs.get(targetIndex + 1), positions.get(targetIndex + 1));
return new SeekMap.SeekPoints(leftSeekPoint, rightSeekPoint); return new SeekMap.SeekPoints(leftSeekPoint, rightSeekPoint);
} }
} }
/**
* Adds a seek point to the index.
*
* <p>Seek points must be added in order.
*
* @param timeUs The time of the seek point in microseconds.
* @param position The position in the stream corresponding to the seek point, in bytes.
*/
public void addSeekPoint(long timeUs, long position) {
if (timesUs.size() == 0 && timeUs > 0) {
// Add (position = 0, timeUs = 0) as first entry.
this.positions.add(0L);
this.timesUs.add(0L);
}
positions.add(position);
timesUs.add(timeUs);
}
} }