mirror of
https://github.com/androidx/media.git
synced 2025-05-16 03:59:54 +08:00
Optimize ParsableNalUnitBitArray
Apply the same learnings as in ParsableBitArray. Issue: #3040 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161674119
This commit is contained in:
parent
01c0ccbdbd
commit
5885f34d12
@ -95,7 +95,7 @@ public final class ParsableNalUnitBitArrayTest extends TestCase {
|
|||||||
ParsableNalUnitBitArray array =
|
ParsableNalUnitBitArray array =
|
||||||
new ParsableNalUnitBitArray(createByteArray(0, 0, 3, 128, 0), 0, 5);
|
new ParsableNalUnitBitArray(createByteArray(0, 0, 3, 128, 0), 0, 5);
|
||||||
assertFalse(array.canReadExpGolombCodedNum());
|
assertFalse(array.canReadExpGolombCodedNum());
|
||||||
array.skipBits(1);
|
array.skipBit();
|
||||||
assertTrue(array.canReadExpGolombCodedNum());
|
assertTrue(array.canReadExpGolombCodedNum());
|
||||||
assertEquals(32767, array.readUnsignedExpGolombCodedInt());
|
assertEquals(32767, array.readUnsignedExpGolombCodedInt());
|
||||||
assertFalse(array.canReadBits(1));
|
assertFalse(array.canReadBits(1));
|
||||||
|
@ -316,7 +316,7 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||||||
if (!bitArray.canReadBits(8)) {
|
if (!bitArray.canReadBits(8)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bitArray.skipBits(1); // forbidden_zero_bit
|
bitArray.skipBit(); // forbidden_zero_bit
|
||||||
int nalRefIdc = bitArray.readBits(2);
|
int nalRefIdc = bitArray.readBits(2);
|
||||||
bitArray.skipBits(5); // nal_unit_type
|
bitArray.skipBits(5); // nal_unit_type
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||||||
ParsableNalUnitBitArray bitArray = new ParsableNalUnitBitArray(sps.nalData, 0, sps.nalLength);
|
ParsableNalUnitBitArray bitArray = new ParsableNalUnitBitArray(sps.nalData, 0, sps.nalLength);
|
||||||
bitArray.skipBits(40 + 4); // NAL header, sps_video_parameter_set_id
|
bitArray.skipBits(40 + 4); // NAL header, sps_video_parameter_set_id
|
||||||
int maxSubLayersMinus1 = bitArray.readBits(3);
|
int maxSubLayersMinus1 = bitArray.readBits(3);
|
||||||
bitArray.skipBits(1); // sps_temporal_id_nesting_flag
|
bitArray.skipBit(); // sps_temporal_id_nesting_flag
|
||||||
|
|
||||||
// profile_tier_level(1, sps_max_sub_layers_minus1)
|
// profile_tier_level(1, sps_max_sub_layers_minus1)
|
||||||
bitArray.skipBits(88); // if (profilePresentFlag) {...}
|
bitArray.skipBits(88); // if (profilePresentFlag) {...}
|
||||||
@ -247,7 +247,7 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||||||
bitArray.readUnsignedExpGolombCodedInt(); // sps_seq_parameter_set_id
|
bitArray.readUnsignedExpGolombCodedInt(); // sps_seq_parameter_set_id
|
||||||
int chromaFormatIdc = bitArray.readUnsignedExpGolombCodedInt();
|
int chromaFormatIdc = bitArray.readUnsignedExpGolombCodedInt();
|
||||||
if (chromaFormatIdc == 3) {
|
if (chromaFormatIdc == 3) {
|
||||||
bitArray.skipBits(1); // separate_colour_plane_flag
|
bitArray.skipBit(); // separate_colour_plane_flag
|
||||||
}
|
}
|
||||||
int picWidthInLumaSamples = bitArray.readUnsignedExpGolombCodedInt();
|
int picWidthInLumaSamples = bitArray.readUnsignedExpGolombCodedInt();
|
||||||
int picHeightInLumaSamples = bitArray.readUnsignedExpGolombCodedInt();
|
int picHeightInLumaSamples = bitArray.readUnsignedExpGolombCodedInt();
|
||||||
@ -288,7 +288,7 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||||||
bitArray.skipBits(8);
|
bitArray.skipBits(8);
|
||||||
bitArray.readUnsignedExpGolombCodedInt(); // log2_min_pcm_luma_coding_block_size_minus3
|
bitArray.readUnsignedExpGolombCodedInt(); // log2_min_pcm_luma_coding_block_size_minus3
|
||||||
bitArray.readUnsignedExpGolombCodedInt(); // log2_diff_max_min_pcm_luma_coding_block_size
|
bitArray.readUnsignedExpGolombCodedInt(); // log2_diff_max_min_pcm_luma_coding_block_size
|
||||||
bitArray.skipBits(1); // pcm_loop_filter_disabled_flag
|
bitArray.skipBit(); // pcm_loop_filter_disabled_flag
|
||||||
}
|
}
|
||||||
// Skips all short term reference picture sets.
|
// Skips all short term reference picture sets.
|
||||||
skipShortTermRefPicSets(bitArray);
|
skipShortTermRefPicSets(bitArray);
|
||||||
@ -365,11 +365,11 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||||||
interRefPicSetPredictionFlag = bitArray.readBit();
|
interRefPicSetPredictionFlag = bitArray.readBit();
|
||||||
}
|
}
|
||||||
if (interRefPicSetPredictionFlag) {
|
if (interRefPicSetPredictionFlag) {
|
||||||
bitArray.skipBits(1); // delta_rps_sign
|
bitArray.skipBit(); // delta_rps_sign
|
||||||
bitArray.readUnsignedExpGolombCodedInt(); // abs_delta_rps_minus1
|
bitArray.readUnsignedExpGolombCodedInt(); // abs_delta_rps_minus1
|
||||||
for (int j = 0; j <= previousNumDeltaPocs; j++) {
|
for (int j = 0; j <= previousNumDeltaPocs; j++) {
|
||||||
if (bitArray.readBit()) { // used_by_curr_pic_flag[j]
|
if (bitArray.readBit()) { // used_by_curr_pic_flag[j]
|
||||||
bitArray.skipBits(1); // use_delta_flag[j]
|
bitArray.skipBit(); // use_delta_flag[j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -378,11 +378,11 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||||||
previousNumDeltaPocs = numNegativePics + numPositivePics;
|
previousNumDeltaPocs = numNegativePics + numPositivePics;
|
||||||
for (int i = 0; i < numNegativePics; i++) {
|
for (int i = 0; i < numNegativePics; i++) {
|
||||||
bitArray.readUnsignedExpGolombCodedInt(); // delta_poc_s0_minus1[i]
|
bitArray.readUnsignedExpGolombCodedInt(); // delta_poc_s0_minus1[i]
|
||||||
bitArray.skipBits(1); // used_by_curr_pic_s0_flag[i]
|
bitArray.skipBit(); // used_by_curr_pic_s0_flag[i]
|
||||||
}
|
}
|
||||||
for (int i = 0; i < numPositivePics; i++) {
|
for (int i = 0; i < numPositivePics; i++) {
|
||||||
bitArray.readUnsignedExpGolombCodedInt(); // delta_poc_s1_minus1[i]
|
bitArray.readUnsignedExpGolombCodedInt(); // delta_poc_s1_minus1[i]
|
||||||
bitArray.skipBits(1); // used_by_curr_pic_s1_flag[i]
|
bitArray.skipBit(); // used_by_curr_pic_s1_flag[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +265,7 @@ public final class NalUnitUtil {
|
|||||||
}
|
}
|
||||||
data.readUnsignedExpGolombCodedInt(); // bit_depth_luma_minus8
|
data.readUnsignedExpGolombCodedInt(); // bit_depth_luma_minus8
|
||||||
data.readUnsignedExpGolombCodedInt(); // bit_depth_chroma_minus8
|
data.readUnsignedExpGolombCodedInt(); // bit_depth_chroma_minus8
|
||||||
data.skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
data.skipBit(); // qpprime_y_zero_transform_bypass_flag
|
||||||
boolean seqScalingMatrixPresentFlag = data.readBit();
|
boolean seqScalingMatrixPresentFlag = data.readBit();
|
||||||
if (seqScalingMatrixPresentFlag) {
|
if (seqScalingMatrixPresentFlag) {
|
||||||
int limit = (chromaFormatIdc != 3) ? 8 : 12;
|
int limit = (chromaFormatIdc != 3) ? 8 : 12;
|
||||||
@ -295,17 +295,17 @@ public final class NalUnitUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.readUnsignedExpGolombCodedInt(); // max_num_ref_frames
|
data.readUnsignedExpGolombCodedInt(); // max_num_ref_frames
|
||||||
data.skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
data.skipBit(); // gaps_in_frame_num_value_allowed_flag
|
||||||
|
|
||||||
int picWidthInMbs = data.readUnsignedExpGolombCodedInt() + 1;
|
int picWidthInMbs = data.readUnsignedExpGolombCodedInt() + 1;
|
||||||
int picHeightInMapUnits = data.readUnsignedExpGolombCodedInt() + 1;
|
int picHeightInMapUnits = data.readUnsignedExpGolombCodedInt() + 1;
|
||||||
boolean frameMbsOnlyFlag = data.readBit();
|
boolean frameMbsOnlyFlag = data.readBit();
|
||||||
int frameHeightInMbs = (2 - (frameMbsOnlyFlag ? 1 : 0)) * picHeightInMapUnits;
|
int frameHeightInMbs = (2 - (frameMbsOnlyFlag ? 1 : 0)) * picHeightInMapUnits;
|
||||||
if (!frameMbsOnlyFlag) {
|
if (!frameMbsOnlyFlag) {
|
||||||
data.skipBits(1); // mb_adaptive_frame_field_flag
|
data.skipBit(); // mb_adaptive_frame_field_flag
|
||||||
}
|
}
|
||||||
|
|
||||||
data.skipBits(1); // direct_8x8_inference_flag
|
data.skipBit(); // direct_8x8_inference_flag
|
||||||
int frameWidth = picWidthInMbs * 16;
|
int frameWidth = picWidthInMbs * 16;
|
||||||
int frameHeight = frameHeightInMbs * 16;
|
int frameHeight = frameHeightInMbs * 16;
|
||||||
boolean frameCroppingFlag = data.readBit();
|
boolean frameCroppingFlag = data.readBit();
|
||||||
@ -368,7 +368,7 @@ public final class NalUnitUtil {
|
|||||||
data.skipBits(8); // nal_unit
|
data.skipBits(8); // nal_unit
|
||||||
int picParameterSetId = data.readUnsignedExpGolombCodedInt();
|
int picParameterSetId = data.readUnsignedExpGolombCodedInt();
|
||||||
int seqParameterSetId = data.readUnsignedExpGolombCodedInt();
|
int seqParameterSetId = data.readUnsignedExpGolombCodedInt();
|
||||||
data.skipBits(1); // entropy_coding_mode_flag
|
data.skipBit(); // entropy_coding_mode_flag
|
||||||
boolean bottomFieldPicOrderInFramePresentFlag = data.readBit();
|
boolean bottomFieldPicOrderInFramePresentFlag = data.readBit();
|
||||||
return new PpsData(picParameterSetId, seqParameterSetId, bottomFieldPicOrderInFramePresentFlag);
|
return new PpsData(picParameterSetId, seqParameterSetId, bottomFieldPicOrderInFramePresentFlag);
|
||||||
}
|
}
|
||||||
|
@ -54,15 +54,27 @@ public final class ParsableNalUnitBitArray {
|
|||||||
assertValidOffset();
|
assertValidOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skips a single bit.
|
||||||
|
*/
|
||||||
|
public void skipBit() {
|
||||||
|
if (++bitOffset == 8) {
|
||||||
|
bitOffset = 0;
|
||||||
|
byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1;
|
||||||
|
}
|
||||||
|
assertValidOffset();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skips bits and moves current reading position forward.
|
* Skips bits and moves current reading position forward.
|
||||||
*
|
*
|
||||||
* @param n The number of bits to skip.
|
* @param numBits The number of bits to skip.
|
||||||
*/
|
*/
|
||||||
public void skipBits(int n) {
|
public void skipBits(int numBits) {
|
||||||
int oldByteOffset = byteOffset;
|
int oldByteOffset = byteOffset;
|
||||||
byteOffset += (n / 8);
|
int numBytes = numBits / 8;
|
||||||
bitOffset += (n % 8);
|
byteOffset += numBytes;
|
||||||
|
bitOffset += numBits - (numBytes * 8);
|
||||||
if (bitOffset > 7) {
|
if (bitOffset > 7) {
|
||||||
byteOffset++;
|
byteOffset++;
|
||||||
bitOffset -= 8;
|
bitOffset -= 8;
|
||||||
@ -81,13 +93,14 @@ public final class ParsableNalUnitBitArray {
|
|||||||
* Returns whether it's possible to read {@code n} bits starting from the current offset. The
|
* Returns whether it's possible to read {@code n} bits starting from the current offset. The
|
||||||
* offset is not modified.
|
* offset is not modified.
|
||||||
*
|
*
|
||||||
* @param n The number of bits.
|
* @param numBits The number of bits.
|
||||||
* @return Whether it is possible to read {@code n} bits.
|
* @return Whether it is possible to read {@code n} bits.
|
||||||
*/
|
*/
|
||||||
public boolean canReadBits(int n) {
|
public boolean canReadBits(int numBits) {
|
||||||
int oldByteOffset = byteOffset;
|
int oldByteOffset = byteOffset;
|
||||||
int newByteOffset = byteOffset + (n / 8);
|
int numBytes = numBits / 8;
|
||||||
int newBitOffset = bitOffset + (n % 8);
|
int newByteOffset = byteOffset + numBytes;
|
||||||
|
int newBitOffset = bitOffset + numBits - (numBytes * 8);
|
||||||
if (newBitOffset > 7) {
|
if (newBitOffset > 7) {
|
||||||
newByteOffset++;
|
newByteOffset++;
|
||||||
newBitOffset -= 8;
|
newBitOffset -= 8;
|
||||||
@ -108,7 +121,9 @@ public final class ParsableNalUnitBitArray {
|
|||||||
* @return Whether the bit is set.
|
* @return Whether the bit is set.
|
||||||
*/
|
*/
|
||||||
public boolean readBit() {
|
public boolean readBit() {
|
||||||
return readBits(1) == 1;
|
boolean returnValue = (data[byteOffset] & (0x80 >> bitOffset)) != 0;
|
||||||
|
skipBit();
|
||||||
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,50 +133,19 @@ public final class ParsableNalUnitBitArray {
|
|||||||
* @return An integer whose bottom n bits hold the read data.
|
* @return An integer whose bottom n bits hold the read data.
|
||||||
*/
|
*/
|
||||||
public int readBits(int numBits) {
|
public int readBits(int numBits) {
|
||||||
if (numBits == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int returnValue = 0;
|
int returnValue = 0;
|
||||||
|
bitOffset += numBits;
|
||||||
// Read as many whole bytes as we can.
|
while (bitOffset > 8) {
|
||||||
int wholeBytes = (numBits / 8);
|
bitOffset -= 8;
|
||||||
for (int i = 0; i < wholeBytes; i++) {
|
returnValue |= (data[byteOffset] & 0xFF) << bitOffset;
|
||||||
int nextByteOffset = shouldSkipByte(byteOffset + 1) ? byteOffset + 2 : byteOffset + 1;
|
byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1;
|
||||||
int byteValue;
|
|
||||||
if (bitOffset != 0) {
|
|
||||||
byteValue = ((data[byteOffset] & 0xFF) << bitOffset)
|
|
||||||
| ((data[nextByteOffset] & 0xFF) >>> (8 - bitOffset));
|
|
||||||
} else {
|
|
||||||
byteValue = data[byteOffset];
|
|
||||||
}
|
|
||||||
numBits -= 8;
|
|
||||||
returnValue |= (byteValue & 0xFF) << numBits;
|
|
||||||
byteOffset = nextByteOffset;
|
|
||||||
}
|
}
|
||||||
|
returnValue |= (data[byteOffset] & 0xFF) >> 8 - bitOffset;
|
||||||
// Read any remaining bits.
|
returnValue &= 0xFFFFFFFF >>> (32 - numBits);
|
||||||
if (numBits > 0) {
|
if (bitOffset == 8) {
|
||||||
int nextBit = bitOffset + numBits;
|
bitOffset = 0;
|
||||||
byte writeMask = (byte) (0xFF >> (8 - numBits));
|
byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1;
|
||||||
int nextByteOffset = shouldSkipByte(byteOffset + 1) ? byteOffset + 2 : byteOffset + 1;
|
|
||||||
|
|
||||||
if (nextBit > 8) {
|
|
||||||
// Combine bits from current byte and next byte.
|
|
||||||
returnValue |= ((((data[byteOffset] & 0xFF) << (nextBit - 8)
|
|
||||||
| ((data[nextByteOffset] & 0xFF) >> (16 - nextBit))) & writeMask));
|
|
||||||
byteOffset = nextByteOffset;
|
|
||||||
} else {
|
|
||||||
// Bits to be read only within current byte.
|
|
||||||
returnValue |= (((data[byteOffset] & 0xFF) >> (8 - nextBit)) & writeMask);
|
|
||||||
if (nextBit == 8) {
|
|
||||||
byteOffset = nextByteOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitOffset = nextBit % 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assertValidOffset();
|
assertValidOffset();
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
@ -220,7 +204,6 @@ public final class ParsableNalUnitBitArray {
|
|||||||
private void assertValidOffset() {
|
private void assertValidOffset() {
|
||||||
// It is fine for position to be at the end of the array, but no further.
|
// It is fine for position to be at the end of the array, but no further.
|
||||||
Assertions.checkState(byteOffset >= 0
|
Assertions.checkState(byteOffset >= 0
|
||||||
&& (bitOffset >= 0 && bitOffset < 8)
|
|
||||||
&& (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0)));
|
&& (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user