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