1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/signaling/src/common/YuvStamper.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,468 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifdef HAVE_NETINET_IN_H 1.9 +#include <netinet/in.h> 1.10 +#elif defined XP_WIN 1.11 +#include <winsock2.h> 1.12 +#endif 1.13 +#include <string.h> 1.14 + 1.15 +#include "nspr.h" 1.16 +#include "YuvStamper.h" 1.17 + 1.18 +typedef uint32_t UINT4; //Needed for r_crc32() call 1.19 +extern "C" { 1.20 +#include "r_crc32.h" 1.21 +} 1.22 + 1.23 +namespace mozilla { 1.24 + 1.25 +#define ON_5 0x20 1.26 +#define ON_4 0x10 1.27 +#define ON_3 0x08 1.28 +#define ON_2 0x04 1.29 +#define ON_1 0x02 1.30 +#define ON_0 0x01 1.31 + 1.32 +/* 1.33 + 0, 0, 1, 1, 0, 0, 1.34 + 0, 1, 0, 0, 1, 0, 1.35 + 1, 0, 0, 0, 0, 1, 1.36 + 1, 0, 0, 0, 0, 1, 1.37 + 1, 0, 0, 0, 0, 1, 1.38 + 0, 1, 0, 0, 1, 0, 1.39 + 0, 0, 1, 1, 0, 0 1.40 +*/ 1.41 +static unsigned char DIGIT_0 [] = 1.42 + { ON_3 | ON_2, 1.43 + ON_4 | ON_1, 1.44 + ON_5 | ON_0, 1.45 + ON_5 | ON_0, 1.46 + ON_5 | ON_0, 1.47 + ON_4 | ON_1, 1.48 + ON_3 | ON_2 1.49 + }; 1.50 + 1.51 +/* 1.52 + 0, 0, 0, 1, 0, 0, 1.53 + 0, 0, 0, 1, 0, 0, 1.54 + 0, 0, 0, 1, 0, 0, 1.55 + 0, 0, 0, 1, 0, 0, 1.56 + 0, 0, 0, 1, 0, 0, 1.57 + 0, 0, 0, 1, 0, 0, 1.58 + 0, 0, 0, 1, 0, 0, 1.59 +*/ 1.60 +static unsigned char DIGIT_1 [] = 1.61 + { ON_2, 1.62 + ON_2, 1.63 + ON_2, 1.64 + ON_2, 1.65 + ON_2, 1.66 + ON_2, 1.67 + ON_2 1.68 + }; 1.69 + 1.70 +/* 1.71 + 1, 1, 1, 1, 1, 0, 1.72 + 0, 0, 0, 0, 0, 1, 1.73 + 0, 0, 0, 0, 0, 1, 1.74 + 0, 1, 1, 1, 1, 0, 1.75 + 1, 0, 0, 0, 0, 0, 1.76 + 1, 0, 0, 0, 0, 0, 1.77 + 0, 1, 1, 1, 1, 1, 1.78 +*/ 1.79 +static unsigned char DIGIT_2 [] = 1.80 + { ON_5 | ON_4 | ON_3 | ON_2 | ON_1, 1.81 + ON_0, 1.82 + ON_0, 1.83 + ON_4 | ON_3 | ON_2 | ON_1, 1.84 + ON_5, 1.85 + ON_5, 1.86 + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.87 + }; 1.88 + 1.89 +/* 1.90 + 1, 1, 1, 1, 1, 0, 1.91 + 0, 0, 0, 0, 0, 1, 1.92 + 0, 0, 0, 0, 0, 1, 1.93 + 0, 1, 1, 1, 1, 1, 1.94 + 0, 0, 0, 0, 0, 1, 1.95 + 0, 0, 0, 0, 0, 1, 1.96 + 1, 1, 1, 1, 1, 0, 1.97 +*/ 1.98 +static unsigned char DIGIT_3 [] = 1.99 + { ON_5 | ON_4 | ON_3 | ON_2 | ON_1, 1.100 + ON_0, 1.101 + ON_0, 1.102 + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.103 + ON_0, 1.104 + ON_0, 1.105 + ON_5 | ON_4 | ON_3 | ON_2 | ON_1, 1.106 + }; 1.107 + 1.108 +/* 1.109 + 0, 1, 0, 0, 0, 1, 1.110 + 0, 1, 0, 0, 0, 1, 1.111 + 0, 1, 0, 0, 0, 1, 1.112 + 0, 1, 1, 1, 1, 1, 1.113 + 0, 0, 0, 0, 0, 1, 1.114 + 0, 0, 0, 0, 0, 1, 1.115 + 0, 0, 0, 0, 0, 1 1.116 +*/ 1.117 +static unsigned char DIGIT_4 [] = 1.118 + { ON_4 | ON_0, 1.119 + ON_4 | ON_0, 1.120 + ON_4 | ON_0, 1.121 + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.122 + ON_0, 1.123 + ON_0, 1.124 + ON_0, 1.125 + }; 1.126 + 1.127 +/* 1.128 + 0, 1, 1, 1, 1, 1, 1.129 + 1, 0, 0, 0, 0, 0, 1.130 + 1, 0, 0, 0, 0, 0, 1.131 + 0, 1, 1, 1, 1, 0, 1.132 + 0, 0, 0, 0, 0, 1, 1.133 + 0, 0, 0, 0, 0, 1, 1.134 + 1, 1, 1, 1, 1, 0, 1.135 +*/ 1.136 +static unsigned char DIGIT_5 [] = 1.137 + { ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.138 + ON_5, 1.139 + ON_5, 1.140 + ON_4 | ON_3 | ON_2 | ON_1, 1.141 + ON_0, 1.142 + ON_0, 1.143 + ON_5 | ON_4 | ON_3 | ON_2 | ON_1, 1.144 + }; 1.145 + 1.146 +/* 1.147 + 0, 1, 1, 1, 1, 1, 1.148 + 1, 0, 0, 0, 0, 0, 1.149 + 1, 0, 0, 0, 0, 0, 1.150 + 1, 1, 1, 1, 1, 0, 1.151 + 1, 0, 0, 0, 0, 1, 1.152 + 1, 0, 0, 0, 0, 1, 1.153 + 0, 1, 1, 1, 1, 0, 1.154 +*/ 1.155 +static unsigned char DIGIT_6 [] = 1.156 + { ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.157 + ON_5, 1.158 + ON_5, 1.159 + ON_4 | ON_3 | ON_2 | ON_1, 1.160 + ON_5 | ON_0, 1.161 + ON_5 | ON_0, 1.162 + ON_4 | ON_3 | ON_2 | ON_1, 1.163 + }; 1.164 + 1.165 +/* 1.166 + 1, 1, 1, 1, 1, 1, 1.167 + 0, 0, 0, 0, 0, 1, 1.168 + 0, 0, 0, 0, 1, 0, 1.169 + 0, 0, 0, 1, 0, 0, 1.170 + 0, 0, 1, 0, 0, 0, 1.171 + 0, 1, 0, 0, 0, 0, 1.172 + 1, 0, 0, 0, 0, 0 1.173 +*/ 1.174 +static unsigned char DIGIT_7 [] = 1.175 + { ON_5 | ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.176 + ON_0, 1.177 + ON_1, 1.178 + ON_2, 1.179 + ON_3, 1.180 + ON_4, 1.181 + ON_5 1.182 + }; 1.183 + 1.184 +/* 1.185 + 0, 1, 1, 1, 1, 1, 1.186 + 1, 0, 0, 0, 0, 1, 1.187 + 1, 0, 0, 0, 0, 1, 1.188 + 0, 1, 1, 1, 1, 0, 1.189 + 1, 0, 0, 0, 0, 1, 1.190 + 1, 0, 0, 0, 0, 1, 1.191 + 0, 1, 1, 1, 1, 0 1.192 +*/ 1.193 +static unsigned char DIGIT_8 [] = 1.194 + { ON_4 | ON_3 | ON_2 | ON_1, 1.195 + ON_5 | ON_0, 1.196 + ON_5 | ON_0, 1.197 + ON_4 | ON_3 | ON_2 | ON_1, 1.198 + ON_5 | ON_0, 1.199 + ON_5 | ON_0, 1.200 + ON_4 | ON_3 | ON_2 | ON_1, 1.201 + }; 1.202 + 1.203 +/* 1.204 + 0, 1, 1, 1, 1, 1, 1.205 + 1, 0, 0, 0, 0, 1, 1.206 + 1, 0, 0, 0, 0, 1, 1.207 + 0, 1, 1, 1, 1, 1, 1.208 + 0, 0, 0, 0, 0, 1, 1.209 + 0, 0, 0, 0, 0, 1, 1.210 + 0, 1, 1, 1, 1, 0 1.211 +*/ 1.212 +static unsigned char DIGIT_9 [] = 1.213 + { ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.214 + ON_5 | ON_0, 1.215 + ON_5 | ON_0, 1.216 + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, 1.217 + ON_0, 1.218 + ON_0, 1.219 + ON_4 | ON_3 | ON_2 | ON_1, 1.220 + }; 1.221 + 1.222 +static unsigned char *DIGITS[] = { 1.223 + DIGIT_0, 1.224 + DIGIT_1, 1.225 + DIGIT_2, 1.226 + DIGIT_3, 1.227 + DIGIT_4, 1.228 + DIGIT_5, 1.229 + DIGIT_6, 1.230 + DIGIT_7, 1.231 + DIGIT_8, 1.232 + DIGIT_9 1.233 +}; 1.234 + 1.235 + YuvStamper::YuvStamper(unsigned char* pYData, 1.236 + uint32_t width, 1.237 + uint32_t height, 1.238 + uint32_t stride, 1.239 + uint32_t x, 1.240 + uint32_t y, 1.241 + unsigned char symbol_width, 1.242 + unsigned char symbol_height): 1.243 + pYData(pYData), mStride(stride), 1.244 + mWidth(width), mHeight(height), 1.245 + mSymbolWidth(symbol_width), mSymbolHeight(symbol_height), 1.246 + mCursor(x, y) {} 1.247 + 1.248 + bool YuvStamper::Encode(uint32_t width, uint32_t height, uint32_t stride, 1.249 + unsigned char* pYData, unsigned char* pMsg, size_t msg_len, 1.250 + uint32_t x, uint32_t y) 1.251 + { 1.252 + YuvStamper stamper(pYData, width, height, stride, 1.253 + x, y, sBitSize, sBitSize); 1.254 + 1.255 + // Reserve space for a checksum. 1.256 + if (stamper.Capacity() < 8 * (msg_len + sizeof(uint32_t))) 1.257 + { 1.258 + return false; 1.259 + } 1.260 + 1.261 + bool ok = false; 1.262 + uint32_t crc; 1.263 + unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc); 1.264 + r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &crc); 1.265 + crc = htonl(crc); 1.266 + 1.267 + while (msg_len-- > 0) { 1.268 + if (!stamper.Write8(*pMsg++)) { 1.269 + return false; 1.270 + } 1.271 + } 1.272 + 1.273 + // Add checksum after the message. 1.274 + ok = stamper.Write8(*pCrc++) && 1.275 + stamper.Write8(*pCrc++) && 1.276 + stamper.Write8(*pCrc++) && 1.277 + stamper.Write8(*pCrc++); 1.278 + 1.279 + return ok; 1.280 + } 1.281 + 1.282 + bool YuvStamper::Decode(uint32_t width, uint32_t height, uint32_t stride, 1.283 + unsigned char* pYData, unsigned char* pMsg, size_t msg_len, 1.284 + uint32_t x, uint32_t y) 1.285 + { 1.286 + YuvStamper stamper(pYData, width, height, stride, 1.287 + x, y, sBitSize, sBitSize); 1.288 + 1.289 + unsigned char* ptr = pMsg; 1.290 + size_t len = msg_len; 1.291 + uint32_t crc, msg_crc; 1.292 + unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc); 1.293 + 1.294 + // Account for space reserved for the checksum 1.295 + if (stamper.Capacity() < 8 * (len + sizeof(uint32_t))) { 1.296 + return false; 1.297 + } 1.298 + 1.299 + while (len-- > 0) { 1.300 + if(!stamper.Read8(*ptr++)) { 1.301 + return false; 1.302 + } 1.303 + } 1.304 + 1.305 + if (!(stamper.Read8(*pCrc++) && 1.306 + stamper.Read8(*pCrc++) && 1.307 + stamper.Read8(*pCrc++) && 1.308 + stamper.Read8(*pCrc++))) { 1.309 + return false; 1.310 + } 1.311 + 1.312 + r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &msg_crc); 1.313 + return crc == htonl(msg_crc); 1.314 + } 1.315 + 1.316 + inline uint32_t YuvStamper::Capacity() 1.317 + { 1.318 + // Enforce at least a symbol width and height offset from outer edges. 1.319 + if (mCursor.y + mSymbolHeight > mHeight) { 1.320 + return 0; 1.321 + } 1.322 + 1.323 + if (mCursor.x + mSymbolWidth > mWidth && !AdvanceCursor()) { 1.324 + return 0; 1.325 + } 1.326 + 1.327 + // Normalize frame integral to mSymbolWidth x mSymbolHeight 1.328 + uint32_t width = mWidth / mSymbolWidth; 1.329 + uint32_t height = mHeight / mSymbolHeight; 1.330 + uint32_t x = mCursor.x / mSymbolWidth; 1.331 + uint32_t y = mCursor.y / mSymbolHeight; 1.332 + 1.333 + return (width * height - width * y)- x; 1.334 + } 1.335 + 1.336 + bool YuvStamper::Write8(unsigned char value) 1.337 + { 1.338 + // Encode MSB to LSB. 1.339 + unsigned char mask = 0x80; 1.340 + while (mask) { 1.341 + if (!WriteBit(!!(value & mask))) { 1.342 + return false; 1.343 + } 1.344 + mask >>= 1; 1.345 + } 1.346 + return true; 1.347 + } 1.348 + 1.349 + bool YuvStamper::WriteBit(bool one) 1.350 + { 1.351 + // A bit is mapped to a mSymbolWidth x mSymbolHeight square of luma data points. 1.352 + // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708 1.353 + unsigned char value; 1.354 + if (one) 1.355 + value = sYOn; 1.356 + else 1.357 + value = sYOff; 1.358 + 1.359 + for (uint32_t y = 0; y < mSymbolHeight; y++) { 1.360 + for (uint32_t x = 0; x < mSymbolWidth; x++) { 1.361 + *(pYData + (mCursor.x + x) + ((mCursor.y + y) * mStride)) = value; 1.362 + } 1.363 + } 1.364 + 1.365 + return AdvanceCursor(); 1.366 + } 1.367 + 1.368 + bool YuvStamper::AdvanceCursor() 1.369 + { 1.370 + mCursor.x += mSymbolWidth; 1.371 + if (mCursor.x + mSymbolWidth > mWidth) { 1.372 + // move to the start of the next row if possible. 1.373 + mCursor.y += mSymbolHeight; 1.374 + if (mCursor.y + mSymbolHeight > mHeight) { 1.375 + // end of frame, do not advance 1.376 + mCursor.y -= mSymbolHeight; 1.377 + mCursor.x -= mSymbolWidth; 1.378 + return false; 1.379 + } else { 1.380 + mCursor.x = 0; 1.381 + } 1.382 + } 1.383 + 1.384 + return true; 1.385 + } 1.386 + 1.387 + bool YuvStamper::Read8(unsigned char &value) 1.388 + { 1.389 + unsigned char octet = 0; 1.390 + unsigned char bit = 0; 1.391 + 1.392 + for (int i = 8; i > 0; --i) { 1.393 + if (!ReadBit(bit)) { 1.394 + return false; 1.395 + } 1.396 + octet <<= 1; 1.397 + octet |= bit; 1.398 + } 1.399 + 1.400 + value = octet; 1.401 + return true; 1.402 + } 1.403 + 1.404 + bool YuvStamper::ReadBit(unsigned char &bit) 1.405 + { 1.406 + uint32_t sum = 0; 1.407 + for (uint32_t y = 0; y < mSymbolHeight; y++) { 1.408 + for (uint32_t x = 0; x < mSymbolWidth; x++) { 1.409 + sum += *(pYData + mStride * (mCursor.y + y) + mCursor.x + x); 1.410 + } 1.411 + } 1.412 + 1.413 + // apply threshold to collected bit square 1.414 + bit = (sum > (sBitThreshold * mSymbolWidth * mSymbolHeight)) ? 1 : 0; 1.415 + return AdvanceCursor(); 1.416 + } 1.417 + 1.418 + bool YuvStamper::WriteDigits(uint32_t value) 1.419 + { 1.420 + char buf[20]; 1.421 + PR_snprintf(buf, sizeof(buf), "%.5u", value); 1.422 + size_t size = strlen(buf); 1.423 + 1.424 + if (Capacity() < size) { 1.425 + return false; 1.426 + } 1.427 + 1.428 + for (size_t i=0; i < size; ++i) { 1.429 + if (!WriteDigit(buf[i] - '0')) 1.430 + return false; 1.431 + if (!AdvanceCursor()) { 1.432 + return false; 1.433 + } 1.434 + } 1.435 + 1.436 + return true; 1.437 + } 1.438 + 1.439 + bool YuvStamper::WriteDigit(unsigned char digit) { 1.440 + if (digit > sizeof(DIGITS)/sizeof(DIGITS[0])) 1.441 + return false; 1.442 + 1.443 + unsigned char *dig = DIGITS[digit]; 1.444 + for (uint32_t row = 0; row < sDigitHeight; ++row) { 1.445 + unsigned char mask = 0x01 << (sDigitWidth - 1); 1.446 + for (uint32_t col = 0; col < sDigitWidth; ++col, mask >>= 1) { 1.447 + if (dig[row] & mask) { 1.448 + for (uint32_t xx=0; xx < sPixelSize; ++xx) { 1.449 + for (uint32_t yy=0; yy < sPixelSize; ++yy) { 1.450 + WritePixel(pYData, 1.451 + mCursor.x + (col * sPixelSize) + xx, 1.452 + mCursor.y + (row * sPixelSize) + yy); 1.453 + } 1.454 + } 1.455 + } 1.456 + } 1.457 + } 1.458 + 1.459 + return true; 1.460 + } 1.461 + 1.462 + void YuvStamper::WritePixel(unsigned char *data, uint32_t x, uint32_t y) { 1.463 + unsigned char *ptr = &data[y * mStride + x]; 1.464 + // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708 1.465 + if (*ptr > sLumaThreshold) 1.466 + *ptr = sLumaMin; 1.467 + else 1.468 + *ptr = sLumaMax; 1.469 + } 1.470 + 1.471 +} // Namespace mozilla.