media/webrtc/signaling/src/common/YuvStamper.cpp

changeset 0
6474c204b198
     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.

mercurial