Bug 970691 - Part2: Restore digit stamping function to YuvStamper. r=jesup
☠☠ backed out by d8014e46546e ☠ ☠
authorPaul Kerr [:pkerr] <paulrkerr@gmail.com>
Wed, 23 Apr 2014 10:03:18 -0700
changeset 199393 83f7aec5a083650f8cba8701c577cfb6502fcfea
parent 199392 94348d189ed5b93f8494f01467d18ca55262a9f3
child 199394 972268fe6a0dc06f3e09d29ba61a5370e6ed7577
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs970691
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 970691 - Part2: 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.
media/webrtc/signaling/src/media-conduit/YuvStamper.cpp
media/webrtc/signaling/src/media-conduit/YuvStamper.h
--- a/media/webrtc/signaling/src/media-conduit/YuvStamper.cpp
+++ b/media/webrtc/signaling/src/media-conduit/YuvStamper.cpp
@@ -3,40 +3,255 @@
  * 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 "nspr.h"
 #include "YuvStamper.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(uint8_t* pYData,
 			 uint32_t width,
 			 uint32_t height,
 			 uint32_t stride,
 			 uint32_t x,
-			 uint32_t y):
+			 uint32_t y,
+			 uint8_t symbol_width,
+			 uint8_t 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,
 			  uint8_t* pYData, uint8_t* 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)))
     {
       return false;
     }
 
     bool ok = false;
@@ -59,17 +274,19 @@ namespace mozilla {
 
     return ok;
   }
 
   bool YuvStamper::Decode(uint32_t width, uint32_t height, uint32_t stride,
 			  uint8_t* pYData, uint8_t* 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);
+
     uint8_t* ptr = pMsg;
     size_t len = msg_len;
     uint32_t crc, msg_crc;
     uint8_t* pCrc = reinterpret_cast<uint8_t*>(&crc);
 
     // Account for space reserved for the checksum
     if (stamper.Capacity() < 8 * (len + sizeof(uint32_t))) {
       return false;
@@ -90,29 +307,29 @@ namespace mozilla {
 
     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 + 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;
+    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(uint8_t value)
   {
     // Encode MSB to LSB.
     uint8_t mask = 0x80;
@@ -124,45 +341,46 @@ namespace mozilla {
     }
     return true;
   }
 
   bool YuvStamper::WriteBit(bool one)
   {
     // A bit is mapped to a sBitSize x sBitSize square of luma data points.
     uint8_t 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;
       }
     }
 
     return AdvanceCursor();
   }
 
   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;
       }
     }
 
     return true;
   }
 
-  bool YuvStamper::Read8(uint8_t &value) {
+  bool YuvStamper::Read8(uint8_t &value)
+  {
     uint8_t octet = 0;
     uint8_t bit = 0;
 
     for (int i = 8; i > 0; --i) {
       if (!ReadBit(bit)) {
 	return false;
       }
       octet <<= 1;
@@ -171,20 +389,70 @@ namespace mozilla {
 
     value = octet;
     return true;
   }
 
   bool YuvStamper::ReadBit(uint8_t &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(uint8_t 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(uint8_t *data, uint32_t x, uint32_t y) {
+    uint8_t *ptr = &data[y * mStride + x];
+    *ptr = (*ptr > sLumaThreshold) ? sLumaMin : sLumaMax;
+    return;
+   }
+
 }  // Namespace mozilla.
--- a/media/webrtc/signaling/src/media-conduit/YuvStamper.h
+++ b/media/webrtc/signaling/src/media-conduit/YuvStamper.h
@@ -2,44 +2,73 @@
  * 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/. */
 
 namespace mozilla {
 
 class
 YuvStamper {
 public:
-  YuvStamper(uint8_t* pYData,
-	     uint32_t width, uint32_t height, uint32_t stride,
-	     uint32_t x = 0, uint32_t y = 0);
+  bool WriteDigits(uint32_t value);
+
+  template<typename T>
+  static bool Write(uint32_t width, uint32_t height, uint32_t stride,
+                    uint8_t *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,
 		     uint8_t* pYData, uint8_t* 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,
 		     uint8_t* pYData, uint8_t* pMsg, size_t msg_len,
-		     uint32_t x, uint32_t y);
+		     uint32_t x = 0, uint32_t y = 0);
 
  private:
+  YuvStamper(uint8_t* pYData,
+	     uint32_t width, uint32_t height, uint32_t stride,
+	     uint32_t x, uint32_t y,
+	     uint8_t symbol_width, uint8_t symbol_height);
+
+  bool WriteDigit(uint8_t digit);
+  void WritePixel(uint8_t* data, uint32_t x, uint32_t y);
+
   uint32_t Capacity();
   bool AdvanceCursor();
   bool WriteBit(bool one);
   bool Write8(uint8_t value);
   bool ReadBit(uint8_t &value);
   bool Read8(uint8_t &bit);
 
+  const static uint8_t sPixelSize = 3;
+  const static uint8_t sDigitWidth = 6;
+  const static uint8_t sDigitHeight = 7;
+  const static uint8_t sInterDigit = 1;
+  const static uint8_t sInterLine = 1;
   const static uint32_t sBitSize = 4;
   const static uint32_t sBitThreshold = 60;
   const static uint8_t sYOn = 0x80;
   const static uint8_t sYOff = 0;
+  const static uint8_t sLumaThreshold = 96;
+  const static uint8_t sLumaMin = 16;
+  const static uint8_t sLumaMax = 235;
 
   uint8_t* pYData;
   uint32_t mStride;
   uint32_t mWidth;
   uint32_t mHeight;
+  uint8_t mSymbolWidth;
+  uint8_t mSymbolHeight;
 
   struct Cursor {
     Cursor(uint32_t x, uint32_t y):
       x(x), y(y) {}
     uint32_t x;
     uint32_t y;
   } mCursor;
 };