1 /* 2 * libjingle 3 * Copyright 2004--2014 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/media/base/yuvframegenerator.h" 29 30 #include <string.h> 31 #include <sstream> 32 33 #include "webrtc/base/basictypes.h" 34 #include "webrtc/base/common.h" 35 36 namespace cricket { 37 38 // These values were figured out by trial and error. If you change any 39 // basic parameters e.g. unit-bar size or bars-x-offset, you may need to change 40 // background-width/background-height. 41 const int kBarcodeBackgroundWidth = 160; 42 const int kBarcodeBackgroundHeight = 100; 43 const int kBarsXOffset = 12; 44 const int kBarsYOffset = 4; 45 const int kUnitBarSize = 2; 46 const int kBarcodeNormalBarHeight = 80; 47 const int kBarcodeGuardBarHeight = 96; 48 const int kBarcodeMaxEncodableDigits = 7; 49 50 YuvFrameGenerator::YuvFrameGenerator(int width, int height, 51 bool enable_barcode) { 52 width_ = width; 53 height_ = height; 54 frame_index_ = 0; 55 int size = width_ * height_; 56 int qsize = size / 4; 57 frame_data_size_ = size + 2 * qsize; 58 y_data_ = new uint8_t[size]; 59 u_data_ = new uint8_t[qsize]; 60 v_data_ = new uint8_t[qsize]; 61 if (enable_barcode) { 62 ASSERT(width_ >= kBarcodeBackgroundWidth); 63 ASSERT(height_>= kBarcodeBackgroundHeight); 64 barcode_start_x_ = 0; 65 barcode_start_y_ = height_ - kBarcodeBackgroundHeight; 66 } else { 67 barcode_start_x_ = -1; 68 barcode_start_y_ = -1; 69 } 70 } 71 72 YuvFrameGenerator::~YuvFrameGenerator() { 73 delete y_data_; 74 delete u_data_; 75 delete v_data_; 76 } 77 78 void YuvFrameGenerator::GenerateNextFrame(uint8_t* frame_buffer, 79 int32_t barcode_value) { 80 int size = width_ * height_; 81 int qsize = size / 4; 82 memset(y_data_, 0, size); 83 memset(u_data_, 0, qsize); 84 memset(v_data_, 0, qsize); 85 86 DrawLandscape(y_data_, width_, height_); 87 DrawGradientX(u_data_, width_/2, height_/2); 88 DrawGradientY(v_data_, width_/2, height_/2); 89 DrawMovingLineX(u_data_, width_/2, height_/2, frame_index_); 90 DrawMovingLineY(v_data_, width_/2, height_/2, frame_index_); 91 DrawBouncingCube(y_data_, width_, height_, frame_index_); 92 93 if (barcode_value >= 0) { 94 ASSERT(barcode_start_x_ != -1); 95 DrawBarcode(barcode_value); 96 } 97 98 memcpy(frame_buffer, y_data_, size); 99 frame_buffer += size; 100 memcpy(frame_buffer, u_data_, qsize); 101 frame_buffer += qsize; 102 memcpy(frame_buffer, v_data_, qsize); 103 104 frame_index_ = (frame_index_ + 1) & 0x0000FFFF; 105 } 106 107 void YuvFrameGenerator::DrawLandscape(uint8_t* p, int w, int h) { 108 int x, y; 109 for (y = 0; y < h; y++) { 110 for (x = 0; x < w; x++) { 111 p[x + y * w] = x % (y+1); 112 if (((x > w / 2 - (w / 32)) && (x < w / 2 + (w / 32))) || 113 ((y > h / 2 - (h / 32)) && (y < h / 2 + (h / 32)))) { 114 p[x + y * w] = (((x + y) / 8 % 2)) ? 255 : 0; 115 } 116 } 117 } 118 } 119 120 void YuvFrameGenerator::DrawGradientX(uint8_t* p, int w, int h) { 121 int x, y; 122 for (y = 0; y < h; y++) { 123 for (x = 0; x < w; x++) { 124 p[x + y * w] = (x << 8) / w; 125 } 126 } 127 } 128 129 void YuvFrameGenerator::DrawGradientY(uint8_t* p, int w, int h) { 130 int x, y; 131 for (y = 0; y < h; y++) { 132 for (x = 0; x < w; x++) { 133 p[x + y * w] = (y << 8) / h; 134 } 135 } 136 } 137 138 void YuvFrameGenerator::DrawMovingLineX(uint8_t* p, int w, int h, int n) { 139 int x, y; 140 x = n % (w * 2); 141 if (x >= w) x = w + w - x - 1; 142 for (y = 0; y < h; y++) { 143 p[x + y * w] = 255; 144 } 145 } 146 147 void YuvFrameGenerator::DrawMovingLineY(uint8_t* p, int w, int h, int n) { 148 int x, y; 149 y = n % (h * 2); 150 if (y >= h) y = h + h - y - 1; 151 for (x = 0; x < w; x++) { 152 p[x + y * w] = 255; 153 } 154 } 155 156 void YuvFrameGenerator::DrawBouncingCube(uint8_t* p, int w, int h, int n) { 157 int x, y, pw, ph, px, py; 158 pw = w / 16; 159 ph = h / 16; 160 px = n % (w * 2); 161 py = n % (h * 2); 162 if (px >= w) px = w + w - px - 1; 163 if (py >= h) py = h + h - py - 1; 164 for (y = py - ph; y < py + ph; y++) { 165 if (y >=0 && y < h) { 166 for (x = px - pw; x < px + pw; x++) { 167 if (x >= 0 && x < w) { 168 p[x + y * w] = 255; 169 } 170 } 171 } 172 } 173 } 174 175 void YuvFrameGenerator::GetBarcodeBounds(int* top, int* left, 176 int* width, int* height) { 177 ASSERT(barcode_start_x_ != -1); 178 *top = barcode_start_y_; 179 *left = barcode_start_x_; 180 *width = kBarcodeBackgroundWidth; 181 *height = kBarcodeBackgroundHeight; 182 } 183 184 static void ComputeBarcodeDigits(uint32_t value, std::stringstream* result) { 185 // Serialize |value| as 7-char string, padded with 0's to the left. 186 result->width(kBarcodeMaxEncodableDigits); 187 result->fill('0'); 188 *result << value; 189 190 // Compute check-digit and append to result. Steps described here: 191 // http://en.wikipedia.org/wiki/European_Article_Number#Calculation_of_checksum_digit 192 int sum = 0; 193 for (int pos = 1; pos <= kBarcodeMaxEncodableDigits; pos++) { 194 char next_char; 195 result->get(next_char); 196 uint8_t digit = next_char - '0'; 197 sum += digit * (pos % 2 ? 3 : 1); 198 } 199 uint8_t check_digit = sum % 10; 200 if (check_digit != 0) { 201 check_digit = 10 - check_digit; 202 } 203 204 *result << static_cast<int>(check_digit); 205 result->seekg(0); 206 } 207 208 void YuvFrameGenerator::DrawBarcode(uint32_t value) { 209 std::stringstream value_str_stream; 210 ComputeBarcodeDigits(value, &value_str_stream); 211 212 // Draw white filled rectangle as background to barcode. 213 DrawBlockRectangle(y_data_, barcode_start_x_, barcode_start_y_, 214 kBarcodeBackgroundWidth, kBarcodeBackgroundHeight, 215 width_, 255); 216 DrawBlockRectangle(u_data_, barcode_start_x_ / 2, barcode_start_y_ / 2, 217 kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2, 218 width_ / 2, 128); 219 DrawBlockRectangle(v_data_, barcode_start_x_ / 2, barcode_start_y_ / 2, 220 kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2, 221 width_ / 2, 128); 222 223 // Scan through chars (digits) and draw black bars. 224 int x = barcode_start_x_ + kBarsXOffset; 225 int y = barcode_start_y_ + kBarsYOffset; 226 int pos = 0; 227 x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight); 228 while (true) { 229 char next_char; 230 value_str_stream.get(next_char); 231 if (!value_str_stream.good()) { 232 break; 233 } 234 if (pos++ == 4) { 235 x = DrawMiddleGuardBars(x, y, kBarcodeGuardBarHeight); 236 } 237 uint8_t digit = next_char - '0'; 238 x = DrawEanEncodedDigit(digit, x, y, kBarcodeNormalBarHeight, pos > 4); 239 } 240 x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight); 241 } 242 243 int YuvFrameGenerator::DrawMiddleGuardBars(int x, int y, int height) { 244 x += kUnitBarSize; 245 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 246 x += (kUnitBarSize * 2); 247 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 248 return x + (kUnitBarSize * 2); 249 } 250 251 int YuvFrameGenerator::DrawSideGuardBars(int x, int y, int height) { 252 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 253 x += (kUnitBarSize * 2); 254 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 255 return x + kUnitBarSize; 256 } 257 258 // For each digit: 0-9, |kEanEncodings| contains a bit-mask indicating 259 // which bars are black (1) and which are blank (0). These are for the L-code 260 // only. R-code values are bitwise negation of these. Reference: 261 // http://en.wikipedia.org/wiki/European_Article_Number#Binary_encoding_of_data_digits_into_EAN-13_barcode // NOLINT 262 const uint8_t kEanEncodings[] = {13, 25, 19, 61, 35, 49, 47, 59, 55, 11}; 263 264 int YuvFrameGenerator::DrawEanEncodedDigit(int digit, int x, int y, 265 int height, bool flip) { 266 uint8_t ean_encoding = kEanEncodings[digit]; 267 if (flip) { 268 ean_encoding = ~ean_encoding; 269 } 270 uint8_t mask = 0x40; 271 for (int i = 6; i >= 0; i--, mask >>= 1) { 272 if (ean_encoding & mask) { 273 DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0); 274 } 275 x += kUnitBarSize; 276 } 277 return x; 278 } 279 280 void YuvFrameGenerator::DrawBlockRectangle(uint8_t* p, 281 int x_start, 282 int y_start, 283 int width, 284 int height, 285 int pitch, 286 uint8_t value) { 287 for (int x = x_start; x < x_start + width; x++) { 288 for (int y = y_start; y < y_start + height; y++) { 289 p[x + y * pitch] = value; 290 } 291 } 292 } 293 294 } // namespace cricket 295