summaryrefslogtreecommitdiffstats
path: root/media/webrtc/signaling/src/common/YuvStamper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/webrtc/signaling/src/common/YuvStamper.cpp')
-rw-r--r--media/webrtc/signaling/src/common/YuvStamper.cpp469
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.