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