1 #include "talk/media/base/yuvframegenerator.h" 2 3 #include <string.h> 4 #include <sstream> 5 6 #include "talk/base/basictypes.h" 7 #include "talk/base/common.h" 8 9 namespace cricket { 10 11 // These values were figured out by trial and error. If you change any 12 // basic parameters e.g. unit-bar size or bars-x-offset, you may need to change 13 // background-width/background-height. 14 const int kBarcodeBackgroundWidth = 160; 15 const int kBarcodeBackgroundHeight = 100; 16 const int kBarsXOffset = 12; 17 const int kBarsYOffset = 4; 18 const int kUnitBarSize = 2; 19 const int kBarcodeNormalBarHeight = 80; 20 const int kBarcodeGuardBarHeight = 96; 21 const int kBarcodeMaxEncodableDigits = 7; 22 23 YuvFrameGenerator::YuvFrameGenerator(int width, int height, 24 bool enable_barcode) { 25 width_ = width; 26 height_ = height; 27 frame_index_ = 0; 28 int size = width_ * height_; 29 int qsize = size / 4; 30 frame_data_size_ = size + 2 * qsize; 31 y_data_ = new uint8[size]; 32 u_data_ = new uint8[qsize]; 33 v_data_ = new uint8[qsize]; 34 if (enable_barcode) { 35 ASSERT(width_ >= kBarcodeBackgroundWidth); 36 ASSERT(height_>= kBarcodeBackgroundHeight); 37 barcode_start_x_ = 0; 38 barcode_start_y_ = height_ - kBarcodeBackgroundHeight; 39 } else { 40 barcode_start_x_ = -1; 41 barcode_start_y_ = -1; 42 } 43 } 44 45 YuvFrameGenerator::~YuvFrameGenerator() { 46 delete y_data_; 47 delete u_data_; 48 delete v_data_; 49 } 50 51 void YuvFrameGenerator::GenerateNextFrame(uint8* frame_buffer, 52 int32 barcode_value) { 53 int size = width_ * height_; 54 int qsize = size / 4; 55 memset(y_data_, 0, size); 56 memset(u_data_, 0, qsize); 57 memset(v_data_, 0, qsize); 58 59 DrawLandscape(y_data_, width_, height_); 60 DrawGradientX(u_data_, width_/2, height_/2); 61 DrawGradientY(v_data_, width_/2, height_/2); 62 DrawMovingLineX(u_data_, width_/2, height_/2, frame_index_); 63 DrawMovingLineY(v_data_, width_/2, height_/2, frame_index_); 64 DrawBouncingCube(y_data_, width_, height_, frame_index_); 65 66 if (barcode_value >= 0) { 67 ASSERT(barcode_start_x_ != -1); 68 DrawBarcode(barcode_value); 69 } 70 71 memcpy(frame_buffer, y_data_, size); 72 frame_buffer += size; 73 memcpy(frame_buffer, u_data_, qsize); 74 frame_buffer += qsize; 75 memcpy(frame_buffer, v_data_, qsize); 76 77 frame_index_ = (frame_index_ + 1) & 0x0000FFFF; 78 } 79 80 void YuvFrameGenerator::DrawLandscape(uint8 *p, int w, int h) { 81 int x, y; 82 for (y = 0; y < h; y++) { 83 for (x = 0; x < w; x++) { 84 p[x + y * w] = x % (y+1); 85 if (((x > w / 2 - (w / 32)) && (x < w / 2 + (w / 32))) || 86 ((y > h / 2 - (h / 32)) && (y < h / 2 + (h / 32)))) { 87 p[x + y * w] = (((x + y) / 8 % 2)) ? 255 : 0; 88 } 89 } 90 } 91 } 92 93 void YuvFrameGenerator::DrawGradientX(uint8 *p, int w, int h) { 94 int x, y; 95 for (y = 0; y < h; y++) { 96 for (x = 0; x < w; x++) { 97 p[x + y * w] = (x << 8) / w; 98 } 99 } 100 } 101 102 void YuvFrameGenerator::DrawGradientY(uint8 *p, int w, int h) { 103 int x, y; 104 for (y = 0; y < h; y++) { 105 for (x = 0; x < w; x++) { 106 p[x + y * w] = (y << 8) / h; 107 } 108 } 109 } 110 111 void YuvFrameGenerator::DrawMovingLineX(uint8 *p, int w, int h, int n) { 112 int x, y; 113 x = n % (w * 2); 114 if (x >= w) x = w + w - x - 1; 115 for (y = 0; y < h; y++) { 116 p[x + y * w] = 255; 117 } 118 } 119 120 void YuvFrameGenerator::DrawMovingLineY(uint8 *p, int w, int h, int n) { 121 int x, y; 122 y = n % (h * 2); 123 if (y >= h) y = h + h - y - 1; 124 for (x = 0; x < w; x++) { 125 p[x + y * w] = 255; 126 } 127 } 128 129 void YuvFrameGenerator::DrawBouncingCube(uint8 *p, int w, int h, int n) { 130 int x, y, pw, ph, px, py; 131 pw = w / 16; 132 ph = h / 16; 133 px = n % (w * 2); 134 py = n % (h * 2); 135 if (px >= w) px = w + w - px - 1; 136 if (py >= h) py = h + h - py - 1; 137 for (y = py - ph; y < py + ph; y++) { 138 if (y >=0 && y < h) { 139 for (x = px - pw; x < px + pw; x++) { 140 if (x >= 0 && x < w) { 141 p[x + y * w] = 255; 142 } 143 } 144 } 145 } 146 } 147 148 void YuvFrameGenerator::GetBarcodeBounds(int* top, int* left, 149 int* width, int* height) { 150 ASSERT(barcode_start_x_ != -1); 151 *top = barcode_start_y_; 152 *left = barcode_start_x_; 153 *width = kBarcodeBackgroundWidth; 154 *height = kBarcodeBackgroundHeight; 155 } 156 157 static void ComputeBarcodeDigits(uint32 value, std::stringstream* result) { 158 // Serialize |value| as 7-char string, padded with 0's to the left. 159 result->width(kBarcodeMaxEncodableDigits); 160 result->fill('0'); 161 *result << value; 162 163 // Compute check-digit and append to result. Steps described here: 164 // http://en.wikipedia.org/wiki/European_Article_Number#Calculation_of_checksum_digit 165 int sum = 0; 166 for (int pos = 1; pos <= kBarcodeMaxEncodableDigits; pos++) { 167 char next_char; 168 result->get(next_char); 169 uint8 digit = next_char - '0'; 170 sum += digit * (pos % 2 ? 3 : 1); 171 } 172 uint8 check_digit = sum % 10; 173 if (check_digit != 0) { 174 check_digit = 10 - check_digit; 175 } 176 177 *result << static_cast<int>(check_digit); 178 result->seekg(0); 179 } 180 181 void YuvFrameGenerator::DrawBarcode(uint32 value) { 182 std::stringstream value_str_stream; 183 ComputeBarcodeDigits(value, &value_str_stream); 184 185 // Draw white filled rectangle as background to barcode. 186 DrawBlockRectangle(y_data_, barcode_start_x_, barcode_start_y_, 187 kBarcodeBackgroundWidth, kBarcodeBackgroundHeight, 188 width_, 255); 189 DrawBlockRectangle(u_data_, barcode_start_x_ / 2, barcode_start_y_ / 2, 190 kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2, 191 width_ / 2, 128); 192 DrawBlockRectangle(v_data_, barcode_start_x_ / 2, barcode_start_y_ / 2, 193 kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2, 194 width_ / 2, 128); 195 196 // Scan through chars (digits) and draw black bars. 197 int x = barcode_start_x_ + kBarsXOffset; 198 int y = barcode_start_y_ + kBarsYOffset; 199 int pos = 0; 200 x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight); 201 while (true) { 202 char next_char; 203 value_str_stream.get(next_char); 204 if (!value_str_stream.good()) { 205 break; 206 } 207 if (pos++ == 4) { 208 x = DrawMiddleGuardBars(x, y, kBarcodeGuardBarHeight); 209 } 210 uint8 digit = next_char - '0'; 211 x = DrawEanEncodedDigit(digit, x, y, kBarcodeNormalBarHeight, pos > 4); 212 } 213 x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight); 214 } 215 216 int YuvFrameGenerator::DrawMiddleGuardBars(int x, int y, int height) { 217 x += kUnitBarSize; 218 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 219 x += (kUnitBarSize * 2); 220 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 221 return x + (kUnitBarSize * 2); 222 } 223 224 int YuvFrameGenerator::DrawSideGuardBars(int x, int y, int height) { 225 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 226 x += (kUnitBarSize * 2); 227 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 228 return x + kUnitBarSize; 229 } 230 231 // For each digit: 0-9, |kEanEncodings| contains a bit-mask indicating 232 // which bars are black (1) and which are blank (0). These are for the L-code 233 // only. R-code values are bitwise negation of these. Reference: 234 // http://en.wikipedia.org/wiki/European_Article_Number#Binary_encoding_of_data_digits_into_EAN-13_barcode // NOLINT 235 const uint8 kEanEncodings[] = { 13, 25, 19, 61, 35, 49, 47, 59, 55, 11 }; 236 237 int YuvFrameGenerator::DrawEanEncodedDigit(int digit, int x, int y, 238 int height, bool flip) { 239 uint8 ean_encoding = kEanEncodings[digit]; 240 if (flip) { 241 ean_encoding = ~ean_encoding; 242 } 243 uint8 mask = 0x40; 244 for (int i = 6; i >= 0; i--, mask >>= 1) { 245 if (ean_encoding & mask) { 246 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 247 } 248 x += kUnitBarSize; 249 } 250 return x; 251 } 252 253 void YuvFrameGenerator::DrawBlockRectangle(uint8* p, 254 int x_start, int y_start, int width, int height, int pitch, uint8 value) { 255 for (int x = x_start; x < x_start + width; x++) { 256 for (int y = y_start; y < y_start + height; y++) { 257 p[x + y * pitch] = value; 258 } 259 } 260 } 261 262 } // namespace cricket 263