• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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