5b3930c9dcacac620b449f1484c67c96b50a13bd
[deliverable/linux.git] / drivers / media / platform / vivid / vivid-tpg.c
1 /*
2 * vivid-tpg.c - Test Pattern Generator
3 *
4 * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
5 * vivi.c source for the copyright information of those functions.
6 *
7 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
8 *
9 * This program is free software; you may redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
17 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "vivid-tpg.h"
24
25 /* Must remain in sync with enum tpg_pattern */
26 const char * const tpg_pattern_strings[] = {
27 "75% Colorbar",
28 "100% Colorbar",
29 "CSC Colorbar",
30 "Horizontal 100% Colorbar",
31 "100% Color Squares",
32 "100% Black",
33 "100% White",
34 "100% Red",
35 "100% Green",
36 "100% Blue",
37 "16x16 Checkers",
38 "2x2 Checkers",
39 "1x1 Checkers",
40 "2x2 Red/Green Checkers",
41 "1x1 Red/Green Checkers",
42 "Alternating Hor Lines",
43 "Alternating Vert Lines",
44 "One Pixel Wide Cross",
45 "Two Pixels Wide Cross",
46 "Ten Pixels Wide Cross",
47 "Gray Ramp",
48 "Noise",
49 NULL
50 };
51
52 /* Must remain in sync with enum tpg_aspect */
53 const char * const tpg_aspect_strings[] = {
54 "Source Width x Height",
55 "4x3",
56 "14x9",
57 "16x9",
58 "16x9 Anamorphic",
59 NULL
60 };
61
62 /*
63 * Sine table: sin[0] = 127 * sin(-180 degrees)
64 * sin[128] = 127 * sin(0 degrees)
65 * sin[256] = 127 * sin(180 degrees)
66 */
67 static const s8 sin[257] = {
68 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
69 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
70 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
71 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
72 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
73 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
74 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
75 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
76 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
77 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
78 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
79 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
80 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
81 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
82 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
83 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
84 0,
85 };
86
87 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
88
89 /* Global font descriptor */
90 static const u8 *font8x16;
91
92 void tpg_set_font(const u8 *f)
93 {
94 font8x16 = f;
95 }
96
97 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
98 {
99 memset(tpg, 0, sizeof(*tpg));
100 tpg->scaled_width = tpg->src_width = w;
101 tpg->src_height = tpg->buf_height = h;
102 tpg->crop.width = tpg->compose.width = w;
103 tpg->crop.height = tpg->compose.height = h;
104 tpg->recalc_colors = true;
105 tpg->recalc_square_border = true;
106 tpg->brightness = 128;
107 tpg->contrast = 128;
108 tpg->saturation = 128;
109 tpg->hue = 0;
110 tpg->mv_hor_mode = TPG_MOVE_NONE;
111 tpg->mv_vert_mode = TPG_MOVE_NONE;
112 tpg->field = V4L2_FIELD_NONE;
113 tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
114 tpg->colorspace = V4L2_COLORSPACE_SRGB;
115 tpg->perc_fill = 100;
116 }
117
118 int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
119 {
120 unsigned pat;
121 unsigned plane;
122
123 tpg->max_line_width = max_w;
124 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
125 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
126 unsigned pixelsz = plane ? 1 : 4;
127
128 tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
129 if (!tpg->lines[pat][plane])
130 return -ENOMEM;
131 if (plane == 0)
132 continue;
133 tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
134 if (!tpg->downsampled_lines[pat][plane])
135 return -ENOMEM;
136 }
137 }
138 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
139 unsigned pixelsz = plane ? 1 : 4;
140
141 tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
142 if (!tpg->contrast_line[plane])
143 return -ENOMEM;
144 tpg->black_line[plane] = vzalloc(max_w * pixelsz);
145 if (!tpg->black_line[plane])
146 return -ENOMEM;
147 tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
148 if (!tpg->random_line[plane])
149 return -ENOMEM;
150 }
151 return 0;
152 }
153
154 void tpg_free(struct tpg_data *tpg)
155 {
156 unsigned pat;
157 unsigned plane;
158
159 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
160 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
161 vfree(tpg->lines[pat][plane]);
162 tpg->lines[pat][plane] = NULL;
163 if (plane == 0)
164 continue;
165 vfree(tpg->downsampled_lines[pat][plane]);
166 tpg->downsampled_lines[pat][plane] = NULL;
167 }
168 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
169 vfree(tpg->contrast_line[plane]);
170 vfree(tpg->black_line[plane]);
171 vfree(tpg->random_line[plane]);
172 tpg->contrast_line[plane] = NULL;
173 tpg->black_line[plane] = NULL;
174 tpg->random_line[plane] = NULL;
175 }
176 }
177
178 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
179 {
180 tpg->fourcc = fourcc;
181 tpg->planes = 1;
182 tpg->buffers = 1;
183 tpg->recalc_colors = true;
184 tpg->vdownsampling[0] = 1;
185 tpg->hdownsampling[0] = 1;
186
187 switch (fourcc) {
188 case V4L2_PIX_FMT_RGB565:
189 case V4L2_PIX_FMT_RGB565X:
190 case V4L2_PIX_FMT_RGB555:
191 case V4L2_PIX_FMT_XRGB555:
192 case V4L2_PIX_FMT_ARGB555:
193 case V4L2_PIX_FMT_RGB555X:
194 case V4L2_PIX_FMT_RGB24:
195 case V4L2_PIX_FMT_BGR24:
196 case V4L2_PIX_FMT_RGB32:
197 case V4L2_PIX_FMT_BGR32:
198 case V4L2_PIX_FMT_XRGB32:
199 case V4L2_PIX_FMT_XBGR32:
200 case V4L2_PIX_FMT_ARGB32:
201 case V4L2_PIX_FMT_ABGR32:
202 tpg->is_yuv = false;
203 break;
204 case V4L2_PIX_FMT_NV16M:
205 case V4L2_PIX_FMT_NV61M:
206 tpg->vdownsampling[1] = 1;
207 tpg->hdownsampling[1] = 1;
208 tpg->buffers = 2;
209 tpg->planes = 2;
210 /* fall-through */
211 case V4L2_PIX_FMT_YUYV:
212 case V4L2_PIX_FMT_UYVY:
213 case V4L2_PIX_FMT_YVYU:
214 case V4L2_PIX_FMT_VYUY:
215 tpg->is_yuv = true;
216 break;
217 default:
218 return false;
219 }
220
221 switch (fourcc) {
222 case V4L2_PIX_FMT_RGB565:
223 case V4L2_PIX_FMT_RGB565X:
224 case V4L2_PIX_FMT_RGB555:
225 case V4L2_PIX_FMT_XRGB555:
226 case V4L2_PIX_FMT_ARGB555:
227 case V4L2_PIX_FMT_RGB555X:
228 case V4L2_PIX_FMT_YUYV:
229 case V4L2_PIX_FMT_UYVY:
230 case V4L2_PIX_FMT_YVYU:
231 case V4L2_PIX_FMT_VYUY:
232 tpg->twopixelsize[0] = 2 * 2;
233 break;
234 case V4L2_PIX_FMT_RGB24:
235 case V4L2_PIX_FMT_BGR24:
236 tpg->twopixelsize[0] = 2 * 3;
237 break;
238 case V4L2_PIX_FMT_RGB32:
239 case V4L2_PIX_FMT_BGR32:
240 case V4L2_PIX_FMT_XRGB32:
241 case V4L2_PIX_FMT_XBGR32:
242 case V4L2_PIX_FMT_ARGB32:
243 case V4L2_PIX_FMT_ABGR32:
244 tpg->twopixelsize[0] = 2 * 4;
245 break;
246 case V4L2_PIX_FMT_NV16M:
247 case V4L2_PIX_FMT_NV61M:
248 tpg->twopixelsize[0] = 2;
249 tpg->twopixelsize[1] = 2;
250 break;
251 }
252 return true;
253 }
254
255 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
256 const struct v4l2_rect *compose)
257 {
258 tpg->crop = *crop;
259 tpg->compose = *compose;
260 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
261 tpg->crop.width - 1) / tpg->crop.width;
262 tpg->scaled_width &= ~1;
263 if (tpg->scaled_width > tpg->max_line_width)
264 tpg->scaled_width = tpg->max_line_width;
265 if (tpg->scaled_width < 2)
266 tpg->scaled_width = 2;
267 tpg->recalc_lines = true;
268 }
269
270 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
271 u32 field)
272 {
273 unsigned p;
274
275 tpg->src_width = width;
276 tpg->src_height = height;
277 tpg->field = field;
278 tpg->buf_height = height;
279 if (V4L2_FIELD_HAS_T_OR_B(field))
280 tpg->buf_height /= 2;
281 tpg->scaled_width = width;
282 tpg->crop.top = tpg->crop.left = 0;
283 tpg->crop.width = width;
284 tpg->crop.height = height;
285 tpg->compose.top = tpg->compose.left = 0;
286 tpg->compose.width = width;
287 tpg->compose.height = tpg->buf_height;
288 for (p = 0; p < tpg->planes; p++)
289 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
290 (2 * tpg->hdownsampling[p]);
291 tpg->recalc_square_border = true;
292 }
293
294 static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
295 {
296 switch (tpg->pattern) {
297 case TPG_PAT_BLACK:
298 return TPG_COLOR_100_WHITE;
299 case TPG_PAT_CSC_COLORBAR:
300 return TPG_COLOR_CSC_BLACK;
301 default:
302 return TPG_COLOR_100_BLACK;
303 }
304 }
305
306 static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
307 {
308 switch (tpg->pattern) {
309 case TPG_PAT_75_COLORBAR:
310 case TPG_PAT_CSC_COLORBAR:
311 return TPG_COLOR_CSC_WHITE;
312 case TPG_PAT_BLACK:
313 return TPG_COLOR_100_BLACK;
314 default:
315 return TPG_COLOR_100_WHITE;
316 }
317 }
318
319 static inline int rec709_to_linear(int v)
320 {
321 v = clamp(v, 0, 0xff0);
322 return tpg_rec709_to_linear[v];
323 }
324
325 static inline int linear_to_rec709(int v)
326 {
327 v = clamp(v, 0, 0xff0);
328 return tpg_linear_to_rec709[v];
329 }
330
331 static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
332 int y_offset, int *y, int *cb, int *cr)
333 {
334 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
335 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
336 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
337 }
338
339 static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
340 int *y, int *cb, int *cr)
341 {
342 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
343
344 static const int bt601[3][3] = {
345 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
346 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
347 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
348 };
349 static const int bt601_full[3][3] = {
350 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
351 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
352 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
353 };
354 static const int rec709[3][3] = {
355 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
356 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
357 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
358 };
359 static const int rec709_full[3][3] = {
360 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
361 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
362 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
363 };
364 static const int smpte240m[3][3] = {
365 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
366 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
367 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
368 };
369 static const int bt2020[3][3] = {
370 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
371 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
372 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
373 };
374 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
375 unsigned y_offset = full ? 0 : 16;
376 int lin_y, yc;
377
378 switch (tpg->real_ycbcr_enc) {
379 case V4L2_YCBCR_ENC_601:
380 case V4L2_YCBCR_ENC_XV601:
381 case V4L2_YCBCR_ENC_SYCC:
382 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
383 break;
384 case V4L2_YCBCR_ENC_BT2020:
385 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
386 break;
387 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
388 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
389 COEFF(0.6780, 255) * rec709_to_linear(g) +
390 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
391 yc = linear_to_rec709(lin_y);
392 *y = (yc * 219) / 255 + (16 << 4);
393 if (b <= yc)
394 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
395 else
396 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
397 if (r <= yc)
398 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
399 else
400 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
401 break;
402 case V4L2_YCBCR_ENC_SMPTE240M:
403 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
404 break;
405 case V4L2_YCBCR_ENC_709:
406 case V4L2_YCBCR_ENC_XV709:
407 default:
408 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
409 break;
410 }
411 }
412
413 static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
414 int y_offset, int *r, int *g, int *b)
415 {
416 y -= y_offset << 4;
417 cb -= 128 << 4;
418 cr -= 128 << 4;
419 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
420 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
421 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
422 *r = clamp(*r >> 12, 0, 0xff0);
423 *g = clamp(*g >> 12, 0, 0xff0);
424 *b = clamp(*b >> 12, 0, 0xff0);
425 }
426
427 static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
428 int *r, int *g, int *b)
429 {
430 #undef COEFF
431 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
432 static const int bt601[3][3] = {
433 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
434 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
435 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
436 };
437 static const int bt601_full[3][3] = {
438 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
439 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
440 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
441 };
442 static const int rec709[3][3] = {
443 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
444 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
445 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
446 };
447 static const int rec709_full[3][3] = {
448 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
449 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
450 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
451 };
452 static const int smpte240m[3][3] = {
453 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
454 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
455 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
456 };
457 static const int bt2020[3][3] = {
458 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
459 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
460 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
461 };
462 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
463 unsigned y_offset = full ? 0 : 16;
464 int lin_r, lin_g, lin_b, lin_y;
465
466 switch (tpg->real_ycbcr_enc) {
467 case V4L2_YCBCR_ENC_601:
468 case V4L2_YCBCR_ENC_XV601:
469 case V4L2_YCBCR_ENC_SYCC:
470 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
471 break;
472 case V4L2_YCBCR_ENC_BT2020:
473 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
474 break;
475 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
476 y -= 16 << 4;
477 cb -= 128 << 4;
478 cr -= 128 << 4;
479
480 if (cb <= 0)
481 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
482 else
483 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
484 *b = *b >> 12;
485 if (cr <= 0)
486 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
487 else
488 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
489 *r = *r >> 12;
490 lin_r = rec709_to_linear(*r);
491 lin_b = rec709_to_linear(*b);
492 lin_y = rec709_to_linear((y * 255) / 219);
493
494 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
495 COEFF(0.2627 / 0.6780, 255) * lin_r -
496 COEFF(0.0593 / 0.6780, 255) * lin_b;
497 *g = linear_to_rec709(lin_g >> 12);
498 break;
499 case V4L2_YCBCR_ENC_SMPTE240M:
500 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
501 break;
502 case V4L2_YCBCR_ENC_709:
503 case V4L2_YCBCR_ENC_XV709:
504 default:
505 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
506 break;
507 }
508 }
509
510 /* precalculate color bar values to speed up rendering */
511 static void precalculate_color(struct tpg_data *tpg, int k)
512 {
513 int col = k;
514 int r = tpg_colors[col].r;
515 int g = tpg_colors[col].g;
516 int b = tpg_colors[col].b;
517
518 if (k == TPG_COLOR_TEXTBG) {
519 col = tpg_get_textbg_color(tpg);
520
521 r = tpg_colors[col].r;
522 g = tpg_colors[col].g;
523 b = tpg_colors[col].b;
524 } else if (k == TPG_COLOR_TEXTFG) {
525 col = tpg_get_textfg_color(tpg);
526
527 r = tpg_colors[col].r;
528 g = tpg_colors[col].g;
529 b = tpg_colors[col].b;
530 } else if (tpg->pattern == TPG_PAT_NOISE) {
531 r = g = b = prandom_u32_max(256);
532 } else if (k == TPG_COLOR_RANDOM) {
533 r = g = b = tpg->qual_offset + prandom_u32_max(196);
534 } else if (k >= TPG_COLOR_RAMP) {
535 r = g = b = k - TPG_COLOR_RAMP;
536 }
537
538 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
539 r = tpg_csc_colors[tpg->colorspace][col].r;
540 g = tpg_csc_colors[tpg->colorspace][col].g;
541 b = tpg_csc_colors[tpg->colorspace][col].b;
542 } else {
543 r <<= 4;
544 g <<= 4;
545 b <<= 4;
546 }
547 if (tpg->qual == TPG_QUAL_GRAY) {
548 /* Rec. 709 Luma function */
549 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
550 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
551 }
552
553 /*
554 * The assumption is that the RGB output is always full range,
555 * so only if the rgb_range overrides the 'real' rgb range do
556 * we need to convert the RGB values.
557 *
558 * Remember that r, g and b are still in the 0 - 0xff0 range.
559 */
560 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
561 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
562 /*
563 * Convert from full range (which is what r, g and b are)
564 * to limited range (which is the 'real' RGB range), which
565 * is then interpreted as full range.
566 */
567 r = (r * 219) / 255 + (16 << 4);
568 g = (g * 219) / 255 + (16 << 4);
569 b = (b * 219) / 255 + (16 << 4);
570 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
571 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
572 /*
573 * Clamp r, g and b to the limited range and convert to full
574 * range since that's what we deliver.
575 */
576 r = clamp(r, 16 << 4, 235 << 4);
577 g = clamp(g, 16 << 4, 235 << 4);
578 b = clamp(b, 16 << 4, 235 << 4);
579 r = (r - (16 << 4)) * 255 / 219;
580 g = (g - (16 << 4)) * 255 / 219;
581 b = (b - (16 << 4)) * 255 / 219;
582 }
583
584 if (tpg->brightness != 128 || tpg->contrast != 128 ||
585 tpg->saturation != 128 || tpg->hue) {
586 /* Implement these operations */
587 int y, cb, cr;
588 int tmp_cb, tmp_cr;
589
590 /* First convert to YCbCr */
591
592 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
593
594 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
595 y += (tpg->brightness << 4) - (128 << 4);
596
597 cb -= 128 << 4;
598 cr -= 128 << 4;
599 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
600 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
601
602 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
603 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
604 if (tpg->is_yuv) {
605 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
606 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
607 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
608 return;
609 }
610 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
611 }
612
613 if (tpg->is_yuv) {
614 /* Convert to YCbCr */
615 int y, cb, cr;
616
617 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
618
619 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
620 y = clamp(y, 16 << 4, 235 << 4);
621 cb = clamp(cb, 16 << 4, 240 << 4);
622 cr = clamp(cr, 16 << 4, 240 << 4);
623 }
624 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
625 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
626 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
627 } else {
628 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
629 r = (r * 219) / 255 + (16 << 4);
630 g = (g * 219) / 255 + (16 << 4);
631 b = (b * 219) / 255 + (16 << 4);
632 }
633 switch (tpg->fourcc) {
634 case V4L2_PIX_FMT_RGB565:
635 case V4L2_PIX_FMT_RGB565X:
636 r >>= 7;
637 g >>= 6;
638 b >>= 7;
639 break;
640 case V4L2_PIX_FMT_RGB555:
641 case V4L2_PIX_FMT_XRGB555:
642 case V4L2_PIX_FMT_ARGB555:
643 case V4L2_PIX_FMT_RGB555X:
644 r >>= 7;
645 g >>= 7;
646 b >>= 7;
647 break;
648 default:
649 r >>= 4;
650 g >>= 4;
651 b >>= 4;
652 break;
653 }
654
655 tpg->colors[k][0] = r;
656 tpg->colors[k][1] = g;
657 tpg->colors[k][2] = b;
658 }
659 }
660
661 static void tpg_precalculate_colors(struct tpg_data *tpg)
662 {
663 int k;
664
665 for (k = 0; k < TPG_COLOR_MAX; k++)
666 precalculate_color(tpg, k);
667 }
668
669 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
670 static void gen_twopix(struct tpg_data *tpg,
671 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
672 {
673 unsigned offset = odd * tpg->twopixelsize[0] / 2;
674 u8 alpha = tpg->alpha_component;
675 u8 r_y, g_u, b_v;
676
677 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
678 color != TPG_COLOR_100_RED &&
679 color != TPG_COLOR_75_RED)
680 alpha = 0;
681 if (color == TPG_COLOR_RANDOM)
682 precalculate_color(tpg, color);
683 r_y = tpg->colors[color][0]; /* R or precalculated Y */
684 g_u = tpg->colors[color][1]; /* G or precalculated U */
685 b_v = tpg->colors[color][2]; /* B or precalculated V */
686
687 switch (tpg->fourcc) {
688 case V4L2_PIX_FMT_NV16M:
689 buf[0][offset] = r_y;
690 if (odd) {
691 buf[1][0] = (buf[1][0] + g_u) / 2;
692 buf[1][1] = (buf[1][1] + b_v) / 2;
693 break;
694 }
695 buf[1][0] = g_u;
696 buf[1][1] = b_v;
697 break;
698 case V4L2_PIX_FMT_NV61M:
699 buf[0][offset] = r_y;
700 if (odd) {
701 buf[1][0] = (buf[1][0] + b_v) / 2;
702 buf[1][1] = (buf[1][1] + g_u) / 2;
703 break;
704 }
705 buf[1][0] = b_v;
706 buf[1][1] = g_u;
707 break;
708
709 case V4L2_PIX_FMT_YUYV:
710 buf[0][offset] = r_y;
711 if (odd) {
712 buf[0][1] = (buf[0][1] + g_u) / 2;
713 buf[0][3] = (buf[0][3] + b_v) / 2;
714 break;
715 }
716 buf[0][1] = g_u;
717 buf[0][3] = b_v;
718 break;
719 case V4L2_PIX_FMT_UYVY:
720 buf[0][offset + 1] = r_y;
721 if (odd) {
722 buf[0][0] = (buf[0][0] + g_u) / 2;
723 buf[0][2] = (buf[0][2] + b_v) / 2;
724 break;
725 }
726 buf[0][0] = g_u;
727 buf[0][2] = b_v;
728 break;
729 case V4L2_PIX_FMT_YVYU:
730 buf[0][offset] = r_y;
731 if (odd) {
732 buf[0][1] = (buf[0][1] + b_v) / 2;
733 buf[0][3] = (buf[0][3] + g_u) / 2;
734 break;
735 }
736 buf[0][1] = b_v;
737 buf[0][3] = g_u;
738 break;
739 case V4L2_PIX_FMT_VYUY:
740 buf[0][offset + 1] = r_y;
741 if (odd) {
742 buf[0][0] = (buf[0][0] + b_v) / 2;
743 buf[0][2] = (buf[0][2] + g_u) / 2;
744 break;
745 }
746 buf[0][0] = b_v;
747 buf[0][2] = g_u;
748 break;
749 case V4L2_PIX_FMT_RGB565:
750 buf[0][offset] = (g_u << 5) | b_v;
751 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
752 break;
753 case V4L2_PIX_FMT_RGB565X:
754 buf[0][offset] = (r_y << 3) | (g_u >> 3);
755 buf[0][offset + 1] = (g_u << 5) | b_v;
756 break;
757 case V4L2_PIX_FMT_RGB555:
758 case V4L2_PIX_FMT_XRGB555:
759 alpha = 0;
760 /* fall through */
761 case V4L2_PIX_FMT_ARGB555:
762 buf[0][offset] = (g_u << 5) | b_v;
763 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
764 break;
765 case V4L2_PIX_FMT_RGB555X:
766 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
767 buf[0][offset + 1] = (g_u << 5) | b_v;
768 break;
769 case V4L2_PIX_FMT_RGB24:
770 buf[0][offset] = r_y;
771 buf[0][offset + 1] = g_u;
772 buf[0][offset + 2] = b_v;
773 break;
774 case V4L2_PIX_FMT_BGR24:
775 buf[0][offset] = b_v;
776 buf[0][offset + 1] = g_u;
777 buf[0][offset + 2] = r_y;
778 break;
779 case V4L2_PIX_FMT_RGB32:
780 case V4L2_PIX_FMT_XRGB32:
781 alpha = 0;
782 /* fall through */
783 case V4L2_PIX_FMT_ARGB32:
784 buf[0][offset] = alpha;
785 buf[0][offset + 1] = r_y;
786 buf[0][offset + 2] = g_u;
787 buf[0][offset + 3] = b_v;
788 break;
789 case V4L2_PIX_FMT_BGR32:
790 case V4L2_PIX_FMT_XBGR32:
791 alpha = 0;
792 /* fall through */
793 case V4L2_PIX_FMT_ABGR32:
794 buf[0][offset] = b_v;
795 buf[0][offset + 1] = g_u;
796 buf[0][offset + 2] = r_y;
797 buf[0][offset + 3] = alpha;
798 break;
799 }
800 }
801
802 /* Return how many pattern lines are used by the current pattern. */
803 static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
804 {
805 switch (tpg->pattern) {
806 case TPG_PAT_CHECKERS_16X16:
807 case TPG_PAT_CHECKERS_2X2:
808 case TPG_PAT_CHECKERS_1X1:
809 case TPG_PAT_COLOR_CHECKERS_2X2:
810 case TPG_PAT_COLOR_CHECKERS_1X1:
811 case TPG_PAT_ALTERNATING_HLINES:
812 case TPG_PAT_CROSS_1_PIXEL:
813 case TPG_PAT_CROSS_2_PIXELS:
814 case TPG_PAT_CROSS_10_PIXELS:
815 return 2;
816 case TPG_PAT_100_COLORSQUARES:
817 case TPG_PAT_100_HCOLORBAR:
818 return 8;
819 default:
820 return 1;
821 }
822 }
823
824 /* Which pattern line should be used for the given frame line. */
825 static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
826 {
827 switch (tpg->pattern) {
828 case TPG_PAT_CHECKERS_16X16:
829 return (line >> 4) & 1;
830 case TPG_PAT_CHECKERS_1X1:
831 case TPG_PAT_COLOR_CHECKERS_1X1:
832 case TPG_PAT_ALTERNATING_HLINES:
833 return line & 1;
834 case TPG_PAT_CHECKERS_2X2:
835 case TPG_PAT_COLOR_CHECKERS_2X2:
836 return (line & 2) >> 1;
837 case TPG_PAT_100_COLORSQUARES:
838 case TPG_PAT_100_HCOLORBAR:
839 return (line * 8) / tpg->src_height;
840 case TPG_PAT_CROSS_1_PIXEL:
841 return line == tpg->src_height / 2;
842 case TPG_PAT_CROSS_2_PIXELS:
843 return (line + 1) / 2 == tpg->src_height / 4;
844 case TPG_PAT_CROSS_10_PIXELS:
845 return (line + 10) / 20 == tpg->src_height / 40;
846 default:
847 return 0;
848 }
849 }
850
851 /*
852 * Which color should be used for the given pattern line and X coordinate.
853 * Note: x is in the range 0 to 2 * tpg->src_width.
854 */
855 static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
856 unsigned pat_line, unsigned x)
857 {
858 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
859 should be modified */
860 static const enum tpg_color bars[3][8] = {
861 /* Standard ITU-R 75% color bar sequence */
862 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
863 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
864 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
865 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
866 /* Standard ITU-R 100% color bar sequence */
867 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
868 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
869 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
870 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
871 /* Color bar sequence suitable to test CSC */
872 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
873 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
874 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
875 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
876 };
877
878 switch (tpg->pattern) {
879 case TPG_PAT_75_COLORBAR:
880 case TPG_PAT_100_COLORBAR:
881 case TPG_PAT_CSC_COLORBAR:
882 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
883 case TPG_PAT_100_COLORSQUARES:
884 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
885 case TPG_PAT_100_HCOLORBAR:
886 return bars[1][pat_line];
887 case TPG_PAT_BLACK:
888 return TPG_COLOR_100_BLACK;
889 case TPG_PAT_WHITE:
890 return TPG_COLOR_100_WHITE;
891 case TPG_PAT_RED:
892 return TPG_COLOR_100_RED;
893 case TPG_PAT_GREEN:
894 return TPG_COLOR_100_GREEN;
895 case TPG_PAT_BLUE:
896 return TPG_COLOR_100_BLUE;
897 case TPG_PAT_CHECKERS_16X16:
898 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
899 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
900 case TPG_PAT_CHECKERS_1X1:
901 return ((x & 1) ^ (pat_line & 1)) ?
902 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
903 case TPG_PAT_COLOR_CHECKERS_1X1:
904 return ((x & 1) ^ (pat_line & 1)) ?
905 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
906 case TPG_PAT_CHECKERS_2X2:
907 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
908 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
909 case TPG_PAT_COLOR_CHECKERS_2X2:
910 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
911 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
912 case TPG_PAT_ALTERNATING_HLINES:
913 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
914 case TPG_PAT_ALTERNATING_VLINES:
915 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
916 case TPG_PAT_CROSS_1_PIXEL:
917 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
918 return TPG_COLOR_100_BLACK;
919 return TPG_COLOR_100_WHITE;
920 case TPG_PAT_CROSS_2_PIXELS:
921 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
922 return TPG_COLOR_100_BLACK;
923 return TPG_COLOR_100_WHITE;
924 case TPG_PAT_CROSS_10_PIXELS:
925 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
926 return TPG_COLOR_100_BLACK;
927 return TPG_COLOR_100_WHITE;
928 case TPG_PAT_GRAY_RAMP:
929 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
930 default:
931 return TPG_COLOR_100_RED;
932 }
933 }
934
935 /*
936 * Given the pixel aspect ratio and video aspect ratio calculate the
937 * coordinates of a centered square and the coordinates of the border of
938 * the active video area. The coordinates are relative to the source
939 * frame rectangle.
940 */
941 static void tpg_calculate_square_border(struct tpg_data *tpg)
942 {
943 unsigned w = tpg->src_width;
944 unsigned h = tpg->src_height;
945 unsigned sq_w, sq_h;
946
947 sq_w = (w * 2 / 5) & ~1;
948 if (((w - sq_w) / 2) & 1)
949 sq_w += 2;
950 sq_h = sq_w;
951 tpg->square.width = sq_w;
952 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
953 unsigned ana_sq_w = (sq_w / 4) * 3;
954
955 if (((w - ana_sq_w) / 2) & 1)
956 ana_sq_w += 2;
957 tpg->square.width = ana_sq_w;
958 }
959 tpg->square.left = (w - tpg->square.width) / 2;
960 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
961 sq_h = sq_w * 10 / 11;
962 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
963 sq_h = sq_w * 59 / 54;
964 tpg->square.height = sq_h;
965 tpg->square.top = (h - sq_h) / 2;
966 tpg->border.left = 0;
967 tpg->border.width = w;
968 tpg->border.top = 0;
969 tpg->border.height = h;
970 switch (tpg->vid_aspect) {
971 case TPG_VIDEO_ASPECT_4X3:
972 if (tpg->pix_aspect)
973 return;
974 if (3 * w >= 4 * h) {
975 tpg->border.width = ((4 * h) / 3) & ~1;
976 if (((w - tpg->border.width) / 2) & ~1)
977 tpg->border.width -= 2;
978 tpg->border.left = (w - tpg->border.width) / 2;
979 break;
980 }
981 tpg->border.height = ((3 * w) / 4) & ~1;
982 tpg->border.top = (h - tpg->border.height) / 2;
983 break;
984 case TPG_VIDEO_ASPECT_14X9_CENTRE:
985 if (tpg->pix_aspect) {
986 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
987 tpg->border.top = (h - tpg->border.height) / 2;
988 break;
989 }
990 if (9 * w >= 14 * h) {
991 tpg->border.width = ((14 * h) / 9) & ~1;
992 if (((w - tpg->border.width) / 2) & ~1)
993 tpg->border.width -= 2;
994 tpg->border.left = (w - tpg->border.width) / 2;
995 break;
996 }
997 tpg->border.height = ((9 * w) / 14) & ~1;
998 tpg->border.top = (h - tpg->border.height) / 2;
999 break;
1000 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1001 if (tpg->pix_aspect) {
1002 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1003 tpg->border.top = (h - tpg->border.height) / 2;
1004 break;
1005 }
1006 if (9 * w >= 16 * h) {
1007 tpg->border.width = ((16 * h) / 9) & ~1;
1008 if (((w - tpg->border.width) / 2) & ~1)
1009 tpg->border.width -= 2;
1010 tpg->border.left = (w - tpg->border.width) / 2;
1011 break;
1012 }
1013 tpg->border.height = ((9 * w) / 16) & ~1;
1014 tpg->border.top = (h - tpg->border.height) / 2;
1015 break;
1016 default:
1017 break;
1018 }
1019 }
1020
1021 static void tpg_precalculate_line(struct tpg_data *tpg)
1022 {
1023 enum tpg_color contrast;
1024 unsigned pat;
1025 unsigned p;
1026 unsigned x;
1027
1028 switch (tpg->pattern) {
1029 case TPG_PAT_GREEN:
1030 contrast = TPG_COLOR_100_RED;
1031 break;
1032 case TPG_PAT_CSC_COLORBAR:
1033 contrast = TPG_COLOR_CSC_GREEN;
1034 break;
1035 default:
1036 contrast = TPG_COLOR_100_GREEN;
1037 break;
1038 }
1039
1040 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1041 /* Coarse scaling with Bresenham */
1042 unsigned int_part = tpg->src_width / tpg->scaled_width;
1043 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1044 unsigned src_x = 0;
1045 unsigned error = 0;
1046
1047 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1048 unsigned real_x = src_x;
1049 enum tpg_color color1, color2;
1050 u8 pix[TPG_MAX_PLANES][8];
1051
1052 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1053 color1 = tpg_get_color(tpg, pat, real_x);
1054
1055 src_x += int_part;
1056 error += fract_part;
1057 if (error >= tpg->scaled_width) {
1058 error -= tpg->scaled_width;
1059 src_x++;
1060 }
1061
1062 real_x = src_x;
1063 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1064 color2 = tpg_get_color(tpg, pat, real_x);
1065
1066 src_x += int_part;
1067 error += fract_part;
1068 if (error >= tpg->scaled_width) {
1069 error -= tpg->scaled_width;
1070 src_x++;
1071 }
1072
1073 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1074 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1075 for (p = 0; p < tpg->planes; p++) {
1076 unsigned twopixsize = tpg->twopixelsize[p];
1077 unsigned hdiv = tpg->hdownsampling[p];
1078 u8 *pos = tpg->lines[pat][p] +
1079 (x / hdiv) * twopixsize / 2;
1080
1081 memcpy(pos, pix[p], twopixsize / hdiv);
1082 }
1083 }
1084 }
1085
1086 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1087 unsigned pat_lines = tpg_get_pat_lines(tpg);
1088
1089 for (pat = 0; pat < pat_lines; pat++) {
1090 unsigned next_pat = (pat + 1) % pat_lines;
1091
1092 for (p = 1; p < tpg->planes; p++) {
1093 unsigned twopixsize = tpg->twopixelsize[p];
1094 unsigned hdiv = tpg->hdownsampling[p];
1095
1096 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1097 unsigned offset = (x / hdiv) * twopixsize / 2;
1098 u8 *pos1 = tpg->lines[pat][p] + offset;
1099 u8 *pos2 = tpg->lines[next_pat][p] + offset;
1100 u8 *dest = tpg->downsampled_lines[pat][p] + offset;
1101 unsigned i;
1102
1103 for (i = 0; i < twopixsize / hdiv; i++, dest++, pos1++, pos2++)
1104 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1105 }
1106 }
1107 }
1108 }
1109
1110 for (x = 0; x < tpg->scaled_width; x += 2) {
1111 u8 pix[TPG_MAX_PLANES][8];
1112
1113 gen_twopix(tpg, pix, contrast, 0);
1114 gen_twopix(tpg, pix, contrast, 1);
1115 for (p = 0; p < tpg->planes; p++) {
1116 unsigned twopixsize = tpg->twopixelsize[p];
1117 u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
1118
1119 memcpy(pos, pix[p], twopixsize);
1120 }
1121 }
1122 for (x = 0; x < tpg->scaled_width; x += 2) {
1123 u8 pix[TPG_MAX_PLANES][8];
1124
1125 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1126 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1127 for (p = 0; p < tpg->planes; p++) {
1128 unsigned twopixsize = tpg->twopixelsize[p];
1129 u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
1130
1131 memcpy(pos, pix[p], twopixsize);
1132 }
1133 }
1134 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1135 u8 pix[TPG_MAX_PLANES][8];
1136
1137 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1138 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1139 for (p = 0; p < tpg->planes; p++) {
1140 unsigned twopixsize = tpg->twopixelsize[p];
1141 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1142
1143 memcpy(pos, pix[p], twopixsize);
1144 }
1145 }
1146 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1147 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1148 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1149 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1150 }
1151
1152 /* need this to do rgb24 rendering */
1153 typedef struct { u16 __; u8 _; } __packed x24;
1154
1155 void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1156 int y, int x, char *text)
1157 {
1158 int line;
1159 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1160 unsigned div = step;
1161 unsigned first = 0;
1162 unsigned len = strlen(text);
1163 unsigned p;
1164
1165 if (font8x16 == NULL || basep == NULL)
1166 return;
1167
1168 /* Checks if it is possible to show string */
1169 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1170 return;
1171
1172 if (len > (tpg->compose.width - x) / 8)
1173 len = (tpg->compose.width - x) / 8;
1174 if (tpg->vflip)
1175 y = tpg->compose.height - y - 16;
1176 if (tpg->hflip)
1177 x = tpg->compose.width - x - 8;
1178 y += tpg->compose.top;
1179 x += tpg->compose.left;
1180 if (tpg->field == V4L2_FIELD_BOTTOM)
1181 first = 1;
1182 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1183 div = 2;
1184
1185 for (p = 0; p < tpg->planes; p++) {
1186 /* Print stream time */
1187 #define PRINTSTR(PIXTYPE) do { \
1188 PIXTYPE fg; \
1189 PIXTYPE bg; \
1190 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1191 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1192 \
1193 for (line = first; line < 16; line += step) { \
1194 int l = tpg->vflip ? 15 - line : line; \
1195 PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
1196 ((y * step + l) / div) * tpg->bytesperline[p] + \
1197 x * sizeof(PIXTYPE)); \
1198 unsigned s; \
1199 \
1200 for (s = 0; s < len; s++) { \
1201 u8 chr = font8x16[text[s] * 16 + line]; \
1202 \
1203 if (tpg->hflip) { \
1204 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1205 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1206 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1207 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1208 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1209 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1210 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1211 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1212 } else { \
1213 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1214 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1215 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1216 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1217 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1218 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1219 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1220 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1221 } \
1222 \
1223 pos += tpg->hflip ? -8 : 8; \
1224 } \
1225 } \
1226 } while (0)
1227
1228 switch (tpg->twopixelsize[p]) {
1229 case 2:
1230 PRINTSTR(u8); break;
1231 case 4:
1232 PRINTSTR(u16); break;
1233 case 6:
1234 PRINTSTR(x24); break;
1235 case 8:
1236 PRINTSTR(u32); break;
1237 }
1238 }
1239 }
1240
1241 void tpg_update_mv_step(struct tpg_data *tpg)
1242 {
1243 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1244
1245 if (tpg->hflip)
1246 factor = -factor;
1247 switch (tpg->mv_hor_mode) {
1248 case TPG_MOVE_NEG_FAST:
1249 case TPG_MOVE_POS_FAST:
1250 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1251 break;
1252 case TPG_MOVE_NEG:
1253 case TPG_MOVE_POS:
1254 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1255 break;
1256 case TPG_MOVE_NEG_SLOW:
1257 case TPG_MOVE_POS_SLOW:
1258 tpg->mv_hor_step = 2;
1259 break;
1260 case TPG_MOVE_NONE:
1261 tpg->mv_hor_step = 0;
1262 break;
1263 }
1264 if (factor < 0)
1265 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1266
1267 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1268 switch (tpg->mv_vert_mode) {
1269 case TPG_MOVE_NEG_FAST:
1270 case TPG_MOVE_POS_FAST:
1271 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1272 break;
1273 case TPG_MOVE_NEG:
1274 case TPG_MOVE_POS:
1275 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1276 break;
1277 case TPG_MOVE_NEG_SLOW:
1278 case TPG_MOVE_POS_SLOW:
1279 tpg->mv_vert_step = 1;
1280 break;
1281 case TPG_MOVE_NONE:
1282 tpg->mv_vert_step = 0;
1283 break;
1284 }
1285 if (factor < 0)
1286 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1287 }
1288
1289 /* Map the line number relative to the crop rectangle to a frame line number */
1290 static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
1291 unsigned field)
1292 {
1293 switch (field) {
1294 case V4L2_FIELD_TOP:
1295 return tpg->crop.top + src_y * 2;
1296 case V4L2_FIELD_BOTTOM:
1297 return tpg->crop.top + src_y * 2 + 1;
1298 default:
1299 return src_y + tpg->crop.top;
1300 }
1301 }
1302
1303 /*
1304 * Map the line number relative to the compose rectangle to a destination
1305 * buffer line number.
1306 */
1307 static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
1308 unsigned field)
1309 {
1310 y += tpg->compose.top;
1311 switch (field) {
1312 case V4L2_FIELD_SEQ_TB:
1313 if (y & 1)
1314 return tpg->buf_height / 2 + y / 2;
1315 return y / 2;
1316 case V4L2_FIELD_SEQ_BT:
1317 if (y & 1)
1318 return y / 2;
1319 return tpg->buf_height / 2 + y / 2;
1320 default:
1321 return y;
1322 }
1323 }
1324
1325 static void tpg_recalc(struct tpg_data *tpg)
1326 {
1327 if (tpg->recalc_colors) {
1328 tpg->recalc_colors = false;
1329 tpg->recalc_lines = true;
1330 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1331 tpg->real_quantization = tpg->quantization;
1332 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1333 switch (tpg->colorspace) {
1334 case V4L2_COLORSPACE_REC709:
1335 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1336 break;
1337 case V4L2_COLORSPACE_SRGB:
1338 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1339 break;
1340 case V4L2_COLORSPACE_BT2020:
1341 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1342 break;
1343 case V4L2_COLORSPACE_SMPTE240M:
1344 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1345 break;
1346 case V4L2_COLORSPACE_SMPTE170M:
1347 case V4L2_COLORSPACE_470_SYSTEM_M:
1348 case V4L2_COLORSPACE_470_SYSTEM_BG:
1349 case V4L2_COLORSPACE_ADOBERGB:
1350 default:
1351 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1352 break;
1353 }
1354 }
1355 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1356 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1357 if (tpg->is_yuv) {
1358 switch (tpg->real_ycbcr_enc) {
1359 case V4L2_YCBCR_ENC_SYCC:
1360 case V4L2_YCBCR_ENC_XV601:
1361 case V4L2_YCBCR_ENC_XV709:
1362 break;
1363 default:
1364 tpg->real_quantization =
1365 V4L2_QUANTIZATION_LIM_RANGE;
1366 break;
1367 }
1368 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1369 /* R'G'B' BT.2020 is limited range */
1370 tpg->real_quantization =
1371 V4L2_QUANTIZATION_LIM_RANGE;
1372 }
1373 }
1374 tpg_precalculate_colors(tpg);
1375 }
1376 if (tpg->recalc_square_border) {
1377 tpg->recalc_square_border = false;
1378 tpg_calculate_square_border(tpg);
1379 }
1380 if (tpg->recalc_lines) {
1381 tpg->recalc_lines = false;
1382 tpg_precalculate_line(tpg);
1383 }
1384 }
1385
1386 void tpg_calc_text_basep(struct tpg_data *tpg,
1387 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1388 {
1389 unsigned stride = tpg->bytesperline[p];
1390
1391 tpg_recalc(tpg);
1392
1393 basep[p][0] = vbuf;
1394 basep[p][1] = vbuf;
1395 if (tpg->field == V4L2_FIELD_SEQ_TB)
1396 basep[p][1] += tpg->buf_height * stride / 2;
1397 else if (tpg->field == V4L2_FIELD_SEQ_BT)
1398 basep[p][0] += tpg->buf_height * stride / 2;
1399 }
1400
1401 void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1402 {
1403 bool is_tv = std;
1404 bool is_60hz = is_tv && (std & V4L2_STD_525_60);
1405 unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
1406 unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
1407 unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1408 unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1409 unsigned wss_width;
1410 unsigned f;
1411 int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1412 int h;
1413 unsigned twopixsize = tpg->twopixelsize[p];
1414 unsigned img_width = tpg->compose.width * twopixsize / 2;
1415 unsigned line_offset;
1416 unsigned left_pillar_width = 0;
1417 unsigned right_pillar_start = img_width;
1418 unsigned stride = tpg->bytesperline[p];
1419 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1420 u8 *orig_vbuf = vbuf;
1421
1422 /* Coarse scaling with Bresenham */
1423 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1424 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1425 unsigned src_y = 0;
1426 unsigned error = 0;
1427
1428 tpg_recalc(tpg);
1429
1430 mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
1431 mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
1432 wss_width = tpg->crop.left < tpg->src_width / 2 ?
1433 tpg->src_width / 2 - tpg->crop.left : 0;
1434 if (wss_width > tpg->crop.width)
1435 wss_width = tpg->crop.width;
1436 wss_width = wss_width * tpg->scaled_width / tpg->src_width;
1437
1438 vbuf += tpg->compose.left * twopixsize / 2;
1439 line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
1440 line_offset = (line_offset & ~1) * twopixsize / 2;
1441 if (tpg->crop.left < tpg->border.left) {
1442 left_pillar_width = tpg->border.left - tpg->crop.left;
1443 if (left_pillar_width > tpg->crop.width)
1444 left_pillar_width = tpg->crop.width;
1445 left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
1446 left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
1447 }
1448 if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
1449 right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
1450 right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
1451 right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
1452 if (right_pillar_start > img_width)
1453 right_pillar_start = img_width;
1454 }
1455
1456 f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1457
1458 for (h = 0; h < tpg->compose.height; h++) {
1459 bool even;
1460 bool fill_blank = false;
1461 unsigned frame_line;
1462 unsigned buf_line;
1463 unsigned pat_line_old;
1464 unsigned pat_line_new;
1465 u8 *linestart_older;
1466 u8 *linestart_newer;
1467 u8 *linestart_top;
1468 u8 *linestart_bottom;
1469
1470 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1471 even = !(frame_line & 1);
1472 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1473 src_y += int_part;
1474 error += fract_part;
1475 if (error >= tpg->compose.height) {
1476 error -= tpg->compose.height;
1477 src_y++;
1478 }
1479
1480 if (h >= hmax) {
1481 if (hmax == tpg->compose.height)
1482 continue;
1483 if (!tpg->perc_fill_blank)
1484 continue;
1485 fill_blank = true;
1486 }
1487
1488 if (tpg->vflip)
1489 frame_line = tpg->src_height - frame_line - 1;
1490
1491 if (fill_blank) {
1492 linestart_older = tpg->contrast_line[p];
1493 linestart_newer = tpg->contrast_line[p];
1494 } else if (tpg->qual != TPG_QUAL_NOISE &&
1495 (frame_line < tpg->border.top ||
1496 frame_line >= tpg->border.top + tpg->border.height)) {
1497 linestart_older = tpg->black_line[p];
1498 linestart_newer = tpg->black_line[p];
1499 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1500 linestart_older = tpg->random_line[p] +
1501 twopixsize * prandom_u32_max(tpg->src_width / 2);
1502 linestart_newer = tpg->random_line[p] +
1503 twopixsize * prandom_u32_max(tpg->src_width / 2);
1504 } else {
1505 pat_line_old = tpg_get_pat_line(tpg,
1506 (frame_line + mv_vert_old) % tpg->src_height);
1507 pat_line_new = tpg_get_pat_line(tpg,
1508 (frame_line + mv_vert_new) % tpg->src_height);
1509 linestart_older = tpg->lines[pat_line_old][p] +
1510 mv_hor_old * twopixsize / 2;
1511 linestart_newer = tpg->lines[pat_line_new][p] +
1512 mv_hor_new * twopixsize / 2;
1513 linestart_older += line_offset;
1514 linestart_newer += line_offset;
1515 }
1516 if (tpg->field_alternate) {
1517 linestart_top = linestart_bottom = linestart_older;
1518 } else if (is_60hz) {
1519 linestart_top = linestart_newer;
1520 linestart_bottom = linestart_older;
1521 } else {
1522 linestart_top = linestart_older;
1523 linestart_bottom = linestart_newer;
1524 }
1525
1526 switch (tpg->field) {
1527 case V4L2_FIELD_INTERLACED:
1528 case V4L2_FIELD_INTERLACED_TB:
1529 case V4L2_FIELD_SEQ_TB:
1530 case V4L2_FIELD_SEQ_BT:
1531 if (even)
1532 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1533 else
1534 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1535 break;
1536 case V4L2_FIELD_INTERLACED_BT:
1537 if (even)
1538 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1539 else
1540 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1541 break;
1542 case V4L2_FIELD_TOP:
1543 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1544 break;
1545 case V4L2_FIELD_BOTTOM:
1546 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1547 break;
1548 case V4L2_FIELD_NONE:
1549 default:
1550 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1551 break;
1552 }
1553
1554 if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
1555 /*
1556 * Replace the first half of the top line of a 50 Hz frame
1557 * with random data to simulate a WSS signal.
1558 */
1559 u8 *wss = tpg->random_line[p] +
1560 twopixsize * prandom_u32_max(tpg->src_width / 2);
1561
1562 memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
1563 }
1564 }
1565
1566 vbuf = orig_vbuf;
1567 vbuf += tpg->compose.left * twopixsize / 2;
1568 src_y = 0;
1569 error = 0;
1570 for (h = 0; h < tpg->compose.height; h++) {
1571 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1572 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1573 const struct v4l2_rect *sq = &tpg->square;
1574 const struct v4l2_rect *b = &tpg->border;
1575 const struct v4l2_rect *c = &tpg->crop;
1576
1577 src_y += int_part;
1578 error += fract_part;
1579 if (error >= tpg->compose.height) {
1580 error -= tpg->compose.height;
1581 src_y++;
1582 }
1583
1584 if (tpg->show_border && frame_line >= b->top &&
1585 frame_line < b->top + b->height) {
1586 unsigned bottom = b->top + b->height - 1;
1587 unsigned left = left_pillar_width;
1588 unsigned right = right_pillar_start;
1589
1590 if (frame_line == b->top || frame_line == b->top + 1 ||
1591 frame_line == bottom || frame_line == bottom - 1) {
1592 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1593 right - left);
1594 } else {
1595 if (b->left >= c->left &&
1596 b->left < c->left + c->width)
1597 memcpy(vbuf + buf_line * stride + left,
1598 tpg->contrast_line[p], twopixsize);
1599 if (b->left + b->width > c->left &&
1600 b->left + b->width <= c->left + c->width)
1601 memcpy(vbuf + buf_line * stride + right - twopixsize,
1602 tpg->contrast_line[p], twopixsize);
1603 }
1604 }
1605 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1606 frame_line < b->top + b->height) {
1607 memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
1608 memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
1609 img_width - right_pillar_start);
1610 }
1611 if (tpg->show_square && frame_line >= sq->top &&
1612 frame_line < sq->top + sq->height &&
1613 sq->left < c->left + c->width &&
1614 sq->left + sq->width >= c->left) {
1615 unsigned left = sq->left;
1616 unsigned width = sq->width;
1617
1618 if (c->left > left) {
1619 width -= c->left - left;
1620 left = c->left;
1621 }
1622 if (c->left + c->width < left + width)
1623 width -= left + width - c->left - c->width;
1624 left -= c->left;
1625 left = (left * tpg->scaled_width) / tpg->src_width;
1626 left = (left & ~1) * twopixsize / 2;
1627 width = (width * tpg->scaled_width) / tpg->src_width;
1628 width = (width & ~1) * twopixsize / 2;
1629 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1630 }
1631 if (tpg->insert_sav) {
1632 unsigned offset = (tpg->compose.width / 6) * twopixsize;
1633 u8 *p = vbuf + buf_line * stride + offset;
1634 unsigned vact = 0, hact = 0;
1635
1636 p[0] = 0xff;
1637 p[1] = 0;
1638 p[2] = 0;
1639 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1640 ((hact ^ vact) << 3) |
1641 ((hact ^ f) << 2) |
1642 ((f ^ vact) << 1) |
1643 (hact ^ vact ^ f);
1644 }
1645 if (tpg->insert_eav) {
1646 unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
1647 u8 *p = vbuf + buf_line * stride + offset;
1648 unsigned vact = 0, hact = 1;
1649
1650 p[0] = 0xff;
1651 p[1] = 0;
1652 p[2] = 0;
1653 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1654 ((hact ^ vact) << 3) |
1655 ((hact ^ f) << 2) |
1656 ((f ^ vact) << 1) |
1657 (hact ^ vact ^ f);
1658 }
1659 }
1660 }
1661
1662 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1663 {
1664 unsigned offset = 0;
1665 unsigned i;
1666
1667 if (tpg->buffers > 1) {
1668 tpg_fill_plane_buffer(tpg, std, p, vbuf);
1669 return;
1670 }
1671
1672 for (i = 0; i < tpg->planes; i++) {
1673 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
1674 offset += tpg_calc_plane_size(tpg, i);
1675 }
1676 }
This page took 0.11132 seconds and 4 git commands to generate.