1 #include "talk/media/base/yuvframegenerator.h"
6 #include "talk/base/basictypes.h"
7 #include "talk/base/common.h"
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;
23 YuvFrameGenerator::YuvFrameGenerator(int width, int height,
24 bool enable_barcode) {
28 int size = width_ * height_;
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];
35 ASSERT(width_ >= kBarcodeBackgroundWidth);
36 ASSERT(height_>= kBarcodeBackgroundHeight);
38 barcode_start_y_ = height_ - kBarcodeBackgroundHeight;
40 barcode_start_x_ = -1;
41 barcode_start_y_ = -1;
45 YuvFrameGenerator::~YuvFrameGenerator() {
51 void YuvFrameGenerator::GenerateNextFrame(uint8* frame_buffer,
52 int32 barcode_value) {
53 int size = width_ * height_;
55 memset(y_data_, 0, size);
56 memset(u_data_, 0, qsize);
57 memset(v_data_, 0, qsize);
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_);
66 if (barcode_value >= 0) {
67 ASSERT(barcode_start_x_ != -1);
68 DrawBarcode(barcode_value);
71 memcpy(frame_buffer, y_data_, size);
73 memcpy(frame_buffer, u_data_, qsize);
74 frame_buffer += qsize;
75 memcpy(frame_buffer, v_data_, qsize);
77 frame_index_ = (frame_index_ + 1) & 0x0000FFFF;
80 void YuvFrameGenerator::DrawLandscape(uint8 *p, int w, int h) {
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;
93 void YuvFrameGenerator::DrawGradientX(uint8 *p, int w, int h) {
95 for (y = 0; y < h; y++) {
96 for (x = 0; x < w; x++) {
97 p[x + y * w] = (x << 8) / w;
102 void YuvFrameGenerator::DrawGradientY(uint8 *p, int w, int h) {
104 for (y = 0; y < h; y++) {
105 for (x = 0; x < w; x++) {
106 p[x + y * w] = (y << 8) / h;
111 void YuvFrameGenerator::DrawMovingLineX(uint8 *p, int w, int h, int n) {
114 if (x >= w) x = w + w - x - 1;
115 for (y = 0; y < h; y++) {
120 void YuvFrameGenerator::DrawMovingLineY(uint8 *p, int w, int h, int n) {
123 if (y >= h) y = h + h - y - 1;
124 for (x = 0; x < w; x++) {
129 void YuvFrameGenerator::DrawBouncingCube(uint8 *p, int w, int h, int n) {
130 int x, y, pw, ph, px, py;
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) {
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;
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);
163 // Compute check-digit and append to result. Steps described here:
164 // http://en.wikipedia.org/wiki/European_Article_Number#Calculation_of_checksum_digit
166 for (int pos = 1; pos <= kBarcodeMaxEncodableDigits; pos++) {
168 result->get(next_char);
169 uint8 digit = next_char - '0';
170 sum += digit * (pos % 2 ? 3 : 1);
172 uint8 check_digit = sum % 10;
173 if (check_digit != 0) {
174 check_digit = 10 - check_digit;
177 *result << static_cast<int>(check_digit);
181 void YuvFrameGenerator::DrawBarcode(uint32 value) {
182 std::stringstream value_str_stream;
183 ComputeBarcodeDigits(value, &value_str_stream);
185 // Draw white filled rectangle as background to barcode.
186 DrawBlockRectangle(y_data_, barcode_start_x_, barcode_start_y_,
187 kBarcodeBackgroundWidth, kBarcodeBackgroundHeight,
189 DrawBlockRectangle(u_data_, barcode_start_x_ / 2, barcode_start_y_ / 2,
190 kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2,
192 DrawBlockRectangle(v_data_, barcode_start_x_ / 2, barcode_start_y_ / 2,
193 kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2,
196 // Scan through chars (digits) and draw black bars.
197 int x = barcode_start_x_ + kBarsXOffset;
198 int y = barcode_start_y_ + kBarsYOffset;
200 x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight);
203 value_str_stream.get(next_char);
204 if (!value_str_stream.good()) {
208 x = DrawMiddleGuardBars(x, y, kBarcodeGuardBarHeight);
210 uint8 digit = next_char - '0';
211 x = DrawEanEncodedDigit(digit, x, y, kBarcodeNormalBarHeight, pos > 4);
213 x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight);
216 int YuvFrameGenerator::DrawMiddleGuardBars(int x, int y, int height) {
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);
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;
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 };
237 int YuvFrameGenerator::DrawEanEncodedDigit(int digit, int x, int y,
238 int height, bool flip) {
239 uint8 ean_encoding = kEanEncodings[digit];
241 ean_encoding = ~ean_encoding;
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);
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;
262 } // namespace cricket