1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.util; 17 18 /** 19 * Wraps a byte array, providing methods that allow it to be read as a NAL unit bitstream. 20 * <p> 21 * Whenever the byte sequence [0, 0, 3] appears in the wrapped byte array, it is treated as [0, 0] 22 * for all reading/skipping operations, which makes the bitstream appear to be unescaped. 23 */ 24 public final class ParsableNalUnitBitArray { 25 26 private byte[] data; 27 private int byteLimit; 28 29 // The byte offset is never equal to the offset of the 3rd byte in a subsequence [0, 0, 3]. 30 private int byteOffset; 31 private int bitOffset; 32 33 /** 34 * @param data The data to wrap. 35 * @param offset The byte offset in {@code data} to start reading from. 36 * @param limit The byte offset of the end of the bitstream in {@code data}. 37 */ 38 @SuppressWarnings({"initialization.fields.uninitialized", "method.invocation.invalid"}) ParsableNalUnitBitArray(byte[] data, int offset, int limit)39 public ParsableNalUnitBitArray(byte[] data, int offset, int limit) { 40 reset(data, offset, limit); 41 } 42 43 /** 44 * Resets the wrapped data, limit and offset. 45 * 46 * @param data The data to wrap. 47 * @param offset The byte offset in {@code data} to start reading from. 48 * @param limit The byte offset of the end of the bitstream in {@code data}. 49 */ reset(byte[] data, int offset, int limit)50 public void reset(byte[] data, int offset, int limit) { 51 this.data = data; 52 byteOffset = offset; 53 byteLimit = limit; 54 bitOffset = 0; 55 assertValidOffset(); 56 } 57 58 /** 59 * Skips a single bit. 60 */ skipBit()61 public void skipBit() { 62 if (++bitOffset == 8) { 63 bitOffset = 0; 64 byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1; 65 } 66 assertValidOffset(); 67 } 68 69 /** 70 * Skips bits and moves current reading position forward. 71 * 72 * @param numBits The number of bits to skip. 73 */ skipBits(int numBits)74 public void skipBits(int numBits) { 75 int oldByteOffset = byteOffset; 76 int numBytes = numBits / 8; 77 byteOffset += numBytes; 78 bitOffset += numBits - (numBytes * 8); 79 if (bitOffset > 7) { 80 byteOffset++; 81 bitOffset -= 8; 82 } 83 for (int i = oldByteOffset + 1; i <= byteOffset; i++) { 84 if (shouldSkipByte(i)) { 85 // Skip the byte and move forward to check three bytes ahead. 86 byteOffset++; 87 i += 2; 88 } 89 } 90 assertValidOffset(); 91 } 92 93 /** 94 * Returns whether it's possible to read {@code n} bits starting from the current offset. The 95 * offset is not modified. 96 * 97 * @param numBits The number of bits. 98 * @return Whether it is possible to read {@code n} bits. 99 */ canReadBits(int numBits)100 public boolean canReadBits(int numBits) { 101 int oldByteOffset = byteOffset; 102 int numBytes = numBits / 8; 103 int newByteOffset = byteOffset + numBytes; 104 int newBitOffset = bitOffset + numBits - (numBytes * 8); 105 if (newBitOffset > 7) { 106 newByteOffset++; 107 newBitOffset -= 8; 108 } 109 for (int i = oldByteOffset + 1; i <= newByteOffset && newByteOffset < byteLimit; i++) { 110 if (shouldSkipByte(i)) { 111 // Skip the byte and move forward to check three bytes ahead. 112 newByteOffset++; 113 i += 2; 114 } 115 } 116 return newByteOffset < byteLimit || (newByteOffset == byteLimit && newBitOffset == 0); 117 } 118 119 /** 120 * Reads a single bit. 121 * 122 * @return Whether the bit is set. 123 */ readBit()124 public boolean readBit() { 125 boolean returnValue = (data[byteOffset] & (0x80 >> bitOffset)) != 0; 126 skipBit(); 127 return returnValue; 128 } 129 130 /** 131 * Reads up to 32 bits. 132 * 133 * @param numBits The number of bits to read. 134 * @return An integer whose bottom n bits hold the read data. 135 */ readBits(int numBits)136 public int readBits(int numBits) { 137 int returnValue = 0; 138 bitOffset += numBits; 139 while (bitOffset > 8) { 140 bitOffset -= 8; 141 returnValue |= (data[byteOffset] & 0xFF) << bitOffset; 142 byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1; 143 } 144 returnValue |= (data[byteOffset] & 0xFF) >> (8 - bitOffset); 145 returnValue &= 0xFFFFFFFF >>> (32 - numBits); 146 if (bitOffset == 8) { 147 bitOffset = 0; 148 byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1; 149 } 150 assertValidOffset(); 151 return returnValue; 152 } 153 154 /** 155 * Returns whether it is possible to read an Exp-Golomb-coded integer starting from the current 156 * offset. The offset is not modified. 157 * 158 * @return Whether it is possible to read an Exp-Golomb-coded integer. 159 */ canReadExpGolombCodedNum()160 public boolean canReadExpGolombCodedNum() { 161 int initialByteOffset = byteOffset; 162 int initialBitOffset = bitOffset; 163 int leadingZeros = 0; 164 while (byteOffset < byteLimit && !readBit()) { 165 leadingZeros++; 166 } 167 boolean hitLimit = byteOffset == byteLimit; 168 byteOffset = initialByteOffset; 169 bitOffset = initialBitOffset; 170 return !hitLimit && canReadBits(leadingZeros * 2 + 1); 171 } 172 173 /** 174 * Reads an unsigned Exp-Golomb-coded format integer. 175 * 176 * @return The value of the parsed Exp-Golomb-coded integer. 177 */ readUnsignedExpGolombCodedInt()178 public int readUnsignedExpGolombCodedInt() { 179 return readExpGolombCodeNum(); 180 } 181 182 /** 183 * Reads an signed Exp-Golomb-coded format integer. 184 * 185 * @return The value of the parsed Exp-Golomb-coded integer. 186 */ readSignedExpGolombCodedInt()187 public int readSignedExpGolombCodedInt() { 188 int codeNum = readExpGolombCodeNum(); 189 return ((codeNum % 2) == 0 ? -1 : 1) * ((codeNum + 1) / 2); 190 } 191 readExpGolombCodeNum()192 private int readExpGolombCodeNum() { 193 int leadingZeros = 0; 194 while (!readBit()) { 195 leadingZeros++; 196 } 197 return (1 << leadingZeros) - 1 + (leadingZeros > 0 ? readBits(leadingZeros) : 0); 198 } 199 shouldSkipByte(int offset)200 private boolean shouldSkipByte(int offset) { 201 return 2 <= offset && offset < byteLimit && data[offset] == (byte) 0x03 202 && data[offset - 2] == (byte) 0x00 && data[offset - 1] == (byte) 0x00; 203 } 204 assertValidOffset()205 private void assertValidOffset() { 206 // It is fine for position to be at the end of the array, but no further. 207 Assertions.checkState(byteOffset >= 0 208 && (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0))); 209 } 210 211 } 212