diff options
Diffstat (limited to 'media/webrtc/signaling/src/common/YuvStamper.cpp')
-rw-r--r-- | media/webrtc/signaling/src/common/YuvStamper.cpp | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/media/webrtc/signaling/src/common/YuvStamper.cpp b/media/webrtc/signaling/src/common/YuvStamper.cpp new file mode 100644 index 000000000..892b640bf --- /dev/null +++ b/media/webrtc/signaling/src/common/YuvStamper.cpp @@ -0,0 +1,469 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#elif defined XP_WIN +#include <winsock2.h> +#endif +#include <string.h> + +#include "nspr.h" +#include "YuvStamper.h" +#include "mozilla/Sprintf.h" + +typedef uint32_t UINT4; //Needed for r_crc32() call +extern "C" { +#include "r_crc32.h" +} + +namespace mozilla { + +#define ON_5 0x20 +#define ON_4 0x10 +#define ON_3 0x08 +#define ON_2 0x04 +#define ON_1 0x02 +#define ON_0 0x01 + +/* + 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, + 0, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0 +*/ +static unsigned char DIGIT_0 [] = + { ON_3 | ON_2, + ON_4 | ON_1, + ON_5 | ON_0, + ON_5 | ON_0, + ON_5 | ON_0, + ON_4 | ON_1, + ON_3 | ON_2 + }; + +/* + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, +*/ +static unsigned char DIGIT_1 [] = + { ON_2, + ON_2, + ON_2, + ON_2, + ON_2, + ON_2, + ON_2 + }; + +/* + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, +*/ +static unsigned char DIGIT_2 [] = + { ON_5 | ON_4 | ON_3 | ON_2 | ON_1, + ON_0, + ON_0, + ON_4 | ON_3 | ON_2 | ON_1, + ON_5, + ON_5, + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + }; + +/* + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 0, +*/ +static unsigned char DIGIT_3 [] = + { ON_5 | ON_4 | ON_3 | ON_2 | ON_1, + ON_0, + ON_0, + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + ON_0, + ON_0, + ON_5 | ON_4 | ON_3 | ON_2 | ON_1, + }; + +/* + 0, 1, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1 +*/ +static unsigned char DIGIT_4 [] = + { ON_4 | ON_0, + ON_4 | ON_0, + ON_4 | ON_0, + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + ON_0, + ON_0, + ON_0, + }; + +/* + 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 0, +*/ +static unsigned char DIGIT_5 [] = + { ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + ON_5, + ON_5, + ON_4 | ON_3 | ON_2 | ON_1, + ON_0, + ON_0, + ON_5 | ON_4 | ON_3 | ON_2 | ON_1, + }; + +/* + 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 0, +*/ +static unsigned char DIGIT_6 [] = + { ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + ON_5, + ON_5, + ON_4 | ON_3 | ON_2 | ON_1, + ON_5 | ON_0, + ON_5 | ON_0, + ON_4 | ON_3 | ON_2 | ON_1, + }; + +/* + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0 +*/ +static unsigned char DIGIT_7 [] = + { ON_5 | ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + ON_0, + ON_1, + ON_2, + ON_3, + ON_4, + ON_5 + }; + +/* + 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 0 +*/ +static unsigned char DIGIT_8 [] = + { ON_4 | ON_3 | ON_2 | ON_1, + ON_5 | ON_0, + ON_5 | ON_0, + ON_4 | ON_3 | ON_2 | ON_1, + ON_5 | ON_0, + ON_5 | ON_0, + ON_4 | ON_3 | ON_2 | ON_1, + }; + +/* + 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 0 +*/ +static unsigned char DIGIT_9 [] = + { ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + ON_5 | ON_0, + ON_5 | ON_0, + ON_4 | ON_3 | ON_2 | ON_1 | ON_0, + ON_0, + ON_0, + ON_4 | ON_3 | ON_2 | ON_1, + }; + +static unsigned char *DIGITS[] = { + DIGIT_0, + DIGIT_1, + DIGIT_2, + DIGIT_3, + DIGIT_4, + DIGIT_5, + DIGIT_6, + DIGIT_7, + DIGIT_8, + DIGIT_9 +}; + + YuvStamper::YuvStamper(unsigned char* pYData, + uint32_t width, + uint32_t height, + uint32_t stride, + uint32_t x, + uint32_t y, + unsigned char symbol_width, + unsigned char symbol_height): + pYData(pYData), mStride(stride), + mWidth(width), mHeight(height), + mSymbolWidth(symbol_width), mSymbolHeight(symbol_height), + mCursor(x, y) {} + + bool YuvStamper::Encode(uint32_t width, uint32_t height, uint32_t stride, + unsigned char* pYData, unsigned char* pMsg, size_t msg_len, + uint32_t x, uint32_t y) + { + YuvStamper stamper(pYData, width, height, stride, + x, y, sBitSize, sBitSize); + + // Reserve space for a checksum. + if (stamper.Capacity() < 8 * (msg_len + sizeof(uint32_t))) + { + return false; + } + + bool ok = false; + uint32_t crc; + unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc); + r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &crc); + crc = htonl(crc); + + while (msg_len-- > 0) { + if (!stamper.Write8(*pMsg++)) { + return false; + } + } + + // Add checksum after the message. + ok = stamper.Write8(*pCrc++) && + stamper.Write8(*pCrc++) && + stamper.Write8(*pCrc++) && + stamper.Write8(*pCrc++); + + return ok; + } + + bool YuvStamper::Decode(uint32_t width, uint32_t height, uint32_t stride, + unsigned char* pYData, unsigned char* pMsg, size_t msg_len, + uint32_t x, uint32_t y) + { + YuvStamper stamper(pYData, width, height, stride, + x, y, sBitSize, sBitSize); + + unsigned char* ptr = pMsg; + size_t len = msg_len; + uint32_t crc, msg_crc; + unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc); + + // Account for space reserved for the checksum + if (stamper.Capacity() < 8 * (len + sizeof(uint32_t))) { + return false; + } + + while (len-- > 0) { + if(!stamper.Read8(*ptr++)) { + return false; + } + } + + if (!(stamper.Read8(*pCrc++) && + stamper.Read8(*pCrc++) && + stamper.Read8(*pCrc++) && + stamper.Read8(*pCrc++))) { + return false; + } + + r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &msg_crc); + return crc == htonl(msg_crc); + } + + inline uint32_t YuvStamper::Capacity() + { + // Enforce at least a symbol width and height offset from outer edges. + if (mCursor.y + mSymbolHeight > mHeight) { + return 0; + } + + if (mCursor.x + mSymbolWidth > mWidth && !AdvanceCursor()) { + return 0; + } + + // Normalize frame integral to mSymbolWidth x mSymbolHeight + uint32_t width = mWidth / mSymbolWidth; + uint32_t height = mHeight / mSymbolHeight; + uint32_t x = mCursor.x / mSymbolWidth; + uint32_t y = mCursor.y / mSymbolHeight; + + return (width * height - width * y)- x; + } + + bool YuvStamper::Write8(unsigned char value) + { + // Encode MSB to LSB. + unsigned char mask = 0x80; + while (mask) { + if (!WriteBit(!!(value & mask))) { + return false; + } + mask >>= 1; + } + return true; + } + + bool YuvStamper::WriteBit(bool one) + { + // A bit is mapped to a mSymbolWidth x mSymbolHeight square of luma data points. + // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708 + unsigned char value; + if (one) + value = sYOn; + else + value = sYOff; + + for (uint32_t y = 0; y < mSymbolHeight; y++) { + for (uint32_t x = 0; x < mSymbolWidth; x++) { + *(pYData + (mCursor.x + x) + ((mCursor.y + y) * mStride)) = value; + } + } + + return AdvanceCursor(); + } + + bool YuvStamper::AdvanceCursor() + { + mCursor.x += mSymbolWidth; + if (mCursor.x + mSymbolWidth > mWidth) { + // move to the start of the next row if possible. + mCursor.y += mSymbolHeight; + if (mCursor.y + mSymbolHeight > mHeight) { + // end of frame, do not advance + mCursor.y -= mSymbolHeight; + mCursor.x -= mSymbolWidth; + return false; + } else { + mCursor.x = 0; + } + } + + return true; + } + + bool YuvStamper::Read8(unsigned char &value) + { + unsigned char octet = 0; + unsigned char bit = 0; + + for (int i = 8; i > 0; --i) { + if (!ReadBit(bit)) { + return false; + } + octet <<= 1; + octet |= bit; + } + + value = octet; + return true; + } + + bool YuvStamper::ReadBit(unsigned char &bit) + { + uint32_t sum = 0; + for (uint32_t y = 0; y < mSymbolHeight; y++) { + for (uint32_t x = 0; x < mSymbolWidth; x++) { + sum += *(pYData + mStride * (mCursor.y + y) + mCursor.x + x); + } + } + + // apply threshold to collected bit square + bit = (sum > (sBitThreshold * mSymbolWidth * mSymbolHeight)) ? 1 : 0; + return AdvanceCursor(); + } + + bool YuvStamper::WriteDigits(uint32_t value) + { + char buf[20]; + SprintfLiteral(buf, "%.5u", value); + size_t size = strlen(buf); + + if (Capacity() < size) { + return false; + } + + for (size_t i=0; i < size; ++i) { + if (!WriteDigit(buf[i] - '0')) + return false; + if (!AdvanceCursor()) { + return false; + } + } + + return true; + } + + bool YuvStamper::WriteDigit(unsigned char digit) { + if (digit > sizeof(DIGITS)/sizeof(DIGITS[0])) + return false; + + unsigned char *dig = DIGITS[digit]; + for (uint32_t row = 0; row < sDigitHeight; ++row) { + unsigned char mask = 0x01 << (sDigitWidth - 1); + for (uint32_t col = 0; col < sDigitWidth; ++col, mask >>= 1) { + if (dig[row] & mask) { + for (uint32_t xx=0; xx < sPixelSize; ++xx) { + for (uint32_t yy=0; yy < sPixelSize; ++yy) { + WritePixel(pYData, + mCursor.x + (col * sPixelSize) + xx, + mCursor.y + (row * sPixelSize) + yy); + } + } + } + } + } + + return true; + } + + void YuvStamper::WritePixel(unsigned char *data, uint32_t x, uint32_t y) { + unsigned char *ptr = &data[y * mStride + x]; + // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708 + if (*ptr > sLumaThreshold) + *ptr = sLumaMin; + else + *ptr = sLumaMax; + } + +} // namespace mozilla. |