/src/mozilla-central/dom/media/BitReader.cpp
Line | Count | Source (jump to first uncovered line) |
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/. */ |
4 | | |
5 | | // Derived from Stagefright's ABitReader. |
6 | | |
7 | | #include "BitReader.h" |
8 | | |
9 | | namespace mozilla |
10 | | { |
11 | | |
12 | | BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer) |
13 | | : BitReader(aBuffer->Elements(), aBuffer->Length() * 8) |
14 | 0 | { |
15 | 0 | } |
16 | | |
17 | | BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer, size_t aBits) |
18 | | : BitReader(aBuffer->Elements(), aBits) |
19 | 0 | { |
20 | 0 | } |
21 | | |
22 | | BitReader::BitReader(const uint8_t* aBuffer, size_t aBits) |
23 | | : mData(aBuffer) |
24 | | , mOriginalBitSize(aBits) |
25 | | , mTotalBitsLeft(aBits) |
26 | | , mSize((aBits + 7) / 8) |
27 | | , mReservoir(0) |
28 | | , mNumBitsLeft(0) |
29 | 0 | { |
30 | 0 | } |
31 | | |
32 | 0 | BitReader::~BitReader() { } |
33 | | |
34 | | uint32_t |
35 | | BitReader::ReadBits(size_t aNum) |
36 | 0 | { |
37 | 0 | MOZ_ASSERT(aNum <= 32); |
38 | 0 | if (mTotalBitsLeft < aNum) { |
39 | 0 | NS_ASSERTION(false, "Reading past end of buffer"); |
40 | 0 | return 0; |
41 | 0 | } |
42 | 0 | uint32_t result = 0; |
43 | 0 | while (aNum > 0) { |
44 | 0 | if (mNumBitsLeft == 0) { |
45 | 0 | FillReservoir(); |
46 | 0 | } |
47 | 0 |
|
48 | 0 | size_t m = aNum; |
49 | 0 | if (m > mNumBitsLeft) { |
50 | 0 | m = mNumBitsLeft; |
51 | 0 | } |
52 | 0 |
|
53 | 0 | result = (result << m) | (mReservoir >> (32 - m)); |
54 | 0 | mReservoir <<= m; |
55 | 0 | mNumBitsLeft -= m; |
56 | 0 | mTotalBitsLeft -= m; |
57 | 0 |
|
58 | 0 | aNum -= m; |
59 | 0 | } |
60 | 0 |
|
61 | 0 | return result; |
62 | 0 | } |
63 | | |
64 | | // Read unsigned integer Exp-Golomb-coded. |
65 | | uint32_t |
66 | | BitReader::ReadUE() |
67 | 0 | { |
68 | 0 | uint32_t i = 0; |
69 | 0 |
|
70 | 0 | while (ReadBit() == 0 && i < 32) { |
71 | 0 | i++; |
72 | 0 | } |
73 | 0 | if (i == 32) { |
74 | 0 | // This can happen if the data is invalid, or if it's |
75 | 0 | // short, since ReadBit() will return 0 when it runs |
76 | 0 | // off the end of the buffer. |
77 | 0 | NS_WARNING("Invalid H.264 data"); |
78 | 0 | return 0; |
79 | 0 | } |
80 | 0 | uint32_t r = ReadBits(i); |
81 | 0 | r += (1 << i) - 1; |
82 | 0 | return r; |
83 | 0 | } |
84 | | |
85 | | // Read signed integer Exp-Golomb-coded. |
86 | | int32_t |
87 | | BitReader::ReadSE() |
88 | 0 | { |
89 | 0 | int32_t r = ReadUE(); |
90 | 0 | if (r & 1) { |
91 | 0 | return (r+1) / 2; |
92 | 0 | } else { |
93 | 0 | return -r / 2; |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | | uint64_t |
98 | | BitReader::ReadU64() |
99 | 0 | { |
100 | 0 | uint64_t hi = ReadU32(); |
101 | 0 | uint32_t lo = ReadU32(); |
102 | 0 | return (hi << 32) | lo; |
103 | 0 | } |
104 | | |
105 | | uint64_t |
106 | | BitReader::ReadUTF8() |
107 | 0 | { |
108 | 0 | int64_t val = ReadBits(8); |
109 | 0 | uint32_t top = (val & 0x80) >> 1; |
110 | 0 |
|
111 | 0 | if ((val & 0xc0) == 0x80 || val >= 0xFE) { |
112 | 0 | // error. |
113 | 0 | return -1; |
114 | 0 | } |
115 | 0 | while (val & top) { |
116 | 0 | int tmp = ReadBits(8) - 128; |
117 | 0 | if (tmp >> 6) { |
118 | 0 | // error. |
119 | 0 | return -1; |
120 | 0 | } |
121 | 0 | val = (val << 6) + tmp; |
122 | 0 | top <<= 5; |
123 | 0 | } |
124 | 0 | val &= (top << 1) - 1; |
125 | 0 | return val; |
126 | 0 | } |
127 | | |
128 | | size_t |
129 | | BitReader::BitCount() const |
130 | 0 | { |
131 | 0 | return mOriginalBitSize - mTotalBitsLeft; |
132 | 0 | } |
133 | | |
134 | | size_t |
135 | | BitReader::BitsLeft() const |
136 | 0 | { |
137 | 0 | return mTotalBitsLeft; |
138 | 0 | } |
139 | | |
140 | | void |
141 | | BitReader::FillReservoir() |
142 | 0 | { |
143 | 0 | if (mSize == 0) { |
144 | 0 | NS_ASSERTION(false, "Attempting to fill reservoir from past end of data"); |
145 | 0 | return; |
146 | 0 | } |
147 | 0 |
|
148 | 0 | mReservoir = 0; |
149 | 0 | size_t i; |
150 | 0 | for (i = 0; mSize > 0 && i < 4; i++) { |
151 | 0 | mReservoir = (mReservoir << 8) | *mData; |
152 | 0 | mData++; |
153 | 0 | mSize--; |
154 | 0 | } |
155 | 0 |
|
156 | 0 | mNumBitsLeft = 8 * i; |
157 | 0 | mReservoir <<= 32 - mNumBitsLeft; |
158 | 0 | } |
159 | | |
160 | | /* static */ uint32_t |
161 | | BitReader::GetBitLength(const mozilla::MediaByteBuffer* aNAL) |
162 | 0 | { |
163 | 0 | size_t size = aNAL->Length(); |
164 | 0 |
|
165 | 0 | while (size > 0 && aNAL->ElementAt(size - 1) == 0) { |
166 | 0 | size--; |
167 | 0 | } |
168 | 0 |
|
169 | 0 | if (!size) { |
170 | 0 | return 0; |
171 | 0 | } |
172 | 0 | |
173 | 0 | if (size > UINT32_MAX / 8) { |
174 | 0 | // We can't represent it, we'll use as much as we can. |
175 | 0 | return UINT32_MAX; |
176 | 0 | } |
177 | 0 | |
178 | 0 | uint8_t v = aNAL->ElementAt(size - 1); |
179 | 0 | size *= 8; |
180 | 0 |
|
181 | 0 | // Remove the stop bit and following trailing zeros. |
182 | 0 | if (v) { |
183 | 0 | // Count the consecutive zero bits (trailing) on the right by binary search. |
184 | 0 | // Adapted from Matt Whitlock algorithm to only bother with 8 bits integers. |
185 | 0 | uint32_t c; |
186 | 0 | if (v & 1) { |
187 | 0 | // Special case for odd v (assumed to happen half of the time). |
188 | 0 | c = 0; |
189 | 0 | } else { |
190 | 0 | c = 1; |
191 | 0 | if ((v & 0xf) == 0) { |
192 | 0 | v >>= 4; |
193 | 0 | c += 4; |
194 | 0 | } |
195 | 0 | if ((v & 0x3) == 0) { |
196 | 0 | v >>= 2; |
197 | 0 | c += 2; |
198 | 0 | } |
199 | 0 | c -= v & 0x1; |
200 | 0 | } |
201 | 0 | size -= c + 1; |
202 | 0 | } |
203 | 0 | return size; |
204 | 0 | } |
205 | | |
206 | | } // namespace mozilla |