YuvStamper.cpp (9861B)
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 "YuvStamper.h" 13 #include "mozilla/Sprintf.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[] = {ON_3 | ON_2, ON_4 | ON_1, ON_5 | ON_0, 39 ON_5 | ON_0, ON_5 | ON_0, ON_4 | ON_1, 40 ON_3 | ON_2}; 41 42 /* 43 0, 0, 0, 1, 0, 0, 44 0, 0, 0, 1, 0, 0, 45 0, 0, 0, 1, 0, 0, 46 0, 0, 0, 1, 0, 0, 47 0, 0, 0, 1, 0, 0, 48 0, 0, 0, 1, 0, 0, 49 0, 0, 0, 1, 0, 0, 50 */ 51 static unsigned char DIGIT_1[] = {ON_2, ON_2, ON_2, ON_2, ON_2, ON_2, ON_2}; 52 53 /* 54 1, 1, 1, 1, 1, 0, 55 0, 0, 0, 0, 0, 1, 56 0, 0, 0, 0, 0, 1, 57 0, 1, 1, 1, 1, 0, 58 1, 0, 0, 0, 0, 0, 59 1, 0, 0, 0, 0, 0, 60 0, 1, 1, 1, 1, 1, 61 */ 62 static unsigned char DIGIT_2[] = { 63 ON_5 | ON_4 | ON_3 | ON_2 | ON_1, ON_0, ON_0, 64 ON_4 | ON_3 | ON_2 | ON_1, ON_5, ON_5, 65 ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 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, 1, 73 0, 0, 0, 0, 0, 1, 74 0, 0, 0, 0, 0, 1, 75 1, 1, 1, 1, 1, 0, 76 */ 77 static unsigned char DIGIT_3[] = { 78 ON_5 | ON_4 | ON_3 | ON_2 | ON_1, ON_0, ON_0, 79 ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_0, ON_0, 80 ON_5 | ON_4 | ON_3 | ON_2 | ON_1, 81 }; 82 83 /* 84 0, 1, 0, 0, 0, 1, 85 0, 1, 0, 0, 0, 1, 86 0, 1, 0, 0, 0, 1, 87 0, 1, 1, 1, 1, 1, 88 0, 0, 0, 0, 0, 1, 89 0, 0, 0, 0, 0, 1, 90 0, 0, 0, 0, 0, 1 91 */ 92 static unsigned char DIGIT_4[] = { 93 ON_4 | ON_0, ON_4 | ON_0, ON_4 | ON_0, ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 94 ON_0, ON_0, ON_0, 95 }; 96 97 /* 98 0, 1, 1, 1, 1, 1, 99 1, 0, 0, 0, 0, 0, 100 1, 0, 0, 0, 0, 0, 101 0, 1, 1, 1, 1, 0, 102 0, 0, 0, 0, 0, 1, 103 0, 0, 0, 0, 0, 1, 104 1, 1, 1, 1, 1, 0, 105 */ 106 static unsigned char DIGIT_5[] = { 107 ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_5, ON_5, 108 ON_4 | ON_3 | ON_2 | ON_1, ON_0, ON_0, 109 ON_5 | ON_4 | ON_3 | ON_2 | ON_1, 110 }; 111 112 /* 113 0, 1, 1, 1, 1, 1, 114 1, 0, 0, 0, 0, 0, 115 1, 0, 0, 0, 0, 0, 116 1, 1, 1, 1, 1, 0, 117 1, 0, 0, 0, 0, 1, 118 1, 0, 0, 0, 0, 1, 119 0, 1, 1, 1, 1, 0, 120 */ 121 static unsigned char DIGIT_6[] = { 122 ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_5, ON_5, 123 ON_4 | ON_3 | ON_2 | ON_1, ON_5 | ON_0, ON_5 | ON_0, 124 ON_4 | ON_3 | ON_2 | ON_1, 125 }; 126 127 /* 128 1, 1, 1, 1, 1, 1, 129 0, 0, 0, 0, 0, 1, 130 0, 0, 0, 0, 1, 0, 131 0, 0, 0, 1, 0, 0, 132 0, 0, 1, 0, 0, 0, 133 0, 1, 0, 0, 0, 0, 134 1, 0, 0, 0, 0, 0 135 */ 136 static unsigned char DIGIT_7[] = {ON_5 | ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 137 ON_0, 138 ON_1, 139 ON_2, 140 ON_3, 141 ON_4, 142 ON_5}; 143 144 /* 145 0, 1, 1, 1, 1, 1, 146 1, 0, 0, 0, 0, 1, 147 1, 0, 0, 0, 0, 1, 148 0, 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_8[] = { 154 ON_4 | ON_3 | ON_2 | ON_1, ON_5 | ON_0, ON_5 | ON_0, 155 ON_4 | ON_3 | ON_2 | ON_1, ON_5 | ON_0, ON_5 | ON_0, 156 ON_4 | ON_3 | ON_2 | ON_1, 157 }; 158 159 /* 160 0, 1, 1, 1, 1, 1, 161 1, 0, 0, 0, 0, 1, 162 1, 0, 0, 0, 0, 1, 163 0, 1, 1, 1, 1, 1, 164 0, 0, 0, 0, 0, 1, 165 0, 0, 0, 0, 0, 1, 166 0, 1, 1, 1, 1, 0 167 */ 168 static unsigned char DIGIT_9[] = { 169 ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_5 | ON_0, ON_5 | ON_0, 170 ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_0, ON_0, 171 ON_4 | ON_3 | ON_2 | ON_1, 172 }; 173 174 static unsigned char* DIGITS[] = {DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3, DIGIT_4, 175 DIGIT_5, DIGIT_6, DIGIT_7, DIGIT_8, DIGIT_9}; 176 177 YuvStamper::YuvStamper(unsigned char* pYData, uint32_t width, uint32_t height, 178 uint32_t stride, uint32_t x, uint32_t y, 179 unsigned char symbol_width, unsigned char symbol_height) 180 : pYData(pYData), 181 mStride(stride), 182 mWidth(width), 183 mHeight(height), 184 mSymbolWidth(symbol_width), 185 mSymbolHeight(symbol_height), 186 mCursor(x, y) {} 187 188 bool YuvStamper::Encode(uint32_t width, uint32_t height, uint32_t stride, 189 unsigned char* pYData, unsigned char* pMsg, 190 size_t msg_len, uint32_t x, uint32_t y) { 191 YuvStamper stamper(pYData, width, height, stride, x, y, sBitSize, sBitSize); 192 193 // Reserve space for a checksum. 194 if (stamper.Capacity() < 8 * (msg_len + sizeof(uint32_t))) { 195 return false; 196 } 197 198 bool ok = false; 199 uint32_t crc; 200 unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc); 201 r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &crc); 202 crc = htonl(crc); 203 204 while (msg_len-- > 0) { 205 if (!stamper.Write8(*pMsg++)) { 206 return false; 207 } 208 } 209 210 // Add checksum after the message. 211 ok = stamper.Write8(*pCrc++) && stamper.Write8(*pCrc++) && 212 stamper.Write8(*pCrc++) && stamper.Write8(*pCrc++); 213 214 return ok; 215 } 216 217 bool YuvStamper::Decode(uint32_t width, uint32_t height, uint32_t stride, 218 unsigned char* pYData, unsigned char* pMsg, 219 size_t msg_len, uint32_t x, uint32_t y) { 220 YuvStamper stamper(pYData, width, height, stride, x, y, sBitSize, sBitSize); 221 222 unsigned char* ptr = pMsg; 223 size_t len = msg_len; 224 uint32_t crc, msg_crc; 225 unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc); 226 227 // Account for space reserved for the checksum 228 if (stamper.Capacity() < 8 * (len + sizeof(uint32_t))) { 229 return false; 230 } 231 232 while (len-- > 0) { 233 if (!stamper.Read8(*ptr++)) { 234 return false; 235 } 236 } 237 238 if (!(stamper.Read8(*pCrc++) && stamper.Read8(*pCrc++) && 239 stamper.Read8(*pCrc++) && stamper.Read8(*pCrc++))) { 240 return false; 241 } 242 243 r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &msg_crc); 244 return crc == htonl(msg_crc); 245 } 246 247 inline uint32_t YuvStamper::Capacity() { 248 // Enforce at least a symbol width and height offset from outer edges. 249 if (mCursor.y + mSymbolHeight > mHeight) { 250 return 0; 251 } 252 253 if (mCursor.x + mSymbolWidth > mWidth && !AdvanceCursor()) { 254 return 0; 255 } 256 257 // Normalize frame integral to mSymbolWidth x mSymbolHeight 258 uint32_t width = mWidth / mSymbolWidth; 259 uint32_t height = mHeight / mSymbolHeight; 260 uint32_t x = mCursor.x / mSymbolWidth; 261 uint32_t y = mCursor.y / mSymbolHeight; 262 263 return (width * height - width * y) - x; 264 } 265 266 bool YuvStamper::Write8(unsigned char value) { 267 // Encode MSB to LSB. 268 unsigned char mask = 0x80; 269 while (mask) { 270 if (!WriteBit(!!(value & mask))) { 271 return false; 272 } 273 mask >>= 1; 274 } 275 return true; 276 } 277 278 bool YuvStamper::WriteBit(bool one) { 279 // A bit is mapped to a mSymbolWidth x mSymbolHeight square of luma data 280 // points. Don't use ternary op.: 281 // https://bugzilla.mozilla.org/show_bug.cgi?id=1001708 282 unsigned char value; 283 if (one) 284 value = sYOn; 285 else 286 value = sYOff; 287 288 for (uint32_t y = 0; y < mSymbolHeight; y++) { 289 for (uint32_t x = 0; x < mSymbolWidth; x++) { 290 *(pYData + (mCursor.x + x) + ((mCursor.y + y) * mStride)) = value; 291 } 292 } 293 294 return AdvanceCursor(); 295 } 296 297 bool YuvStamper::AdvanceCursor() { 298 mCursor.x += mSymbolWidth; 299 if (mCursor.x + mSymbolWidth > mWidth) { 300 // move to the start of the next row if possible. 301 mCursor.y += mSymbolHeight; 302 if (mCursor.y + mSymbolHeight > mHeight) { 303 // end of frame, do not advance 304 mCursor.y -= mSymbolHeight; 305 mCursor.x -= mSymbolWidth; 306 return false; 307 } else { 308 mCursor.x = 0; 309 } 310 } 311 312 return true; 313 } 314 315 bool YuvStamper::Read8(unsigned char& value) { 316 unsigned char octet = 0; 317 unsigned char bit = 0; 318 319 for (int i = 8; i > 0; --i) { 320 if (!ReadBit(bit)) { 321 return false; 322 } 323 octet <<= 1; 324 octet |= bit; 325 } 326 327 value = octet; 328 return true; 329 } 330 331 bool YuvStamper::ReadBit(unsigned char& bit) { 332 uint32_t sum = 0; 333 for (uint32_t y = 0; y < mSymbolHeight; y++) { 334 for (uint32_t x = 0; x < mSymbolWidth; x++) { 335 sum += *(pYData + mStride * (mCursor.y + y) + mCursor.x + x); 336 } 337 } 338 339 // apply threshold to collected bit square 340 bit = (sum > (sBitThreshold * mSymbolWidth * mSymbolHeight)) ? 1 : 0; 341 return AdvanceCursor(); 342 } 343 344 bool YuvStamper::WriteDigits(uint32_t value) { 345 char buf[20]; 346 SprintfLiteral(buf, "%.5u", value); 347 size_t size = strlen(buf); 348 349 if (Capacity() < size) { 350 return false; 351 } 352 353 for (size_t i = 0; i < size; ++i) { 354 if (!WriteDigit(buf[i] - '0')) return false; 355 if (!AdvanceCursor()) { 356 return false; 357 } 358 } 359 360 return true; 361 } 362 363 bool YuvStamper::WriteDigit(unsigned char digit) { 364 if (digit > sizeof(DIGITS) / sizeof(DIGITS[0])) return false; 365 366 unsigned char* dig = DIGITS[digit]; 367 for (uint32_t row = 0; row < sDigitHeight; ++row) { 368 unsigned char mask = 0x01 << (sDigitWidth - 1); 369 for (uint32_t col = 0; col < sDigitWidth; ++col, mask >>= 1) { 370 if (dig[row] & mask) { 371 for (uint32_t xx = 0; xx < sPixelSize; ++xx) { 372 for (uint32_t yy = 0; yy < sPixelSize; ++yy) { 373 WritePixel(pYData, mCursor.x + (col * sPixelSize) + xx, 374 mCursor.y + (row * sPixelSize) + yy); 375 } 376 } 377 } 378 } 379 } 380 381 return true; 382 } 383 384 void YuvStamper::WritePixel(unsigned char* data, uint32_t x, uint32_t y) { 385 unsigned char* ptr = &data[y * mStride + x]; 386 // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708 387 if (*ptr > sLumaThreshold) 388 *ptr = sLumaMin; 389 else 390 *ptr = sLumaMax; 391 } 392 393 } // namespace mozilla.