Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
[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 "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 * 2 * 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 inline int rec709_to_linear(int v)
300 {
301 v = clamp(v, 0, 0xff0);
302 return tpg_rec709_to_linear[v];
303 }
304
305 static inline int linear_to_rec709(int v)
306 {
307 v = clamp(v, 0, 0xff0);
308 return tpg_linear_to_rec709[v];
309 }
310
311 static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
312 int y_offset, int *y, int *cb, int *cr)
313 {
314 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
315 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
316 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
317 }
318
319 static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
320 int *y, int *cb, int *cr)
321 {
322 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
323
324 static const int bt601[3][3] = {
325 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
326 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
327 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
328 };
329 static const int bt601_full[3][3] = {
330 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
331 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
332 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
333 };
334 static const int rec709[3][3] = {
335 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
336 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
337 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
338 };
339 static const int rec709_full[3][3] = {
340 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
341 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
342 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
343 };
344 static const int smpte240m[3][3] = {
345 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
346 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
347 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
348 };
349 static const int bt2020[3][3] = {
350 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
351 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
352 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
353 };
354 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
355 unsigned y_offset = full ? 0 : 16;
356 int lin_y, yc;
357
358 switch (tpg->real_ycbcr_enc) {
359 case V4L2_YCBCR_ENC_601:
360 case V4L2_YCBCR_ENC_XV601:
361 case V4L2_YCBCR_ENC_SYCC:
362 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
363 break;
364 case V4L2_YCBCR_ENC_BT2020:
365 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
366 break;
367 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
368 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
369 COEFF(0.6780, 255) * rec709_to_linear(g) +
370 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
371 yc = linear_to_rec709(lin_y);
372 *y = (yc * 219) / 255 + (16 << 4);
373 if (b <= yc)
374 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
375 else
376 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
377 if (r <= yc)
378 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
379 else
380 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
381 break;
382 case V4L2_YCBCR_ENC_SMPTE240M:
383 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
384 break;
385 case V4L2_YCBCR_ENC_709:
386 case V4L2_YCBCR_ENC_XV709:
387 default:
388 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
389 break;
390 }
391 }
392
393 static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
394 int y_offset, int *r, int *g, int *b)
395 {
396 y -= y_offset << 4;
397 cb -= 128 << 4;
398 cr -= 128 << 4;
399 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
400 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
401 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
402 *r = clamp(*r >> 12, 0, 0xff0);
403 *g = clamp(*g >> 12, 0, 0xff0);
404 *b = clamp(*b >> 12, 0, 0xff0);
405 }
406
407 static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
408 int *r, int *g, int *b)
409 {
410 #undef COEFF
411 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
412 static const int bt601[3][3] = {
413 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
414 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
415 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
416 };
417 static const int bt601_full[3][3] = {
418 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
419 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
420 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
421 };
422 static const int rec709[3][3] = {
423 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
424 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
425 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
426 };
427 static const int rec709_full[3][3] = {
428 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
429 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
430 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
431 };
432 static const int smpte240m[3][3] = {
433 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
434 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
435 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
436 };
437 static const int bt2020[3][3] = {
438 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
439 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
440 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
441 };
442 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
443 unsigned y_offset = full ? 0 : 16;
444 int lin_r, lin_g, lin_b, lin_y;
445
446 switch (tpg->real_ycbcr_enc) {
447 case V4L2_YCBCR_ENC_601:
448 case V4L2_YCBCR_ENC_XV601:
449 case V4L2_YCBCR_ENC_SYCC:
450 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
451 break;
452 case V4L2_YCBCR_ENC_BT2020:
453 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
454 break;
455 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
456 y -= 16 << 4;
457 cb -= 128 << 4;
458 cr -= 128 << 4;
459
460 if (cb <= 0)
461 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
462 else
463 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
464 *b = *b >> 12;
465 if (cr <= 0)
466 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
467 else
468 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
469 *r = *r >> 12;
470 lin_r = rec709_to_linear(*r);
471 lin_b = rec709_to_linear(*b);
472 lin_y = rec709_to_linear((y * 255) / 219);
473
474 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
475 COEFF(0.2627 / 0.6780, 255) * lin_r -
476 COEFF(0.0593 / 0.6780, 255) * lin_b;
477 *g = linear_to_rec709(lin_g >> 12);
478 break;
479 case V4L2_YCBCR_ENC_SMPTE240M:
480 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
481 break;
482 case V4L2_YCBCR_ENC_709:
483 case V4L2_YCBCR_ENC_XV709:
484 default:
485 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
486 break;
487 }
488 }
489
490 /* precalculate color bar values to speed up rendering */
491 static void precalculate_color(struct tpg_data *tpg, int k)
492 {
493 int col = k;
494 int r = tpg_colors[col].r;
495 int g = tpg_colors[col].g;
496 int b = tpg_colors[col].b;
497
498 if (k == TPG_COLOR_TEXTBG) {
499 col = tpg_get_textbg_color(tpg);
500
501 r = tpg_colors[col].r;
502 g = tpg_colors[col].g;
503 b = tpg_colors[col].b;
504 } else if (k == TPG_COLOR_TEXTFG) {
505 col = tpg_get_textfg_color(tpg);
506
507 r = tpg_colors[col].r;
508 g = tpg_colors[col].g;
509 b = tpg_colors[col].b;
510 } else if (tpg->pattern == TPG_PAT_NOISE) {
511 r = g = b = prandom_u32_max(256);
512 } else if (k == TPG_COLOR_RANDOM) {
513 r = g = b = tpg->qual_offset + prandom_u32_max(196);
514 } else if (k >= TPG_COLOR_RAMP) {
515 r = g = b = k - TPG_COLOR_RAMP;
516 }
517
518 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
519 r = tpg_csc_colors[tpg->colorspace][col].r;
520 g = tpg_csc_colors[tpg->colorspace][col].g;
521 b = tpg_csc_colors[tpg->colorspace][col].b;
522 } else {
523 r <<= 4;
524 g <<= 4;
525 b <<= 4;
526 }
527 if (tpg->qual == TPG_QUAL_GRAY) {
528 /* Rec. 709 Luma function */
529 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
530 r = g = b = ((13879 * r + 46688 * g + 4713 * b) >> 16) + (16 << 4);
531 }
532
533 /*
534 * The assumption is that the RGB output is always full range,
535 * so only if the rgb_range overrides the 'real' rgb range do
536 * we need to convert the RGB values.
537 *
538 * Remember that r, g and b are still in the 0 - 0xff0 range.
539 */
540 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
541 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
542 /*
543 * Convert from full range (which is what r, g and b are)
544 * to limited range (which is the 'real' RGB range), which
545 * is then interpreted as full range.
546 */
547 r = (r * 219) / 255 + (16 << 4);
548 g = (g * 219) / 255 + (16 << 4);
549 b = (b * 219) / 255 + (16 << 4);
550 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
551 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
552 /*
553 * Clamp r, g and b to the limited range and convert to full
554 * range since that's what we deliver.
555 */
556 r = clamp(r, 16 << 4, 235 << 4);
557 g = clamp(g, 16 << 4, 235 << 4);
558 b = clamp(b, 16 << 4, 235 << 4);
559 r = (r - (16 << 4)) * 255 / 219;
560 g = (g - (16 << 4)) * 255 / 219;
561 b = (b - (16 << 4)) * 255 / 219;
562 }
563
564 if (tpg->brightness != 128 || tpg->contrast != 128 ||
565 tpg->saturation != 128 || tpg->hue) {
566 /* Implement these operations */
567 int y, cb, cr;
568 int tmp_cb, tmp_cr;
569
570 /* First convert to YCbCr */
571
572 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
573
574 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
575 y += (tpg->brightness << 4) - (128 << 4);
576
577 cb -= 128 << 4;
578 cr -= 128 << 4;
579 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
580 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
581
582 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
583 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
584 if (tpg->is_yuv) {
585 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
586 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
587 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
588 return;
589 }
590 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
591 }
592
593 if (tpg->is_yuv) {
594 /* Convert to YCbCr */
595 int y, cb, cr;
596
597 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
598
599 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
600 y = clamp(y, 16 << 4, 235 << 4);
601 cb = clamp(cb, 16 << 4, 240 << 4);
602 cr = clamp(cr, 16 << 4, 240 << 4);
603 }
604 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
605 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
606 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
607 } else {
608 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
609 r = (r * 219) / 255 + (16 << 4);
610 g = (g * 219) / 255 + (16 << 4);
611 b = (b * 219) / 255 + (16 << 4);
612 }
613 switch (tpg->fourcc) {
614 case V4L2_PIX_FMT_RGB565:
615 case V4L2_PIX_FMT_RGB565X:
616 r >>= 7;
617 g >>= 6;
618 b >>= 7;
619 break;
620 case V4L2_PIX_FMT_RGB555:
621 case V4L2_PIX_FMT_XRGB555:
622 case V4L2_PIX_FMT_ARGB555:
623 case V4L2_PIX_FMT_RGB555X:
624 r >>= 7;
625 g >>= 7;
626 b >>= 7;
627 break;
628 default:
629 r >>= 4;
630 g >>= 4;
631 b >>= 4;
632 break;
633 }
634
635 tpg->colors[k][0] = r;
636 tpg->colors[k][1] = g;
637 tpg->colors[k][2] = b;
638 }
639 }
640
641 static void tpg_precalculate_colors(struct tpg_data *tpg)
642 {
643 int k;
644
645 for (k = 0; k < TPG_COLOR_MAX; k++)
646 precalculate_color(tpg, k);
647 }
648
649 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
650 static void gen_twopix(struct tpg_data *tpg,
651 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
652 {
653 unsigned offset = odd * tpg->twopixelsize[0] / 2;
654 u8 alpha = tpg->alpha_component;
655 u8 r_y, g_u, b_v;
656
657 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
658 color != TPG_COLOR_100_RED &&
659 color != TPG_COLOR_75_RED)
660 alpha = 0;
661 if (color == TPG_COLOR_RANDOM)
662 precalculate_color(tpg, color);
663 r_y = tpg->colors[color][0]; /* R or precalculated Y */
664 g_u = tpg->colors[color][1]; /* G or precalculated U */
665 b_v = tpg->colors[color][2]; /* B or precalculated V */
666
667 switch (tpg->fourcc) {
668 case V4L2_PIX_FMT_NV16M:
669 buf[0][offset] = r_y;
670 buf[1][offset] = odd ? b_v : g_u;
671 break;
672 case V4L2_PIX_FMT_NV61M:
673 buf[0][offset] = r_y;
674 buf[1][offset] = odd ? g_u : b_v;
675 break;
676
677 case V4L2_PIX_FMT_YUYV:
678 buf[0][offset] = r_y;
679 buf[0][offset + 1] = odd ? b_v : g_u;
680 break;
681 case V4L2_PIX_FMT_UYVY:
682 buf[0][offset] = odd ? b_v : g_u;
683 buf[0][offset + 1] = r_y;
684 break;
685 case V4L2_PIX_FMT_YVYU:
686 buf[0][offset] = r_y;
687 buf[0][offset + 1] = odd ? g_u : b_v;
688 break;
689 case V4L2_PIX_FMT_VYUY:
690 buf[0][offset] = odd ? g_u : b_v;
691 buf[0][offset + 1] = r_y;
692 break;
693 case V4L2_PIX_FMT_RGB565:
694 buf[0][offset] = (g_u << 5) | b_v;
695 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
696 break;
697 case V4L2_PIX_FMT_RGB565X:
698 buf[0][offset] = (r_y << 3) | (g_u >> 3);
699 buf[0][offset + 1] = (g_u << 5) | b_v;
700 break;
701 case V4L2_PIX_FMT_RGB555:
702 case V4L2_PIX_FMT_XRGB555:
703 alpha = 0;
704 /* fall through */
705 case V4L2_PIX_FMT_ARGB555:
706 buf[0][offset] = (g_u << 5) | b_v;
707 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
708 break;
709 case V4L2_PIX_FMT_RGB555X:
710 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
711 buf[0][offset + 1] = (g_u << 5) | b_v;
712 break;
713 case V4L2_PIX_FMT_RGB24:
714 buf[0][offset] = r_y;
715 buf[0][offset + 1] = g_u;
716 buf[0][offset + 2] = b_v;
717 break;
718 case V4L2_PIX_FMT_BGR24:
719 buf[0][offset] = b_v;
720 buf[0][offset + 1] = g_u;
721 buf[0][offset + 2] = r_y;
722 break;
723 case V4L2_PIX_FMT_RGB32:
724 case V4L2_PIX_FMT_XRGB32:
725 alpha = 0;
726 /* fall through */
727 case V4L2_PIX_FMT_ARGB32:
728 buf[0][offset] = alpha;
729 buf[0][offset + 1] = r_y;
730 buf[0][offset + 2] = g_u;
731 buf[0][offset + 3] = b_v;
732 break;
733 case V4L2_PIX_FMT_BGR32:
734 case V4L2_PIX_FMT_XBGR32:
735 alpha = 0;
736 /* fall through */
737 case V4L2_PIX_FMT_ABGR32:
738 buf[0][offset] = b_v;
739 buf[0][offset + 1] = g_u;
740 buf[0][offset + 2] = r_y;
741 buf[0][offset + 3] = alpha;
742 break;
743 }
744 }
745
746 /* Return how many pattern lines are used by the current pattern. */
747 static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
748 {
749 switch (tpg->pattern) {
750 case TPG_PAT_CHECKERS_16X16:
751 case TPG_PAT_CHECKERS_1X1:
752 case TPG_PAT_ALTERNATING_HLINES:
753 case TPG_PAT_CROSS_1_PIXEL:
754 case TPG_PAT_CROSS_2_PIXELS:
755 case TPG_PAT_CROSS_10_PIXELS:
756 return 2;
757 case TPG_PAT_100_COLORSQUARES:
758 case TPG_PAT_100_HCOLORBAR:
759 return 8;
760 default:
761 return 1;
762 }
763 }
764
765 /* Which pattern line should be used for the given frame line. */
766 static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
767 {
768 switch (tpg->pattern) {
769 case TPG_PAT_CHECKERS_16X16:
770 return (line >> 4) & 1;
771 case TPG_PAT_CHECKERS_1X1:
772 case TPG_PAT_ALTERNATING_HLINES:
773 return line & 1;
774 case TPG_PAT_100_COLORSQUARES:
775 case TPG_PAT_100_HCOLORBAR:
776 return (line * 8) / tpg->src_height;
777 case TPG_PAT_CROSS_1_PIXEL:
778 return line == tpg->src_height / 2;
779 case TPG_PAT_CROSS_2_PIXELS:
780 return (line + 1) / 2 == tpg->src_height / 4;
781 case TPG_PAT_CROSS_10_PIXELS:
782 return (line + 10) / 20 == tpg->src_height / 40;
783 default:
784 return 0;
785 }
786 }
787
788 /*
789 * Which color should be used for the given pattern line and X coordinate.
790 * Note: x is in the range 0 to 2 * tpg->src_width.
791 */
792 static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x)
793 {
794 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
795 should be modified */
796 static const enum tpg_color bars[3][8] = {
797 /* Standard ITU-R 75% color bar sequence */
798 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
799 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
800 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
801 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
802 /* Standard ITU-R 100% color bar sequence */
803 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
804 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
805 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
806 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
807 /* Color bar sequence suitable to test CSC */
808 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
809 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
810 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
811 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
812 };
813
814 switch (tpg->pattern) {
815 case TPG_PAT_75_COLORBAR:
816 case TPG_PAT_100_COLORBAR:
817 case TPG_PAT_CSC_COLORBAR:
818 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
819 case TPG_PAT_100_COLORSQUARES:
820 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
821 case TPG_PAT_100_HCOLORBAR:
822 return bars[1][pat_line];
823 case TPG_PAT_BLACK:
824 return TPG_COLOR_100_BLACK;
825 case TPG_PAT_WHITE:
826 return TPG_COLOR_100_WHITE;
827 case TPG_PAT_RED:
828 return TPG_COLOR_100_RED;
829 case TPG_PAT_GREEN:
830 return TPG_COLOR_100_GREEN;
831 case TPG_PAT_BLUE:
832 return TPG_COLOR_100_BLUE;
833 case TPG_PAT_CHECKERS_16X16:
834 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
835 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
836 case TPG_PAT_CHECKERS_1X1:
837 return ((x & 1) ^ (pat_line & 1)) ?
838 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
839 case TPG_PAT_ALTERNATING_HLINES:
840 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
841 case TPG_PAT_ALTERNATING_VLINES:
842 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
843 case TPG_PAT_CROSS_1_PIXEL:
844 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
845 return TPG_COLOR_100_BLACK;
846 return TPG_COLOR_100_WHITE;
847 case TPG_PAT_CROSS_2_PIXELS:
848 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
849 return TPG_COLOR_100_BLACK;
850 return TPG_COLOR_100_WHITE;
851 case TPG_PAT_CROSS_10_PIXELS:
852 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
853 return TPG_COLOR_100_BLACK;
854 return TPG_COLOR_100_WHITE;
855 case TPG_PAT_GRAY_RAMP:
856 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
857 default:
858 return TPG_COLOR_100_RED;
859 }
860 }
861
862 /*
863 * Given the pixel aspect ratio and video aspect ratio calculate the
864 * coordinates of a centered square and the coordinates of the border of
865 * the active video area. The coordinates are relative to the source
866 * frame rectangle.
867 */
868 static void tpg_calculate_square_border(struct tpg_data *tpg)
869 {
870 unsigned w = tpg->src_width;
871 unsigned h = tpg->src_height;
872 unsigned sq_w, sq_h;
873
874 sq_w = (w * 2 / 5) & ~1;
875 if (((w - sq_w) / 2) & 1)
876 sq_w += 2;
877 sq_h = sq_w;
878 tpg->square.width = sq_w;
879 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
880 unsigned ana_sq_w = (sq_w / 4) * 3;
881
882 if (((w - ana_sq_w) / 2) & 1)
883 ana_sq_w += 2;
884 tpg->square.width = ana_sq_w;
885 }
886 tpg->square.left = (w - tpg->square.width) / 2;
887 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
888 sq_h = sq_w * 10 / 11;
889 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
890 sq_h = sq_w * 59 / 54;
891 tpg->square.height = sq_h;
892 tpg->square.top = (h - sq_h) / 2;
893 tpg->border.left = 0;
894 tpg->border.width = w;
895 tpg->border.top = 0;
896 tpg->border.height = h;
897 switch (tpg->vid_aspect) {
898 case TPG_VIDEO_ASPECT_4X3:
899 if (tpg->pix_aspect)
900 return;
901 if (3 * w >= 4 * h) {
902 tpg->border.width = ((4 * h) / 3) & ~1;
903 if (((w - tpg->border.width) / 2) & ~1)
904 tpg->border.width -= 2;
905 tpg->border.left = (w - tpg->border.width) / 2;
906 break;
907 }
908 tpg->border.height = ((3 * w) / 4) & ~1;
909 tpg->border.top = (h - tpg->border.height) / 2;
910 break;
911 case TPG_VIDEO_ASPECT_14X9_CENTRE:
912 if (tpg->pix_aspect) {
913 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
914 tpg->border.top = (h - tpg->border.height) / 2;
915 break;
916 }
917 if (9 * w >= 14 * h) {
918 tpg->border.width = ((14 * h) / 9) & ~1;
919 if (((w - tpg->border.width) / 2) & ~1)
920 tpg->border.width -= 2;
921 tpg->border.left = (w - tpg->border.width) / 2;
922 break;
923 }
924 tpg->border.height = ((9 * w) / 14) & ~1;
925 tpg->border.top = (h - tpg->border.height) / 2;
926 break;
927 case TPG_VIDEO_ASPECT_16X9_CENTRE:
928 if (tpg->pix_aspect) {
929 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
930 tpg->border.top = (h - tpg->border.height) / 2;
931 break;
932 }
933 if (9 * w >= 16 * h) {
934 tpg->border.width = ((16 * h) / 9) & ~1;
935 if (((w - tpg->border.width) / 2) & ~1)
936 tpg->border.width -= 2;
937 tpg->border.left = (w - tpg->border.width) / 2;
938 break;
939 }
940 tpg->border.height = ((9 * w) / 16) & ~1;
941 tpg->border.top = (h - tpg->border.height) / 2;
942 break;
943 default:
944 break;
945 }
946 }
947
948 static void tpg_precalculate_line(struct tpg_data *tpg)
949 {
950 enum tpg_color contrast;
951 unsigned pat;
952 unsigned p;
953 unsigned x;
954
955 switch (tpg->pattern) {
956 case TPG_PAT_GREEN:
957 contrast = TPG_COLOR_100_RED;
958 break;
959 case TPG_PAT_CSC_COLORBAR:
960 contrast = TPG_COLOR_CSC_GREEN;
961 break;
962 default:
963 contrast = TPG_COLOR_100_GREEN;
964 break;
965 }
966
967 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
968 /* Coarse scaling with Bresenham */
969 unsigned int_part = tpg->src_width / tpg->scaled_width;
970 unsigned fract_part = tpg->src_width % tpg->scaled_width;
971 unsigned src_x = 0;
972 unsigned error = 0;
973
974 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
975 unsigned real_x = src_x;
976 enum tpg_color color1, color2;
977 u8 pix[TPG_MAX_PLANES][8];
978
979 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
980 color1 = tpg_get_color(tpg, pat, real_x);
981
982 src_x += int_part;
983 error += fract_part;
984 if (error >= tpg->scaled_width) {
985 error -= tpg->scaled_width;
986 src_x++;
987 }
988
989 real_x = src_x;
990 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
991 color2 = tpg_get_color(tpg, pat, real_x);
992
993 src_x += int_part;
994 error += fract_part;
995 if (error >= tpg->scaled_width) {
996 error -= tpg->scaled_width;
997 src_x++;
998 }
999
1000 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1001 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1002 for (p = 0; p < tpg->planes; p++) {
1003 unsigned twopixsize = tpg->twopixelsize[p];
1004 u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
1005
1006 memcpy(pos, pix[p], twopixsize);
1007 }
1008 }
1009 }
1010 for (x = 0; x < tpg->scaled_width; x += 2) {
1011 u8 pix[TPG_MAX_PLANES][8];
1012
1013 gen_twopix(tpg, pix, contrast, 0);
1014 gen_twopix(tpg, pix, contrast, 1);
1015 for (p = 0; p < tpg->planes; p++) {
1016 unsigned twopixsize = tpg->twopixelsize[p];
1017 u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
1018
1019 memcpy(pos, pix[p], twopixsize);
1020 }
1021 }
1022 for (x = 0; x < tpg->scaled_width; x += 2) {
1023 u8 pix[TPG_MAX_PLANES][8];
1024
1025 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1026 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1027 for (p = 0; p < tpg->planes; p++) {
1028 unsigned twopixsize = tpg->twopixelsize[p];
1029 u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
1030
1031 memcpy(pos, pix[p], twopixsize);
1032 }
1033 }
1034 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1035 u8 pix[TPG_MAX_PLANES][8];
1036
1037 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1038 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1039 for (p = 0; p < tpg->planes; p++) {
1040 unsigned twopixsize = tpg->twopixelsize[p];
1041 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1042
1043 memcpy(pos, pix[p], twopixsize);
1044 }
1045 }
1046 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1047 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1048 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1049 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1050 }
1051
1052 /* need this to do rgb24 rendering */
1053 typedef struct { u16 __; u8 _; } __packed x24;
1054
1055 void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1056 int y, int x, char *text)
1057 {
1058 int line;
1059 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1060 unsigned div = step;
1061 unsigned first = 0;
1062 unsigned len = strlen(text);
1063 unsigned p;
1064
1065 if (font8x16 == NULL || basep == NULL)
1066 return;
1067
1068 /* Checks if it is possible to show string */
1069 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1070 return;
1071
1072 if (len > (tpg->compose.width - x) / 8)
1073 len = (tpg->compose.width - x) / 8;
1074 if (tpg->vflip)
1075 y = tpg->compose.height - y - 16;
1076 if (tpg->hflip)
1077 x = tpg->compose.width - x - 8;
1078 y += tpg->compose.top;
1079 x += tpg->compose.left;
1080 if (tpg->field == V4L2_FIELD_BOTTOM)
1081 first = 1;
1082 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1083 div = 2;
1084
1085 for (p = 0; p < tpg->planes; p++) {
1086 /* Print stream time */
1087 #define PRINTSTR(PIXTYPE) do { \
1088 PIXTYPE fg; \
1089 PIXTYPE bg; \
1090 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1091 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1092 \
1093 for (line = first; line < 16; line += step) { \
1094 int l = tpg->vflip ? 15 - line : line; \
1095 PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
1096 ((y * step + l) / div) * tpg->bytesperline[p] + \
1097 x * sizeof(PIXTYPE)); \
1098 unsigned s; \
1099 \
1100 for (s = 0; s < len; s++) { \
1101 u8 chr = font8x16[text[s] * 16 + line]; \
1102 \
1103 if (tpg->hflip) { \
1104 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1105 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1106 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1107 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1108 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1109 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1110 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1111 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1112 } else { \
1113 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1114 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1115 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1116 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1117 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1118 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1119 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1120 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1121 } \
1122 \
1123 pos += tpg->hflip ? -8 : 8; \
1124 } \
1125 } \
1126 } while (0)
1127
1128 switch (tpg->twopixelsize[p]) {
1129 case 2:
1130 PRINTSTR(u8); break;
1131 case 4:
1132 PRINTSTR(u16); break;
1133 case 6:
1134 PRINTSTR(x24); break;
1135 case 8:
1136 PRINTSTR(u32); break;
1137 }
1138 }
1139 }
1140
1141 void tpg_update_mv_step(struct tpg_data *tpg)
1142 {
1143 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1144
1145 if (tpg->hflip)
1146 factor = -factor;
1147 switch (tpg->mv_hor_mode) {
1148 case TPG_MOVE_NEG_FAST:
1149 case TPG_MOVE_POS_FAST:
1150 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1151 break;
1152 case TPG_MOVE_NEG:
1153 case TPG_MOVE_POS:
1154 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1155 break;
1156 case TPG_MOVE_NEG_SLOW:
1157 case TPG_MOVE_POS_SLOW:
1158 tpg->mv_hor_step = 2;
1159 break;
1160 case TPG_MOVE_NONE:
1161 tpg->mv_hor_step = 0;
1162 break;
1163 }
1164 if (factor < 0)
1165 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1166
1167 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1168 switch (tpg->mv_vert_mode) {
1169 case TPG_MOVE_NEG_FAST:
1170 case TPG_MOVE_POS_FAST:
1171 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1172 break;
1173 case TPG_MOVE_NEG:
1174 case TPG_MOVE_POS:
1175 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1176 break;
1177 case TPG_MOVE_NEG_SLOW:
1178 case TPG_MOVE_POS_SLOW:
1179 tpg->mv_vert_step = 1;
1180 break;
1181 case TPG_MOVE_NONE:
1182 tpg->mv_vert_step = 0;
1183 break;
1184 }
1185 if (factor < 0)
1186 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1187 }
1188
1189 /* Map the line number relative to the crop rectangle to a frame line number */
1190 static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
1191 unsigned field)
1192 {
1193 switch (field) {
1194 case V4L2_FIELD_TOP:
1195 return tpg->crop.top + src_y * 2;
1196 case V4L2_FIELD_BOTTOM:
1197 return tpg->crop.top + src_y * 2 + 1;
1198 default:
1199 return src_y + tpg->crop.top;
1200 }
1201 }
1202
1203 /*
1204 * Map the line number relative to the compose rectangle to a destination
1205 * buffer line number.
1206 */
1207 static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
1208 unsigned field)
1209 {
1210 y += tpg->compose.top;
1211 switch (field) {
1212 case V4L2_FIELD_SEQ_TB:
1213 if (y & 1)
1214 return tpg->buf_height / 2 + y / 2;
1215 return y / 2;
1216 case V4L2_FIELD_SEQ_BT:
1217 if (y & 1)
1218 return y / 2;
1219 return tpg->buf_height / 2 + y / 2;
1220 default:
1221 return y;
1222 }
1223 }
1224
1225 static void tpg_recalc(struct tpg_data *tpg)
1226 {
1227 if (tpg->recalc_colors) {
1228 tpg->recalc_colors = false;
1229 tpg->recalc_lines = true;
1230 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1231 tpg->real_quantization = tpg->quantization;
1232 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1233 switch (tpg->colorspace) {
1234 case V4L2_COLORSPACE_REC709:
1235 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1236 break;
1237 case V4L2_COLORSPACE_SRGB:
1238 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1239 break;
1240 case V4L2_COLORSPACE_BT2020:
1241 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1242 break;
1243 case V4L2_COLORSPACE_SMPTE240M:
1244 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1245 break;
1246 case V4L2_COLORSPACE_SMPTE170M:
1247 case V4L2_COLORSPACE_470_SYSTEM_M:
1248 case V4L2_COLORSPACE_470_SYSTEM_BG:
1249 case V4L2_COLORSPACE_ADOBERGB:
1250 default:
1251 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1252 break;
1253 }
1254 }
1255 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1256 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1257 if (tpg->is_yuv) {
1258 switch (tpg->real_ycbcr_enc) {
1259 case V4L2_YCBCR_ENC_SYCC:
1260 case V4L2_YCBCR_ENC_XV601:
1261 case V4L2_YCBCR_ENC_XV709:
1262 break;
1263 default:
1264 tpg->real_quantization =
1265 V4L2_QUANTIZATION_LIM_RANGE;
1266 break;
1267 }
1268 }
1269 }
1270 tpg_precalculate_colors(tpg);
1271 }
1272 if (tpg->recalc_square_border) {
1273 tpg->recalc_square_border = false;
1274 tpg_calculate_square_border(tpg);
1275 }
1276 if (tpg->recalc_lines) {
1277 tpg->recalc_lines = false;
1278 tpg_precalculate_line(tpg);
1279 }
1280 }
1281
1282 void tpg_calc_text_basep(struct tpg_data *tpg,
1283 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1284 {
1285 unsigned stride = tpg->bytesperline[p];
1286
1287 tpg_recalc(tpg);
1288
1289 basep[p][0] = vbuf;
1290 basep[p][1] = vbuf;
1291 if (tpg->field == V4L2_FIELD_SEQ_TB)
1292 basep[p][1] += tpg->buf_height * stride / 2;
1293 else if (tpg->field == V4L2_FIELD_SEQ_BT)
1294 basep[p][0] += tpg->buf_height * stride / 2;
1295 }
1296
1297 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1298 {
1299 bool is_tv = std;
1300 bool is_60hz = is_tv && (std & V4L2_STD_525_60);
1301 unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
1302 unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
1303 unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1304 unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1305 unsigned wss_width;
1306 unsigned f;
1307 int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1308 int h;
1309 unsigned twopixsize = tpg->twopixelsize[p];
1310 unsigned img_width = tpg->compose.width * twopixsize / 2;
1311 unsigned line_offset;
1312 unsigned left_pillar_width = 0;
1313 unsigned right_pillar_start = img_width;
1314 unsigned stride = tpg->bytesperline[p];
1315 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1316 u8 *orig_vbuf = vbuf;
1317
1318 /* Coarse scaling with Bresenham */
1319 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1320 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1321 unsigned src_y = 0;
1322 unsigned error = 0;
1323
1324 tpg_recalc(tpg);
1325
1326 mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
1327 mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
1328 wss_width = tpg->crop.left < tpg->src_width / 2 ?
1329 tpg->src_width / 2 - tpg->crop.left : 0;
1330 if (wss_width > tpg->crop.width)
1331 wss_width = tpg->crop.width;
1332 wss_width = wss_width * tpg->scaled_width / tpg->src_width;
1333
1334 vbuf += tpg->compose.left * twopixsize / 2;
1335 line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
1336 line_offset = (line_offset & ~1) * twopixsize / 2;
1337 if (tpg->crop.left < tpg->border.left) {
1338 left_pillar_width = tpg->border.left - tpg->crop.left;
1339 if (left_pillar_width > tpg->crop.width)
1340 left_pillar_width = tpg->crop.width;
1341 left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
1342 left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
1343 }
1344 if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
1345 right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
1346 right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
1347 right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
1348 if (right_pillar_start > img_width)
1349 right_pillar_start = img_width;
1350 }
1351
1352 f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1353
1354 for (h = 0; h < tpg->compose.height; h++) {
1355 bool even;
1356 bool fill_blank = false;
1357 unsigned frame_line;
1358 unsigned buf_line;
1359 unsigned pat_line_old;
1360 unsigned pat_line_new;
1361 u8 *linestart_older;
1362 u8 *linestart_newer;
1363 u8 *linestart_top;
1364 u8 *linestart_bottom;
1365
1366 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1367 even = !(frame_line & 1);
1368 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1369 src_y += int_part;
1370 error += fract_part;
1371 if (error >= tpg->compose.height) {
1372 error -= tpg->compose.height;
1373 src_y++;
1374 }
1375
1376 if (h >= hmax) {
1377 if (hmax == tpg->compose.height)
1378 continue;
1379 if (!tpg->perc_fill_blank)
1380 continue;
1381 fill_blank = true;
1382 }
1383
1384 if (tpg->vflip)
1385 frame_line = tpg->src_height - frame_line - 1;
1386
1387 if (fill_blank) {
1388 linestart_older = tpg->contrast_line[p];
1389 linestart_newer = tpg->contrast_line[p];
1390 } else if (tpg->qual != TPG_QUAL_NOISE &&
1391 (frame_line < tpg->border.top ||
1392 frame_line >= tpg->border.top + tpg->border.height)) {
1393 linestart_older = tpg->black_line[p];
1394 linestart_newer = tpg->black_line[p];
1395 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1396 linestart_older = tpg->random_line[p] +
1397 twopixsize * prandom_u32_max(tpg->src_width / 2);
1398 linestart_newer = tpg->random_line[p] +
1399 twopixsize * prandom_u32_max(tpg->src_width / 2);
1400 } else {
1401 pat_line_old = tpg_get_pat_line(tpg,
1402 (frame_line + mv_vert_old) % tpg->src_height);
1403 pat_line_new = tpg_get_pat_line(tpg,
1404 (frame_line + mv_vert_new) % tpg->src_height);
1405 linestart_older = tpg->lines[pat_line_old][p] +
1406 mv_hor_old * twopixsize / 2;
1407 linestart_newer = tpg->lines[pat_line_new][p] +
1408 mv_hor_new * twopixsize / 2;
1409 linestart_older += line_offset;
1410 linestart_newer += line_offset;
1411 }
1412 if (is_60hz) {
1413 linestart_top = linestart_newer;
1414 linestart_bottom = linestart_older;
1415 } else {
1416 linestart_top = linestart_older;
1417 linestart_bottom = linestart_newer;
1418 }
1419
1420 switch (tpg->field) {
1421 case V4L2_FIELD_INTERLACED:
1422 case V4L2_FIELD_INTERLACED_TB:
1423 case V4L2_FIELD_SEQ_TB:
1424 case V4L2_FIELD_SEQ_BT:
1425 if (even)
1426 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1427 else
1428 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1429 break;
1430 case V4L2_FIELD_INTERLACED_BT:
1431 if (even)
1432 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1433 else
1434 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1435 break;
1436 case V4L2_FIELD_TOP:
1437 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1438 break;
1439 case V4L2_FIELD_BOTTOM:
1440 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1441 break;
1442 case V4L2_FIELD_NONE:
1443 default:
1444 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1445 break;
1446 }
1447
1448 if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
1449 /*
1450 * Replace the first half of the top line of a 50 Hz frame
1451 * with random data to simulate a WSS signal.
1452 */
1453 u8 *wss = tpg->random_line[p] +
1454 twopixsize * prandom_u32_max(tpg->src_width / 2);
1455
1456 memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
1457 }
1458 }
1459
1460 vbuf = orig_vbuf;
1461 vbuf += tpg->compose.left * twopixsize / 2;
1462 src_y = 0;
1463 error = 0;
1464 for (h = 0; h < tpg->compose.height; h++) {
1465 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1466 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1467 const struct v4l2_rect *sq = &tpg->square;
1468 const struct v4l2_rect *b = &tpg->border;
1469 const struct v4l2_rect *c = &tpg->crop;
1470
1471 src_y += int_part;
1472 error += fract_part;
1473 if (error >= tpg->compose.height) {
1474 error -= tpg->compose.height;
1475 src_y++;
1476 }
1477
1478 if (tpg->show_border && frame_line >= b->top &&
1479 frame_line < b->top + b->height) {
1480 unsigned bottom = b->top + b->height - 1;
1481 unsigned left = left_pillar_width;
1482 unsigned right = right_pillar_start;
1483
1484 if (frame_line == b->top || frame_line == b->top + 1 ||
1485 frame_line == bottom || frame_line == bottom - 1) {
1486 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1487 right - left);
1488 } else {
1489 if (b->left >= c->left &&
1490 b->left < c->left + c->width)
1491 memcpy(vbuf + buf_line * stride + left,
1492 tpg->contrast_line[p], twopixsize);
1493 if (b->left + b->width > c->left &&
1494 b->left + b->width <= c->left + c->width)
1495 memcpy(vbuf + buf_line * stride + right - twopixsize,
1496 tpg->contrast_line[p], twopixsize);
1497 }
1498 }
1499 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1500 frame_line < b->top + b->height) {
1501 memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
1502 memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
1503 img_width - right_pillar_start);
1504 }
1505 if (tpg->show_square && frame_line >= sq->top &&
1506 frame_line < sq->top + sq->height &&
1507 sq->left < c->left + c->width &&
1508 sq->left + sq->width >= c->left) {
1509 unsigned left = sq->left;
1510 unsigned width = sq->width;
1511
1512 if (c->left > left) {
1513 width -= c->left - left;
1514 left = c->left;
1515 }
1516 if (c->left + c->width < left + width)
1517 width -= left + width - c->left - c->width;
1518 left -= c->left;
1519 left = (left * tpg->scaled_width) / tpg->src_width;
1520 left = (left & ~1) * twopixsize / 2;
1521 width = (width * tpg->scaled_width) / tpg->src_width;
1522 width = (width & ~1) * twopixsize / 2;
1523 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1524 }
1525 if (tpg->insert_sav) {
1526 unsigned offset = (tpg->compose.width / 6) * twopixsize;
1527 u8 *p = vbuf + buf_line * stride + offset;
1528 unsigned vact = 0, hact = 0;
1529
1530 p[0] = 0xff;
1531 p[1] = 0;
1532 p[2] = 0;
1533 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1534 ((hact ^ vact) << 3) |
1535 ((hact ^ f) << 2) |
1536 ((f ^ vact) << 1) |
1537 (hact ^ vact ^ f);
1538 }
1539 if (tpg->insert_eav) {
1540 unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
1541 u8 *p = vbuf + buf_line * stride + offset;
1542 unsigned vact = 0, hact = 1;
1543
1544 p[0] = 0xff;
1545 p[1] = 0;
1546 p[2] = 0;
1547 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1548 ((hact ^ vact) << 3) |
1549 ((hact ^ f) << 2) |
1550 ((f ^ vact) << 1) |
1551 (hact ^ vact ^ f);
1552 }
1553 }
1554 }
This page took 0.068849 seconds and 6 git commands to generate.