From 8dc11ae04aab8c92feabacf4e3c9d12b26931e22 Mon Sep 17 00:00:00 2001 From: "Paul Kerr [:pkerr]" Date: Thu, 24 Apr 2014 19:58:21 -0700 Subject: [PATCH] Bug 970691 - Part 2: Restore digit stamping function to YuvStamper. r=jesup Refactor digit writing method to use the new internals. Allows digit string to wrap through multiple lines in a small frame. --- .../signaling/src/common/YuvStamper.cpp | 317 ++++++++++++++++-- .../webrtc/signaling/src/common/YuvStamper.h | 38 ++- 2 files changed, 326 insertions(+), 29 deletions(-) diff --git a/media/webrtc/signaling/src/common/YuvStamper.cpp b/media/webrtc/signaling/src/common/YuvStamper.cpp index 4359880dbd8a..7c0824f1a01b 100644 --- a/media/webrtc/signaling/src/common/YuvStamper.cpp +++ b/media/webrtc/signaling/src/common/YuvStamper.cpp @@ -7,7 +7,9 @@ #elif defined XP_WIN #include #endif +#include +#include "nspr.h" #include "YuvStamper.h" typedef uint32_t UINT4; //Needed for r_crc32() call @@ -17,21 +19,235 @@ extern "C" { 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): + 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); + YuvStamper stamper(pYData, width, height, stride, + x, y, sBitSize, sBitSize); // Reserve space for a checksum. if (stamper.Capacity() < 8 * (msg_len + sizeof(uint32_t))) @@ -41,7 +257,7 @@ namespace mozilla { bool ok = false; uint32_t crc; - uint8_t* pCrc = reinterpret_cast(&crc); + unsigned char* pCrc = reinterpret_cast(&crc); r_crc32(reinterpret_cast(pMsg), (int)msg_len, &crc); crc = htonl(crc); @@ -64,7 +280,9 @@ namespace mozilla { unsigned char* pYData, unsigned char* pMsg, size_t msg_len, uint32_t x, uint32_t y) { - YuvStamper stamper(pYData, width, height, stride, x, 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; @@ -95,19 +313,19 @@ namespace mozilla { inline uint32_t YuvStamper::Capacity() { // Enforce at least a symbol width and height offset from outer edges. - if (mCursor.y + sBitSize > mHeight) { + if (mCursor.y + mSymbolHeight > mHeight) { return 0; } - if (mCursor.x + sBitSize > mWidth && !AdvanceCursor()) { + if (mCursor.x + mSymbolWidth > mWidth && !AdvanceCursor()) { return 0; } - // Normalize frame integral to sBitSize x sBitSize - uint32_t width = mWidth / sBitSize; - uint32_t height = mHeight / sBitSize; - uint32_t x = mCursor.x / sBitSize; - uint32_t y = mCursor.y / sBitSize; + // 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; } @@ -127,10 +345,10 @@ namespace mozilla { bool YuvStamper::WriteBit(bool one) { - // A bit is mapped to a sBitSize x sBitSize square of luma data points. + // A bit is mapped to a mSymbolWidth x mSymbolHeight square of luma data points. unsigned char value = one ? sYOn : sYOff; - for (uint32_t y = 0; y < sBitSize; y++) { - for (uint32_t x = 0; x < sBitSize; x++) { + 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; } } @@ -140,14 +358,14 @@ namespace mozilla { bool YuvStamper::AdvanceCursor() { - mCursor.x += sBitSize; - if (mCursor.x + sBitSize > mWidth) { + mCursor.x += mSymbolWidth; + if (mCursor.x + mSymbolWidth > mWidth) { // move to the start of the next row if possible. - mCursor.y += sBitSize; - if (mCursor.y + sBitSize > mHeight) { + mCursor.y += mSymbolHeight; + if (mCursor.y + mSymbolHeight > mHeight) { // end of frame, do not advance - mCursor.y -= sBitSize; - mCursor.x -= sBitSize; + mCursor.y -= mSymbolHeight; + mCursor.x -= mSymbolWidth; return false; } else { mCursor.x = 0; @@ -157,7 +375,8 @@ namespace mozilla { return true; } - bool YuvStamper::Read8(unsigned char &value) { + bool YuvStamper::Read8(unsigned char &value) + { unsigned char octet = 0; unsigned char bit = 0; @@ -176,15 +395,65 @@ namespace mozilla { bool YuvStamper::ReadBit(unsigned char &bit) { uint32_t sum = 0; - for (uint32_t y = 0; y < sBitSize; y++) { - for (uint32_t x = 0; x < sBitSize; x++) { + 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 * sBitSize * sBitSize)) ? 1 : 0; + bit = (sum > (sBitThreshold * mSymbolWidth * mSymbolHeight)) ? 1 : 0; return AdvanceCursor(); } + bool YuvStamper::WriteDigits(uint32_t value) + { + char buf[20]; + PR_snprintf(buf, sizeof(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]; + *ptr = (*ptr > sLumaThreshold) ? sLumaMin : sLumaMax; + return; + } + } // Namespace mozilla. diff --git a/media/webrtc/signaling/src/common/YuvStamper.h b/media/webrtc/signaling/src/common/YuvStamper.h index 54a8d2454877..fb2d6e466440 100644 --- a/media/webrtc/signaling/src/common/YuvStamper.h +++ b/media/webrtc/signaling/src/common/YuvStamper.h @@ -12,18 +12,36 @@ namespace mozilla { class YuvStamper { public: - YuvStamper(unsigned char* pYData, - uint32_t width, uint32_t height, uint32_t stride, - uint32_t x = 0, uint32_t y = 0); + bool WriteDigits(uint32_t value); + + template + static bool Write(uint32_t width, uint32_t height, uint32_t stride, + unsigned char *pYData, const T& value, + uint32_t x=0, uint32_t y=0) + { + YuvStamper stamper(pYData, width, height, stride, + x, y, + (sDigitWidth + sInterDigit) * sPixelSize, + (sDigitHeight + sInterLine) * sPixelSize); + return stamper.WriteDigits(value); + } + static bool 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); + uint32_t x = 0, uint32_t y = 0); static bool 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); + uint32_t x = 0, uint32_t y = 0); private: + 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); + + bool WriteDigit(unsigned char digit); + void WritePixel(unsigned char* data, uint32_t x, uint32_t y); uint32_t Capacity(); bool AdvanceCursor(); bool WriteBit(bool one); @@ -31,15 +49,25 @@ public: bool ReadBit(unsigned char &value); bool Read8(unsigned char &bit); + const static unsigned char sPixelSize = 3; + const static unsigned char sDigitWidth = 6; + const static unsigned char sDigitHeight = 7; + const static unsigned char sInterDigit = 1; + const static unsigned char sInterLine = 1; const static uint32_t sBitSize = 4; const static uint32_t sBitThreshold = 60; const static unsigned char sYOn = 0x80; const static unsigned char sYOff = 0; + const static unsigned char sLumaThreshold = 96; + const static unsigned char sLumaMin = 16; + const static unsigned char sLumaMax = 235; unsigned char* pYData; uint32_t mStride; uint32_t mWidth; uint32_t mHeight; + unsigned char mSymbolWidth; + unsigned char mSymbolHeight; struct Cursor { Cursor(uint32_t x, uint32_t y):