Add readLeb128 and readLeb128ToInt to ParsableByteArray.
Leb128 is a little-endian long of variable byte length. The format is used during the extraction of the size of the OBU configuration for the iacb configuration box. PiperOrigin-RevId: 650295002
This commit is contained in:
parent
007c258ceb
commit
972007abef
@ -19,6 +19,7 @@ import androidx.annotation.Nullable;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.primitives.Chars;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.UnsignedBytes;
|
||||
import com.google.errorprone.annotations.CheckReturnValue;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -597,6 +598,41 @@ public final class ParsableByteArray {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a little endian long of variable length.
|
||||
*
|
||||
* @throws IllegalStateException if the byte to be read is over the limit of the parsable byte
|
||||
* array
|
||||
* @return long value
|
||||
*/
|
||||
public long readUnsignedLeb128ToLong() {
|
||||
long value = 0;
|
||||
// At most, 63 bits of unsigned data can be stored in a long, which corresponds to 63/7=9 bytes
|
||||
// in LEB128.
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (this.position == limit) {
|
||||
throw new IllegalStateException("Attempting to read a byte over the limit.");
|
||||
}
|
||||
long currentByte = this.readUnsignedByte();
|
||||
value |= (currentByte & 0x7F) << (i * 7);
|
||||
if ((currentByte & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a little endian integer of variable length.
|
||||
*
|
||||
* @throws IllegalArgumentException if the read value is greater than {@link Integer#MAX_VALUE} or
|
||||
* less than {@link Integer#MIN_VALUE}
|
||||
* @return integer value
|
||||
*/
|
||||
public int readUnsignedLeb128ToInt() {
|
||||
return Ints.checkedCast(readUnsignedLeb128ToLong());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a UTF byte order mark (BOM) and returns the UTF {@link Charset} it represents. Returns
|
||||
* {@code null} without advancing {@link #getPosition() position} if no BOM is found.
|
||||
|
@ -18,6 +18,7 @@ package androidx.media3.common.util;
|
||||
import static androidx.media3.test.utils.TestUtil.createByteArray;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.nio.charset.Charset.forName;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
@ -917,4 +918,67 @@ public final class ParsableByteArrayTest {
|
||||
assertThat(parser.getPosition()).isEqualTo(22);
|
||||
assertThat(parser.readLine(Charsets.UTF_16LE)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readUnsignedLeb128ToLong() {
|
||||
byte[] bytes = new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x0F};
|
||||
ParsableByteArray testArray = new ParsableByteArray(bytes);
|
||||
|
||||
long readValue = testArray.readUnsignedLeb128ToLong();
|
||||
|
||||
assertThat(readValue).isEqualTo(0xFFFFFFFFL);
|
||||
assertThat(testArray.getPosition()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMaxUnsignedLeb128ToLong() {
|
||||
byte[] bytes =
|
||||
new byte[] {
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFF,
|
||||
(byte) 0x7F
|
||||
};
|
||||
ParsableByteArray testArray = new ParsableByteArray(bytes);
|
||||
|
||||
long readValue = testArray.readUnsignedLeb128ToLong();
|
||||
|
||||
assertThat(readValue).isEqualTo(Long.MAX_VALUE);
|
||||
assertThat(testArray.getPosition()).isEqualTo(9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readUnsignedLeb128ToInt() {
|
||||
byte[] bytes = new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x0F};
|
||||
ParsableByteArray testArray = new ParsableByteArray(bytes);
|
||||
|
||||
int readValue = testArray.readUnsignedLeb128ToInt();
|
||||
|
||||
assertThat(readValue).isEqualTo(0x1FFFFFF);
|
||||
assertThat(testArray.getPosition()).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMaxUnsignedLeb128ToInt() {
|
||||
byte[] bytes = new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x07};
|
||||
ParsableByteArray testArray = new ParsableByteArray(bytes);
|
||||
|
||||
int readValue = testArray.readUnsignedLeb128ToInt();
|
||||
|
||||
assertThat(readValue).isEqualTo(Integer.MAX_VALUE);
|
||||
assertThat(testArray.getPosition()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readTooLongUnsignedLeb128ToInt() {
|
||||
byte[] bytes = new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x0F};
|
||||
ParsableByteArray testArray = new ParsableByteArray(bytes);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, testArray::readUnsignedLeb128ToInt);
|
||||
}
|
||||
}
|
||||
|
@ -1920,17 +1920,7 @@ import java.util.Objects;
|
||||
} else if (childAtomType == Atom.TYPE_iacb) {
|
||||
parent.setPosition(
|
||||
childPosition + Atom.HEADER_SIZE + 1); // header and configuration version
|
||||
int configObusSize = 0;
|
||||
for (int i = 0; i <= 4; i++) {
|
||||
int currentByte = parent.readUnsignedByte();
|
||||
configObusSize |= (currentByte & 0x7F) << (i * 7);
|
||||
if ((currentByte & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (configObusSize < 0) {
|
||||
throw ParserException.createForUnsupportedContainerFeature("OBU too large.");
|
||||
}
|
||||
int configObusSize = parent.readUnsignedLeb128ToInt();
|
||||
byte[] initializationDataBytes = new byte[configObusSize];
|
||||
parent.readBytes(initializationDataBytes, /* offset= */ 0, configObusSize);
|
||||
initializationData = ImmutableList.of(initializationDataBytes);
|
||||
|
Loading…
x
Reference in New Issue
Block a user