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:
olly 2017-07-12 09:25:08 -07:00 committed by Oliver Woodman
parent 01c0ccbdbd
commit 5885f34d12
5 changed files with 48 additions and 65 deletions

View File

@ -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));

View File

@ -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

View File

@ -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]
} }
} }
} }

View File

@ -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);
} }

View File

@ -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 |= (data[byteOffset] & 0xFF) >> 8 - bitOffset;
returnValue |= (byteValue & 0xFF) << numBits; returnValue &= 0xFFFFFFFF >>> (32 - numBits);
byteOffset = nextByteOffset; if (bitOffset == 8) {
bitOffset = 0;
byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1;
} }
// Read any remaining bits.
if (numBits > 0) {
int nextBit = bitOffset + numBits;
byte writeMask = (byte) (0xFF >> (8 - numBits));
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)));
} }