blob: f4f0b746d778be0f27af1925ea53a872b0630ae4 [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;
204 case V4L2_PIX_FMT_NV16M:
205 case V4L2_PIX_FMT_NV61M:
Hans Verkuilba01f672015-03-07 13:57:27 -0300206 tpg->vdownsampling[1] = 1;
207 tpg->hdownsampling[1] = 1;
Hans Verkuil06d1f0c2015-03-07 13:01:53 -0300208 tpg->buffers = 2;
Hans Verkuil63881df2014-08-25 08:02:14 -0300209 tpg->planes = 2;
210 /* fall-through */
211 case V4L2_PIX_FMT_YUYV:
212 case V4L2_PIX_FMT_UYVY:
213 case V4L2_PIX_FMT_YVYU:
214 case V4L2_PIX_FMT_VYUY:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300215 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300216 break;
217 default:
218 return false;
219 }
220
221 switch (fourcc) {
222 case V4L2_PIX_FMT_RGB565:
223 case V4L2_PIX_FMT_RGB565X:
224 case V4L2_PIX_FMT_RGB555:
225 case V4L2_PIX_FMT_XRGB555:
226 case V4L2_PIX_FMT_ARGB555:
227 case V4L2_PIX_FMT_RGB555X:
228 case V4L2_PIX_FMT_YUYV:
229 case V4L2_PIX_FMT_UYVY:
230 case V4L2_PIX_FMT_YVYU:
231 case V4L2_PIX_FMT_VYUY:
232 tpg->twopixelsize[0] = 2 * 2;
233 break;
234 case V4L2_PIX_FMT_RGB24:
235 case V4L2_PIX_FMT_BGR24:
236 tpg->twopixelsize[0] = 2 * 3;
237 break;
238 case V4L2_PIX_FMT_RGB32:
239 case V4L2_PIX_FMT_BGR32:
240 case V4L2_PIX_FMT_XRGB32:
241 case V4L2_PIX_FMT_XBGR32:
242 case V4L2_PIX_FMT_ARGB32:
243 case V4L2_PIX_FMT_ABGR32:
244 tpg->twopixelsize[0] = 2 * 4;
245 break;
246 case V4L2_PIX_FMT_NV16M:
247 case V4L2_PIX_FMT_NV61M:
248 tpg->twopixelsize[0] = 2;
249 tpg->twopixelsize[1] = 2;
250 break;
251 }
252 return true;
253}
254
255void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
256 const struct v4l2_rect *compose)
257{
258 tpg->crop = *crop;
259 tpg->compose = *compose;
260 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
261 tpg->crop.width - 1) / tpg->crop.width;
262 tpg->scaled_width &= ~1;
263 if (tpg->scaled_width > tpg->max_line_width)
264 tpg->scaled_width = tpg->max_line_width;
265 if (tpg->scaled_width < 2)
266 tpg->scaled_width = 2;
267 tpg->recalc_lines = true;
268}
269
270void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300271 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300272{
273 unsigned p;
274
275 tpg->src_width = width;
276 tpg->src_height = height;
277 tpg->field = field;
278 tpg->buf_height = height;
279 if (V4L2_FIELD_HAS_T_OR_B(field))
280 tpg->buf_height /= 2;
281 tpg->scaled_width = width;
282 tpg->crop.top = tpg->crop.left = 0;
283 tpg->crop.width = width;
284 tpg->crop.height = height;
285 tpg->compose.top = tpg->compose.left = 0;
286 tpg->compose.width = width;
287 tpg->compose.height = tpg->buf_height;
288 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300289 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
290 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300291 tpg->recalc_square_border = true;
292}
293
294static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
295{
296 switch (tpg->pattern) {
297 case TPG_PAT_BLACK:
298 return TPG_COLOR_100_WHITE;
299 case TPG_PAT_CSC_COLORBAR:
300 return TPG_COLOR_CSC_BLACK;
301 default:
302 return TPG_COLOR_100_BLACK;
303 }
304}
305
306static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
307{
308 switch (tpg->pattern) {
309 case TPG_PAT_75_COLORBAR:
310 case TPG_PAT_CSC_COLORBAR:
311 return TPG_COLOR_CSC_WHITE;
312 case TPG_PAT_BLACK:
313 return TPG_COLOR_100_BLACK;
314 default:
315 return TPG_COLOR_100_WHITE;
316 }
317}
318
Hans Verkuil481b97a2014-11-17 10:14:32 -0300319static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300320{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300321 v = clamp(v, 0, 0xff0);
322 return tpg_rec709_to_linear[v];
323}
324
325static inline int linear_to_rec709(int v)
326{
327 v = clamp(v, 0, 0xff0);
328 return tpg_linear_to_rec709[v];
329}
330
331static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
332 int y_offset, int *y, int *cb, int *cr)
333{
334 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
335 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
336 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
337}
338
339static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
340 int *y, int *cb, int *cr)
341{
342#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
343
344 static const int bt601[3][3] = {
345 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
346 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
347 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
348 };
349 static const int bt601_full[3][3] = {
350 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
351 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
352 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
353 };
354 static const int rec709[3][3] = {
355 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
356 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
357 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
358 };
359 static const int rec709_full[3][3] = {
360 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
361 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
362 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
363 };
364 static const int smpte240m[3][3] = {
365 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
366 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
367 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
368 };
369 static const int bt2020[3][3] = {
370 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
371 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
372 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
373 };
374 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300375 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300376 int lin_y, yc;
377
378 switch (tpg->real_ycbcr_enc) {
379 case V4L2_YCBCR_ENC_601:
380 case V4L2_YCBCR_ENC_XV601:
381 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300382 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300383 break;
384 case V4L2_YCBCR_ENC_BT2020:
385 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
386 break;
387 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
388 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
389 COEFF(0.6780, 255) * rec709_to_linear(g) +
390 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
391 yc = linear_to_rec709(lin_y);
392 *y = (yc * 219) / 255 + (16 << 4);
393 if (b <= yc)
394 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
395 else
396 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
397 if (r <= yc)
398 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
399 else
400 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
401 break;
402 case V4L2_YCBCR_ENC_SMPTE240M:
403 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
404 break;
405 case V4L2_YCBCR_ENC_709:
406 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300407 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300408 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300409 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300410 }
411}
412
Hans Verkuil481b97a2014-11-17 10:14:32 -0300413static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
414 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300415{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300416 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300417 cb -= 128 << 4;
418 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300419 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
420 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
421 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
422 *r = clamp(*r >> 12, 0, 0xff0);
423 *g = clamp(*g >> 12, 0, 0xff0);
424 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300425}
426
Hans Verkuil481b97a2014-11-17 10:14:32 -0300427static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
428 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300429{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300430#undef COEFF
431#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
432 static const int bt601[3][3] = {
433 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
434 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
435 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
436 };
437 static const int bt601_full[3][3] = {
438 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
439 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
440 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
441 };
442 static const int rec709[3][3] = {
443 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
444 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
445 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
446 };
447 static const int rec709_full[3][3] = {
448 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
449 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
450 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
451 };
452 static const int smpte240m[3][3] = {
453 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
454 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
455 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
456 };
457 static const int bt2020[3][3] = {
458 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
459 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
460 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
461 };
462 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300463 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300464 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300465
Hans Verkuil481b97a2014-11-17 10:14:32 -0300466 switch (tpg->real_ycbcr_enc) {
467 case V4L2_YCBCR_ENC_601:
468 case V4L2_YCBCR_ENC_XV601:
469 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300470 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300471 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300472 case V4L2_YCBCR_ENC_BT2020:
473 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300474 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300475 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
476 y -= 16 << 4;
477 cb -= 128 << 4;
478 cr -= 128 << 4;
479
480 if (cb <= 0)
481 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
482 else
483 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
484 *b = *b >> 12;
485 if (cr <= 0)
486 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
487 else
488 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
489 *r = *r >> 12;
490 lin_r = rec709_to_linear(*r);
491 lin_b = rec709_to_linear(*b);
492 lin_y = rec709_to_linear((y * 255) / 219);
493
494 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
495 COEFF(0.2627 / 0.6780, 255) * lin_r -
496 COEFF(0.0593 / 0.6780, 255) * lin_b;
497 *g = linear_to_rec709(lin_g >> 12);
498 break;
499 case V4L2_YCBCR_ENC_SMPTE240M:
500 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
501 break;
502 case V4L2_YCBCR_ENC_709:
503 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300504 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300505 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300506 break;
507 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300508}
509
510/* precalculate color bar values to speed up rendering */
511static void precalculate_color(struct tpg_data *tpg, int k)
512{
513 int col = k;
514 int r = tpg_colors[col].r;
515 int g = tpg_colors[col].g;
516 int b = tpg_colors[col].b;
517
518 if (k == TPG_COLOR_TEXTBG) {
519 col = tpg_get_textbg_color(tpg);
520
521 r = tpg_colors[col].r;
522 g = tpg_colors[col].g;
523 b = tpg_colors[col].b;
524 } else if (k == TPG_COLOR_TEXTFG) {
525 col = tpg_get_textfg_color(tpg);
526
527 r = tpg_colors[col].r;
528 g = tpg_colors[col].g;
529 b = tpg_colors[col].b;
530 } else if (tpg->pattern == TPG_PAT_NOISE) {
531 r = g = b = prandom_u32_max(256);
532 } else if (k == TPG_COLOR_RANDOM) {
533 r = g = b = tpg->qual_offset + prandom_u32_max(196);
534 } else if (k >= TPG_COLOR_RAMP) {
535 r = g = b = k - TPG_COLOR_RAMP;
536 }
537
538 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
539 r = tpg_csc_colors[tpg->colorspace][col].r;
540 g = tpg_csc_colors[tpg->colorspace][col].g;
541 b = tpg_csc_colors[tpg->colorspace][col].b;
542 } else {
543 r <<= 4;
544 g <<= 4;
545 b <<= 4;
546 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300547 if (tpg->qual == TPG_QUAL_GRAY) {
548 /* Rec. 709 Luma function */
549 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300550 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300551 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300552
553 /*
554 * The assumption is that the RGB output is always full range,
555 * so only if the rgb_range overrides the 'real' rgb range do
556 * we need to convert the RGB values.
557 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300558 * Remember that r, g and b are still in the 0 - 0xff0 range.
559 */
560 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
561 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
562 /*
563 * Convert from full range (which is what r, g and b are)
564 * to limited range (which is the 'real' RGB range), which
565 * is then interpreted as full range.
566 */
567 r = (r * 219) / 255 + (16 << 4);
568 g = (g * 219) / 255 + (16 << 4);
569 b = (b * 219) / 255 + (16 << 4);
570 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
571 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
572 /*
573 * Clamp r, g and b to the limited range and convert to full
574 * range since that's what we deliver.
575 */
576 r = clamp(r, 16 << 4, 235 << 4);
577 g = clamp(g, 16 << 4, 235 << 4);
578 b = clamp(b, 16 << 4, 235 << 4);
579 r = (r - (16 << 4)) * 255 / 219;
580 g = (g - (16 << 4)) * 255 / 219;
581 b = (b - (16 << 4)) * 255 / 219;
582 }
583
584 if (tpg->brightness != 128 || tpg->contrast != 128 ||
585 tpg->saturation != 128 || tpg->hue) {
586 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300587 int y, cb, cr;
588 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300589
590 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300591
592 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300593
594 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
595 y += (tpg->brightness << 4) - (128 << 4);
596
597 cb -= 128 << 4;
598 cr -= 128 << 4;
599 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
600 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
601
602 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
603 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
604 if (tpg->is_yuv) {
605 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
606 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
607 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
608 return;
609 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300610 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300611 }
612
613 if (tpg->is_yuv) {
614 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300615 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300616
Hans Verkuil481b97a2014-11-17 10:14:32 -0300617 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
618
619 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
620 y = clamp(y, 16 << 4, 235 << 4);
621 cb = clamp(cb, 16 << 4, 240 << 4);
622 cr = clamp(cr, 16 << 4, 240 << 4);
623 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300624 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
625 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
626 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
627 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300628 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
629 r = (r * 219) / 255 + (16 << 4);
630 g = (g * 219) / 255 + (16 << 4);
631 b = (b * 219) / 255 + (16 << 4);
632 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300633 switch (tpg->fourcc) {
634 case V4L2_PIX_FMT_RGB565:
635 case V4L2_PIX_FMT_RGB565X:
636 r >>= 7;
637 g >>= 6;
638 b >>= 7;
639 break;
640 case V4L2_PIX_FMT_RGB555:
641 case V4L2_PIX_FMT_XRGB555:
642 case V4L2_PIX_FMT_ARGB555:
643 case V4L2_PIX_FMT_RGB555X:
644 r >>= 7;
645 g >>= 7;
646 b >>= 7;
647 break;
648 default:
649 r >>= 4;
650 g >>= 4;
651 b >>= 4;
652 break;
653 }
654
655 tpg->colors[k][0] = r;
656 tpg->colors[k][1] = g;
657 tpg->colors[k][2] = b;
658 }
659}
660
661static void tpg_precalculate_colors(struct tpg_data *tpg)
662{
663 int k;
664
665 for (k = 0; k < TPG_COLOR_MAX; k++)
666 precalculate_color(tpg, k);
667}
668
669/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
670static void gen_twopix(struct tpg_data *tpg,
671 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
672{
673 unsigned offset = odd * tpg->twopixelsize[0] / 2;
674 u8 alpha = tpg->alpha_component;
675 u8 r_y, g_u, b_v;
676
677 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
678 color != TPG_COLOR_100_RED &&
679 color != TPG_COLOR_75_RED)
680 alpha = 0;
681 if (color == TPG_COLOR_RANDOM)
682 precalculate_color(tpg, color);
683 r_y = tpg->colors[color][0]; /* R or precalculated Y */
684 g_u = tpg->colors[color][1]; /* G or precalculated U */
685 b_v = tpg->colors[color][2]; /* B or precalculated V */
686
687 switch (tpg->fourcc) {
688 case V4L2_PIX_FMT_NV16M:
689 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300690 if (odd) {
691 buf[1][0] = (buf[1][0] + g_u) / 2;
692 buf[1][1] = (buf[1][1] + b_v) / 2;
693 break;
694 }
695 buf[1][0] = g_u;
696 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300697 break;
698 case V4L2_PIX_FMT_NV61M:
699 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300700 if (odd) {
701 buf[1][0] = (buf[1][0] + b_v) / 2;
702 buf[1][1] = (buf[1][1] + g_u) / 2;
703 break;
704 }
705 buf[1][0] = b_v;
706 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300707 break;
708
709 case V4L2_PIX_FMT_YUYV:
710 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300711 if (odd) {
712 buf[0][1] = (buf[0][1] + g_u) / 2;
713 buf[0][3] = (buf[0][3] + b_v) / 2;
714 break;
715 }
716 buf[0][1] = g_u;
717 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300718 break;
719 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300720 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300721 if (odd) {
722 buf[0][0] = (buf[0][0] + g_u) / 2;
723 buf[0][2] = (buf[0][2] + b_v) / 2;
724 break;
725 }
726 buf[0][0] = g_u;
727 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300728 break;
729 case V4L2_PIX_FMT_YVYU:
730 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300731 if (odd) {
732 buf[0][1] = (buf[0][1] + b_v) / 2;
733 buf[0][3] = (buf[0][3] + g_u) / 2;
734 break;
735 }
736 buf[0][1] = b_v;
737 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300738 break;
739 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300740 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300741 if (odd) {
742 buf[0][0] = (buf[0][0] + b_v) / 2;
743 buf[0][2] = (buf[0][2] + g_u) / 2;
744 break;
745 }
746 buf[0][0] = b_v;
747 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300748 break;
749 case V4L2_PIX_FMT_RGB565:
750 buf[0][offset] = (g_u << 5) | b_v;
751 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
752 break;
753 case V4L2_PIX_FMT_RGB565X:
754 buf[0][offset] = (r_y << 3) | (g_u >> 3);
755 buf[0][offset + 1] = (g_u << 5) | b_v;
756 break;
757 case V4L2_PIX_FMT_RGB555:
758 case V4L2_PIX_FMT_XRGB555:
759 alpha = 0;
760 /* fall through */
761 case V4L2_PIX_FMT_ARGB555:
762 buf[0][offset] = (g_u << 5) | b_v;
763 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
764 break;
765 case V4L2_PIX_FMT_RGB555X:
766 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
767 buf[0][offset + 1] = (g_u << 5) | b_v;
768 break;
769 case V4L2_PIX_FMT_RGB24:
770 buf[0][offset] = r_y;
771 buf[0][offset + 1] = g_u;
772 buf[0][offset + 2] = b_v;
773 break;
774 case V4L2_PIX_FMT_BGR24:
775 buf[0][offset] = b_v;
776 buf[0][offset + 1] = g_u;
777 buf[0][offset + 2] = r_y;
778 break;
779 case V4L2_PIX_FMT_RGB32:
780 case V4L2_PIX_FMT_XRGB32:
781 alpha = 0;
782 /* fall through */
783 case V4L2_PIX_FMT_ARGB32:
784 buf[0][offset] = alpha;
785 buf[0][offset + 1] = r_y;
786 buf[0][offset + 2] = g_u;
787 buf[0][offset + 3] = b_v;
788 break;
789 case V4L2_PIX_FMT_BGR32:
790 case V4L2_PIX_FMT_XBGR32:
791 alpha = 0;
792 /* fall through */
793 case V4L2_PIX_FMT_ABGR32:
794 buf[0][offset] = b_v;
795 buf[0][offset + 1] = g_u;
796 buf[0][offset + 2] = r_y;
797 buf[0][offset + 3] = alpha;
798 break;
799 }
800}
801
802/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300803static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -0300804{
805 switch (tpg->pattern) {
806 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300807 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -0300808 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300809 case TPG_PAT_COLOR_CHECKERS_2X2:
810 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300811 case TPG_PAT_ALTERNATING_HLINES:
812 case TPG_PAT_CROSS_1_PIXEL:
813 case TPG_PAT_CROSS_2_PIXELS:
814 case TPG_PAT_CROSS_10_PIXELS:
815 return 2;
816 case TPG_PAT_100_COLORSQUARES:
817 case TPG_PAT_100_HCOLORBAR:
818 return 8;
819 default:
820 return 1;
821 }
822}
823
824/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300825static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -0300826{
827 switch (tpg->pattern) {
828 case TPG_PAT_CHECKERS_16X16:
829 return (line >> 4) & 1;
830 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300831 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300832 case TPG_PAT_ALTERNATING_HLINES:
833 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -0300834 case TPG_PAT_CHECKERS_2X2:
835 case TPG_PAT_COLOR_CHECKERS_2X2:
836 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300837 case TPG_PAT_100_COLORSQUARES:
838 case TPG_PAT_100_HCOLORBAR:
839 return (line * 8) / tpg->src_height;
840 case TPG_PAT_CROSS_1_PIXEL:
841 return line == tpg->src_height / 2;
842 case TPG_PAT_CROSS_2_PIXELS:
843 return (line + 1) / 2 == tpg->src_height / 4;
844 case TPG_PAT_CROSS_10_PIXELS:
845 return (line + 10) / 20 == tpg->src_height / 40;
846 default:
847 return 0;
848 }
849}
850
851/*
852 * Which color should be used for the given pattern line and X coordinate.
853 * Note: x is in the range 0 to 2 * tpg->src_width.
854 */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300855static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
856 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -0300857{
858 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
859 should be modified */
860 static const enum tpg_color bars[3][8] = {
861 /* Standard ITU-R 75% color bar sequence */
862 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
863 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
864 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
865 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
866 /* Standard ITU-R 100% color bar sequence */
867 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
868 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
869 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
870 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
871 /* Color bar sequence suitable to test CSC */
872 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
873 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
874 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
875 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
876 };
877
878 switch (tpg->pattern) {
879 case TPG_PAT_75_COLORBAR:
880 case TPG_PAT_100_COLORBAR:
881 case TPG_PAT_CSC_COLORBAR:
882 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
883 case TPG_PAT_100_COLORSQUARES:
884 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
885 case TPG_PAT_100_HCOLORBAR:
886 return bars[1][pat_line];
887 case TPG_PAT_BLACK:
888 return TPG_COLOR_100_BLACK;
889 case TPG_PAT_WHITE:
890 return TPG_COLOR_100_WHITE;
891 case TPG_PAT_RED:
892 return TPG_COLOR_100_RED;
893 case TPG_PAT_GREEN:
894 return TPG_COLOR_100_GREEN;
895 case TPG_PAT_BLUE:
896 return TPG_COLOR_100_BLUE;
897 case TPG_PAT_CHECKERS_16X16:
898 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
899 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
900 case TPG_PAT_CHECKERS_1X1:
901 return ((x & 1) ^ (pat_line & 1)) ?
902 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -0300903 case TPG_PAT_COLOR_CHECKERS_1X1:
904 return ((x & 1) ^ (pat_line & 1)) ?
905 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
906 case TPG_PAT_CHECKERS_2X2:
907 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
908 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
909 case TPG_PAT_COLOR_CHECKERS_2X2:
910 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
911 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -0300912 case TPG_PAT_ALTERNATING_HLINES:
913 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
914 case TPG_PAT_ALTERNATING_VLINES:
915 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
916 case TPG_PAT_CROSS_1_PIXEL:
917 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
918 return TPG_COLOR_100_BLACK;
919 return TPG_COLOR_100_WHITE;
920 case TPG_PAT_CROSS_2_PIXELS:
921 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
922 return TPG_COLOR_100_BLACK;
923 return TPG_COLOR_100_WHITE;
924 case TPG_PAT_CROSS_10_PIXELS:
925 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
926 return TPG_COLOR_100_BLACK;
927 return TPG_COLOR_100_WHITE;
928 case TPG_PAT_GRAY_RAMP:
929 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
930 default:
931 return TPG_COLOR_100_RED;
932 }
933}
934
935/*
936 * Given the pixel aspect ratio and video aspect ratio calculate the
937 * coordinates of a centered square and the coordinates of the border of
938 * the active video area. The coordinates are relative to the source
939 * frame rectangle.
940 */
941static void tpg_calculate_square_border(struct tpg_data *tpg)
942{
943 unsigned w = tpg->src_width;
944 unsigned h = tpg->src_height;
945 unsigned sq_w, sq_h;
946
947 sq_w = (w * 2 / 5) & ~1;
948 if (((w - sq_w) / 2) & 1)
949 sq_w += 2;
950 sq_h = sq_w;
951 tpg->square.width = sq_w;
952 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
953 unsigned ana_sq_w = (sq_w / 4) * 3;
954
955 if (((w - ana_sq_w) / 2) & 1)
956 ana_sq_w += 2;
957 tpg->square.width = ana_sq_w;
958 }
959 tpg->square.left = (w - tpg->square.width) / 2;
960 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
961 sq_h = sq_w * 10 / 11;
962 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
963 sq_h = sq_w * 59 / 54;
964 tpg->square.height = sq_h;
965 tpg->square.top = (h - sq_h) / 2;
966 tpg->border.left = 0;
967 tpg->border.width = w;
968 tpg->border.top = 0;
969 tpg->border.height = h;
970 switch (tpg->vid_aspect) {
971 case TPG_VIDEO_ASPECT_4X3:
972 if (tpg->pix_aspect)
973 return;
974 if (3 * w >= 4 * h) {
975 tpg->border.width = ((4 * h) / 3) & ~1;
976 if (((w - tpg->border.width) / 2) & ~1)
977 tpg->border.width -= 2;
978 tpg->border.left = (w - tpg->border.width) / 2;
979 break;
980 }
981 tpg->border.height = ((3 * w) / 4) & ~1;
982 tpg->border.top = (h - tpg->border.height) / 2;
983 break;
984 case TPG_VIDEO_ASPECT_14X9_CENTRE:
985 if (tpg->pix_aspect) {
986 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
987 tpg->border.top = (h - tpg->border.height) / 2;
988 break;
989 }
990 if (9 * w >= 14 * h) {
991 tpg->border.width = ((14 * h) / 9) & ~1;
992 if (((w - tpg->border.width) / 2) & ~1)
993 tpg->border.width -= 2;
994 tpg->border.left = (w - tpg->border.width) / 2;
995 break;
996 }
997 tpg->border.height = ((9 * w) / 14) & ~1;
998 tpg->border.top = (h - tpg->border.height) / 2;
999 break;
1000 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1001 if (tpg->pix_aspect) {
1002 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1003 tpg->border.top = (h - tpg->border.height) / 2;
1004 break;
1005 }
1006 if (9 * w >= 16 * h) {
1007 tpg->border.width = ((16 * h) / 9) & ~1;
1008 if (((w - tpg->border.width) / 2) & ~1)
1009 tpg->border.width -= 2;
1010 tpg->border.left = (w - tpg->border.width) / 2;
1011 break;
1012 }
1013 tpg->border.height = ((9 * w) / 16) & ~1;
1014 tpg->border.top = (h - tpg->border.height) / 2;
1015 break;
1016 default:
1017 break;
1018 }
1019}
1020
1021static void tpg_precalculate_line(struct tpg_data *tpg)
1022{
1023 enum tpg_color contrast;
1024 unsigned pat;
1025 unsigned p;
1026 unsigned x;
1027
1028 switch (tpg->pattern) {
1029 case TPG_PAT_GREEN:
1030 contrast = TPG_COLOR_100_RED;
1031 break;
1032 case TPG_PAT_CSC_COLORBAR:
1033 contrast = TPG_COLOR_CSC_GREEN;
1034 break;
1035 default:
1036 contrast = TPG_COLOR_100_GREEN;
1037 break;
1038 }
1039
1040 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1041 /* Coarse scaling with Bresenham */
1042 unsigned int_part = tpg->src_width / tpg->scaled_width;
1043 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1044 unsigned src_x = 0;
1045 unsigned error = 0;
1046
1047 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1048 unsigned real_x = src_x;
1049 enum tpg_color color1, color2;
1050 u8 pix[TPG_MAX_PLANES][8];
1051
1052 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1053 color1 = tpg_get_color(tpg, pat, real_x);
1054
1055 src_x += int_part;
1056 error += fract_part;
1057 if (error >= tpg->scaled_width) {
1058 error -= tpg->scaled_width;
1059 src_x++;
1060 }
1061
1062 real_x = src_x;
1063 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1064 color2 = tpg_get_color(tpg, pat, real_x);
1065
1066 src_x += int_part;
1067 error += fract_part;
1068 if (error >= tpg->scaled_width) {
1069 error -= tpg->scaled_width;
1070 src_x++;
1071 }
1072
1073 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1074 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1075 for (p = 0; p < tpg->planes; p++) {
1076 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001077 unsigned hdiv = tpg->hdownsampling[p];
1078 u8 *pos = tpg->lines[pat][p] +
1079 (x / hdiv) * twopixsize / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001080
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001081 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001082 }
1083 }
1084 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001085
1086 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1087 unsigned pat_lines = tpg_get_pat_lines(tpg);
1088
1089 for (pat = 0; pat < pat_lines; pat++) {
1090 unsigned next_pat = (pat + 1) % pat_lines;
1091
1092 for (p = 1; p < tpg->planes; p++) {
1093 unsigned twopixsize = tpg->twopixelsize[p];
1094 unsigned hdiv = tpg->hdownsampling[p];
1095
1096 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1097 unsigned offset = (x / hdiv) * twopixsize / 2;
1098 u8 *pos1 = tpg->lines[pat][p] + offset;
1099 u8 *pos2 = tpg->lines[next_pat][p] + offset;
1100 u8 *dest = tpg->downsampled_lines[pat][p] + offset;
1101 unsigned i;
1102
1103 for (i = 0; i < twopixsize / hdiv; i++, dest++, pos1++, pos2++)
1104 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1105 }
1106 }
1107 }
1108 }
1109
Hans Verkuil63881df2014-08-25 08:02:14 -03001110 for (x = 0; x < tpg->scaled_width; x += 2) {
1111 u8 pix[TPG_MAX_PLANES][8];
1112
1113 gen_twopix(tpg, pix, contrast, 0);
1114 gen_twopix(tpg, pix, contrast, 1);
1115 for (p = 0; p < tpg->planes; p++) {
1116 unsigned twopixsize = tpg->twopixelsize[p];
1117 u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
1118
1119 memcpy(pos, pix[p], twopixsize);
1120 }
1121 }
1122 for (x = 0; x < tpg->scaled_width; x += 2) {
1123 u8 pix[TPG_MAX_PLANES][8];
1124
1125 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1126 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1127 for (p = 0; p < tpg->planes; p++) {
1128 unsigned twopixsize = tpg->twopixelsize[p];
1129 u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
1130
1131 memcpy(pos, pix[p], twopixsize);
1132 }
1133 }
1134 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1135 u8 pix[TPG_MAX_PLANES][8];
1136
1137 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1138 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1139 for (p = 0; p < tpg->planes; p++) {
1140 unsigned twopixsize = tpg->twopixelsize[p];
1141 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1142
1143 memcpy(pos, pix[p], twopixsize);
1144 }
1145 }
1146 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1147 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1148 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1149 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1150}
1151
1152/* need this to do rgb24 rendering */
1153typedef struct { u16 __; u8 _; } __packed x24;
1154
1155void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1156 int y, int x, char *text)
1157{
1158 int line;
1159 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1160 unsigned div = step;
1161 unsigned first = 0;
1162 unsigned len = strlen(text);
1163 unsigned p;
1164
1165 if (font8x16 == NULL || basep == NULL)
1166 return;
1167
1168 /* Checks if it is possible to show string */
1169 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1170 return;
1171
1172 if (len > (tpg->compose.width - x) / 8)
1173 len = (tpg->compose.width - x) / 8;
1174 if (tpg->vflip)
1175 y = tpg->compose.height - y - 16;
1176 if (tpg->hflip)
1177 x = tpg->compose.width - x - 8;
1178 y += tpg->compose.top;
1179 x += tpg->compose.left;
1180 if (tpg->field == V4L2_FIELD_BOTTOM)
1181 first = 1;
1182 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1183 div = 2;
1184
1185 for (p = 0; p < tpg->planes; p++) {
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001186 unsigned vdiv = tpg->vdownsampling[p];
1187 unsigned hdiv = tpg->hdownsampling[p];
1188
1189 /* Print text */
Hans Verkuil63881df2014-08-25 08:02:14 -03001190#define PRINTSTR(PIXTYPE) do { \
1191 PIXTYPE fg; \
1192 PIXTYPE bg; \
1193 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1194 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1195 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001196 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001197 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001198 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1199 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1200 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001201 unsigned s; \
1202 \
1203 for (s = 0; s < len; s++) { \
1204 u8 chr = font8x16[text[s] * 16 + line]; \
1205 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001206 if (hdiv == 2 && tpg->hflip) { \
1207 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1208 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1209 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1210 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1211 } else if (hdiv == 2) { \
1212 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1213 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1214 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1215 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1216 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001217 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1218 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1219 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1220 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1221 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1222 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1223 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1224 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1225 } else { \
1226 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1227 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1228 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1229 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1230 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1231 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1232 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1233 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1234 } \
1235 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001236 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001237 } \
1238 } \
1239} while (0)
1240
1241 switch (tpg->twopixelsize[p]) {
1242 case 2:
1243 PRINTSTR(u8); break;
1244 case 4:
1245 PRINTSTR(u16); break;
1246 case 6:
1247 PRINTSTR(x24); break;
1248 case 8:
1249 PRINTSTR(u32); break;
1250 }
1251 }
1252}
1253
1254void tpg_update_mv_step(struct tpg_data *tpg)
1255{
1256 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1257
1258 if (tpg->hflip)
1259 factor = -factor;
1260 switch (tpg->mv_hor_mode) {
1261 case TPG_MOVE_NEG_FAST:
1262 case TPG_MOVE_POS_FAST:
1263 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1264 break;
1265 case TPG_MOVE_NEG:
1266 case TPG_MOVE_POS:
1267 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1268 break;
1269 case TPG_MOVE_NEG_SLOW:
1270 case TPG_MOVE_POS_SLOW:
1271 tpg->mv_hor_step = 2;
1272 break;
1273 case TPG_MOVE_NONE:
1274 tpg->mv_hor_step = 0;
1275 break;
1276 }
1277 if (factor < 0)
1278 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1279
1280 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1281 switch (tpg->mv_vert_mode) {
1282 case TPG_MOVE_NEG_FAST:
1283 case TPG_MOVE_POS_FAST:
1284 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1285 break;
1286 case TPG_MOVE_NEG:
1287 case TPG_MOVE_POS:
1288 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1289 break;
1290 case TPG_MOVE_NEG_SLOW:
1291 case TPG_MOVE_POS_SLOW:
1292 tpg->mv_vert_step = 1;
1293 break;
1294 case TPG_MOVE_NONE:
1295 tpg->mv_vert_step = 0;
1296 break;
1297 }
1298 if (factor < 0)
1299 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1300}
1301
1302/* Map the line number relative to the crop rectangle to a frame line number */
1303static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
1304 unsigned field)
1305{
1306 switch (field) {
1307 case V4L2_FIELD_TOP:
1308 return tpg->crop.top + src_y * 2;
1309 case V4L2_FIELD_BOTTOM:
1310 return tpg->crop.top + src_y * 2 + 1;
1311 default:
1312 return src_y + tpg->crop.top;
1313 }
1314}
1315
1316/*
1317 * Map the line number relative to the compose rectangle to a destination
1318 * buffer line number.
1319 */
1320static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
1321 unsigned field)
1322{
1323 y += tpg->compose.top;
1324 switch (field) {
1325 case V4L2_FIELD_SEQ_TB:
1326 if (y & 1)
1327 return tpg->buf_height / 2 + y / 2;
1328 return y / 2;
1329 case V4L2_FIELD_SEQ_BT:
1330 if (y & 1)
1331 return y / 2;
1332 return tpg->buf_height / 2 + y / 2;
1333 default:
1334 return y;
1335 }
1336}
1337
1338static void tpg_recalc(struct tpg_data *tpg)
1339{
1340 if (tpg->recalc_colors) {
1341 tpg->recalc_colors = false;
1342 tpg->recalc_lines = true;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001343 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1344 tpg->real_quantization = tpg->quantization;
1345 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1346 switch (tpg->colorspace) {
1347 case V4L2_COLORSPACE_REC709:
1348 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1349 break;
1350 case V4L2_COLORSPACE_SRGB:
1351 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1352 break;
1353 case V4L2_COLORSPACE_BT2020:
1354 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1355 break;
1356 case V4L2_COLORSPACE_SMPTE240M:
1357 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1358 break;
1359 case V4L2_COLORSPACE_SMPTE170M:
1360 case V4L2_COLORSPACE_470_SYSTEM_M:
1361 case V4L2_COLORSPACE_470_SYSTEM_BG:
1362 case V4L2_COLORSPACE_ADOBERGB:
1363 default:
1364 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1365 break;
1366 }
1367 }
1368 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1369 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1370 if (tpg->is_yuv) {
1371 switch (tpg->real_ycbcr_enc) {
1372 case V4L2_YCBCR_ENC_SYCC:
1373 case V4L2_YCBCR_ENC_XV601:
1374 case V4L2_YCBCR_ENC_XV709:
1375 break;
1376 default:
1377 tpg->real_quantization =
1378 V4L2_QUANTIZATION_LIM_RANGE;
1379 break;
1380 }
Hans Verkuilc0b50d92015-03-08 04:53:33 -03001381 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1382 /* R'G'B' BT.2020 is limited range */
1383 tpg->real_quantization =
1384 V4L2_QUANTIZATION_LIM_RANGE;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001385 }
1386 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001387 tpg_precalculate_colors(tpg);
1388 }
1389 if (tpg->recalc_square_border) {
1390 tpg->recalc_square_border = false;
1391 tpg_calculate_square_border(tpg);
1392 }
1393 if (tpg->recalc_lines) {
1394 tpg->recalc_lines = false;
1395 tpg_precalculate_line(tpg);
1396 }
1397}
1398
1399void tpg_calc_text_basep(struct tpg_data *tpg,
1400 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1401{
1402 unsigned stride = tpg->bytesperline[p];
1403
1404 tpg_recalc(tpg);
1405
1406 basep[p][0] = vbuf;
1407 basep[p][1] = vbuf;
1408 if (tpg->field == V4L2_FIELD_SEQ_TB)
1409 basep[p][1] += tpg->buf_height * stride / 2;
1410 else if (tpg->field == V4L2_FIELD_SEQ_BT)
1411 basep[p][0] += tpg->buf_height * stride / 2;
1412}
1413
Hans Verkuil4db22042015-03-07 13:39:01 -03001414void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03001415{
1416 bool is_tv = std;
1417 bool is_60hz = is_tv && (std & V4L2_STD_525_60);
1418 unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
1419 unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
1420 unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1421 unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1422 unsigned wss_width;
1423 unsigned f;
1424 int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1425 int h;
1426 unsigned twopixsize = tpg->twopixelsize[p];
1427 unsigned img_width = tpg->compose.width * twopixsize / 2;
1428 unsigned line_offset;
1429 unsigned left_pillar_width = 0;
1430 unsigned right_pillar_start = img_width;
1431 unsigned stride = tpg->bytesperline[p];
1432 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1433 u8 *orig_vbuf = vbuf;
1434
1435 /* Coarse scaling with Bresenham */
1436 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1437 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1438 unsigned src_y = 0;
1439 unsigned error = 0;
1440
1441 tpg_recalc(tpg);
1442
1443 mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
1444 mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
1445 wss_width = tpg->crop.left < tpg->src_width / 2 ?
1446 tpg->src_width / 2 - tpg->crop.left : 0;
1447 if (wss_width > tpg->crop.width)
1448 wss_width = tpg->crop.width;
1449 wss_width = wss_width * tpg->scaled_width / tpg->src_width;
1450
1451 vbuf += tpg->compose.left * twopixsize / 2;
1452 line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
1453 line_offset = (line_offset & ~1) * twopixsize / 2;
1454 if (tpg->crop.left < tpg->border.left) {
1455 left_pillar_width = tpg->border.left - tpg->crop.left;
1456 if (left_pillar_width > tpg->crop.width)
1457 left_pillar_width = tpg->crop.width;
1458 left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
1459 left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
1460 }
1461 if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
1462 right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
1463 right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
1464 right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
1465 if (right_pillar_start > img_width)
1466 right_pillar_start = img_width;
1467 }
1468
1469 f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1470
1471 for (h = 0; h < tpg->compose.height; h++) {
1472 bool even;
1473 bool fill_blank = false;
1474 unsigned frame_line;
1475 unsigned buf_line;
1476 unsigned pat_line_old;
1477 unsigned pat_line_new;
1478 u8 *linestart_older;
1479 u8 *linestart_newer;
1480 u8 *linestart_top;
1481 u8 *linestart_bottom;
1482
1483 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1484 even = !(frame_line & 1);
1485 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1486 src_y += int_part;
1487 error += fract_part;
1488 if (error >= tpg->compose.height) {
1489 error -= tpg->compose.height;
1490 src_y++;
1491 }
1492
1493 if (h >= hmax) {
1494 if (hmax == tpg->compose.height)
1495 continue;
1496 if (!tpg->perc_fill_blank)
1497 continue;
1498 fill_blank = true;
1499 }
1500
1501 if (tpg->vflip)
1502 frame_line = tpg->src_height - frame_line - 1;
1503
1504 if (fill_blank) {
1505 linestart_older = tpg->contrast_line[p];
1506 linestart_newer = tpg->contrast_line[p];
1507 } else if (tpg->qual != TPG_QUAL_NOISE &&
1508 (frame_line < tpg->border.top ||
1509 frame_line >= tpg->border.top + tpg->border.height)) {
1510 linestart_older = tpg->black_line[p];
1511 linestart_newer = tpg->black_line[p];
1512 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1513 linestart_older = tpg->random_line[p] +
1514 twopixsize * prandom_u32_max(tpg->src_width / 2);
1515 linestart_newer = tpg->random_line[p] +
1516 twopixsize * prandom_u32_max(tpg->src_width / 2);
1517 } else {
1518 pat_line_old = tpg_get_pat_line(tpg,
1519 (frame_line + mv_vert_old) % tpg->src_height);
1520 pat_line_new = tpg_get_pat_line(tpg,
1521 (frame_line + mv_vert_new) % tpg->src_height);
1522 linestart_older = tpg->lines[pat_line_old][p] +
1523 mv_hor_old * twopixsize / 2;
1524 linestart_newer = tpg->lines[pat_line_new][p] +
1525 mv_hor_new * twopixsize / 2;
1526 linestart_older += line_offset;
1527 linestart_newer += line_offset;
1528 }
Hans Verkuil43047f62015-03-07 12:38:42 -03001529 if (tpg->field_alternate) {
1530 linestart_top = linestart_bottom = linestart_older;
1531 } else if (is_60hz) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001532 linestart_top = linestart_newer;
1533 linestart_bottom = linestart_older;
1534 } else {
1535 linestart_top = linestart_older;
1536 linestart_bottom = linestart_newer;
1537 }
1538
1539 switch (tpg->field) {
1540 case V4L2_FIELD_INTERLACED:
1541 case V4L2_FIELD_INTERLACED_TB:
1542 case V4L2_FIELD_SEQ_TB:
1543 case V4L2_FIELD_SEQ_BT:
1544 if (even)
1545 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1546 else
1547 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1548 break;
1549 case V4L2_FIELD_INTERLACED_BT:
1550 if (even)
1551 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1552 else
1553 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1554 break;
1555 case V4L2_FIELD_TOP:
1556 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1557 break;
1558 case V4L2_FIELD_BOTTOM:
1559 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1560 break;
1561 case V4L2_FIELD_NONE:
1562 default:
1563 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1564 break;
1565 }
1566
1567 if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
1568 /*
1569 * Replace the first half of the top line of a 50 Hz frame
1570 * with random data to simulate a WSS signal.
1571 */
1572 u8 *wss = tpg->random_line[p] +
1573 twopixsize * prandom_u32_max(tpg->src_width / 2);
1574
1575 memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
1576 }
1577 }
1578
1579 vbuf = orig_vbuf;
1580 vbuf += tpg->compose.left * twopixsize / 2;
1581 src_y = 0;
1582 error = 0;
1583 for (h = 0; h < tpg->compose.height; h++) {
1584 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1585 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1586 const struct v4l2_rect *sq = &tpg->square;
1587 const struct v4l2_rect *b = &tpg->border;
1588 const struct v4l2_rect *c = &tpg->crop;
1589
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
1597 if (tpg->show_border && frame_line >= b->top &&
1598 frame_line < b->top + b->height) {
1599 unsigned bottom = b->top + b->height - 1;
1600 unsigned left = left_pillar_width;
1601 unsigned right = right_pillar_start;
1602
1603 if (frame_line == b->top || frame_line == b->top + 1 ||
1604 frame_line == bottom || frame_line == bottom - 1) {
1605 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1606 right - left);
1607 } else {
1608 if (b->left >= c->left &&
1609 b->left < c->left + c->width)
1610 memcpy(vbuf + buf_line * stride + left,
1611 tpg->contrast_line[p], twopixsize);
1612 if (b->left + b->width > c->left &&
1613 b->left + b->width <= c->left + c->width)
1614 memcpy(vbuf + buf_line * stride + right - twopixsize,
1615 tpg->contrast_line[p], twopixsize);
1616 }
1617 }
1618 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1619 frame_line < b->top + b->height) {
1620 memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
1621 memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
1622 img_width - right_pillar_start);
1623 }
1624 if (tpg->show_square && frame_line >= sq->top &&
1625 frame_line < sq->top + sq->height &&
1626 sq->left < c->left + c->width &&
1627 sq->left + sq->width >= c->left) {
1628 unsigned left = sq->left;
1629 unsigned width = sq->width;
1630
1631 if (c->left > left) {
1632 width -= c->left - left;
1633 left = c->left;
1634 }
1635 if (c->left + c->width < left + width)
1636 width -= left + width - c->left - c->width;
1637 left -= c->left;
1638 left = (left * tpg->scaled_width) / tpg->src_width;
1639 left = (left & ~1) * twopixsize / 2;
1640 width = (width * tpg->scaled_width) / tpg->src_width;
1641 width = (width & ~1) * twopixsize / 2;
1642 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1643 }
1644 if (tpg->insert_sav) {
1645 unsigned offset = (tpg->compose.width / 6) * twopixsize;
1646 u8 *p = vbuf + buf_line * stride + offset;
1647 unsigned vact = 0, hact = 0;
1648
1649 p[0] = 0xff;
1650 p[1] = 0;
1651 p[2] = 0;
1652 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1653 ((hact ^ vact) << 3) |
1654 ((hact ^ f) << 2) |
1655 ((f ^ vact) << 1) |
1656 (hact ^ vact ^ f);
1657 }
1658 if (tpg->insert_eav) {
1659 unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
1660 u8 *p = vbuf + buf_line * stride + offset;
1661 unsigned vact = 0, hact = 1;
1662
1663 p[0] = 0xff;
1664 p[1] = 0;
1665 p[2] = 0;
1666 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1667 ((hact ^ vact) << 3) |
1668 ((hact ^ f) << 2) |
1669 ((f ^ vact) << 1) |
1670 (hact ^ vact ^ f);
1671 }
1672 }
1673}
Hans Verkuil4db22042015-03-07 13:39:01 -03001674
1675void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1676{
1677 unsigned offset = 0;
1678 unsigned i;
1679
1680 if (tpg->buffers > 1) {
1681 tpg_fill_plane_buffer(tpg, std, p, vbuf);
1682 return;
1683 }
1684
1685 for (i = 0; i < tpg->planes; i++) {
1686 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
1687 offset += tpg_calc_plane_size(tpg, i);
1688 }
1689}