mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add ParsableByteArray#ensureCapacity() method that keeps data
#exofixit PiperOrigin-RevId: 344845328
This commit is contained in:
parent
7e635d9560
commit
84a7ffc12a
@ -19,6 +19,7 @@ import androidx.annotation.Nullable;
|
|||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a byte array, providing a set of methods for parsing data from it. Numerical values are
|
* Wraps a byte array, providing a set of methods for parsing data from it. Numerical values are
|
||||||
@ -100,8 +101,21 @@ public final class ParsableByteArray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of bytes yet to be read.
|
* Ensures the backing array is at least {@code requiredCapacity} long.
|
||||||
|
*
|
||||||
|
* <p>{@link #getPosition() position}, {@link #limit() limit}, and all data in the underlying
|
||||||
|
* array (including that beyond {@link #limit()}) are preserved.
|
||||||
|
*
|
||||||
|
* <p>This might replace or wipe the {@link #getData() underlying array}, potentially invalidating
|
||||||
|
* any local references.
|
||||||
*/
|
*/
|
||||||
|
public void ensureCapacity(int requiredCapacity) {
|
||||||
|
if (requiredCapacity > capacity()) {
|
||||||
|
data = Arrays.copyOf(data, requiredCapacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of bytes yet to be read. */
|
||||||
public int bytesLeft() {
|
public int bytesLeft() {
|
||||||
return limit - position;
|
return limit - position;
|
||||||
}
|
}
|
||||||
@ -148,8 +162,8 @@ public final class ParsableByteArray {
|
|||||||
*
|
*
|
||||||
* <p>Changes to this array are reflected in the results of the {@code read...()} methods.
|
* <p>Changes to this array are reflected in the results of the {@code read...()} methods.
|
||||||
*
|
*
|
||||||
* <p>This reference must be assumed to become invalid when {@link #reset} is called (because the
|
* <p>This reference must be assumed to become invalid when {@link #reset} or {@link
|
||||||
* array might get reallocated).
|
* #ensureCapacity} are called (because the array might get reallocated).
|
||||||
*/
|
*/
|
||||||
public byte[] getData() {
|
public byte[] getData() {
|
||||||
return data;
|
return data;
|
||||||
|
@ -2214,9 +2214,8 @@ public final class Util {
|
|||||||
if (input.bytesLeft() <= 0) {
|
if (input.bytesLeft() <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
byte[] outputData = output.getData();
|
if (output.capacity() < input.bytesLeft()) {
|
||||||
if (outputData.length < input.bytesLeft()) {
|
output.ensureCapacity(2 * input.bytesLeft());
|
||||||
outputData = new byte[2 * input.bytesLeft()];
|
|
||||||
}
|
}
|
||||||
if (inflater == null) {
|
if (inflater == null) {
|
||||||
inflater = new Inflater();
|
inflater = new Inflater();
|
||||||
@ -2225,16 +2224,17 @@ public final class Util {
|
|||||||
try {
|
try {
|
||||||
int outputSize = 0;
|
int outputSize = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
outputSize += inflater.inflate(outputData, outputSize, outputData.length - outputSize);
|
outputSize +=
|
||||||
|
inflater.inflate(output.getData(), outputSize, output.capacity() - outputSize);
|
||||||
if (inflater.finished()) {
|
if (inflater.finished()) {
|
||||||
output.reset(outputData, outputSize);
|
output.setLimit(outputSize);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (inflater.needsDictionary() || inflater.needsInput()) {
|
if (inflater.needsDictionary() || inflater.needsInput()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (outputSize == outputData.length) {
|
if (outputSize == output.capacity()) {
|
||||||
outputData = Arrays.copyOf(outputData, outputData.length * 2);
|
output.ensureCapacity(output.capacity() * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (DataFormatException e) {
|
} catch (DataFormatException e) {
|
||||||
|
@ -20,6 +20,7 @@ import static java.nio.charset.Charset.forName;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -38,6 +39,36 @@ public final class ParsableByteArrayTest {
|
|||||||
return testArray;
|
return testArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensureCapacity_doesntReallocateNeedlesslyAndPreservesPositionAndLimit() {
|
||||||
|
ParsableByteArray array = getTestDataArray();
|
||||||
|
byte[] dataBefore = array.getData();
|
||||||
|
byte[] copyOfDataBefore = dataBefore.clone();
|
||||||
|
|
||||||
|
array.setPosition(3);
|
||||||
|
array.setLimit(4);
|
||||||
|
array.ensureCapacity(array.capacity() - 1);
|
||||||
|
|
||||||
|
assertThat(array.getData()).isSameInstanceAs(dataBefore);
|
||||||
|
assertThat(array.getData()).isEqualTo(copyOfDataBefore);
|
||||||
|
assertThat(array.getPosition()).isEqualTo(3);
|
||||||
|
assertThat(array.limit()).isEqualTo(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensureCapacity_preservesDataPositionAndLimitWhenReallocating() {
|
||||||
|
ParsableByteArray array = getTestDataArray();
|
||||||
|
byte[] copyOfDataBefore = array.getData().clone();
|
||||||
|
|
||||||
|
array.setPosition(3);
|
||||||
|
array.setLimit(4);
|
||||||
|
array.ensureCapacity(array.capacity() + 1);
|
||||||
|
|
||||||
|
assertThat(array.getData()).isEqualTo(Bytes.concat(copyOfDataBefore, new byte[] {0}));
|
||||||
|
assertThat(array.getPosition()).isEqualTo(3);
|
||||||
|
assertThat(array.limit()).isEqualTo(4);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void readShort() {
|
public void readShort() {
|
||||||
testReadShort((short) -1);
|
testReadShort((short) -1);
|
||||||
|
@ -1341,9 +1341,7 @@ public class MatroskaExtractor implements Extractor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (scratch.capacity() < requiredLength) {
|
if (scratch.capacity() < requiredLength) {
|
||||||
scratch.reset(
|
scratch.ensureCapacity(max(scratch.capacity() * 2, requiredLength));
|
||||||
Arrays.copyOf(scratch.getData(), max(scratch.getData().length * 2, requiredLength)),
|
|
||||||
scratch.limit());
|
|
||||||
}
|
}
|
||||||
input.readFully(scratch.getData(), scratch.limit(), requiredLength - scratch.limit());
|
input.readFully(scratch.getData(), scratch.limit(), requiredLength - scratch.limit());
|
||||||
scratch.setLimit(requiredLength);
|
scratch.setLimit(requiredLength);
|
||||||
|
@ -87,11 +87,7 @@ import java.util.Arrays;
|
|||||||
int size = calculatePacketSize(currentSegmentIndex);
|
int size = calculatePacketSize(currentSegmentIndex);
|
||||||
int segmentIndex = currentSegmentIndex + segmentCount;
|
int segmentIndex = currentSegmentIndex + segmentCount;
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
if (packetArray.capacity() < packetArray.limit() + size) {
|
packetArray.ensureCapacity(packetArray.limit() + size);
|
||||||
packetArray.reset(
|
|
||||||
Arrays.copyOf(packetArray.getData(), packetArray.limit() + size),
|
|
||||||
/* limit= */ packetArray.limit());
|
|
||||||
}
|
|
||||||
input.readFully(packetArray.getData(), packetArray.limit(), size);
|
input.readFully(packetArray.getData(), packetArray.limit(), size);
|
||||||
packetArray.setLimit(packetArray.limit() + size);
|
packetArray.setLimit(packetArray.limit() + size);
|
||||||
populated = pageHeader.laces[segmentIndex - 1] != 255;
|
populated = pageHeader.laces[segmentIndex - 1] != 255;
|
||||||
|
@ -23,7 +23,6 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
|||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads section data packets and feeds the whole sections to a given {@link SectionPayloadReader}.
|
* Reads section data packets and feeds the whole sections to a given {@link SectionPayloadReader}.
|
||||||
@ -107,12 +106,9 @@ public final class SectionReader implements TsPayloadReader {
|
|||||||
(((secondHeaderByte & 0x0F) << 8) | thirdHeaderByte) + SECTION_HEADER_LENGTH;
|
(((secondHeaderByte & 0x0F) << 8) | thirdHeaderByte) + SECTION_HEADER_LENGTH;
|
||||||
if (sectionData.capacity() < totalSectionLength) {
|
if (sectionData.capacity() < totalSectionLength) {
|
||||||
// Ensure there is enough space to keep the whole section.
|
// Ensure there is enough space to keep the whole section.
|
||||||
byte[] bytes = sectionData.getData();
|
int limit =
|
||||||
int limit = min(MAX_SECTION_LENGTH, max(totalSectionLength, bytes.length * 2));
|
min(MAX_SECTION_LENGTH, max(totalSectionLength, sectionData.capacity() * 2));
|
||||||
if (limit > bytes.length) {
|
sectionData.ensureCapacity(limit);
|
||||||
bytes = Arrays.copyOf(sectionData.getData(), limit);
|
|
||||||
}
|
|
||||||
sectionData.reset(bytes, limit);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user