]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/media/platform/vivid/vivid-tpg.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux
[mirror_ubuntu-bionic-kernel.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 "1x1 Checkers",
39 "Alternating Hor Lines",
40 "Alternating Vert Lines",
41 "One Pixel Wide Cross",
42 "Two Pixels Wide Cross",
43 "Ten Pixels Wide Cross",
44 "Gray Ramp",
45 "Noise",
46 NULL
47 };
48
49 /* Must remain in sync with enum tpg_aspect */
50 const char * const tpg_aspect_strings[] = {
51 "Source Width x Height",
52 "4x3",
53 "14x9",
54 "16x9",
55 "16x9 Anamorphic",
56 NULL
57 };
58
59 /*
60 * Sine table: sin[0] = 127 * sin(-180 degrees)
61 * sin[128] = 127 * sin(0 degrees)
62 * sin[256] = 127 * sin(180 degrees)
63 */
64 static const s8 sin[257] = {
65 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
66 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
67 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
68 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
69 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
70 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
71 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
72 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
73 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
74 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
75 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
76 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
77 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
78 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
79 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
80 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
81 0,
82 };
83
84 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
85
86 /* Global font descriptor */
87 static const u8 *font8x16;
88
89 void tpg_set_font(const u8 *f)
90 {
91 font8x16 = f;
92 }
93
94 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
95 {
96 memset(tpg, 0, sizeof(*tpg));
97 tpg->scaled_width = tpg->src_width = w;
98 tpg->src_height = tpg->buf_height = h;
99 tpg->crop.width = tpg->compose.width = w;
100 tpg->crop.height = tpg->compose.height = h;
101 tpg->recalc_colors = true;
102 tpg->recalc_square_border = true;
103 tpg->brightness = 128;
104 tpg->contrast = 128;
105 tpg->saturation = 128;
106 tpg->hue = 0;
107 tpg->mv_hor_mode = TPG_MOVE_NONE;
108 tpg->mv_vert_mode = TPG_MOVE_NONE;
109 tpg->field = V4L2_FIELD_NONE;
110 tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
111 tpg->colorspace = V4L2_COLORSPACE_SRGB;
112 tpg->perc_fill = 100;
113 }
114
115 int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
116 {
117 unsigned pat;
118 unsigned plane;
119
120 tpg->max_line_width = max_w;
121 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
122 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
123 unsigned pixelsz = plane ? 1 : 4;
124
125 tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
126 if (!tpg->lines[pat][plane])
127 return -ENOMEM;
128 }
129 }
130 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
131 unsigned pixelsz = plane ? 1 : 4;
132
133 tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
134 if (!tpg->contrast_line[plane])
135 return -ENOMEM;
136 tpg->black_line[plane] = vzalloc(max_w * pixelsz);
137 if (!tpg->black_line[plane])
138 return -ENOMEM;
139 tpg->random_line[plane] = vzalloc(max_w * pixelsz);
140 if (!tpg->random_line[plane])
141 return -ENOMEM;
142 }
143 return 0;
144 }
145
146 void tpg_free(struct tpg_data *tpg)
147 {
148 unsigned pat;
149 unsigned plane;
150
151 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
152 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
153 vfree(tpg->lines[pat][plane]);
154 tpg->lines[pat][plane] = NULL;
155 }
156 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
157 vfree(tpg->contrast_line[plane]);
158 vfree(tpg->black_line[plane]);
159 vfree(tpg->random_line[plane]);
160 tpg->contrast_line[plane] = NULL;
161 tpg->black_line[plane] = NULL;
162 tpg->random_line[plane] = NULL;
163 }
164 }
165
166 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
167 {
168 tpg->fourcc = fourcc;
169 tpg->planes = 1;
170 tpg->recalc_colors = true;
171 switch (fourcc) {
172 case V4L2_PIX_FMT_RGB565:
173 case V4L2_PIX_FMT_RGB565X:
174 case V4L2_PIX_FMT_RGB555:
175 case V4L2_PIX_FMT_XRGB555:
176 case V4L2_PIX_FMT_ARGB555:
177 case V4L2_PIX_FMT_RGB555X:
178 case V4L2_PIX_FMT_RGB24:
179 case V4L2_PIX_FMT_BGR24:
180 case V4L2_PIX_FMT_RGB32:
181 case V4L2_PIX_FMT_BGR32:
182 case V4L2_PIX_FMT_XRGB32:
183 case V4L2_PIX_FMT_XBGR32:
184 case V4L2_PIX_FMT_ARGB32:
185 case V4L2_PIX_FMT_ABGR32:
186 tpg->is_yuv = false;
187 break;
188 case V4L2_PIX_FMT_NV16M:
189 case V4L2_PIX_FMT_NV61M:
190 tpg->planes = 2;
191 /* fall-through */
192 case V4L2_PIX_FMT_YUYV:
193 case V4L2_PIX_FMT_UYVY:
194 case V4L2_PIX_FMT_YVYU:
195 case V4L2_PIX_FMT_VYUY:
196 tpg->is_yuv = true;
197 break;
198 default:
199 return false;
200 }
201
202 switch (fourcc) {
203 case V4L2_PIX_FMT_RGB565:
204 case V4L2_PIX_FMT_RGB565X:
205 case V4L2_PIX_FMT_RGB555:
206 case V4L2_PIX_FMT_XRGB555:
207 case V4L2_PIX_FMT_ARGB555:
208 case V4L2_PIX_FMT_RGB555X:
209 case V4L2_PIX_FMT_YUYV:
210 case V4L2_PIX_FMT_UYVY:
211 case V4L2_PIX_FMT_YVYU:
212 case V4L2_PIX_FMT_VYUY:
213 tpg->twopixelsize[0] = 2 * 2;
214 break;
215 case V4L2_PIX_FMT_RGB24:
216 case V4L2_PIX_FMT_BGR24:
217 tpg->twopixelsize[0] = 2 * 3;
218 break;
219 case V4L2_PIX_FMT_RGB32:
220 case V4L2_PIX_FMT_BGR32:
221 case V4L2_PIX_FMT_XRGB32:
222 case V4L2_PIX_FMT_XBGR32:
223 case V4L2_PIX_FMT_ARGB32:
224 case V4L2_PIX_FMT_ABGR32:
225 tpg->twopixelsize[0] = 2 * 4;
226 break;
227 case V4L2_PIX_FMT_NV16M:
228 case V4L2_PIX_FMT_NV61M:
229 tpg->twopixelsize[0] = 2;
230 tpg->twopixelsize[1] = 2;
231 break;
232 }
233 return true;
234 }
235
236 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
237 const struct v4l2_rect *compose)
238 {
239 tpg->crop = *crop;
240 tpg->compose = *compose;
241 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
242 tpg->crop.width - 1) / tpg->crop.width;
243 tpg->scaled_width &= ~1;
244 if (tpg->scaled_width > tpg->max_line_width)
245 tpg->scaled_width = tpg->max_line_width;
246 if (tpg->scaled_width < 2)
247 tpg->scaled_width = 2;
248 tpg->recalc_lines = true;
249 }
250
251 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
252 u32 field)
253 {
254 unsigned p;
255
256 tpg->src_width = width;
257 tpg->src_height = height;
258 tpg->field = field;
259 tpg->buf_height = height;
260 if (V4L2_FIELD_HAS_T_OR_B(field))
261 tpg->buf_height /= 2;
262 tpg->scaled_width = width;
263 tpg->crop.top = tpg->crop.left = 0;
264 tpg->crop.width = width;
265 tpg->crop.height = height;
266 tpg->compose.top = tpg->compose.left = 0;
267 tpg->compose.width = width;
268 tpg->compose.height = tpg->buf_height;
269 for (p = 0; p < tpg->planes; p++)
270 tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2;
271 tpg->recalc_square_border = true;
272 }
273
274 static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
275 {
276 switch (tpg->pattern) {
277 case TPG_PAT_BLACK:
278 return TPG_COLOR_100_WHITE;
279 case TPG_PAT_CSC_COLORBAR:
280 return TPG_COLOR_CSC_BLACK;
281 default:
282 return TPG_COLOR_100_BLACK;
283 }
284 }
285
286 static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
287 {
288 switch (tpg->pattern) {
289 case TPG_PAT_75_COLORBAR:
290 case TPG_PAT_CSC_COLORBAR:
291 return TPG_COLOR_CSC_WHITE;
292 case TPG_PAT_BLACK:
293 return TPG_COLOR_100_BLACK;
294 default:
295 return TPG_COLOR_100_WHITE;
296 }
297 }
298
299 static u16 color_to_y(struct tpg_data *tpg, int r, int g, int b)
300 {
301 switch (tpg->colorspace) {
302 case V4L2_COLORSPACE_SMPTE170M:
303 case V4L2_COLORSPACE_470_SYSTEM_M:
304 case V4L2_COLORSPACE_470_SYSTEM_BG:
305 return ((16829 * r + 33039 * g + 6416 * b + 16 * 32768) >> 16) + (16 << 4);
306 case V4L2_COLORSPACE_SMPTE240M:
307 return ((11932 * r + 39455 * g + 4897 * b + 16 * 32768) >> 16) + (16 << 4);
308 case V4L2_COLORSPACE_REC709:
309 case V4L2_COLORSPACE_SRGB:
310 default:
311 return ((11966 * r + 40254 * g + 4064 * b + 16 * 32768) >> 16) + (16 << 4);
312 }
313 }
314
315 static u16 color_to_cb(struct tpg_data *tpg, int r, int g, int b)
316 {
317 switch (tpg->colorspace) {
318 case V4L2_COLORSPACE_SMPTE170M:
319 case V4L2_COLORSPACE_470_SYSTEM_M:
320 case V4L2_COLORSPACE_470_SYSTEM_BG:
321 return ((-9714 * r - 19070 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
322 case V4L2_COLORSPACE_SMPTE240M:
323 return ((-6684 * r - 22100 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
324 case V4L2_COLORSPACE_REC709:
325 case V4L2_COLORSPACE_SRGB:
326 default:
327 return ((-6596 * r - 22189 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
328 }
329 }
330
331 static u16 color_to_cr(struct tpg_data *tpg, int r, int g, int b)
332 {
333 switch (tpg->colorspace) {
334 case V4L2_COLORSPACE_SMPTE170M:
335 case V4L2_COLORSPACE_470_SYSTEM_M:
336 case V4L2_COLORSPACE_470_SYSTEM_BG:
337 return ((28784 * r - 24103 * g - 4681 * b + 16 * 32768) >> 16) + (128 << 4);
338 case V4L2_COLORSPACE_SMPTE240M:
339 return ((28784 * r - 25606 * g - 3178 * b + 16 * 32768) >> 16) + (128 << 4);
340 case V4L2_COLORSPACE_REC709:
341 case V4L2_COLORSPACE_SRGB:
342 default:
343 return ((28784 * r - 26145 * g - 2639 * b + 16 * 32768) >> 16) + (128 << 4);
344 }
345 }
346
347 static u16 ycbcr_to_r(struct tpg_data *tpg, int y, int cb, int cr)
348 {
349 int r;
350
351 y -= 16 << 4;
352 cb -= 128 << 4;
353 cr -= 128 << 4;
354 switch (tpg->colorspace) {
355 case V4L2_COLORSPACE_SMPTE170M:
356 case V4L2_COLORSPACE_470_SYSTEM_M:
357 case V4L2_COLORSPACE_470_SYSTEM_BG:
358 r = 4769 * y + 6537 * cr;
359 break;
360 case V4L2_COLORSPACE_SMPTE240M:
361 r = 4769 * y + 7376 * cr;
362 break;
363 case V4L2_COLORSPACE_REC709:
364 case V4L2_COLORSPACE_SRGB:
365 default:
366 r = 4769 * y + 7343 * cr;
367 break;
368 }
369 return clamp(r >> 12, 0, 0xff0);
370 }
371
372 static u16 ycbcr_to_g(struct tpg_data *tpg, int y, int cb, int cr)
373 {
374 int g;
375
376 y -= 16 << 4;
377 cb -= 128 << 4;
378 cr -= 128 << 4;
379 switch (tpg->colorspace) {
380 case V4L2_COLORSPACE_SMPTE170M:
381 case V4L2_COLORSPACE_470_SYSTEM_M:
382 case V4L2_COLORSPACE_470_SYSTEM_BG:
383 g = 4769 * y - 1605 * cb - 3330 * cr;
384 break;
385 case V4L2_COLORSPACE_SMPTE240M:
386 g = 4769 * y - 1055 * cb - 2341 * cr;
387 break;
388 case V4L2_COLORSPACE_REC709:
389 case V4L2_COLORSPACE_SRGB:
390 default:
391 g = 4769 * y - 873 * cb - 2183 * cr;
392 break;
393 }
394 return clamp(g >> 12, 0, 0xff0);
395 }
396
397 static u16 ycbcr_to_b(struct tpg_data *tpg, int y, int cb, int cr)
398 {
399 int b;
400
401 y -= 16 << 4;
402 cb -= 128 << 4;
403 cr -= 128 << 4;
404 switch (tpg->colorspace) {
405 case V4L2_COLORSPACE_SMPTE170M:
406 case V4L2_COLORSPACE_470_SYSTEM_M:
407 case V4L2_COLORSPACE_470_SYSTEM_BG:
408 b = 4769 * y + 7343 * cb;
409 break;
410 case V4L2_COLORSPACE_SMPTE240M:
411 b = 4769 * y + 8552 * cb;
412 break;
413 case V4L2_COLORSPACE_REC709:
414 case V4L2_COLORSPACE_SRGB:
415 default:
416 b = 4769 * y + 8652 * cb;
417 break;
418 }
419 return clamp(b >> 12, 0, 0xff0);
420 }
421
422 /* precalculate color bar values to speed up rendering */
423 static void precalculate_color(struct tpg_data *tpg, int k)
424 {
425 int col = k;
426 int r = tpg_colors[col].r;
427 int g = tpg_colors[col].g;
428 int b = tpg_colors[col].b;
429
430 if (k == TPG_COLOR_TEXTBG) {
431 col = tpg_get_textbg_color(tpg);
432
433 r = tpg_colors[col].r;
434 g = tpg_colors[col].g;
435 b = tpg_colors[col].b;
436 } else if (k == TPG_COLOR_TEXTFG) {
437 col = tpg_get_textfg_color(tpg);
438
439 r = tpg_colors[col].r;
440 g = tpg_colors[col].g;
441 b = tpg_colors[col].b;
442 } else if (tpg->pattern == TPG_PAT_NOISE) {
443 r = g = b = prandom_u32_max(256);
444 } else if (k == TPG_COLOR_RANDOM) {
445 r = g = b = tpg->qual_offset + prandom_u32_max(196);
446 } else if (k >= TPG_COLOR_RAMP) {
447 r = g = b = k - TPG_COLOR_RAMP;
448 }
449
450 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
451 r = tpg_csc_colors[tpg->colorspace][col].r;
452 g = tpg_csc_colors[tpg->colorspace][col].g;
453 b = tpg_csc_colors[tpg->colorspace][col].b;
454 } else {
455 r <<= 4;
456 g <<= 4;
457 b <<= 4;
458 }
459 if (tpg->qual == TPG_QUAL_GRAY)
460 r = g = b = color_to_y(tpg, r, g, b);
461
462 /*
463 * The assumption is that the RGB output is always full range,
464 * so only if the rgb_range overrides the 'real' rgb range do
465 * we need to convert the RGB values.
466 *
467 * Currently there is no way of signalling to userspace if you
468 * are actually giving it limited range RGB (or full range
469 * YUV for that matter).
470 *
471 * Remember that r, g and b are still in the 0 - 0xff0 range.
472 */
473 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
474 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
475 /*
476 * Convert from full range (which is what r, g and b are)
477 * to limited range (which is the 'real' RGB range), which
478 * is then interpreted as full range.
479 */
480 r = (r * 219) / 255 + (16 << 4);
481 g = (g * 219) / 255 + (16 << 4);
482 b = (b * 219) / 255 + (16 << 4);
483 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
484 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
485 /*
486 * Clamp r, g and b to the limited range and convert to full
487 * range since that's what we deliver.
488 */
489 r = clamp(r, 16 << 4, 235 << 4);
490 g = clamp(g, 16 << 4, 235 << 4);
491 b = clamp(b, 16 << 4, 235 << 4);
492 r = (r - (16 << 4)) * 255 / 219;
493 g = (g - (16 << 4)) * 255 / 219;
494 b = (b - (16 << 4)) * 255 / 219;
495 }
496
497 if (tpg->brightness != 128 || tpg->contrast != 128 ||
498 tpg->saturation != 128 || tpg->hue) {
499 /* Implement these operations */
500
501 /* First convert to YCbCr */
502 int y = color_to_y(tpg, r, g, b); /* Luma */
503 int cb = color_to_cb(tpg, r, g, b); /* Cb */
504 int cr = color_to_cr(tpg, r, g, b); /* Cr */
505 int tmp_cb, tmp_cr;
506
507 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
508 y += (tpg->brightness << 4) - (128 << 4);
509
510 cb -= 128 << 4;
511 cr -= 128 << 4;
512 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
513 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
514
515 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
516 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
517 if (tpg->is_yuv) {
518 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
519 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
520 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
521 return;
522 }
523 r = ycbcr_to_r(tpg, y, cb, cr);
524 g = ycbcr_to_g(tpg, y, cb, cr);
525 b = ycbcr_to_b(tpg, y, cb, cr);
526 }
527
528 if (tpg->is_yuv) {
529 /* Convert to YCbCr */
530 u16 y = color_to_y(tpg, r, g, b); /* Luma */
531 u16 cb = color_to_cb(tpg, r, g, b); /* Cb */
532 u16 cr = color_to_cr(tpg, r, g, b); /* Cr */
533
534 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
535 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
536 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
537 } else {
538 switch (tpg->fourcc) {
539 case V4L2_PIX_FMT_RGB565:
540 case V4L2_PIX_FMT_RGB565X:
541 r >>= 7;
542 g >>= 6;
543 b >>= 7;
544 break;
545 case V4L2_PIX_FMT_RGB555:
546 case V4L2_PIX_FMT_XRGB555:
547 case V4L2_PIX_FMT_ARGB555:
548 case V4L2_PIX_FMT_RGB555X:
549 r >>= 7;
550 g >>= 7;
551 b >>= 7;
552 break;
553 default:
554 r >>= 4;
555 g >>= 4;
556 b >>= 4;
557 break;
558 }
559
560 tpg->colors[k][0] = r;
561 tpg->colors[k][1] = g;
562 tpg->colors[k][2] = b;
563 }
564 }
565
566 static void tpg_precalculate_colors(struct tpg_data *tpg)
567 {
568 int k;
569
570 for (k = 0; k < TPG_COLOR_MAX; k++)
571 precalculate_color(tpg, k);
572 }
573
574 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
575 static void gen_twopix(struct tpg_data *tpg,
576 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
577 {
578 unsigned offset = odd * tpg->twopixelsize[0] / 2;
579 u8 alpha = tpg->alpha_component;
580 u8 r_y, g_u, b_v;
581
582 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
583 color != TPG_COLOR_100_RED &&
584 color != TPG_COLOR_75_RED)
585 alpha = 0;
586 if (color == TPG_COLOR_RANDOM)
587 precalculate_color(tpg, color);
588 r_y = tpg->colors[color][0]; /* R or precalculated Y */
589 g_u = tpg->colors[color][1]; /* G or precalculated U */
590 b_v = tpg->colors[color][2]; /* B or precalculated V */
591
592 switch (tpg->fourcc) {
593 case V4L2_PIX_FMT_NV16M:
594 buf[0][offset] = r_y;
595 buf[1][offset] = odd ? b_v : g_u;
596 break;
597 case V4L2_PIX_FMT_NV61M:
598 buf[0][offset] = r_y;
599 buf[1][offset] = odd ? g_u : b_v;
600 break;
601
602 case V4L2_PIX_FMT_YUYV:
603 buf[0][offset] = r_y;
604 buf[0][offset + 1] = odd ? b_v : g_u;
605 break;
606 case V4L2_PIX_FMT_UYVY:
607 buf[0][offset] = odd ? b_v : g_u;
608 buf[0][offset + 1] = r_y;
609 break;
610 case V4L2_PIX_FMT_YVYU:
611 buf[0][offset] = r_y;
612 buf[0][offset + 1] = odd ? g_u : b_v;
613 break;
614 case V4L2_PIX_FMT_VYUY:
615 buf[0][offset] = odd ? g_u : b_v;
616 buf[0][offset + 1] = r_y;
617 break;
618 case V4L2_PIX_FMT_RGB565:
619 buf[0][offset] = (g_u << 5) | b_v;
620 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
621 break;
622 case V4L2_PIX_FMT_RGB565X:
623 buf[0][offset] = (r_y << 3) | (g_u >> 3);
624 buf[0][offset + 1] = (g_u << 5) | b_v;
625 break;
626 case V4L2_PIX_FMT_RGB555:
627 case V4L2_PIX_FMT_XRGB555:
628 alpha = 0;
629 /* fall through */
630 case V4L2_PIX_FMT_ARGB555:
631 buf[0][offset] = (g_u << 5) | b_v;
632 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
633 break;
634 case V4L2_PIX_FMT_RGB555X:
635 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
636 buf[0][offset + 1] = (g_u << 5) | b_v;
637 break;
638 case V4L2_PIX_FMT_RGB24:
639 buf[0][offset] = r_y;
640 buf[0][offset + 1] = g_u;
641 buf[0][offset + 2] = b_v;
642 break;
643 case V4L2_PIX_FMT_BGR24:
644 buf[0][offset] = b_v;
645 buf[0][offset + 1] = g_u;
646 buf[0][offset + 2] = r_y;
647 break;
648 case V4L2_PIX_FMT_RGB32:
649 case V4L2_PIX_FMT_XRGB32:
650 alpha = 0;
651 /* fall through */
652 case V4L2_PIX_FMT_ARGB32:
653 buf[0][offset] = alpha;
654 buf[0][offset + 1] = r_y;
655 buf[0][offset + 2] = g_u;
656 buf[0][offset + 3] = b_v;
657 break;
658 case V4L2_PIX_FMT_BGR32:
659 case V4L2_PIX_FMT_XBGR32:
660 alpha = 0;
661 /* fall through */
662 case V4L2_PIX_FMT_ABGR32:
663 buf[0][offset] = b_v;
664 buf[0][offset + 1] = g_u;
665 buf[0][offset + 2] = r_y;
666 buf[0][offset + 3] = alpha;
667 break;
668 }
669 }
670
671 /* Return how many pattern lines are used by the current pattern. */
672 static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
673 {
674 switch (tpg->pattern) {
675 case TPG_PAT_CHECKERS_16X16:
676 case TPG_PAT_CHECKERS_1X1:
677 case TPG_PAT_ALTERNATING_HLINES:
678 case TPG_PAT_CROSS_1_PIXEL:
679 case TPG_PAT_CROSS_2_PIXELS:
680 case TPG_PAT_CROSS_10_PIXELS:
681 return 2;
682 case TPG_PAT_100_COLORSQUARES:
683 case TPG_PAT_100_HCOLORBAR:
684 return 8;
685 default:
686 return 1;
687 }
688 }
689
690 /* Which pattern line should be used for the given frame line. */
691 static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
692 {
693 switch (tpg->pattern) {
694 case TPG_PAT_CHECKERS_16X16:
695 return (line >> 4) & 1;
696 case TPG_PAT_CHECKERS_1X1:
697 case TPG_PAT_ALTERNATING_HLINES:
698 return line & 1;
699 case TPG_PAT_100_COLORSQUARES:
700 case TPG_PAT_100_HCOLORBAR:
701 return (line * 8) / tpg->src_height;
702 case TPG_PAT_CROSS_1_PIXEL:
703 return line == tpg->src_height / 2;
704 case TPG_PAT_CROSS_2_PIXELS:
705 return (line + 1) / 2 == tpg->src_height / 4;
706 case TPG_PAT_CROSS_10_PIXELS:
707 return (line + 10) / 20 == tpg->src_height / 40;
708 default:
709 return 0;
710 }
711 }
712
713 /*
714 * Which color should be used for the given pattern line and X coordinate.
715 * Note: x is in the range 0 to 2 * tpg->src_width.
716 */
717 static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x)
718 {
719 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
720 should be modified */
721 static const enum tpg_color bars[3][8] = {
722 /* Standard ITU-R 75% color bar sequence */
723 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
724 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
725 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
726 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
727 /* Standard ITU-R 100% color bar sequence */
728 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
729 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
730 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
731 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
732 /* Color bar sequence suitable to test CSC */
733 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
734 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
735 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
736 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
737 };
738
739 switch (tpg->pattern) {
740 case TPG_PAT_75_COLORBAR:
741 case TPG_PAT_100_COLORBAR:
742 case TPG_PAT_CSC_COLORBAR:
743 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
744 case TPG_PAT_100_COLORSQUARES:
745 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
746 case TPG_PAT_100_HCOLORBAR:
747 return bars[1][pat_line];
748 case TPG_PAT_BLACK:
749 return TPG_COLOR_100_BLACK;
750 case TPG_PAT_WHITE:
751 return TPG_COLOR_100_WHITE;
752 case TPG_PAT_RED:
753 return TPG_COLOR_100_RED;
754 case TPG_PAT_GREEN:
755 return TPG_COLOR_100_GREEN;
756 case TPG_PAT_BLUE:
757 return TPG_COLOR_100_BLUE;
758 case TPG_PAT_CHECKERS_16X16:
759 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
760 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
761 case TPG_PAT_CHECKERS_1X1:
762 return ((x & 1) ^ (pat_line & 1)) ?
763 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
764 case TPG_PAT_ALTERNATING_HLINES:
765 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
766 case TPG_PAT_ALTERNATING_VLINES:
767 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
768 case TPG_PAT_CROSS_1_PIXEL:
769 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
770 return TPG_COLOR_100_BLACK;
771 return TPG_COLOR_100_WHITE;
772 case TPG_PAT_CROSS_2_PIXELS:
773 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
774 return TPG_COLOR_100_BLACK;
775 return TPG_COLOR_100_WHITE;
776 case TPG_PAT_CROSS_10_PIXELS:
777 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
778 return TPG_COLOR_100_BLACK;
779 return TPG_COLOR_100_WHITE;
780 case TPG_PAT_GRAY_RAMP:
781 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
782 default:
783 return TPG_COLOR_100_RED;
784 }
785 }
786
787 /*
788 * Given the pixel aspect ratio and video aspect ratio calculate the
789 * coordinates of a centered square and the coordinates of the border of
790 * the active video area. The coordinates are relative to the source
791 * frame rectangle.
792 */
793 static void tpg_calculate_square_border(struct tpg_data *tpg)
794 {
795 unsigned w = tpg->src_width;
796 unsigned h = tpg->src_height;
797 unsigned sq_w, sq_h;
798
799 sq_w = (w * 2 / 5) & ~1;
800 if (((w - sq_w) / 2) & 1)
801 sq_w += 2;
802 sq_h = sq_w;
803 tpg->square.width = sq_w;
804 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
805 unsigned ana_sq_w = (sq_w / 4) * 3;
806
807 if (((w - ana_sq_w) / 2) & 1)
808 ana_sq_w += 2;
809 tpg->square.width = ana_sq_w;
810 }
811 tpg->square.left = (w - tpg->square.width) / 2;
812 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
813 sq_h = sq_w * 10 / 11;
814 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
815 sq_h = sq_w * 59 / 54;
816 tpg->square.height = sq_h;
817 tpg->square.top = (h - sq_h) / 2;
818 tpg->border.left = 0;
819 tpg->border.width = w;
820 tpg->border.top = 0;
821 tpg->border.height = h;
822 switch (tpg->vid_aspect) {
823 case TPG_VIDEO_ASPECT_4X3:
824 if (tpg->pix_aspect)
825 return;
826 if (3 * w >= 4 * h) {
827 tpg->border.width = ((4 * h) / 3) & ~1;
828 if (((w - tpg->border.width) / 2) & ~1)
829 tpg->border.width -= 2;
830 tpg->border.left = (w - tpg->border.width) / 2;
831 break;
832 }
833 tpg->border.height = ((3 * w) / 4) & ~1;
834 tpg->border.top = (h - tpg->border.height) / 2;
835 break;
836 case TPG_VIDEO_ASPECT_14X9_CENTRE:
837 if (tpg->pix_aspect) {
838 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
839 tpg->border.top = (h - tpg->border.height) / 2;
840 break;
841 }
842 if (9 * w >= 14 * h) {
843 tpg->border.width = ((14 * h) / 9) & ~1;
844 if (((w - tpg->border.width) / 2) & ~1)
845 tpg->border.width -= 2;
846 tpg->border.left = (w - tpg->border.width) / 2;
847 break;
848 }
849 tpg->border.height = ((9 * w) / 14) & ~1;
850 tpg->border.top = (h - tpg->border.height) / 2;
851 break;
852 case TPG_VIDEO_ASPECT_16X9_CENTRE:
853 if (tpg->pix_aspect) {
854 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
855 tpg->border.top = (h - tpg->border.height) / 2;
856 break;
857 }
858 if (9 * w >= 16 * h) {
859 tpg->border.width = ((16 * h) / 9) & ~1;
860 if (((w - tpg->border.width) / 2) & ~1)
861 tpg->border.width -= 2;
862 tpg->border.left = (w - tpg->border.width) / 2;
863 break;
864 }
865 tpg->border.height = ((9 * w) / 16) & ~1;
866 tpg->border.top = (h - tpg->border.height) / 2;
867 break;
868 default:
869 break;
870 }
871 }
872
873 static void tpg_precalculate_line(struct tpg_data *tpg)
874 {
875 enum tpg_color contrast;
876 unsigned pat;
877 unsigned p;
878 unsigned x;
879
880 switch (tpg->pattern) {
881 case TPG_PAT_GREEN:
882 contrast = TPG_COLOR_100_RED;
883 break;
884 case TPG_PAT_CSC_COLORBAR:
885 contrast = TPG_COLOR_CSC_GREEN;
886 break;
887 default:
888 contrast = TPG_COLOR_100_GREEN;
889 break;
890 }
891
892 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
893 /* Coarse scaling with Bresenham */
894 unsigned int_part = tpg->src_width / tpg->scaled_width;
895 unsigned fract_part = tpg->src_width % tpg->scaled_width;
896 unsigned src_x = 0;
897 unsigned error = 0;
898
899 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
900 unsigned real_x = src_x;
901 enum tpg_color color1, color2;
902 u8 pix[TPG_MAX_PLANES][8];
903
904 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
905 color1 = tpg_get_color(tpg, pat, real_x);
906
907 src_x += int_part;
908 error += fract_part;
909 if (error >= tpg->scaled_width) {
910 error -= tpg->scaled_width;
911 src_x++;
912 }
913
914 real_x = src_x;
915 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
916 color2 = tpg_get_color(tpg, pat, real_x);
917
918 src_x += int_part;
919 error += fract_part;
920 if (error >= tpg->scaled_width) {
921 error -= tpg->scaled_width;
922 src_x++;
923 }
924
925 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
926 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
927 for (p = 0; p < tpg->planes; p++) {
928 unsigned twopixsize = tpg->twopixelsize[p];
929 u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
930
931 memcpy(pos, pix[p], twopixsize);
932 }
933 }
934 }
935 for (x = 0; x < tpg->scaled_width; x += 2) {
936 u8 pix[TPG_MAX_PLANES][8];
937
938 gen_twopix(tpg, pix, contrast, 0);
939 gen_twopix(tpg, pix, contrast, 1);
940 for (p = 0; p < tpg->planes; p++) {
941 unsigned twopixsize = tpg->twopixelsize[p];
942 u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
943
944 memcpy(pos, pix[p], twopixsize);
945 }
946 }
947 for (x = 0; x < tpg->scaled_width; x += 2) {
948 u8 pix[TPG_MAX_PLANES][8];
949
950 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
951 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
952 for (p = 0; p < tpg->planes; p++) {
953 unsigned twopixsize = tpg->twopixelsize[p];
954 u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
955
956 memcpy(pos, pix[p], twopixsize);
957 }
958 }
959 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
960 u8 pix[TPG_MAX_PLANES][8];
961
962 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
963 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
964 for (p = 0; p < tpg->planes; p++) {
965 unsigned twopixsize = tpg->twopixelsize[p];
966 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
967
968 memcpy(pos, pix[p], twopixsize);
969 }
970 }
971 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
972 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
973 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
974 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
975 }
976
977 /* need this to do rgb24 rendering */
978 typedef struct { u16 __; u8 _; } __packed x24;
979
980 void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
981 int y, int x, char *text)
982 {
983 int line;
984 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
985 unsigned div = step;
986 unsigned first = 0;
987 unsigned len = strlen(text);
988 unsigned p;
989
990 if (font8x16 == NULL || basep == NULL)
991 return;
992
993 /* Checks if it is possible to show string */
994 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
995 return;
996
997 if (len > (tpg->compose.width - x) / 8)
998 len = (tpg->compose.width - x) / 8;
999 if (tpg->vflip)
1000 y = tpg->compose.height - y - 16;
1001 if (tpg->hflip)
1002 x = tpg->compose.width - x - 8;
1003 y += tpg->compose.top;
1004 x += tpg->compose.left;
1005 if (tpg->field == V4L2_FIELD_BOTTOM)
1006 first = 1;
1007 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1008 div = 2;
1009
1010 for (p = 0; p < tpg->planes; p++) {
1011 /* Print stream time */
1012 #define PRINTSTR(PIXTYPE) do { \
1013 PIXTYPE fg; \
1014 PIXTYPE bg; \
1015 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1016 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1017 \
1018 for (line = first; line < 16; line += step) { \
1019 int l = tpg->vflip ? 15 - line : line; \
1020 PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
1021 ((y * step + l) / div) * tpg->bytesperline[p] + \
1022 x * sizeof(PIXTYPE)); \
1023 unsigned s; \
1024 \
1025 for (s = 0; s < len; s++) { \
1026 u8 chr = font8x16[text[s] * 16 + line]; \
1027 \
1028 if (tpg->hflip) { \
1029 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1030 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1031 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1032 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1033 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1034 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1035 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1036 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1037 } else { \
1038 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1039 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1040 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1041 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1042 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1043 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1044 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1045 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1046 } \
1047 \
1048 pos += tpg->hflip ? -8 : 8; \
1049 } \
1050 } \
1051 } while (0)
1052
1053 switch (tpg->twopixelsize[p]) {
1054 case 2:
1055 PRINTSTR(u8); break;
1056 case 4:
1057 PRINTSTR(u16); break;
1058 case 6:
1059 PRINTSTR(x24); break;
1060 case 8:
1061 PRINTSTR(u32); break;
1062 }
1063 }
1064 }
1065
1066 void tpg_update_mv_step(struct tpg_data *tpg)
1067 {
1068 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1069
1070 if (tpg->hflip)
1071 factor = -factor;
1072 switch (tpg->mv_hor_mode) {
1073 case TPG_MOVE_NEG_FAST:
1074 case TPG_MOVE_POS_FAST:
1075 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1076 break;
1077 case TPG_MOVE_NEG:
1078 case TPG_MOVE_POS:
1079 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1080 break;
1081 case TPG_MOVE_NEG_SLOW:
1082 case TPG_MOVE_POS_SLOW:
1083 tpg->mv_hor_step = 2;
1084 break;
1085 case TPG_MOVE_NONE:
1086 tpg->mv_hor_step = 0;
1087 break;
1088 }
1089 if (factor < 0)
1090 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1091
1092 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1093 switch (tpg->mv_vert_mode) {
1094 case TPG_MOVE_NEG_FAST:
1095 case TPG_MOVE_POS_FAST:
1096 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1097 break;
1098 case TPG_MOVE_NEG:
1099 case TPG_MOVE_POS:
1100 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1101 break;
1102 case TPG_MOVE_NEG_SLOW:
1103 case TPG_MOVE_POS_SLOW:
1104 tpg->mv_vert_step = 1;
1105 break;
1106 case TPG_MOVE_NONE:
1107 tpg->mv_vert_step = 0;
1108 break;
1109 }
1110 if (factor < 0)
1111 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1112 }
1113
1114 /* Map the line number relative to the crop rectangle to a frame line number */
1115 static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
1116 unsigned field)
1117 {
1118 switch (field) {
1119 case V4L2_FIELD_TOP:
1120 return tpg->crop.top + src_y * 2;
1121 case V4L2_FIELD_BOTTOM:
1122 return tpg->crop.top + src_y * 2 + 1;
1123 default:
1124 return src_y + tpg->crop.top;
1125 }
1126 }
1127
1128 /*
1129 * Map the line number relative to the compose rectangle to a destination
1130 * buffer line number.
1131 */
1132 static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
1133 unsigned field)
1134 {
1135 y += tpg->compose.top;
1136 switch (field) {
1137 case V4L2_FIELD_SEQ_TB:
1138 if (y & 1)
1139 return tpg->buf_height / 2 + y / 2;
1140 return y / 2;
1141 case V4L2_FIELD_SEQ_BT:
1142 if (y & 1)
1143 return y / 2;
1144 return tpg->buf_height / 2 + y / 2;
1145 default:
1146 return y;
1147 }
1148 }
1149
1150 static void tpg_recalc(struct tpg_data *tpg)
1151 {
1152 if (tpg->recalc_colors) {
1153 tpg->recalc_colors = false;
1154 tpg->recalc_lines = true;
1155 tpg_precalculate_colors(tpg);
1156 }
1157 if (tpg->recalc_square_border) {
1158 tpg->recalc_square_border = false;
1159 tpg_calculate_square_border(tpg);
1160 }
1161 if (tpg->recalc_lines) {
1162 tpg->recalc_lines = false;
1163 tpg_precalculate_line(tpg);
1164 }
1165 }
1166
1167 void tpg_calc_text_basep(struct tpg_data *tpg,
1168 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1169 {
1170 unsigned stride = tpg->bytesperline[p];
1171
1172 tpg_recalc(tpg);
1173
1174 basep[p][0] = vbuf;
1175 basep[p][1] = vbuf;
1176 if (tpg->field == V4L2_FIELD_SEQ_TB)
1177 basep[p][1] += tpg->buf_height * stride / 2;
1178 else if (tpg->field == V4L2_FIELD_SEQ_BT)
1179 basep[p][0] += tpg->buf_height * stride / 2;
1180 }
1181
1182 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1183 {
1184 bool is_tv = std;
1185 bool is_60hz = is_tv && (std & V4L2_STD_525_60);
1186 unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
1187 unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
1188 unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1189 unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1190 unsigned wss_width;
1191 unsigned f;
1192 int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1193 int h;
1194 unsigned twopixsize = tpg->twopixelsize[p];
1195 unsigned img_width = tpg->compose.width * twopixsize / 2;
1196 unsigned line_offset;
1197 unsigned left_pillar_width = 0;
1198 unsigned right_pillar_start = img_width;
1199 unsigned stride = tpg->bytesperline[p];
1200 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1201 u8 *orig_vbuf = vbuf;
1202
1203 /* Coarse scaling with Bresenham */
1204 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1205 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1206 unsigned src_y = 0;
1207 unsigned error = 0;
1208
1209 tpg_recalc(tpg);
1210
1211 mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
1212 mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
1213 wss_width = tpg->crop.left < tpg->src_width / 2 ?
1214 tpg->src_width / 2 - tpg->crop.left : 0;
1215 if (wss_width > tpg->crop.width)
1216 wss_width = tpg->crop.width;
1217 wss_width = wss_width * tpg->scaled_width / tpg->src_width;
1218
1219 vbuf += tpg->compose.left * twopixsize / 2;
1220 line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
1221 line_offset = (line_offset & ~1) * twopixsize / 2;
1222 if (tpg->crop.left < tpg->border.left) {
1223 left_pillar_width = tpg->border.left - tpg->crop.left;
1224 if (left_pillar_width > tpg->crop.width)
1225 left_pillar_width = tpg->crop.width;
1226 left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
1227 left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
1228 }
1229 if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
1230 right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
1231 right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
1232 right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
1233 if (right_pillar_start > img_width)
1234 right_pillar_start = img_width;
1235 }
1236
1237 f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1238
1239 for (h = 0; h < tpg->compose.height; h++) {
1240 bool even;
1241 bool fill_blank = false;
1242 unsigned frame_line;
1243 unsigned buf_line;
1244 unsigned pat_line_old;
1245 unsigned pat_line_new;
1246 u8 *linestart_older;
1247 u8 *linestart_newer;
1248 u8 *linestart_top;
1249 u8 *linestart_bottom;
1250
1251 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1252 even = !(frame_line & 1);
1253 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1254 src_y += int_part;
1255 error += fract_part;
1256 if (error >= tpg->compose.height) {
1257 error -= tpg->compose.height;
1258 src_y++;
1259 }
1260
1261 if (h >= hmax) {
1262 if (hmax == tpg->compose.height)
1263 continue;
1264 if (!tpg->perc_fill_blank)
1265 continue;
1266 fill_blank = true;
1267 }
1268
1269 if (tpg->vflip)
1270 frame_line = tpg->src_height - frame_line - 1;
1271
1272 if (fill_blank) {
1273 linestart_older = tpg->contrast_line[p];
1274 linestart_newer = tpg->contrast_line[p];
1275 } else if (tpg->qual != TPG_QUAL_NOISE &&
1276 (frame_line < tpg->border.top ||
1277 frame_line >= tpg->border.top + tpg->border.height)) {
1278 linestart_older = tpg->black_line[p];
1279 linestart_newer = tpg->black_line[p];
1280 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1281 linestart_older = tpg->random_line[p] +
1282 twopixsize * prandom_u32_max(tpg->src_width / 2);
1283 linestart_newer = tpg->random_line[p] +
1284 twopixsize * prandom_u32_max(tpg->src_width / 2);
1285 } else {
1286 pat_line_old = tpg_get_pat_line(tpg,
1287 (frame_line + mv_vert_old) % tpg->src_height);
1288 pat_line_new = tpg_get_pat_line(tpg,
1289 (frame_line + mv_vert_new) % tpg->src_height);
1290 linestart_older = tpg->lines[pat_line_old][p] +
1291 mv_hor_old * twopixsize / 2;
1292 linestart_newer = tpg->lines[pat_line_new][p] +
1293 mv_hor_new * twopixsize / 2;
1294 linestart_older += line_offset;
1295 linestart_newer += line_offset;
1296 }
1297 if (is_60hz) {
1298 linestart_top = linestart_newer;
1299 linestart_bottom = linestart_older;
1300 } else {
1301 linestart_top = linestart_older;
1302 linestart_bottom = linestart_newer;
1303 }
1304
1305 switch (tpg->field) {
1306 case V4L2_FIELD_INTERLACED:
1307 case V4L2_FIELD_INTERLACED_TB:
1308 case V4L2_FIELD_SEQ_TB:
1309 case V4L2_FIELD_SEQ_BT:
1310 if (even)
1311 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1312 else
1313 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1314 break;
1315 case V4L2_FIELD_INTERLACED_BT:
1316 if (even)
1317 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1318 else
1319 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1320 break;
1321 case V4L2_FIELD_TOP:
1322 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1323 break;
1324 case V4L2_FIELD_BOTTOM:
1325 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1326 break;
1327 case V4L2_FIELD_NONE:
1328 default:
1329 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1330 break;
1331 }
1332
1333 if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
1334 /*
1335 * Replace the first half of the top line of a 50 Hz frame
1336 * with random data to simulate a WSS signal.
1337 */
1338 u8 *wss = tpg->random_line[p] +
1339 twopixsize * prandom_u32_max(tpg->src_width / 2);
1340
1341 memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
1342 }
1343 }
1344
1345 vbuf = orig_vbuf;
1346 vbuf += tpg->compose.left * twopixsize / 2;
1347 src_y = 0;
1348 error = 0;
1349 for (h = 0; h < tpg->compose.height; h++) {
1350 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1351 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1352 const struct v4l2_rect *sq = &tpg->square;
1353 const struct v4l2_rect *b = &tpg->border;
1354 const struct v4l2_rect *c = &tpg->crop;
1355
1356 src_y += int_part;
1357 error += fract_part;
1358 if (error >= tpg->compose.height) {
1359 error -= tpg->compose.height;
1360 src_y++;
1361 }
1362
1363 if (tpg->show_border && frame_line >= b->top &&
1364 frame_line < b->top + b->height) {
1365 unsigned bottom = b->top + b->height - 1;
1366 unsigned left = left_pillar_width;
1367 unsigned right = right_pillar_start;
1368
1369 if (frame_line == b->top || frame_line == b->top + 1 ||
1370 frame_line == bottom || frame_line == bottom - 1) {
1371 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1372 right - left);
1373 } else {
1374 if (b->left >= c->left &&
1375 b->left < c->left + c->width)
1376 memcpy(vbuf + buf_line * stride + left,
1377 tpg->contrast_line[p], twopixsize);
1378 if (b->left + b->width > c->left &&
1379 b->left + b->width <= c->left + c->width)
1380 memcpy(vbuf + buf_line * stride + right - twopixsize,
1381 tpg->contrast_line[p], twopixsize);
1382 }
1383 }
1384 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1385 frame_line < b->top + b->height) {
1386 memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
1387 memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
1388 img_width - right_pillar_start);
1389 }
1390 if (tpg->show_square && frame_line >= sq->top &&
1391 frame_line < sq->top + sq->height &&
1392 sq->left < c->left + c->width &&
1393 sq->left + sq->width >= c->left) {
1394 unsigned left = sq->left;
1395 unsigned width = sq->width;
1396
1397 if (c->left > left) {
1398 width -= c->left - left;
1399 left = c->left;
1400 }
1401 if (c->left + c->width < left + width)
1402 width -= left + width - c->left - c->width;
1403 left -= c->left;
1404 left = (left * tpg->scaled_width) / tpg->src_width;
1405 left = (left & ~1) * twopixsize / 2;
1406 width = (width * tpg->scaled_width) / tpg->src_width;
1407 width = (width & ~1) * twopixsize / 2;
1408 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1409 }
1410 if (tpg->insert_sav) {
1411 unsigned offset = (tpg->compose.width / 6) * twopixsize;
1412 u8 *p = vbuf + buf_line * stride + offset;
1413 unsigned vact = 0, hact = 0;
1414
1415 p[0] = 0xff;
1416 p[1] = 0;
1417 p[2] = 0;
1418 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1419 ((hact ^ vact) << 3) |
1420 ((hact ^ f) << 2) |
1421 ((f ^ vact) << 1) |
1422 (hact ^ vact ^ f);
1423 }
1424 if (tpg->insert_eav) {
1425 unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
1426 u8 *p = vbuf + buf_line * stride + offset;
1427 unsigned vact = 0, hact = 1;
1428
1429 p[0] = 0xff;
1430 p[1] = 0;
1431 p[2] = 0;
1432 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1433 ((hact ^ vact) << 3) |
1434 ((hact ^ f) << 2) |
1435 ((f ^ vact) << 1) |
1436 (hact ^ vact ^ f);
1437 }
1438 }
1439 }