blob: 79dc3101eb86fb4a66d8799e2993dff005994ea2 [file] [log] [blame]
Hans Verkuil63881df2014-08-25 08:02:14 -03001/*
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 */
26const 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",
Hans Verkuil1a05d312015-03-07 12:49:57 -030038 "2x2 Checkers",
Hans Verkuil63881df2014-08-25 08:02:14 -030039 "1x1 Checkers",
Hans Verkuil1a05d312015-03-07 12:49:57 -030040 "2x2 Red/Green Checkers",
41 "1x1 Red/Green Checkers",
Hans Verkuil63881df2014-08-25 08:02:14 -030042 "Alternating Hor Lines",
43 "Alternating Vert Lines",
44 "One Pixel Wide Cross",
45 "Two Pixels Wide Cross",
46 "Ten Pixels Wide Cross",
47 "Gray Ramp",
48 "Noise",
49 NULL
50};
51
52/* Must remain in sync with enum tpg_aspect */
53const char * const tpg_aspect_strings[] = {
54 "Source Width x Height",
55 "4x3",
56 "14x9",
57 "16x9",
58 "16x9 Anamorphic",
59 NULL
60};
61
62/*
63 * Sine table: sin[0] = 127 * sin(-180 degrees)
64 * sin[128] = 127 * sin(0 degrees)
65 * sin[256] = 127 * sin(180 degrees)
66 */
67static const s8 sin[257] = {
68 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
69 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
70 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
71 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
72 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
73 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
74 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
75 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
76 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
77 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
78 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
79 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
80 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
81 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
82 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
83 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
84 0,
85};
86
87#define cos(idx) sin[((idx) + 64) % sizeof(sin)]
88
89/* Global font descriptor */
90static const u8 *font8x16;
91
92void tpg_set_font(const u8 *f)
93{
94 font8x16 = f;
95}
96
97void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
98{
99 memset(tpg, 0, sizeof(*tpg));
100 tpg->scaled_width = tpg->src_width = w;
101 tpg->src_height = tpg->buf_height = h;
102 tpg->crop.width = tpg->compose.width = w;
103 tpg->crop.height = tpg->compose.height = h;
104 tpg->recalc_colors = true;
105 tpg->recalc_square_border = true;
106 tpg->brightness = 128;
107 tpg->contrast = 128;
108 tpg->saturation = 128;
109 tpg->hue = 0;
110 tpg->mv_hor_mode = TPG_MOVE_NONE;
111 tpg->mv_vert_mode = TPG_MOVE_NONE;
112 tpg->field = V4L2_FIELD_NONE;
113 tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
114 tpg->colorspace = V4L2_COLORSPACE_SRGB;
115 tpg->perc_fill = 100;
116}
117
118int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
119{
120 unsigned pat;
121 unsigned plane;
122
123 tpg->max_line_width = max_w;
124 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
125 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
126 unsigned pixelsz = plane ? 1 : 4;
127
128 tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
129 if (!tpg->lines[pat][plane])
130 return -ENOMEM;
Hans Verkuil5d7c5392015-03-07 14:06:43 -0300131 if (plane == 0)
132 continue;
133 tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
134 if (!tpg->downsampled_lines[pat][plane])
135 return -ENOMEM;
Hans Verkuil63881df2014-08-25 08:02:14 -0300136 }
137 }
138 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
139 unsigned pixelsz = plane ? 1 : 4;
140
141 tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
142 if (!tpg->contrast_line[plane])
143 return -ENOMEM;
144 tpg->black_line[plane] = vzalloc(max_w * pixelsz);
145 if (!tpg->black_line[plane])
146 return -ENOMEM;
Hans Verkuilc204e1f2014-10-07 08:58:55 -0300147 tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
Hans Verkuil63881df2014-08-25 08:02:14 -0300148 if (!tpg->random_line[plane])
149 return -ENOMEM;
150 }
151 return 0;
152}
153
154void tpg_free(struct tpg_data *tpg)
155{
156 unsigned pat;
157 unsigned plane;
158
159 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
160 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
161 vfree(tpg->lines[pat][plane]);
162 tpg->lines[pat][plane] = NULL;
Hans Verkuil5d7c5392015-03-07 14:06:43 -0300163 if (plane == 0)
164 continue;
165 vfree(tpg->downsampled_lines[pat][plane]);
166 tpg->downsampled_lines[pat][plane] = NULL;
Hans Verkuil63881df2014-08-25 08:02:14 -0300167 }
168 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
169 vfree(tpg->contrast_line[plane]);
170 vfree(tpg->black_line[plane]);
171 vfree(tpg->random_line[plane]);
172 tpg->contrast_line[plane] = NULL;
173 tpg->black_line[plane] = NULL;
174 tpg->random_line[plane] = NULL;
175 }
176}
177
178bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
179{
180 tpg->fourcc = fourcc;
181 tpg->planes = 1;
Hans Verkuil06d1f0c2015-03-07 13:01:53 -0300182 tpg->buffers = 1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300183 tpg->recalc_colors = true;
Hans Verkuilba01f672015-03-07 13:57:27 -0300184 tpg->vdownsampling[0] = 1;
185 tpg->hdownsampling[0] = 1;
Hans Verkuil06d1f0c2015-03-07 13:01:53 -0300186
Hans Verkuil63881df2014-08-25 08:02:14 -0300187 switch (fourcc) {
188 case V4L2_PIX_FMT_RGB565:
189 case V4L2_PIX_FMT_RGB565X:
190 case V4L2_PIX_FMT_RGB555:
191 case V4L2_PIX_FMT_XRGB555:
192 case V4L2_PIX_FMT_ARGB555:
193 case V4L2_PIX_FMT_RGB555X:
194 case V4L2_PIX_FMT_RGB24:
195 case V4L2_PIX_FMT_BGR24:
196 case V4L2_PIX_FMT_RGB32:
197 case V4L2_PIX_FMT_BGR32:
198 case V4L2_PIX_FMT_XRGB32:
199 case V4L2_PIX_FMT_XBGR32:
200 case V4L2_PIX_FMT_ARGB32:
201 case V4L2_PIX_FMT_ABGR32:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300202 tpg->is_yuv = false;
Hans Verkuil63881df2014-08-25 08:02:14 -0300203 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300204 case V4L2_PIX_FMT_YUV420M:
205 case V4L2_PIX_FMT_YVU420M:
206 tpg->buffers = 3;
207 /* fall through */
208 case V4L2_PIX_FMT_YUV420:
209 case V4L2_PIX_FMT_YVU420:
210 tpg->vdownsampling[1] = 2;
211 tpg->vdownsampling[2] = 2;
212 tpg->hdownsampling[1] = 2;
213 tpg->hdownsampling[2] = 2;
214 tpg->planes = 3;
215 tpg->is_yuv = true;
216 break;
217 case V4L2_PIX_FMT_YUV422P:
218 tpg->vdownsampling[1] = 1;
219 tpg->vdownsampling[2] = 1;
220 tpg->hdownsampling[1] = 2;
221 tpg->hdownsampling[2] = 2;
222 tpg->planes = 3;
223 tpg->is_yuv = true;
224 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300225 case V4L2_PIX_FMT_NV16M:
226 case V4L2_PIX_FMT_NV61M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300227 tpg->buffers = 2;
228 /* fall through */
229 case V4L2_PIX_FMT_NV16:
230 case V4L2_PIX_FMT_NV61:
Hans Verkuilba01f672015-03-07 13:57:27 -0300231 tpg->vdownsampling[1] = 1;
232 tpg->hdownsampling[1] = 1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300233 tpg->planes = 2;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300234 tpg->is_yuv = true;
235 break;
236 case V4L2_PIX_FMT_NV12M:
237 case V4L2_PIX_FMT_NV21M:
238 tpg->buffers = 2;
239 /* fall through */
240 case V4L2_PIX_FMT_NV12:
241 case V4L2_PIX_FMT_NV21:
242 tpg->vdownsampling[1] = 2;
243 tpg->hdownsampling[1] = 1;
244 tpg->planes = 2;
245 tpg->is_yuv = true;
246 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300247 case V4L2_PIX_FMT_YUYV:
248 case V4L2_PIX_FMT_UYVY:
249 case V4L2_PIX_FMT_YVYU:
250 case V4L2_PIX_FMT_VYUY:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300251 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300252 break;
253 default:
254 return false;
255 }
256
257 switch (fourcc) {
258 case V4L2_PIX_FMT_RGB565:
259 case V4L2_PIX_FMT_RGB565X:
260 case V4L2_PIX_FMT_RGB555:
261 case V4L2_PIX_FMT_XRGB555:
262 case V4L2_PIX_FMT_ARGB555:
263 case V4L2_PIX_FMT_RGB555X:
264 case V4L2_PIX_FMT_YUYV:
265 case V4L2_PIX_FMT_UYVY:
266 case V4L2_PIX_FMT_YVYU:
267 case V4L2_PIX_FMT_VYUY:
268 tpg->twopixelsize[0] = 2 * 2;
269 break;
270 case V4L2_PIX_FMT_RGB24:
271 case V4L2_PIX_FMT_BGR24:
272 tpg->twopixelsize[0] = 2 * 3;
273 break;
274 case V4L2_PIX_FMT_RGB32:
275 case V4L2_PIX_FMT_BGR32:
276 case V4L2_PIX_FMT_XRGB32:
277 case V4L2_PIX_FMT_XBGR32:
278 case V4L2_PIX_FMT_ARGB32:
279 case V4L2_PIX_FMT_ABGR32:
280 tpg->twopixelsize[0] = 2 * 4;
281 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300282 case V4L2_PIX_FMT_NV12:
283 case V4L2_PIX_FMT_NV21:
284 case V4L2_PIX_FMT_NV12M:
285 case V4L2_PIX_FMT_NV21M:
286 tpg->twopixelsize[0] = 2;
287 tpg->twopixelsize[1] = 2;
288 break;
289 case V4L2_PIX_FMT_NV16:
290 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300291 case V4L2_PIX_FMT_NV16M:
292 case V4L2_PIX_FMT_NV61M:
293 tpg->twopixelsize[0] = 2;
294 tpg->twopixelsize[1] = 2;
295 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300296 case V4L2_PIX_FMT_YUV422P:
297 case V4L2_PIX_FMT_YUV420:
298 case V4L2_PIX_FMT_YVU420:
299 case V4L2_PIX_FMT_YUV420M:
300 case V4L2_PIX_FMT_YVU420M:
301 tpg->twopixelsize[0] = 2;
302 tpg->twopixelsize[1] = 2;
303 tpg->twopixelsize[2] = 2;
304 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300305 }
306 return true;
307}
308
309void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
310 const struct v4l2_rect *compose)
311{
312 tpg->crop = *crop;
313 tpg->compose = *compose;
314 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
315 tpg->crop.width - 1) / tpg->crop.width;
316 tpg->scaled_width &= ~1;
317 if (tpg->scaled_width > tpg->max_line_width)
318 tpg->scaled_width = tpg->max_line_width;
319 if (tpg->scaled_width < 2)
320 tpg->scaled_width = 2;
321 tpg->recalc_lines = true;
322}
323
324void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300325 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300326{
327 unsigned p;
328
329 tpg->src_width = width;
330 tpg->src_height = height;
331 tpg->field = field;
332 tpg->buf_height = height;
333 if (V4L2_FIELD_HAS_T_OR_B(field))
334 tpg->buf_height /= 2;
335 tpg->scaled_width = width;
336 tpg->crop.top = tpg->crop.left = 0;
337 tpg->crop.width = width;
338 tpg->crop.height = height;
339 tpg->compose.top = tpg->compose.left = 0;
340 tpg->compose.width = width;
341 tpg->compose.height = tpg->buf_height;
342 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300343 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
344 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300345 tpg->recalc_square_border = true;
346}
347
348static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
349{
350 switch (tpg->pattern) {
351 case TPG_PAT_BLACK:
352 return TPG_COLOR_100_WHITE;
353 case TPG_PAT_CSC_COLORBAR:
354 return TPG_COLOR_CSC_BLACK;
355 default:
356 return TPG_COLOR_100_BLACK;
357 }
358}
359
360static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
361{
362 switch (tpg->pattern) {
363 case TPG_PAT_75_COLORBAR:
364 case TPG_PAT_CSC_COLORBAR:
365 return TPG_COLOR_CSC_WHITE;
366 case TPG_PAT_BLACK:
367 return TPG_COLOR_100_BLACK;
368 default:
369 return TPG_COLOR_100_WHITE;
370 }
371}
372
Hans Verkuil481b97a2014-11-17 10:14:32 -0300373static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300374{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300375 v = clamp(v, 0, 0xff0);
376 return tpg_rec709_to_linear[v];
377}
378
379static inline int linear_to_rec709(int v)
380{
381 v = clamp(v, 0, 0xff0);
382 return tpg_linear_to_rec709[v];
383}
384
385static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
386 int y_offset, int *y, int *cb, int *cr)
387{
388 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
389 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
390 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
391}
392
393static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
394 int *y, int *cb, int *cr)
395{
396#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
397
398 static const int bt601[3][3] = {
399 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
400 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
401 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
402 };
403 static const int bt601_full[3][3] = {
404 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
405 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
406 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
407 };
408 static const int rec709[3][3] = {
409 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
410 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
411 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
412 };
413 static const int rec709_full[3][3] = {
414 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
415 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
416 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
417 };
418 static const int smpte240m[3][3] = {
419 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
420 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
421 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
422 };
423 static const int bt2020[3][3] = {
424 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
425 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
426 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
427 };
428 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300429 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300430 int lin_y, yc;
431
432 switch (tpg->real_ycbcr_enc) {
433 case V4L2_YCBCR_ENC_601:
434 case V4L2_YCBCR_ENC_XV601:
435 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300436 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300437 break;
438 case V4L2_YCBCR_ENC_BT2020:
439 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
440 break;
441 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
442 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
443 COEFF(0.6780, 255) * rec709_to_linear(g) +
444 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
445 yc = linear_to_rec709(lin_y);
446 *y = (yc * 219) / 255 + (16 << 4);
447 if (b <= yc)
448 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
449 else
450 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
451 if (r <= yc)
452 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
453 else
454 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
455 break;
456 case V4L2_YCBCR_ENC_SMPTE240M:
457 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
458 break;
459 case V4L2_YCBCR_ENC_709:
460 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300461 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300462 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300463 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300464 }
465}
466
Hans Verkuil481b97a2014-11-17 10:14:32 -0300467static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
468 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300469{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300470 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300471 cb -= 128 << 4;
472 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300473 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
474 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
475 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
476 *r = clamp(*r >> 12, 0, 0xff0);
477 *g = clamp(*g >> 12, 0, 0xff0);
478 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300479}
480
Hans Verkuil481b97a2014-11-17 10:14:32 -0300481static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
482 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300483{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300484#undef COEFF
485#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
486 static const int bt601[3][3] = {
487 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
488 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
489 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
490 };
491 static const int bt601_full[3][3] = {
492 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
493 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
494 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
495 };
496 static const int rec709[3][3] = {
497 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
498 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
499 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
500 };
501 static const int rec709_full[3][3] = {
502 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
503 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
504 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
505 };
506 static const int smpte240m[3][3] = {
507 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
508 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
509 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
510 };
511 static const int bt2020[3][3] = {
512 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
513 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
514 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
515 };
516 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300517 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300518 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300519
Hans Verkuil481b97a2014-11-17 10:14:32 -0300520 switch (tpg->real_ycbcr_enc) {
521 case V4L2_YCBCR_ENC_601:
522 case V4L2_YCBCR_ENC_XV601:
523 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300524 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300525 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300526 case V4L2_YCBCR_ENC_BT2020:
527 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300528 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300529 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
530 y -= 16 << 4;
531 cb -= 128 << 4;
532 cr -= 128 << 4;
533
534 if (cb <= 0)
535 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
536 else
537 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
538 *b = *b >> 12;
539 if (cr <= 0)
540 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
541 else
542 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
543 *r = *r >> 12;
544 lin_r = rec709_to_linear(*r);
545 lin_b = rec709_to_linear(*b);
546 lin_y = rec709_to_linear((y * 255) / 219);
547
548 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
549 COEFF(0.2627 / 0.6780, 255) * lin_r -
550 COEFF(0.0593 / 0.6780, 255) * lin_b;
551 *g = linear_to_rec709(lin_g >> 12);
552 break;
553 case V4L2_YCBCR_ENC_SMPTE240M:
554 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
555 break;
556 case V4L2_YCBCR_ENC_709:
557 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300558 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300559 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300560 break;
561 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300562}
563
564/* precalculate color bar values to speed up rendering */
565static void precalculate_color(struct tpg_data *tpg, int k)
566{
567 int col = k;
568 int r = tpg_colors[col].r;
569 int g = tpg_colors[col].g;
570 int b = tpg_colors[col].b;
571
572 if (k == TPG_COLOR_TEXTBG) {
573 col = tpg_get_textbg_color(tpg);
574
575 r = tpg_colors[col].r;
576 g = tpg_colors[col].g;
577 b = tpg_colors[col].b;
578 } else if (k == TPG_COLOR_TEXTFG) {
579 col = tpg_get_textfg_color(tpg);
580
581 r = tpg_colors[col].r;
582 g = tpg_colors[col].g;
583 b = tpg_colors[col].b;
584 } else if (tpg->pattern == TPG_PAT_NOISE) {
585 r = g = b = prandom_u32_max(256);
586 } else if (k == TPG_COLOR_RANDOM) {
587 r = g = b = tpg->qual_offset + prandom_u32_max(196);
588 } else if (k >= TPG_COLOR_RAMP) {
589 r = g = b = k - TPG_COLOR_RAMP;
590 }
591
592 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
593 r = tpg_csc_colors[tpg->colorspace][col].r;
594 g = tpg_csc_colors[tpg->colorspace][col].g;
595 b = tpg_csc_colors[tpg->colorspace][col].b;
596 } else {
597 r <<= 4;
598 g <<= 4;
599 b <<= 4;
600 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300601 if (tpg->qual == TPG_QUAL_GRAY) {
602 /* Rec. 709 Luma function */
603 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300604 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300605 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300606
607 /*
608 * The assumption is that the RGB output is always full range,
609 * so only if the rgb_range overrides the 'real' rgb range do
610 * we need to convert the RGB values.
611 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300612 * Remember that r, g and b are still in the 0 - 0xff0 range.
613 */
614 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
615 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
616 /*
617 * Convert from full range (which is what r, g and b are)
618 * to limited range (which is the 'real' RGB range), which
619 * is then interpreted as full range.
620 */
621 r = (r * 219) / 255 + (16 << 4);
622 g = (g * 219) / 255 + (16 << 4);
623 b = (b * 219) / 255 + (16 << 4);
624 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
625 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
626 /*
627 * Clamp r, g and b to the limited range and convert to full
628 * range since that's what we deliver.
629 */
630 r = clamp(r, 16 << 4, 235 << 4);
631 g = clamp(g, 16 << 4, 235 << 4);
632 b = clamp(b, 16 << 4, 235 << 4);
633 r = (r - (16 << 4)) * 255 / 219;
634 g = (g - (16 << 4)) * 255 / 219;
635 b = (b - (16 << 4)) * 255 / 219;
636 }
637
638 if (tpg->brightness != 128 || tpg->contrast != 128 ||
639 tpg->saturation != 128 || tpg->hue) {
640 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300641 int y, cb, cr;
642 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300643
644 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300645
646 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300647
648 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
649 y += (tpg->brightness << 4) - (128 << 4);
650
651 cb -= 128 << 4;
652 cr -= 128 << 4;
653 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
654 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
655
656 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
657 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
658 if (tpg->is_yuv) {
659 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
660 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
661 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
662 return;
663 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300664 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300665 }
666
667 if (tpg->is_yuv) {
668 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300669 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300670
Hans Verkuil481b97a2014-11-17 10:14:32 -0300671 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
672
673 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
674 y = clamp(y, 16 << 4, 235 << 4);
675 cb = clamp(cb, 16 << 4, 240 << 4);
676 cr = clamp(cr, 16 << 4, 240 << 4);
677 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300678 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
679 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
680 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
681 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300682 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
683 r = (r * 219) / 255 + (16 << 4);
684 g = (g * 219) / 255 + (16 << 4);
685 b = (b * 219) / 255 + (16 << 4);
686 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300687 switch (tpg->fourcc) {
688 case V4L2_PIX_FMT_RGB565:
689 case V4L2_PIX_FMT_RGB565X:
690 r >>= 7;
691 g >>= 6;
692 b >>= 7;
693 break;
694 case V4L2_PIX_FMT_RGB555:
695 case V4L2_PIX_FMT_XRGB555:
696 case V4L2_PIX_FMT_ARGB555:
697 case V4L2_PIX_FMT_RGB555X:
698 r >>= 7;
699 g >>= 7;
700 b >>= 7;
701 break;
702 default:
703 r >>= 4;
704 g >>= 4;
705 b >>= 4;
706 break;
707 }
708
709 tpg->colors[k][0] = r;
710 tpg->colors[k][1] = g;
711 tpg->colors[k][2] = b;
712 }
713}
714
715static void tpg_precalculate_colors(struct tpg_data *tpg)
716{
717 int k;
718
719 for (k = 0; k < TPG_COLOR_MAX; k++)
720 precalculate_color(tpg, k);
721}
722
723/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
724static void gen_twopix(struct tpg_data *tpg,
725 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
726{
727 unsigned offset = odd * tpg->twopixelsize[0] / 2;
728 u8 alpha = tpg->alpha_component;
729 u8 r_y, g_u, b_v;
730
731 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
732 color != TPG_COLOR_100_RED &&
733 color != TPG_COLOR_75_RED)
734 alpha = 0;
735 if (color == TPG_COLOR_RANDOM)
736 precalculate_color(tpg, color);
737 r_y = tpg->colors[color][0]; /* R or precalculated Y */
738 g_u = tpg->colors[color][1]; /* G or precalculated U */
739 b_v = tpg->colors[color][2]; /* B or precalculated V */
740
741 switch (tpg->fourcc) {
Hans Verkuil68c90d62015-03-07 14:55:09 -0300742 case V4L2_PIX_FMT_YUV422P:
743 case V4L2_PIX_FMT_YUV420:
744 case V4L2_PIX_FMT_YUV420M:
745 buf[0][offset] = r_y;
746 if (odd) {
747 buf[1][0] = (buf[1][0] + g_u) / 2;
748 buf[2][0] = (buf[2][0] + b_v) / 2;
749 buf[1][1] = buf[1][0];
750 buf[2][1] = buf[2][0];
751 break;
752 }
753 buf[1][0] = g_u;
754 buf[2][0] = b_v;
755 break;
756 case V4L2_PIX_FMT_YVU420:
757 case V4L2_PIX_FMT_YVU420M:
758 buf[0][offset] = r_y;
759 if (odd) {
760 buf[1][0] = (buf[1][0] + b_v) / 2;
761 buf[2][0] = (buf[2][0] + g_u) / 2;
762 buf[1][1] = buf[1][0];
763 buf[2][1] = buf[2][0];
764 break;
765 }
766 buf[1][0] = b_v;
767 buf[2][0] = g_u;
768 break;
769
770 case V4L2_PIX_FMT_NV12:
771 case V4L2_PIX_FMT_NV12M:
772 case V4L2_PIX_FMT_NV16:
Hans Verkuil63881df2014-08-25 08:02:14 -0300773 case V4L2_PIX_FMT_NV16M:
774 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300775 if (odd) {
776 buf[1][0] = (buf[1][0] + g_u) / 2;
777 buf[1][1] = (buf[1][1] + b_v) / 2;
778 break;
779 }
780 buf[1][0] = g_u;
781 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300782 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300783 case V4L2_PIX_FMT_NV21:
784 case V4L2_PIX_FMT_NV21M:
785 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300786 case V4L2_PIX_FMT_NV61M:
787 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300788 if (odd) {
789 buf[1][0] = (buf[1][0] + b_v) / 2;
790 buf[1][1] = (buf[1][1] + g_u) / 2;
791 break;
792 }
793 buf[1][0] = b_v;
794 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300795 break;
796
797 case V4L2_PIX_FMT_YUYV:
798 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300799 if (odd) {
800 buf[0][1] = (buf[0][1] + g_u) / 2;
801 buf[0][3] = (buf[0][3] + b_v) / 2;
802 break;
803 }
804 buf[0][1] = g_u;
805 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300806 break;
807 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300808 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300809 if (odd) {
810 buf[0][0] = (buf[0][0] + g_u) / 2;
811 buf[0][2] = (buf[0][2] + b_v) / 2;
812 break;
813 }
814 buf[0][0] = g_u;
815 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300816 break;
817 case V4L2_PIX_FMT_YVYU:
818 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300819 if (odd) {
820 buf[0][1] = (buf[0][1] + b_v) / 2;
821 buf[0][3] = (buf[0][3] + g_u) / 2;
822 break;
823 }
824 buf[0][1] = b_v;
825 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300826 break;
827 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300828 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300829 if (odd) {
830 buf[0][0] = (buf[0][0] + b_v) / 2;
831 buf[0][2] = (buf[0][2] + g_u) / 2;
832 break;
833 }
834 buf[0][0] = b_v;
835 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300836 break;
837 case V4L2_PIX_FMT_RGB565:
838 buf[0][offset] = (g_u << 5) | b_v;
839 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
840 break;
841 case V4L2_PIX_FMT_RGB565X:
842 buf[0][offset] = (r_y << 3) | (g_u >> 3);
843 buf[0][offset + 1] = (g_u << 5) | b_v;
844 break;
845 case V4L2_PIX_FMT_RGB555:
846 case V4L2_PIX_FMT_XRGB555:
847 alpha = 0;
848 /* fall through */
849 case V4L2_PIX_FMT_ARGB555:
850 buf[0][offset] = (g_u << 5) | b_v;
851 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
852 break;
853 case V4L2_PIX_FMT_RGB555X:
854 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
855 buf[0][offset + 1] = (g_u << 5) | b_v;
856 break;
857 case V4L2_PIX_FMT_RGB24:
858 buf[0][offset] = r_y;
859 buf[0][offset + 1] = g_u;
860 buf[0][offset + 2] = b_v;
861 break;
862 case V4L2_PIX_FMT_BGR24:
863 buf[0][offset] = b_v;
864 buf[0][offset + 1] = g_u;
865 buf[0][offset + 2] = r_y;
866 break;
867 case V4L2_PIX_FMT_RGB32:
868 case V4L2_PIX_FMT_XRGB32:
869 alpha = 0;
870 /* fall through */
871 case V4L2_PIX_FMT_ARGB32:
872 buf[0][offset] = alpha;
873 buf[0][offset + 1] = r_y;
874 buf[0][offset + 2] = g_u;
875 buf[0][offset + 3] = b_v;
876 break;
877 case V4L2_PIX_FMT_BGR32:
878 case V4L2_PIX_FMT_XBGR32:
879 alpha = 0;
880 /* fall through */
881 case V4L2_PIX_FMT_ABGR32:
882 buf[0][offset] = b_v;
883 buf[0][offset + 1] = g_u;
884 buf[0][offset + 2] = r_y;
885 buf[0][offset + 3] = alpha;
886 break;
887 }
888}
889
890/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300891static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -0300892{
893 switch (tpg->pattern) {
894 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300895 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -0300896 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300897 case TPG_PAT_COLOR_CHECKERS_2X2:
898 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300899 case TPG_PAT_ALTERNATING_HLINES:
900 case TPG_PAT_CROSS_1_PIXEL:
901 case TPG_PAT_CROSS_2_PIXELS:
902 case TPG_PAT_CROSS_10_PIXELS:
903 return 2;
904 case TPG_PAT_100_COLORSQUARES:
905 case TPG_PAT_100_HCOLORBAR:
906 return 8;
907 default:
908 return 1;
909 }
910}
911
912/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300913static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -0300914{
915 switch (tpg->pattern) {
916 case TPG_PAT_CHECKERS_16X16:
917 return (line >> 4) & 1;
918 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300919 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300920 case TPG_PAT_ALTERNATING_HLINES:
921 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -0300922 case TPG_PAT_CHECKERS_2X2:
923 case TPG_PAT_COLOR_CHECKERS_2X2:
924 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300925 case TPG_PAT_100_COLORSQUARES:
926 case TPG_PAT_100_HCOLORBAR:
927 return (line * 8) / tpg->src_height;
928 case TPG_PAT_CROSS_1_PIXEL:
929 return line == tpg->src_height / 2;
930 case TPG_PAT_CROSS_2_PIXELS:
931 return (line + 1) / 2 == tpg->src_height / 4;
932 case TPG_PAT_CROSS_10_PIXELS:
933 return (line + 10) / 20 == tpg->src_height / 40;
934 default:
935 return 0;
936 }
937}
938
939/*
940 * Which color should be used for the given pattern line and X coordinate.
941 * Note: x is in the range 0 to 2 * tpg->src_width.
942 */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300943static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
944 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -0300945{
946 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
947 should be modified */
948 static const enum tpg_color bars[3][8] = {
949 /* Standard ITU-R 75% color bar sequence */
950 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
951 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
952 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
953 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
954 /* Standard ITU-R 100% color bar sequence */
955 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
956 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
957 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
958 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
959 /* Color bar sequence suitable to test CSC */
960 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
961 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
962 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
963 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
964 };
965
966 switch (tpg->pattern) {
967 case TPG_PAT_75_COLORBAR:
968 case TPG_PAT_100_COLORBAR:
969 case TPG_PAT_CSC_COLORBAR:
970 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
971 case TPG_PAT_100_COLORSQUARES:
972 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
973 case TPG_PAT_100_HCOLORBAR:
974 return bars[1][pat_line];
975 case TPG_PAT_BLACK:
976 return TPG_COLOR_100_BLACK;
977 case TPG_PAT_WHITE:
978 return TPG_COLOR_100_WHITE;
979 case TPG_PAT_RED:
980 return TPG_COLOR_100_RED;
981 case TPG_PAT_GREEN:
982 return TPG_COLOR_100_GREEN;
983 case TPG_PAT_BLUE:
984 return TPG_COLOR_100_BLUE;
985 case TPG_PAT_CHECKERS_16X16:
986 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
987 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
988 case TPG_PAT_CHECKERS_1X1:
989 return ((x & 1) ^ (pat_line & 1)) ?
990 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -0300991 case TPG_PAT_COLOR_CHECKERS_1X1:
992 return ((x & 1) ^ (pat_line & 1)) ?
993 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
994 case TPG_PAT_CHECKERS_2X2:
995 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
996 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
997 case TPG_PAT_COLOR_CHECKERS_2X2:
998 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
999 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -03001000 case TPG_PAT_ALTERNATING_HLINES:
1001 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1002 case TPG_PAT_ALTERNATING_VLINES:
1003 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1004 case TPG_PAT_CROSS_1_PIXEL:
1005 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1006 return TPG_COLOR_100_BLACK;
1007 return TPG_COLOR_100_WHITE;
1008 case TPG_PAT_CROSS_2_PIXELS:
1009 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1010 return TPG_COLOR_100_BLACK;
1011 return TPG_COLOR_100_WHITE;
1012 case TPG_PAT_CROSS_10_PIXELS:
1013 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1014 return TPG_COLOR_100_BLACK;
1015 return TPG_COLOR_100_WHITE;
1016 case TPG_PAT_GRAY_RAMP:
1017 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1018 default:
1019 return TPG_COLOR_100_RED;
1020 }
1021}
1022
1023/*
1024 * Given the pixel aspect ratio and video aspect ratio calculate the
1025 * coordinates of a centered square and the coordinates of the border of
1026 * the active video area. The coordinates are relative to the source
1027 * frame rectangle.
1028 */
1029static void tpg_calculate_square_border(struct tpg_data *tpg)
1030{
1031 unsigned w = tpg->src_width;
1032 unsigned h = tpg->src_height;
1033 unsigned sq_w, sq_h;
1034
1035 sq_w = (w * 2 / 5) & ~1;
1036 if (((w - sq_w) / 2) & 1)
1037 sq_w += 2;
1038 sq_h = sq_w;
1039 tpg->square.width = sq_w;
1040 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1041 unsigned ana_sq_w = (sq_w / 4) * 3;
1042
1043 if (((w - ana_sq_w) / 2) & 1)
1044 ana_sq_w += 2;
1045 tpg->square.width = ana_sq_w;
1046 }
1047 tpg->square.left = (w - tpg->square.width) / 2;
1048 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1049 sq_h = sq_w * 10 / 11;
1050 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1051 sq_h = sq_w * 59 / 54;
1052 tpg->square.height = sq_h;
1053 tpg->square.top = (h - sq_h) / 2;
1054 tpg->border.left = 0;
1055 tpg->border.width = w;
1056 tpg->border.top = 0;
1057 tpg->border.height = h;
1058 switch (tpg->vid_aspect) {
1059 case TPG_VIDEO_ASPECT_4X3:
1060 if (tpg->pix_aspect)
1061 return;
1062 if (3 * w >= 4 * h) {
1063 tpg->border.width = ((4 * h) / 3) & ~1;
1064 if (((w - tpg->border.width) / 2) & ~1)
1065 tpg->border.width -= 2;
1066 tpg->border.left = (w - tpg->border.width) / 2;
1067 break;
1068 }
1069 tpg->border.height = ((3 * w) / 4) & ~1;
1070 tpg->border.top = (h - tpg->border.height) / 2;
1071 break;
1072 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1073 if (tpg->pix_aspect) {
1074 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1075 tpg->border.top = (h - tpg->border.height) / 2;
1076 break;
1077 }
1078 if (9 * w >= 14 * h) {
1079 tpg->border.width = ((14 * h) / 9) & ~1;
1080 if (((w - tpg->border.width) / 2) & ~1)
1081 tpg->border.width -= 2;
1082 tpg->border.left = (w - tpg->border.width) / 2;
1083 break;
1084 }
1085 tpg->border.height = ((9 * w) / 14) & ~1;
1086 tpg->border.top = (h - tpg->border.height) / 2;
1087 break;
1088 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1089 if (tpg->pix_aspect) {
1090 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1091 tpg->border.top = (h - tpg->border.height) / 2;
1092 break;
1093 }
1094 if (9 * w >= 16 * h) {
1095 tpg->border.width = ((16 * h) / 9) & ~1;
1096 if (((w - tpg->border.width) / 2) & ~1)
1097 tpg->border.width -= 2;
1098 tpg->border.left = (w - tpg->border.width) / 2;
1099 break;
1100 }
1101 tpg->border.height = ((9 * w) / 16) & ~1;
1102 tpg->border.top = (h - tpg->border.height) / 2;
1103 break;
1104 default:
1105 break;
1106 }
1107}
1108
1109static void tpg_precalculate_line(struct tpg_data *tpg)
1110{
1111 enum tpg_color contrast;
1112 unsigned pat;
1113 unsigned p;
1114 unsigned x;
1115
1116 switch (tpg->pattern) {
1117 case TPG_PAT_GREEN:
1118 contrast = TPG_COLOR_100_RED;
1119 break;
1120 case TPG_PAT_CSC_COLORBAR:
1121 contrast = TPG_COLOR_CSC_GREEN;
1122 break;
1123 default:
1124 contrast = TPG_COLOR_100_GREEN;
1125 break;
1126 }
1127
1128 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1129 /* Coarse scaling with Bresenham */
1130 unsigned int_part = tpg->src_width / tpg->scaled_width;
1131 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1132 unsigned src_x = 0;
1133 unsigned error = 0;
1134
1135 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1136 unsigned real_x = src_x;
1137 enum tpg_color color1, color2;
1138 u8 pix[TPG_MAX_PLANES][8];
1139
1140 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1141 color1 = tpg_get_color(tpg, pat, real_x);
1142
1143 src_x += int_part;
1144 error += fract_part;
1145 if (error >= tpg->scaled_width) {
1146 error -= tpg->scaled_width;
1147 src_x++;
1148 }
1149
1150 real_x = src_x;
1151 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1152 color2 = tpg_get_color(tpg, pat, real_x);
1153
1154 src_x += int_part;
1155 error += fract_part;
1156 if (error >= tpg->scaled_width) {
1157 error -= tpg->scaled_width;
1158 src_x++;
1159 }
1160
1161 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1162 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1163 for (p = 0; p < tpg->planes; p++) {
1164 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001165 unsigned hdiv = tpg->hdownsampling[p];
1166 u8 *pos = tpg->lines[pat][p] +
1167 (x / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001168
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001169 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001170 }
1171 }
1172 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001173
1174 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1175 unsigned pat_lines = tpg_get_pat_lines(tpg);
1176
1177 for (pat = 0; pat < pat_lines; pat++) {
1178 unsigned next_pat = (pat + 1) % pat_lines;
1179
1180 for (p = 1; p < tpg->planes; p++) {
1181 unsigned twopixsize = tpg->twopixelsize[p];
1182 unsigned hdiv = tpg->hdownsampling[p];
1183
1184 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1185 unsigned offset = (x / hdiv) * twopixsize / 2;
1186 u8 *pos1 = tpg->lines[pat][p] + offset;
1187 u8 *pos2 = tpg->lines[next_pat][p] + offset;
1188 u8 *dest = tpg->downsampled_lines[pat][p] + offset;
1189 unsigned i;
1190
1191 for (i = 0; i < twopixsize / hdiv; i++, dest++, pos1++, pos2++)
1192 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1193 }
1194 }
1195 }
1196 }
1197
Hans Verkuil63881df2014-08-25 08:02:14 -03001198 for (x = 0; x < tpg->scaled_width; x += 2) {
1199 u8 pix[TPG_MAX_PLANES][8];
1200
1201 gen_twopix(tpg, pix, contrast, 0);
1202 gen_twopix(tpg, pix, contrast, 1);
1203 for (p = 0; p < tpg->planes; p++) {
1204 unsigned twopixsize = tpg->twopixelsize[p];
1205 u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
1206
1207 memcpy(pos, pix[p], twopixsize);
1208 }
1209 }
1210 for (x = 0; x < tpg->scaled_width; x += 2) {
1211 u8 pix[TPG_MAX_PLANES][8];
1212
1213 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1214 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1215 for (p = 0; p < tpg->planes; p++) {
1216 unsigned twopixsize = tpg->twopixelsize[p];
1217 u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
1218
1219 memcpy(pos, pix[p], twopixsize);
1220 }
1221 }
1222 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1223 u8 pix[TPG_MAX_PLANES][8];
1224
1225 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1226 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1227 for (p = 0; p < tpg->planes; p++) {
1228 unsigned twopixsize = tpg->twopixelsize[p];
1229 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1230
1231 memcpy(pos, pix[p], twopixsize);
1232 }
1233 }
1234 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1235 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1236 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1237 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1238}
1239
1240/* need this to do rgb24 rendering */
1241typedef struct { u16 __; u8 _; } __packed x24;
1242
1243void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1244 int y, int x, char *text)
1245{
1246 int line;
1247 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1248 unsigned div = step;
1249 unsigned first = 0;
1250 unsigned len = strlen(text);
1251 unsigned p;
1252
1253 if (font8x16 == NULL || basep == NULL)
1254 return;
1255
1256 /* Checks if it is possible to show string */
1257 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1258 return;
1259
1260 if (len > (tpg->compose.width - x) / 8)
1261 len = (tpg->compose.width - x) / 8;
1262 if (tpg->vflip)
1263 y = tpg->compose.height - y - 16;
1264 if (tpg->hflip)
1265 x = tpg->compose.width - x - 8;
1266 y += tpg->compose.top;
1267 x += tpg->compose.left;
1268 if (tpg->field == V4L2_FIELD_BOTTOM)
1269 first = 1;
1270 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1271 div = 2;
1272
1273 for (p = 0; p < tpg->planes; p++) {
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001274 unsigned vdiv = tpg->vdownsampling[p];
1275 unsigned hdiv = tpg->hdownsampling[p];
1276
1277 /* Print text */
Hans Verkuil63881df2014-08-25 08:02:14 -03001278#define PRINTSTR(PIXTYPE) do { \
1279 PIXTYPE fg; \
1280 PIXTYPE bg; \
1281 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1282 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1283 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001284 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001285 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001286 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1287 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1288 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001289 unsigned s; \
1290 \
1291 for (s = 0; s < len; s++) { \
1292 u8 chr = font8x16[text[s] * 16 + line]; \
1293 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001294 if (hdiv == 2 && tpg->hflip) { \
1295 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1296 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1297 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1298 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1299 } else if (hdiv == 2) { \
1300 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1301 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1302 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1303 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1304 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001305 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1306 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1307 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1308 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1309 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1310 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1311 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1312 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1313 } else { \
1314 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1315 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1316 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1317 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1318 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1319 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1320 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1321 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1322 } \
1323 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001324 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001325 } \
1326 } \
1327} while (0)
1328
1329 switch (tpg->twopixelsize[p]) {
1330 case 2:
1331 PRINTSTR(u8); break;
1332 case 4:
1333 PRINTSTR(u16); break;
1334 case 6:
1335 PRINTSTR(x24); break;
1336 case 8:
1337 PRINTSTR(u32); break;
1338 }
1339 }
1340}
1341
1342void tpg_update_mv_step(struct tpg_data *tpg)
1343{
1344 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1345
1346 if (tpg->hflip)
1347 factor = -factor;
1348 switch (tpg->mv_hor_mode) {
1349 case TPG_MOVE_NEG_FAST:
1350 case TPG_MOVE_POS_FAST:
1351 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1352 break;
1353 case TPG_MOVE_NEG:
1354 case TPG_MOVE_POS:
1355 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1356 break;
1357 case TPG_MOVE_NEG_SLOW:
1358 case TPG_MOVE_POS_SLOW:
1359 tpg->mv_hor_step = 2;
1360 break;
1361 case TPG_MOVE_NONE:
1362 tpg->mv_hor_step = 0;
1363 break;
1364 }
1365 if (factor < 0)
1366 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1367
1368 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1369 switch (tpg->mv_vert_mode) {
1370 case TPG_MOVE_NEG_FAST:
1371 case TPG_MOVE_POS_FAST:
1372 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1373 break;
1374 case TPG_MOVE_NEG:
1375 case TPG_MOVE_POS:
1376 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1377 break;
1378 case TPG_MOVE_NEG_SLOW:
1379 case TPG_MOVE_POS_SLOW:
1380 tpg->mv_vert_step = 1;
1381 break;
1382 case TPG_MOVE_NONE:
1383 tpg->mv_vert_step = 0;
1384 break;
1385 }
1386 if (factor < 0)
1387 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1388}
1389
1390/* Map the line number relative to the crop rectangle to a frame line number */
1391static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
1392 unsigned field)
1393{
1394 switch (field) {
1395 case V4L2_FIELD_TOP:
1396 return tpg->crop.top + src_y * 2;
1397 case V4L2_FIELD_BOTTOM:
1398 return tpg->crop.top + src_y * 2 + 1;
1399 default:
1400 return src_y + tpg->crop.top;
1401 }
1402}
1403
1404/*
1405 * Map the line number relative to the compose rectangle to a destination
1406 * buffer line number.
1407 */
1408static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
1409 unsigned field)
1410{
1411 y += tpg->compose.top;
1412 switch (field) {
1413 case V4L2_FIELD_SEQ_TB:
1414 if (y & 1)
1415 return tpg->buf_height / 2 + y / 2;
1416 return y / 2;
1417 case V4L2_FIELD_SEQ_BT:
1418 if (y & 1)
1419 return y / 2;
1420 return tpg->buf_height / 2 + y / 2;
1421 default:
1422 return y;
1423 }
1424}
1425
1426static void tpg_recalc(struct tpg_data *tpg)
1427{
1428 if (tpg->recalc_colors) {
1429 tpg->recalc_colors = false;
1430 tpg->recalc_lines = true;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001431 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1432 tpg->real_quantization = tpg->quantization;
1433 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1434 switch (tpg->colorspace) {
1435 case V4L2_COLORSPACE_REC709:
1436 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1437 break;
1438 case V4L2_COLORSPACE_SRGB:
1439 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1440 break;
1441 case V4L2_COLORSPACE_BT2020:
1442 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1443 break;
1444 case V4L2_COLORSPACE_SMPTE240M:
1445 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1446 break;
1447 case V4L2_COLORSPACE_SMPTE170M:
1448 case V4L2_COLORSPACE_470_SYSTEM_M:
1449 case V4L2_COLORSPACE_470_SYSTEM_BG:
1450 case V4L2_COLORSPACE_ADOBERGB:
1451 default:
1452 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1453 break;
1454 }
1455 }
1456 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1457 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1458 if (tpg->is_yuv) {
1459 switch (tpg->real_ycbcr_enc) {
1460 case V4L2_YCBCR_ENC_SYCC:
1461 case V4L2_YCBCR_ENC_XV601:
1462 case V4L2_YCBCR_ENC_XV709:
1463 break;
1464 default:
1465 tpg->real_quantization =
1466 V4L2_QUANTIZATION_LIM_RANGE;
1467 break;
1468 }
Hans Verkuilc0b50d92015-03-08 04:53:33 -03001469 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1470 /* R'G'B' BT.2020 is limited range */
1471 tpg->real_quantization =
1472 V4L2_QUANTIZATION_LIM_RANGE;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001473 }
1474 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001475 tpg_precalculate_colors(tpg);
1476 }
1477 if (tpg->recalc_square_border) {
1478 tpg->recalc_square_border = false;
1479 tpg_calculate_square_border(tpg);
1480 }
1481 if (tpg->recalc_lines) {
1482 tpg->recalc_lines = false;
1483 tpg_precalculate_line(tpg);
1484 }
1485}
1486
1487void tpg_calc_text_basep(struct tpg_data *tpg,
1488 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1489{
1490 unsigned stride = tpg->bytesperline[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001491 unsigned h = tpg->buf_height;
Hans Verkuil63881df2014-08-25 08:02:14 -03001492
1493 tpg_recalc(tpg);
1494
1495 basep[p][0] = vbuf;
1496 basep[p][1] = vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001497 h /= tpg->vdownsampling[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001498 if (tpg->field == V4L2_FIELD_SEQ_TB)
Hans Verkuil280abe42015-03-07 14:50:41 -03001499 basep[p][1] += h * stride / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001500 else if (tpg->field == V4L2_FIELD_SEQ_BT)
Hans Verkuil280abe42015-03-07 14:50:41 -03001501 basep[p][0] += h * stride / 2;
1502}
1503
1504static int tpg_pattern_avg(const struct tpg_data *tpg,
1505 unsigned pat1, unsigned pat2)
1506{
1507 unsigned pat_lines = tpg_get_pat_lines(tpg);
1508
1509 if (pat1 == (pat2 + 1) % pat_lines)
1510 return pat2;
1511 if (pat2 == (pat1 + 1) % pat_lines)
1512 return pat1;
1513 return -1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001514}
1515
Hans Verkuil4db22042015-03-07 13:39:01 -03001516void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03001517{
1518 bool is_tv = std;
1519 bool is_60hz = is_tv && (std & V4L2_STD_525_60);
1520 unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
1521 unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
1522 unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1523 unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1524 unsigned wss_width;
1525 unsigned f;
1526 int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1527 int h;
1528 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001529 unsigned hdiv = tpg->hdownsampling[p];
1530 unsigned vdiv = tpg->vdownsampling[p];
1531 unsigned img_width = (tpg->compose.width / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001532 unsigned line_offset;
1533 unsigned left_pillar_width = 0;
1534 unsigned right_pillar_start = img_width;
1535 unsigned stride = tpg->bytesperline[p];
1536 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1537 u8 *orig_vbuf = vbuf;
1538
1539 /* Coarse scaling with Bresenham */
1540 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1541 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1542 unsigned src_y = 0;
1543 unsigned error = 0;
1544
1545 tpg_recalc(tpg);
1546
1547 mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
1548 mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
1549 wss_width = tpg->crop.left < tpg->src_width / 2 ?
1550 tpg->src_width / 2 - tpg->crop.left : 0;
1551 if (wss_width > tpg->crop.width)
1552 wss_width = tpg->crop.width;
1553 wss_width = wss_width * tpg->scaled_width / tpg->src_width;
1554
1555 vbuf += tpg->compose.left * twopixsize / 2;
1556 line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
Hans Verkuil280abe42015-03-07 14:50:41 -03001557 line_offset = ((line_offset & ~1) / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001558 if (tpg->crop.left < tpg->border.left) {
1559 left_pillar_width = tpg->border.left - tpg->crop.left;
1560 if (left_pillar_width > tpg->crop.width)
1561 left_pillar_width = tpg->crop.width;
1562 left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
Hans Verkuil280abe42015-03-07 14:50:41 -03001563 left_pillar_width = ((left_pillar_width & ~1) / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001564 }
1565 if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
1566 right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
1567 right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
Hans Verkuil280abe42015-03-07 14:50:41 -03001568 right_pillar_start = ((right_pillar_start & ~1) / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001569 if (right_pillar_start > img_width)
1570 right_pillar_start = img_width;
1571 }
1572
1573 f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1574
1575 for (h = 0; h < tpg->compose.height; h++) {
1576 bool even;
1577 bool fill_blank = false;
1578 unsigned frame_line;
1579 unsigned buf_line;
1580 unsigned pat_line_old;
1581 unsigned pat_line_new;
1582 u8 *linestart_older;
1583 u8 *linestart_newer;
1584 u8 *linestart_top;
1585 u8 *linestart_bottom;
1586
1587 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1588 even = !(frame_line & 1);
1589 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1590 src_y += int_part;
1591 error += fract_part;
1592 if (error >= tpg->compose.height) {
1593 error -= tpg->compose.height;
1594 src_y++;
1595 }
1596
Hans Verkuil280abe42015-03-07 14:50:41 -03001597 if (vdiv > 1) {
1598 /*
1599 * When doing vertical downsampling the field setting
1600 * matters: for SEQ_BT/TB we downsample each field
1601 * separately (i.e. lines 0+2 are combined, as are
1602 * lines 1+3), for the other field settings we combine
1603 * odd and even lines. Doing that for SEQ_BT/TB would
1604 * be really weird.
1605 */
1606 if (tpg->field == V4L2_FIELD_SEQ_BT ||
1607 tpg->field == V4L2_FIELD_SEQ_TB) {
1608 if ((h & 3) >= 2)
1609 continue;
1610 } else if (h & 1) {
1611 continue;
1612 }
1613
1614 buf_line /= vdiv;
1615 }
1616
Hans Verkuil63881df2014-08-25 08:02:14 -03001617 if (h >= hmax) {
1618 if (hmax == tpg->compose.height)
1619 continue;
1620 if (!tpg->perc_fill_blank)
1621 continue;
1622 fill_blank = true;
1623 }
1624
1625 if (tpg->vflip)
1626 frame_line = tpg->src_height - frame_line - 1;
1627
1628 if (fill_blank) {
1629 linestart_older = tpg->contrast_line[p];
1630 linestart_newer = tpg->contrast_line[p];
1631 } else if (tpg->qual != TPG_QUAL_NOISE &&
1632 (frame_line < tpg->border.top ||
1633 frame_line >= tpg->border.top + tpg->border.height)) {
1634 linestart_older = tpg->black_line[p];
1635 linestart_newer = tpg->black_line[p];
1636 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1637 linestart_older = tpg->random_line[p] +
1638 twopixsize * prandom_u32_max(tpg->src_width / 2);
1639 linestart_newer = tpg->random_line[p] +
1640 twopixsize * prandom_u32_max(tpg->src_width / 2);
1641 } else {
Hans Verkuil280abe42015-03-07 14:50:41 -03001642 unsigned frame_line_old =
1643 (frame_line + mv_vert_old) % tpg->src_height;
1644 unsigned frame_line_new =
1645 (frame_line + mv_vert_new) % tpg->src_height;
1646 unsigned pat_line_next_old;
1647 unsigned pat_line_next_new;
1648
1649 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1650 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
Hans Verkuil63881df2014-08-25 08:02:14 -03001651 linestart_older = tpg->lines[pat_line_old][p] +
Hans Verkuil280abe42015-03-07 14:50:41 -03001652 (mv_hor_old / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001653 linestart_newer = tpg->lines[pat_line_new][p] +
Hans Verkuil280abe42015-03-07 14:50:41 -03001654 (mv_hor_new / hdiv) * twopixsize / 2;
1655
1656 if (vdiv > 1) {
1657 unsigned frame_line_next;
1658 int avg_pat;
1659
1660 /*
1661 * Now decide whether we need to use downsampled_lines[].
1662 * That's necessary if the two lines use different patterns.
1663 */
1664 frame_line_next = tpg_calc_frameline(tpg, src_y, tpg->field);
1665 if (tpg->vflip)
1666 frame_line_next = tpg->src_height - frame_line_next - 1;
1667 pat_line_next_old = tpg_get_pat_line(tpg,
1668 (frame_line_next + mv_vert_old) % tpg->src_height);
1669 pat_line_next_new = tpg_get_pat_line(tpg,
1670 (frame_line_next + mv_vert_new) % tpg->src_height);
1671
1672 switch (tpg->field) {
1673 case V4L2_FIELD_INTERLACED:
1674 case V4L2_FIELD_INTERLACED_BT:
1675 case V4L2_FIELD_INTERLACED_TB:
1676 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
1677 if (avg_pat < 0)
1678 break;
1679 linestart_older = tpg->downsampled_lines[avg_pat][p] +
1680 (mv_hor_old / hdiv) * twopixsize / 2;
1681 linestart_newer = linestart_older;
1682 break;
1683 case V4L2_FIELD_NONE:
1684 case V4L2_FIELD_TOP:
1685 case V4L2_FIELD_BOTTOM:
1686 case V4L2_FIELD_SEQ_BT:
1687 case V4L2_FIELD_SEQ_TB:
1688 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
1689 if (avg_pat >= 0)
1690 linestart_older = tpg->downsampled_lines[avg_pat][p] +
1691 (mv_hor_old / hdiv) * twopixsize / 2;
1692 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
1693 if (avg_pat >= 0)
1694 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
1695 (mv_hor_new / hdiv) * twopixsize / 2;
1696 break;
1697 }
1698 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001699 linestart_older += line_offset;
1700 linestart_newer += line_offset;
1701 }
Hans Verkuil43047f62015-03-07 12:38:42 -03001702 if (tpg->field_alternate) {
1703 linestart_top = linestart_bottom = linestart_older;
1704 } else if (is_60hz) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001705 linestart_top = linestart_newer;
1706 linestart_bottom = linestart_older;
1707 } else {
1708 linestart_top = linestart_older;
1709 linestart_bottom = linestart_newer;
1710 }
1711
1712 switch (tpg->field) {
1713 case V4L2_FIELD_INTERLACED:
1714 case V4L2_FIELD_INTERLACED_TB:
1715 case V4L2_FIELD_SEQ_TB:
1716 case V4L2_FIELD_SEQ_BT:
1717 if (even)
1718 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1719 else
1720 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1721 break;
1722 case V4L2_FIELD_INTERLACED_BT:
1723 if (even)
1724 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1725 else
1726 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1727 break;
1728 case V4L2_FIELD_TOP:
1729 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1730 break;
1731 case V4L2_FIELD_BOTTOM:
1732 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1733 break;
1734 case V4L2_FIELD_NONE:
1735 default:
1736 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1737 break;
1738 }
1739
1740 if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
1741 /*
1742 * Replace the first half of the top line of a 50 Hz frame
1743 * with random data to simulate a WSS signal.
1744 */
1745 u8 *wss = tpg->random_line[p] +
1746 twopixsize * prandom_u32_max(tpg->src_width / 2);
1747
Hans Verkuil280abe42015-03-07 14:50:41 -03001748 memcpy(vbuf + buf_line * stride, wss,
1749 (wss_width / hdiv) * twopixsize / 2);
Hans Verkuil63881df2014-08-25 08:02:14 -03001750 }
1751 }
1752
1753 vbuf = orig_vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001754 vbuf += (tpg->compose.left / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001755 src_y = 0;
1756 error = 0;
1757 for (h = 0; h < tpg->compose.height; h++) {
1758 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1759 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1760 const struct v4l2_rect *sq = &tpg->square;
1761 const struct v4l2_rect *b = &tpg->border;
1762 const struct v4l2_rect *c = &tpg->crop;
1763
1764 src_y += int_part;
1765 error += fract_part;
1766 if (error >= tpg->compose.height) {
1767 error -= tpg->compose.height;
1768 src_y++;
1769 }
1770
Hans Verkuil280abe42015-03-07 14:50:41 -03001771 if (vdiv > 1) {
1772 if (h & 1)
1773 continue;
1774 buf_line /= vdiv;
1775 }
1776
Hans Verkuil63881df2014-08-25 08:02:14 -03001777 if (tpg->show_border && frame_line >= b->top &&
1778 frame_line < b->top + b->height) {
1779 unsigned bottom = b->top + b->height - 1;
1780 unsigned left = left_pillar_width;
1781 unsigned right = right_pillar_start;
1782
1783 if (frame_line == b->top || frame_line == b->top + 1 ||
1784 frame_line == bottom || frame_line == bottom - 1) {
1785 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1786 right - left);
1787 } else {
1788 if (b->left >= c->left &&
1789 b->left < c->left + c->width)
1790 memcpy(vbuf + buf_line * stride + left,
1791 tpg->contrast_line[p], twopixsize);
1792 if (b->left + b->width > c->left &&
1793 b->left + b->width <= c->left + c->width)
1794 memcpy(vbuf + buf_line * stride + right - twopixsize,
1795 tpg->contrast_line[p], twopixsize);
1796 }
1797 }
1798 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1799 frame_line < b->top + b->height) {
1800 memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
1801 memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
1802 img_width - right_pillar_start);
1803 }
1804 if (tpg->show_square && frame_line >= sq->top &&
1805 frame_line < sq->top + sq->height &&
1806 sq->left < c->left + c->width &&
1807 sq->left + sq->width >= c->left) {
1808 unsigned left = sq->left;
1809 unsigned width = sq->width;
1810
1811 if (c->left > left) {
1812 width -= c->left - left;
1813 left = c->left;
1814 }
1815 if (c->left + c->width < left + width)
1816 width -= left + width - c->left - c->width;
1817 left -= c->left;
1818 left = (left * tpg->scaled_width) / tpg->src_width;
Hans Verkuil280abe42015-03-07 14:50:41 -03001819 left = ((left & ~1) / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001820 width = (width * tpg->scaled_width) / tpg->src_width;
Hans Verkuil280abe42015-03-07 14:50:41 -03001821 width = ((width & ~1) / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001822 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1823 }
1824 if (tpg->insert_sav) {
Hans Verkuil280abe42015-03-07 14:50:41 -03001825 unsigned offset = (tpg->compose.width / (6 * hdiv)) * twopixsize;
Hans Verkuil63881df2014-08-25 08:02:14 -03001826 u8 *p = vbuf + buf_line * stride + offset;
1827 unsigned vact = 0, hact = 0;
1828
1829 p[0] = 0xff;
1830 p[1] = 0;
1831 p[2] = 0;
1832 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1833 ((hact ^ vact) << 3) |
1834 ((hact ^ f) << 2) |
1835 ((f ^ vact) << 1) |
1836 (hact ^ vact ^ f);
1837 }
1838 if (tpg->insert_eav) {
Hans Verkuil280abe42015-03-07 14:50:41 -03001839 unsigned offset = (tpg->compose.width / (6 * hdiv)) * 2 * twopixsize;
Hans Verkuil63881df2014-08-25 08:02:14 -03001840 u8 *p = vbuf + buf_line * stride + offset;
1841 unsigned vact = 0, hact = 1;
1842
1843 p[0] = 0xff;
1844 p[1] = 0;
1845 p[2] = 0;
1846 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1847 ((hact ^ vact) << 3) |
1848 ((hact ^ f) << 2) |
1849 ((f ^ vact) << 1) |
1850 (hact ^ vact ^ f);
1851 }
1852 }
1853}
Hans Verkuil4db22042015-03-07 13:39:01 -03001854
1855void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1856{
1857 unsigned offset = 0;
1858 unsigned i;
1859
1860 if (tpg->buffers > 1) {
1861 tpg_fill_plane_buffer(tpg, std, p, vbuf);
1862 return;
1863 }
1864
1865 for (i = 0; i < tpg->planes; i++) {
1866 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
1867 offset += tpg_calc_plane_size(tpg, i);
1868 }
1869}