Bug 1856663 - Add more chunks for Android mochitest-plain. r=jmaher,taskgraph-reviewe...
[gecko.git] / dom / media / BitReader.cpp
blobd5ae26eba7494bf7cd8f8693bea40cac038ba936
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // Derived from Stagefright's ABitReader.
7 #include "BitReader.h"
9 namespace mozilla {
11 BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer)
12 : BitReader(aBuffer->Elements(), aBuffer->Length() * 8) {}
14 BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer, size_t aBits)
15 : BitReader(aBuffer->Elements(), aBits) {}
17 BitReader::BitReader(const uint8_t* aBuffer, size_t aBits)
18 : mData(aBuffer),
19 mOriginalBitSize(aBits),
20 mTotalBitsLeft(aBits),
21 mSize((aBits + 7) / 8),
22 mReservoir(0),
23 mNumBitsLeft(0) {}
25 BitReader::~BitReader() = default;
27 uint32_t BitReader::ReadBits(size_t aNum) {
28 MOZ_ASSERT(aNum <= 32);
29 if (mTotalBitsLeft < aNum) {
30 NS_WARNING("Reading past end of buffer");
31 return 0;
33 uint32_t result = 0;
34 while (aNum > 0) {
35 if (mNumBitsLeft == 0) {
36 FillReservoir();
39 size_t m = aNum;
40 if (m > mNumBitsLeft) {
41 m = mNumBitsLeft;
44 if (m == 32) {
45 result = mReservoir;
46 mReservoir = 0;
47 } else {
48 result = (result << m) | (mReservoir >> (32 - m));
49 mReservoir <<= m;
51 mNumBitsLeft -= m;
52 mTotalBitsLeft -= m;
54 aNum -= m;
57 return result;
60 // Read unsigned integer Exp-Golomb-coded.
61 uint32_t BitReader::ReadUE() {
62 uint32_t i = 0;
64 while (ReadBit() == 0 && i < 32) {
65 i++;
67 if (i == 32) {
68 // This can happen if the data is invalid, or if it's
69 // short, since ReadBit() will return 0 when it runs
70 // off the end of the buffer.
71 NS_WARNING("Invalid H.264 data");
72 return 0;
74 uint32_t r = ReadBits(i);
75 r += (uint32_t(1) << i) - 1;
77 return r;
80 // Read signed integer Exp-Golomb-coded.
81 int32_t BitReader::ReadSE() {
82 int32_t r = ReadUE();
83 if (r & 1) {
84 return (r + 1) / 2;
85 } else {
86 return -r / 2;
90 uint64_t BitReader::ReadU64() {
91 uint64_t hi = ReadU32();
92 uint32_t lo = ReadU32();
93 return (hi << 32) | lo;
96 CheckedUint64 BitReader::ReadULEB128() {
97 // See https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
98 CheckedUint64 value = 0;
99 for (size_t i = 0; i < sizeof(uint64_t) * 8 / 7; i++) {
100 bool more = ReadBit();
101 value += static_cast<uint64_t>(ReadBits(7)) << (i * 7);
102 if (!more) {
103 break;
106 return value;
109 uint64_t BitReader::ReadUTF8() {
110 int64_t val = ReadBits(8);
111 uint32_t top = (val & 0x80) >> 1;
113 if ((val & 0xc0) == 0x80 || val >= 0xFE) {
114 // error.
115 return -1;
117 while (val & top) {
118 int tmp = ReadBits(8) - 128;
119 if (tmp >> 6) {
120 // error.
121 return -1;
123 val = (val << 6) + tmp;
124 top <<= 5;
126 val &= (top << 1) - 1;
127 return val;
130 size_t BitReader::BitCount() const { return mOriginalBitSize - mTotalBitsLeft; }
132 size_t BitReader::BitsLeft() const { return mTotalBitsLeft; }
134 void BitReader::FillReservoir() {
135 if (mSize == 0) {
136 NS_ASSERTION(false, "Attempting to fill reservoir from past end of data");
137 return;
140 mReservoir = 0;
141 size_t i;
142 for (i = 0; mSize > 0 && i < 4; i++) {
143 mReservoir = (mReservoir << 8) | *mData;
144 mData++;
145 mSize--;
148 mNumBitsLeft = 8 * i;
149 mReservoir <<= 32 - mNumBitsLeft;
152 /* static */
153 uint32_t BitReader::GetBitLength(const mozilla::MediaByteBuffer* aNAL) {
154 size_t size = aNAL->Length();
156 while (size > 0 && aNAL->ElementAt(size - 1) == 0) {
157 size--;
160 if (!size) {
161 return 0;
164 if (size > UINT32_MAX / 8) {
165 // We can't represent it, we'll use as much as we can.
166 return UINT32_MAX;
169 uint8_t v = aNAL->ElementAt(size - 1);
170 size *= 8;
172 // Remove the stop bit and following trailing zeros.
173 if (v) {
174 // Count the consecutive zero bits (trailing) on the right by binary search.
175 // Adapted from Matt Whitlock algorithm to only bother with 8 bits integers.
176 uint32_t c;
177 if (v & 1) {
178 // Special case for odd v (assumed to happen half of the time).
179 c = 0;
180 } else {
181 c = 1;
182 if ((v & 0xf) == 0) {
183 v >>= 4;
184 c += 4;
186 if ((v & 0x3) == 0) {
187 v >>= 2;
188 c += 2;
190 c -= v & 0x1;
192 size -= c + 1;
194 return size;
197 } // namespace mozilla