OLD | NEW |
| (Empty) |
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_checksu
m_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 | |
OLD | NEW |