Line data Source code
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 file,
3 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #ifdef HAVE_NETINET_IN_H
6 : #include <netinet/in.h>
7 : #elif defined XP_WIN
8 : #include <winsock2.h>
9 : #endif
10 : #include <string.h>
11 :
12 : #include "nspr.h"
13 : #include "YuvStamper.h"
14 : #include "mozilla/Sprintf.h"
15 :
16 : typedef uint32_t UINT4; //Needed for r_crc32() call
17 : extern "C" {
18 : #include "r_crc32.h"
19 : }
20 :
21 : namespace mozilla {
22 :
23 : #define ON_5 0x20
24 : #define ON_4 0x10
25 : #define ON_3 0x08
26 : #define ON_2 0x04
27 : #define ON_1 0x02
28 : #define ON_0 0x01
29 :
30 : /*
31 : 0, 0, 1, 1, 0, 0,
32 : 0, 1, 0, 0, 1, 0,
33 : 1, 0, 0, 0, 0, 1,
34 : 1, 0, 0, 0, 0, 1,
35 : 1, 0, 0, 0, 0, 1,
36 : 0, 1, 0, 0, 1, 0,
37 : 0, 0, 1, 1, 0, 0
38 : */
39 : static unsigned char DIGIT_0 [] =
40 : { ON_3 | ON_2,
41 : ON_4 | ON_1,
42 : ON_5 | ON_0,
43 : ON_5 | ON_0,
44 : ON_5 | ON_0,
45 : ON_4 | ON_1,
46 : ON_3 | ON_2
47 : };
48 :
49 : /*
50 : 0, 0, 0, 1, 0, 0,
51 : 0, 0, 0, 1, 0, 0,
52 : 0, 0, 0, 1, 0, 0,
53 : 0, 0, 0, 1, 0, 0,
54 : 0, 0, 0, 1, 0, 0,
55 : 0, 0, 0, 1, 0, 0,
56 : 0, 0, 0, 1, 0, 0,
57 : */
58 : static unsigned char DIGIT_1 [] =
59 : { ON_2,
60 : ON_2,
61 : ON_2,
62 : ON_2,
63 : ON_2,
64 : ON_2,
65 : ON_2
66 : };
67 :
68 : /*
69 : 1, 1, 1, 1, 1, 0,
70 : 0, 0, 0, 0, 0, 1,
71 : 0, 0, 0, 0, 0, 1,
72 : 0, 1, 1, 1, 1, 0,
73 : 1, 0, 0, 0, 0, 0,
74 : 1, 0, 0, 0, 0, 0,
75 : 0, 1, 1, 1, 1, 1,
76 : */
77 : static unsigned char DIGIT_2 [] =
78 : { ON_5 | ON_4 | ON_3 | ON_2 | ON_1,
79 : ON_0,
80 : ON_0,
81 : ON_4 | ON_3 | ON_2 | ON_1,
82 : ON_5,
83 : ON_5,
84 : ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
85 : };
86 :
87 : /*
88 : 1, 1, 1, 1, 1, 0,
89 : 0, 0, 0, 0, 0, 1,
90 : 0, 0, 0, 0, 0, 1,
91 : 0, 1, 1, 1, 1, 1,
92 : 0, 0, 0, 0, 0, 1,
93 : 0, 0, 0, 0, 0, 1,
94 : 1, 1, 1, 1, 1, 0,
95 : */
96 : static unsigned char DIGIT_3 [] =
97 : { ON_5 | ON_4 | ON_3 | ON_2 | ON_1,
98 : ON_0,
99 : ON_0,
100 : ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
101 : ON_0,
102 : ON_0,
103 : ON_5 | ON_4 | ON_3 | ON_2 | ON_1,
104 : };
105 :
106 : /*
107 : 0, 1, 0, 0, 0, 1,
108 : 0, 1, 0, 0, 0, 1,
109 : 0, 1, 0, 0, 0, 1,
110 : 0, 1, 1, 1, 1, 1,
111 : 0, 0, 0, 0, 0, 1,
112 : 0, 0, 0, 0, 0, 1,
113 : 0, 0, 0, 0, 0, 1
114 : */
115 : static unsigned char DIGIT_4 [] =
116 : { ON_4 | ON_0,
117 : ON_4 | ON_0,
118 : ON_4 | ON_0,
119 : ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
120 : ON_0,
121 : ON_0,
122 : ON_0,
123 : };
124 :
125 : /*
126 : 0, 1, 1, 1, 1, 1,
127 : 1, 0, 0, 0, 0, 0,
128 : 1, 0, 0, 0, 0, 0,
129 : 0, 1, 1, 1, 1, 0,
130 : 0, 0, 0, 0, 0, 1,
131 : 0, 0, 0, 0, 0, 1,
132 : 1, 1, 1, 1, 1, 0,
133 : */
134 : static unsigned char DIGIT_5 [] =
135 : { ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
136 : ON_5,
137 : ON_5,
138 : ON_4 | ON_3 | ON_2 | ON_1,
139 : ON_0,
140 : ON_0,
141 : ON_5 | ON_4 | ON_3 | ON_2 | ON_1,
142 : };
143 :
144 : /*
145 : 0, 1, 1, 1, 1, 1,
146 : 1, 0, 0, 0, 0, 0,
147 : 1, 0, 0, 0, 0, 0,
148 : 1, 1, 1, 1, 1, 0,
149 : 1, 0, 0, 0, 0, 1,
150 : 1, 0, 0, 0, 0, 1,
151 : 0, 1, 1, 1, 1, 0,
152 : */
153 : static unsigned char DIGIT_6 [] =
154 : { ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
155 : ON_5,
156 : ON_5,
157 : ON_4 | ON_3 | ON_2 | ON_1,
158 : ON_5 | ON_0,
159 : ON_5 | ON_0,
160 : ON_4 | ON_3 | ON_2 | ON_1,
161 : };
162 :
163 : /*
164 : 1, 1, 1, 1, 1, 1,
165 : 0, 0, 0, 0, 0, 1,
166 : 0, 0, 0, 0, 1, 0,
167 : 0, 0, 0, 1, 0, 0,
168 : 0, 0, 1, 0, 0, 0,
169 : 0, 1, 0, 0, 0, 0,
170 : 1, 0, 0, 0, 0, 0
171 : */
172 : static unsigned char DIGIT_7 [] =
173 : { ON_5 | ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
174 : ON_0,
175 : ON_1,
176 : ON_2,
177 : ON_3,
178 : ON_4,
179 : ON_5
180 : };
181 :
182 : /*
183 : 0, 1, 1, 1, 1, 1,
184 : 1, 0, 0, 0, 0, 1,
185 : 1, 0, 0, 0, 0, 1,
186 : 0, 1, 1, 1, 1, 0,
187 : 1, 0, 0, 0, 0, 1,
188 : 1, 0, 0, 0, 0, 1,
189 : 0, 1, 1, 1, 1, 0
190 : */
191 : static unsigned char DIGIT_8 [] =
192 : { ON_4 | ON_3 | ON_2 | ON_1,
193 : ON_5 | ON_0,
194 : ON_5 | ON_0,
195 : ON_4 | ON_3 | ON_2 | ON_1,
196 : ON_5 | ON_0,
197 : ON_5 | ON_0,
198 : ON_4 | ON_3 | ON_2 | ON_1,
199 : };
200 :
201 : /*
202 : 0, 1, 1, 1, 1, 1,
203 : 1, 0, 0, 0, 0, 1,
204 : 1, 0, 0, 0, 0, 1,
205 : 0, 1, 1, 1, 1, 1,
206 : 0, 0, 0, 0, 0, 1,
207 : 0, 0, 0, 0, 0, 1,
208 : 0, 1, 1, 1, 1, 0
209 : */
210 : static unsigned char DIGIT_9 [] =
211 : { ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
212 : ON_5 | ON_0,
213 : ON_5 | ON_0,
214 : ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
215 : ON_0,
216 : ON_0,
217 : ON_4 | ON_3 | ON_2 | ON_1,
218 : };
219 :
220 : static unsigned char *DIGITS[] = {
221 : DIGIT_0,
222 : DIGIT_1,
223 : DIGIT_2,
224 : DIGIT_3,
225 : DIGIT_4,
226 : DIGIT_5,
227 : DIGIT_6,
228 : DIGIT_7,
229 : DIGIT_8,
230 : DIGIT_9
231 : };
232 :
233 0 : YuvStamper::YuvStamper(unsigned char* pYData,
234 : uint32_t width,
235 : uint32_t height,
236 : uint32_t stride,
237 : uint32_t x,
238 : uint32_t y,
239 : unsigned char symbol_width,
240 0 : unsigned char symbol_height):
241 : pYData(pYData), mStride(stride),
242 : mWidth(width), mHeight(height),
243 : mSymbolWidth(symbol_width), mSymbolHeight(symbol_height),
244 0 : mCursor(x, y) {}
245 :
246 0 : bool YuvStamper::Encode(uint32_t width, uint32_t height, uint32_t stride,
247 : unsigned char* pYData, unsigned char* pMsg, size_t msg_len,
248 : uint32_t x, uint32_t y)
249 : {
250 : YuvStamper stamper(pYData, width, height, stride,
251 0 : x, y, sBitSize, sBitSize);
252 :
253 : // Reserve space for a checksum.
254 0 : if (stamper.Capacity() < 8 * (msg_len + sizeof(uint32_t)))
255 : {
256 0 : return false;
257 : }
258 :
259 0 : bool ok = false;
260 : uint32_t crc;
261 0 : unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc);
262 0 : r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &crc);
263 0 : crc = htonl(crc);
264 :
265 0 : while (msg_len-- > 0) {
266 0 : if (!stamper.Write8(*pMsg++)) {
267 0 : return false;
268 : }
269 : }
270 :
271 : // Add checksum after the message.
272 0 : ok = stamper.Write8(*pCrc++) &&
273 0 : stamper.Write8(*pCrc++) &&
274 0 : stamper.Write8(*pCrc++) &&
275 0 : stamper.Write8(*pCrc++);
276 :
277 0 : return ok;
278 : }
279 :
280 0 : bool YuvStamper::Decode(uint32_t width, uint32_t height, uint32_t stride,
281 : unsigned char* pYData, unsigned char* pMsg, size_t msg_len,
282 : uint32_t x, uint32_t y)
283 : {
284 : YuvStamper stamper(pYData, width, height, stride,
285 0 : x, y, sBitSize, sBitSize);
286 :
287 0 : unsigned char* ptr = pMsg;
288 0 : size_t len = msg_len;
289 : uint32_t crc, msg_crc;
290 0 : unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc);
291 :
292 : // Account for space reserved for the checksum
293 0 : if (stamper.Capacity() < 8 * (len + sizeof(uint32_t))) {
294 0 : return false;
295 : }
296 :
297 0 : while (len-- > 0) {
298 0 : if(!stamper.Read8(*ptr++)) {
299 0 : return false;
300 : }
301 : }
302 :
303 0 : if (!(stamper.Read8(*pCrc++) &&
304 0 : stamper.Read8(*pCrc++) &&
305 0 : stamper.Read8(*pCrc++) &&
306 0 : stamper.Read8(*pCrc++))) {
307 0 : return false;
308 : }
309 :
310 0 : r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &msg_crc);
311 0 : return crc == htonl(msg_crc);
312 : }
313 :
314 0 : inline uint32_t YuvStamper::Capacity()
315 : {
316 : // Enforce at least a symbol width and height offset from outer edges.
317 0 : if (mCursor.y + mSymbolHeight > mHeight) {
318 0 : return 0;
319 : }
320 :
321 0 : if (mCursor.x + mSymbolWidth > mWidth && !AdvanceCursor()) {
322 0 : return 0;
323 : }
324 :
325 : // Normalize frame integral to mSymbolWidth x mSymbolHeight
326 0 : uint32_t width = mWidth / mSymbolWidth;
327 0 : uint32_t height = mHeight / mSymbolHeight;
328 0 : uint32_t x = mCursor.x / mSymbolWidth;
329 0 : uint32_t y = mCursor.y / mSymbolHeight;
330 :
331 0 : return (width * height - width * y)- x;
332 : }
333 :
334 0 : bool YuvStamper::Write8(unsigned char value)
335 : {
336 : // Encode MSB to LSB.
337 0 : unsigned char mask = 0x80;
338 0 : while (mask) {
339 0 : if (!WriteBit(!!(value & mask))) {
340 0 : return false;
341 : }
342 0 : mask >>= 1;
343 : }
344 0 : return true;
345 : }
346 :
347 0 : bool YuvStamper::WriteBit(bool one)
348 : {
349 : // A bit is mapped to a mSymbolWidth x mSymbolHeight square of luma data points.
350 : // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708
351 : unsigned char value;
352 0 : if (one)
353 0 : value = sYOn;
354 : else
355 0 : value = sYOff;
356 :
357 0 : for (uint32_t y = 0; y < mSymbolHeight; y++) {
358 0 : for (uint32_t x = 0; x < mSymbolWidth; x++) {
359 0 : *(pYData + (mCursor.x + x) + ((mCursor.y + y) * mStride)) = value;
360 : }
361 : }
362 :
363 0 : return AdvanceCursor();
364 : }
365 :
366 0 : bool YuvStamper::AdvanceCursor()
367 : {
368 0 : mCursor.x += mSymbolWidth;
369 0 : if (mCursor.x + mSymbolWidth > mWidth) {
370 : // move to the start of the next row if possible.
371 0 : mCursor.y += mSymbolHeight;
372 0 : if (mCursor.y + mSymbolHeight > mHeight) {
373 : // end of frame, do not advance
374 0 : mCursor.y -= mSymbolHeight;
375 0 : mCursor.x -= mSymbolWidth;
376 0 : return false;
377 : } else {
378 0 : mCursor.x = 0;
379 : }
380 : }
381 :
382 0 : return true;
383 : }
384 :
385 0 : bool YuvStamper::Read8(unsigned char &value)
386 : {
387 0 : unsigned char octet = 0;
388 0 : unsigned char bit = 0;
389 :
390 0 : for (int i = 8; i > 0; --i) {
391 0 : if (!ReadBit(bit)) {
392 0 : return false;
393 : }
394 0 : octet <<= 1;
395 0 : octet |= bit;
396 : }
397 :
398 0 : value = octet;
399 0 : return true;
400 : }
401 :
402 0 : bool YuvStamper::ReadBit(unsigned char &bit)
403 : {
404 0 : uint32_t sum = 0;
405 0 : for (uint32_t y = 0; y < mSymbolHeight; y++) {
406 0 : for (uint32_t x = 0; x < mSymbolWidth; x++) {
407 0 : sum += *(pYData + mStride * (mCursor.y + y) + mCursor.x + x);
408 : }
409 : }
410 :
411 : // apply threshold to collected bit square
412 0 : bit = (sum > (sBitThreshold * mSymbolWidth * mSymbolHeight)) ? 1 : 0;
413 0 : return AdvanceCursor();
414 : }
415 :
416 0 : bool YuvStamper::WriteDigits(uint32_t value)
417 : {
418 : char buf[20];
419 0 : SprintfLiteral(buf, "%.5u", value);
420 0 : size_t size = strlen(buf);
421 :
422 0 : if (Capacity() < size) {
423 0 : return false;
424 : }
425 :
426 0 : for (size_t i=0; i < size; ++i) {
427 0 : if (!WriteDigit(buf[i] - '0'))
428 0 : return false;
429 0 : if (!AdvanceCursor()) {
430 0 : return false;
431 : }
432 : }
433 :
434 0 : return true;
435 : }
436 :
437 0 : bool YuvStamper::WriteDigit(unsigned char digit) {
438 0 : if (digit > sizeof(DIGITS)/sizeof(DIGITS[0]))
439 0 : return false;
440 :
441 0 : unsigned char *dig = DIGITS[digit];
442 0 : for (uint32_t row = 0; row < sDigitHeight; ++row) {
443 0 : unsigned char mask = 0x01 << (sDigitWidth - 1);
444 0 : for (uint32_t col = 0; col < sDigitWidth; ++col, mask >>= 1) {
445 0 : if (dig[row] & mask) {
446 0 : for (uint32_t xx=0; xx < sPixelSize; ++xx) {
447 0 : for (uint32_t yy=0; yy < sPixelSize; ++yy) {
448 0 : WritePixel(pYData,
449 0 : mCursor.x + (col * sPixelSize) + xx,
450 0 : mCursor.y + (row * sPixelSize) + yy);
451 : }
452 : }
453 : }
454 : }
455 : }
456 :
457 0 : return true;
458 : }
459 :
460 0 : void YuvStamper::WritePixel(unsigned char *data, uint32_t x, uint32_t y) {
461 0 : unsigned char *ptr = &data[y * mStride + x];
462 : // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708
463 0 : if (*ptr > sLumaThreshold)
464 0 : *ptr = sLumaMin;
465 : else
466 0 : *ptr = sLumaMax;
467 0 : }
468 :
469 : } // namespace mozilla.
|