2 * vivid-tpg.c - Test Pattern Generator
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.
7 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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.
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
23 #include "vivid-tpg.h"
25 /* Must remain in sync with enum tpg_pattern */
26 const char * const tpg_pattern_strings
[] = {
30 "Horizontal 100% Colorbar",
39 "Alternating Hor Lines",
40 "Alternating Vert Lines",
41 "One Pixel Wide Cross",
42 "Two Pixels Wide Cross",
43 "Ten Pixels Wide Cross",
49 /* Must remain in sync with enum tpg_aspect */
50 const char * const tpg_aspect_strings
[] = {
51 "Source Width x Height",
60 * Sine table: sin[0] = 127 * sin(-180 degrees)
61 * sin[128] = 127 * sin(0 degrees)
62 * sin[256] = 127 * sin(180 degrees)
64 static const s8 sin
[257] = {
65 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
66 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
67 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
68 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
69 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
70 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
71 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
72 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
73 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
74 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
75 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
76 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
77 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
78 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
79 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
80 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
84 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
86 /* Global font descriptor */
87 static const u8
*font8x16
;
89 void tpg_set_font(const u8
*f
)
94 void tpg_init(struct tpg_data
*tpg
, unsigned w
, unsigned h
)
96 memset(tpg
, 0, sizeof(*tpg
));
97 tpg
->scaled_width
= tpg
->src_width
= w
;
98 tpg
->src_height
= tpg
->buf_height
= h
;
99 tpg
->crop
.width
= tpg
->compose
.width
= w
;
100 tpg
->crop
.height
= tpg
->compose
.height
= h
;
101 tpg
->recalc_colors
= true;
102 tpg
->recalc_square_border
= true;
103 tpg
->brightness
= 128;
105 tpg
->saturation
= 128;
107 tpg
->mv_hor_mode
= TPG_MOVE_NONE
;
108 tpg
->mv_vert_mode
= TPG_MOVE_NONE
;
109 tpg
->field
= V4L2_FIELD_NONE
;
110 tpg_s_fourcc(tpg
, V4L2_PIX_FMT_RGB24
);
111 tpg
->colorspace
= V4L2_COLORSPACE_SRGB
;
112 tpg
->perc_fill
= 100;
115 int tpg_alloc(struct tpg_data
*tpg
, unsigned max_w
)
120 tpg
->max_line_width
= max_w
;
121 for (pat
= 0; pat
< TPG_MAX_PAT_LINES
; pat
++) {
122 for (plane
= 0; plane
< TPG_MAX_PLANES
; plane
++) {
123 unsigned pixelsz
= plane
? 1 : 4;
125 tpg
->lines
[pat
][plane
] = vzalloc(max_w
* 2 * pixelsz
);
126 if (!tpg
->lines
[pat
][plane
])
130 for (plane
= 0; plane
< TPG_MAX_PLANES
; plane
++) {
131 unsigned pixelsz
= plane
? 1 : 4;
133 tpg
->contrast_line
[plane
] = vzalloc(max_w
* pixelsz
);
134 if (!tpg
->contrast_line
[plane
])
136 tpg
->black_line
[plane
] = vzalloc(max_w
* pixelsz
);
137 if (!tpg
->black_line
[plane
])
139 tpg
->random_line
[plane
] = vzalloc(max_w
* pixelsz
);
140 if (!tpg
->random_line
[plane
])
146 void tpg_free(struct tpg_data
*tpg
)
151 for (pat
= 0; pat
< TPG_MAX_PAT_LINES
; pat
++)
152 for (plane
= 0; plane
< TPG_MAX_PLANES
; plane
++) {
153 vfree(tpg
->lines
[pat
][plane
]);
154 tpg
->lines
[pat
][plane
] = NULL
;
156 for (plane
= 0; plane
< TPG_MAX_PLANES
; plane
++) {
157 vfree(tpg
->contrast_line
[plane
]);
158 vfree(tpg
->black_line
[plane
]);
159 vfree(tpg
->random_line
[plane
]);
160 tpg
->contrast_line
[plane
] = NULL
;
161 tpg
->black_line
[plane
] = NULL
;
162 tpg
->random_line
[plane
] = NULL
;
166 bool tpg_s_fourcc(struct tpg_data
*tpg
, u32 fourcc
)
168 tpg
->fourcc
= fourcc
;
170 tpg
->recalc_colors
= true;
172 case V4L2_PIX_FMT_RGB565
:
173 case V4L2_PIX_FMT_RGB565X
:
174 case V4L2_PIX_FMT_RGB555
:
175 case V4L2_PIX_FMT_XRGB555
:
176 case V4L2_PIX_FMT_ARGB555
:
177 case V4L2_PIX_FMT_RGB555X
:
178 case V4L2_PIX_FMT_RGB24
:
179 case V4L2_PIX_FMT_BGR24
:
180 case V4L2_PIX_FMT_RGB32
:
181 case V4L2_PIX_FMT_BGR32
:
182 case V4L2_PIX_FMT_XRGB32
:
183 case V4L2_PIX_FMT_XBGR32
:
184 case V4L2_PIX_FMT_ARGB32
:
185 case V4L2_PIX_FMT_ABGR32
:
188 case V4L2_PIX_FMT_NV16M
:
189 case V4L2_PIX_FMT_NV61M
:
192 case V4L2_PIX_FMT_YUYV
:
193 case V4L2_PIX_FMT_UYVY
:
194 case V4L2_PIX_FMT_YVYU
:
195 case V4L2_PIX_FMT_VYUY
:
203 case V4L2_PIX_FMT_RGB565
:
204 case V4L2_PIX_FMT_RGB565X
:
205 case V4L2_PIX_FMT_RGB555
:
206 case V4L2_PIX_FMT_XRGB555
:
207 case V4L2_PIX_FMT_ARGB555
:
208 case V4L2_PIX_FMT_RGB555X
:
209 case V4L2_PIX_FMT_YUYV
:
210 case V4L2_PIX_FMT_UYVY
:
211 case V4L2_PIX_FMT_YVYU
:
212 case V4L2_PIX_FMT_VYUY
:
213 tpg
->twopixelsize
[0] = 2 * 2;
215 case V4L2_PIX_FMT_RGB24
:
216 case V4L2_PIX_FMT_BGR24
:
217 tpg
->twopixelsize
[0] = 2 * 3;
219 case V4L2_PIX_FMT_RGB32
:
220 case V4L2_PIX_FMT_BGR32
:
221 case V4L2_PIX_FMT_XRGB32
:
222 case V4L2_PIX_FMT_XBGR32
:
223 case V4L2_PIX_FMT_ARGB32
:
224 case V4L2_PIX_FMT_ABGR32
:
225 tpg
->twopixelsize
[0] = 2 * 4;
227 case V4L2_PIX_FMT_NV16M
:
228 case V4L2_PIX_FMT_NV61M
:
229 tpg
->twopixelsize
[0] = 2;
230 tpg
->twopixelsize
[1] = 2;
236 void tpg_s_crop_compose(struct tpg_data
*tpg
, const struct v4l2_rect
*crop
,
237 const struct v4l2_rect
*compose
)
240 tpg
->compose
= *compose
;
241 tpg
->scaled_width
= (tpg
->src_width
* tpg
->compose
.width
+
242 tpg
->crop
.width
- 1) / tpg
->crop
.width
;
243 tpg
->scaled_width
&= ~1;
244 if (tpg
->scaled_width
> tpg
->max_line_width
)
245 tpg
->scaled_width
= tpg
->max_line_width
;
246 if (tpg
->scaled_width
< 2)
247 tpg
->scaled_width
= 2;
248 tpg
->recalc_lines
= true;
251 void tpg_reset_source(struct tpg_data
*tpg
, unsigned width
, unsigned height
,
256 tpg
->src_width
= width
;
257 tpg
->src_height
= height
;
259 tpg
->buf_height
= height
;
260 if (V4L2_FIELD_HAS_T_OR_B(field
))
261 tpg
->buf_height
/= 2;
262 tpg
->scaled_width
= width
;
263 tpg
->crop
.top
= tpg
->crop
.left
= 0;
264 tpg
->crop
.width
= width
;
265 tpg
->crop
.height
= height
;
266 tpg
->compose
.top
= tpg
->compose
.left
= 0;
267 tpg
->compose
.width
= width
;
268 tpg
->compose
.height
= tpg
->buf_height
;
269 for (p
= 0; p
< tpg
->planes
; p
++)
270 tpg
->bytesperline
[p
] = width
* tpg
->twopixelsize
[p
] / 2;
271 tpg
->recalc_square_border
= true;
274 static enum tpg_color
tpg_get_textbg_color(struct tpg_data
*tpg
)
276 switch (tpg
->pattern
) {
278 return TPG_COLOR_100_WHITE
;
279 case TPG_PAT_CSC_COLORBAR
:
280 return TPG_COLOR_CSC_BLACK
;
282 return TPG_COLOR_100_BLACK
;
286 static enum tpg_color
tpg_get_textfg_color(struct tpg_data
*tpg
)
288 switch (tpg
->pattern
) {
289 case TPG_PAT_75_COLORBAR
:
290 case TPG_PAT_CSC_COLORBAR
:
291 return TPG_COLOR_CSC_WHITE
;
293 return TPG_COLOR_100_BLACK
;
295 return TPG_COLOR_100_WHITE
;
299 static u16
color_to_y(struct tpg_data
*tpg
, int r
, int g
, int b
)
301 switch (tpg
->colorspace
) {
302 case V4L2_COLORSPACE_SMPTE170M
:
303 case V4L2_COLORSPACE_470_SYSTEM_M
:
304 case V4L2_COLORSPACE_470_SYSTEM_BG
:
305 return ((16829 * r
+ 33039 * g
+ 6416 * b
+ 16 * 32768) >> 16) + (16 << 4);
306 case V4L2_COLORSPACE_SMPTE240M
:
307 return ((11932 * r
+ 39455 * g
+ 4897 * b
+ 16 * 32768) >> 16) + (16 << 4);
308 case V4L2_COLORSPACE_REC709
:
309 case V4L2_COLORSPACE_SRGB
:
311 return ((11966 * r
+ 40254 * g
+ 4064 * b
+ 16 * 32768) >> 16) + (16 << 4);
315 static u16
color_to_cb(struct tpg_data
*tpg
, int r
, int g
, int b
)
317 switch (tpg
->colorspace
) {
318 case V4L2_COLORSPACE_SMPTE170M
:
319 case V4L2_COLORSPACE_470_SYSTEM_M
:
320 case V4L2_COLORSPACE_470_SYSTEM_BG
:
321 return ((-9714 * r
- 19070 * g
+ 28784 * b
+ 16 * 32768) >> 16) + (128 << 4);
322 case V4L2_COLORSPACE_SMPTE240M
:
323 return ((-6684 * r
- 22100 * g
+ 28784 * b
+ 16 * 32768) >> 16) + (128 << 4);
324 case V4L2_COLORSPACE_REC709
:
325 case V4L2_COLORSPACE_SRGB
:
327 return ((-6596 * r
- 22189 * g
+ 28784 * b
+ 16 * 32768) >> 16) + (128 << 4);
331 static u16
color_to_cr(struct tpg_data
*tpg
, int r
, int g
, int b
)
333 switch (tpg
->colorspace
) {
334 case V4L2_COLORSPACE_SMPTE170M
:
335 case V4L2_COLORSPACE_470_SYSTEM_M
:
336 case V4L2_COLORSPACE_470_SYSTEM_BG
:
337 return ((28784 * r
- 24103 * g
- 4681 * b
+ 16 * 32768) >> 16) + (128 << 4);
338 case V4L2_COLORSPACE_SMPTE240M
:
339 return ((28784 * r
- 25606 * g
- 3178 * b
+ 16 * 32768) >> 16) + (128 << 4);
340 case V4L2_COLORSPACE_REC709
:
341 case V4L2_COLORSPACE_SRGB
:
343 return ((28784 * r
- 26145 * g
- 2639 * b
+ 16 * 32768) >> 16) + (128 << 4);
347 static u16
ycbcr_to_r(struct tpg_data
*tpg
, int y
, int cb
, int cr
)
354 switch (tpg
->colorspace
) {
355 case V4L2_COLORSPACE_SMPTE170M
:
356 case V4L2_COLORSPACE_470_SYSTEM_M
:
357 case V4L2_COLORSPACE_470_SYSTEM_BG
:
358 r
= 4769 * y
+ 6537 * cr
;
360 case V4L2_COLORSPACE_SMPTE240M
:
361 r
= 4769 * y
+ 7376 * cr
;
363 case V4L2_COLORSPACE_REC709
:
364 case V4L2_COLORSPACE_SRGB
:
366 r
= 4769 * y
+ 7343 * cr
;
369 return clamp(r
>> 12, 0, 0xff0);
372 static u16
ycbcr_to_g(struct tpg_data
*tpg
, int y
, int cb
, int cr
)
379 switch (tpg
->colorspace
) {
380 case V4L2_COLORSPACE_SMPTE170M
:
381 case V4L2_COLORSPACE_470_SYSTEM_M
:
382 case V4L2_COLORSPACE_470_SYSTEM_BG
:
383 g
= 4769 * y
- 1605 * cb
- 3330 * cr
;
385 case V4L2_COLORSPACE_SMPTE240M
:
386 g
= 4769 * y
- 1055 * cb
- 2341 * cr
;
388 case V4L2_COLORSPACE_REC709
:
389 case V4L2_COLORSPACE_SRGB
:
391 g
= 4769 * y
- 873 * cb
- 2183 * cr
;
394 return clamp(g
>> 12, 0, 0xff0);
397 static u16
ycbcr_to_b(struct tpg_data
*tpg
, int y
, int cb
, int cr
)
404 switch (tpg
->colorspace
) {
405 case V4L2_COLORSPACE_SMPTE170M
:
406 case V4L2_COLORSPACE_470_SYSTEM_M
:
407 case V4L2_COLORSPACE_470_SYSTEM_BG
:
408 b
= 4769 * y
+ 7343 * cb
;
410 case V4L2_COLORSPACE_SMPTE240M
:
411 b
= 4769 * y
+ 8552 * cb
;
413 case V4L2_COLORSPACE_REC709
:
414 case V4L2_COLORSPACE_SRGB
:
416 b
= 4769 * y
+ 8652 * cb
;
419 return clamp(b
>> 12, 0, 0xff0);
422 /* precalculate color bar values to speed up rendering */
423 static void precalculate_color(struct tpg_data
*tpg
, int k
)
426 int r
= tpg_colors
[col
].r
;
427 int g
= tpg_colors
[col
].g
;
428 int b
= tpg_colors
[col
].b
;
430 if (k
== TPG_COLOR_TEXTBG
) {
431 col
= tpg_get_textbg_color(tpg
);
433 r
= tpg_colors
[col
].r
;
434 g
= tpg_colors
[col
].g
;
435 b
= tpg_colors
[col
].b
;
436 } else if (k
== TPG_COLOR_TEXTFG
) {
437 col
= tpg_get_textfg_color(tpg
);
439 r
= tpg_colors
[col
].r
;
440 g
= tpg_colors
[col
].g
;
441 b
= tpg_colors
[col
].b
;
442 } else if (tpg
->pattern
== TPG_PAT_NOISE
) {
443 r
= g
= b
= prandom_u32_max(256);
444 } else if (k
== TPG_COLOR_RANDOM
) {
445 r
= g
= b
= tpg
->qual_offset
+ prandom_u32_max(196);
446 } else if (k
>= TPG_COLOR_RAMP
) {
447 r
= g
= b
= k
- TPG_COLOR_RAMP
;
450 if (tpg
->pattern
== TPG_PAT_CSC_COLORBAR
&& col
<= TPG_COLOR_CSC_BLACK
) {
451 r
= tpg_csc_colors
[tpg
->colorspace
][col
].r
;
452 g
= tpg_csc_colors
[tpg
->colorspace
][col
].g
;
453 b
= tpg_csc_colors
[tpg
->colorspace
][col
].b
;
459 if (tpg
->qual
== TPG_QUAL_GRAY
)
460 r
= g
= b
= color_to_y(tpg
, r
, g
, b
);
463 * The assumption is that the RGB output is always full range,
464 * so only if the rgb_range overrides the 'real' rgb range do
465 * we need to convert the RGB values.
467 * Currently there is no way of signalling to userspace if you
468 * are actually giving it limited range RGB (or full range
469 * YUV for that matter).
471 * Remember that r, g and b are still in the 0 - 0xff0 range.
473 if (tpg
->real_rgb_range
== V4L2_DV_RGB_RANGE_LIMITED
&&
474 tpg
->rgb_range
== V4L2_DV_RGB_RANGE_FULL
) {
476 * Convert from full range (which is what r, g and b are)
477 * to limited range (which is the 'real' RGB range), which
478 * is then interpreted as full range.
480 r
= (r
* 219) / 255 + (16 << 4);
481 g
= (g
* 219) / 255 + (16 << 4);
482 b
= (b
* 219) / 255 + (16 << 4);
483 } else if (tpg
->real_rgb_range
!= V4L2_DV_RGB_RANGE_LIMITED
&&
484 tpg
->rgb_range
== V4L2_DV_RGB_RANGE_LIMITED
) {
486 * Clamp r, g and b to the limited range and convert to full
487 * range since that's what we deliver.
489 r
= clamp(r
, 16 << 4, 235 << 4);
490 g
= clamp(g
, 16 << 4, 235 << 4);
491 b
= clamp(b
, 16 << 4, 235 << 4);
492 r
= (r
- (16 << 4)) * 255 / 219;
493 g
= (g
- (16 << 4)) * 255 / 219;
494 b
= (b
- (16 << 4)) * 255 / 219;
497 if (tpg
->brightness
!= 128 || tpg
->contrast
!= 128 ||
498 tpg
->saturation
!= 128 || tpg
->hue
) {
499 /* Implement these operations */
501 /* First convert to YCbCr */
502 int y
= color_to_y(tpg
, r
, g
, b
); /* Luma */
503 int cb
= color_to_cb(tpg
, r
, g
, b
); /* Cb */
504 int cr
= color_to_cr(tpg
, r
, g
, b
); /* Cr */
507 y
= (16 << 4) + ((y
- (16 << 4)) * tpg
->contrast
) / 128;
508 y
+= (tpg
->brightness
<< 4) - (128 << 4);
512 tmp_cb
= (cb
* cos(128 + tpg
->hue
)) / 127 + (cr
* sin
[128 + tpg
->hue
]) / 127;
513 tmp_cr
= (cr
* cos(128 + tpg
->hue
)) / 127 - (cb
* sin
[128 + tpg
->hue
]) / 127;
515 cb
= (128 << 4) + (tmp_cb
* tpg
->contrast
* tpg
->saturation
) / (128 * 128);
516 cr
= (128 << 4) + (tmp_cr
* tpg
->contrast
* tpg
->saturation
) / (128 * 128);
518 tpg
->colors
[k
][0] = clamp(y
>> 4, 1, 254);
519 tpg
->colors
[k
][1] = clamp(cb
>> 4, 1, 254);
520 tpg
->colors
[k
][2] = clamp(cr
>> 4, 1, 254);
523 r
= ycbcr_to_r(tpg
, y
, cb
, cr
);
524 g
= ycbcr_to_g(tpg
, y
, cb
, cr
);
525 b
= ycbcr_to_b(tpg
, y
, cb
, cr
);
529 /* Convert to YCbCr */
530 u16 y
= color_to_y(tpg
, r
, g
, b
); /* Luma */
531 u16 cb
= color_to_cb(tpg
, r
, g
, b
); /* Cb */
532 u16 cr
= color_to_cr(tpg
, r
, g
, b
); /* Cr */
534 tpg
->colors
[k
][0] = clamp(y
>> 4, 1, 254);
535 tpg
->colors
[k
][1] = clamp(cb
>> 4, 1, 254);
536 tpg
->colors
[k
][2] = clamp(cr
>> 4, 1, 254);
538 switch (tpg
->fourcc
) {
539 case V4L2_PIX_FMT_RGB565
:
540 case V4L2_PIX_FMT_RGB565X
:
545 case V4L2_PIX_FMT_RGB555
:
546 case V4L2_PIX_FMT_XRGB555
:
547 case V4L2_PIX_FMT_ARGB555
:
548 case V4L2_PIX_FMT_RGB555X
:
560 tpg
->colors
[k
][0] = r
;
561 tpg
->colors
[k
][1] = g
;
562 tpg
->colors
[k
][2] = b
;
566 static void tpg_precalculate_colors(struct tpg_data
*tpg
)
570 for (k
= 0; k
< TPG_COLOR_MAX
; k
++)
571 precalculate_color(tpg
, k
);
574 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
575 static void gen_twopix(struct tpg_data
*tpg
,
576 u8 buf
[TPG_MAX_PLANES
][8], int color
, bool odd
)
578 unsigned offset
= odd
* tpg
->twopixelsize
[0] / 2;
579 u8 alpha
= tpg
->alpha_component
;
582 if (tpg
->alpha_red_only
&& color
!= TPG_COLOR_CSC_RED
&&
583 color
!= TPG_COLOR_100_RED
&&
584 color
!= TPG_COLOR_75_RED
)
586 if (color
== TPG_COLOR_RANDOM
)
587 precalculate_color(tpg
, color
);
588 r_y
= tpg
->colors
[color
][0]; /* R or precalculated Y */
589 g_u
= tpg
->colors
[color
][1]; /* G or precalculated U */
590 b_v
= tpg
->colors
[color
][2]; /* B or precalculated V */
592 switch (tpg
->fourcc
) {
593 case V4L2_PIX_FMT_NV16M
:
594 buf
[0][offset
] = r_y
;
595 buf
[1][offset
] = odd
? b_v
: g_u
;
597 case V4L2_PIX_FMT_NV61M
:
598 buf
[0][offset
] = r_y
;
599 buf
[1][offset
] = odd
? g_u
: b_v
;
602 case V4L2_PIX_FMT_YUYV
:
603 buf
[0][offset
] = r_y
;
604 buf
[0][offset
+ 1] = odd
? b_v
: g_u
;
606 case V4L2_PIX_FMT_UYVY
:
607 buf
[0][offset
] = odd
? b_v
: g_u
;
608 buf
[0][offset
+ 1] = r_y
;
610 case V4L2_PIX_FMT_YVYU
:
611 buf
[0][offset
] = r_y
;
612 buf
[0][offset
+ 1] = odd
? g_u
: b_v
;
614 case V4L2_PIX_FMT_VYUY
:
615 buf
[0][offset
] = odd
? g_u
: b_v
;
616 buf
[0][offset
+ 1] = r_y
;
618 case V4L2_PIX_FMT_RGB565
:
619 buf
[0][offset
] = (g_u
<< 5) | b_v
;
620 buf
[0][offset
+ 1] = (r_y
<< 3) | (g_u
>> 3);
622 case V4L2_PIX_FMT_RGB565X
:
623 buf
[0][offset
] = (r_y
<< 3) | (g_u
>> 3);
624 buf
[0][offset
+ 1] = (g_u
<< 5) | b_v
;
626 case V4L2_PIX_FMT_RGB555
:
627 case V4L2_PIX_FMT_XRGB555
:
630 case V4L2_PIX_FMT_ARGB555
:
631 buf
[0][offset
] = (g_u
<< 5) | b_v
;
632 buf
[0][offset
+ 1] = (alpha
& 0x80) | (r_y
<< 2) | (g_u
>> 3);
634 case V4L2_PIX_FMT_RGB555X
:
635 buf
[0][offset
] = (alpha
& 0x80) | (r_y
<< 2) | (g_u
>> 3);
636 buf
[0][offset
+ 1] = (g_u
<< 5) | b_v
;
638 case V4L2_PIX_FMT_RGB24
:
639 buf
[0][offset
] = r_y
;
640 buf
[0][offset
+ 1] = g_u
;
641 buf
[0][offset
+ 2] = b_v
;
643 case V4L2_PIX_FMT_BGR24
:
644 buf
[0][offset
] = b_v
;
645 buf
[0][offset
+ 1] = g_u
;
646 buf
[0][offset
+ 2] = r_y
;
648 case V4L2_PIX_FMT_RGB32
:
649 case V4L2_PIX_FMT_XRGB32
:
652 case V4L2_PIX_FMT_ARGB32
:
653 buf
[0][offset
] = alpha
;
654 buf
[0][offset
+ 1] = r_y
;
655 buf
[0][offset
+ 2] = g_u
;
656 buf
[0][offset
+ 3] = b_v
;
658 case V4L2_PIX_FMT_BGR32
:
659 case V4L2_PIX_FMT_XBGR32
:
662 case V4L2_PIX_FMT_ABGR32
:
663 buf
[0][offset
] = b_v
;
664 buf
[0][offset
+ 1] = g_u
;
665 buf
[0][offset
+ 2] = r_y
;
666 buf
[0][offset
+ 3] = alpha
;
671 /* Return how many pattern lines are used by the current pattern. */
672 static unsigned tpg_get_pat_lines(struct tpg_data
*tpg
)
674 switch (tpg
->pattern
) {
675 case TPG_PAT_CHECKERS_16X16
:
676 case TPG_PAT_CHECKERS_1X1
:
677 case TPG_PAT_ALTERNATING_HLINES
:
678 case TPG_PAT_CROSS_1_PIXEL
:
679 case TPG_PAT_CROSS_2_PIXELS
:
680 case TPG_PAT_CROSS_10_PIXELS
:
682 case TPG_PAT_100_COLORSQUARES
:
683 case TPG_PAT_100_HCOLORBAR
:
690 /* Which pattern line should be used for the given frame line. */
691 static unsigned tpg_get_pat_line(struct tpg_data
*tpg
, unsigned line
)
693 switch (tpg
->pattern
) {
694 case TPG_PAT_CHECKERS_16X16
:
695 return (line
>> 4) & 1;
696 case TPG_PAT_CHECKERS_1X1
:
697 case TPG_PAT_ALTERNATING_HLINES
:
699 case TPG_PAT_100_COLORSQUARES
:
700 case TPG_PAT_100_HCOLORBAR
:
701 return (line
* 8) / tpg
->src_height
;
702 case TPG_PAT_CROSS_1_PIXEL
:
703 return line
== tpg
->src_height
/ 2;
704 case TPG_PAT_CROSS_2_PIXELS
:
705 return (line
+ 1) / 2 == tpg
->src_height
/ 4;
706 case TPG_PAT_CROSS_10_PIXELS
:
707 return (line
+ 10) / 20 == tpg
->src_height
/ 40;
714 * Which color should be used for the given pattern line and X coordinate.
715 * Note: x is in the range 0 to 2 * tpg->src_width.
717 static enum tpg_color
tpg_get_color(struct tpg_data
*tpg
, unsigned pat_line
, unsigned x
)
719 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
720 should be modified */
721 static const enum tpg_color bars
[3][8] = {
722 /* Standard ITU-R 75% color bar sequence */
723 { TPG_COLOR_CSC_WHITE
, TPG_COLOR_75_YELLOW
,
724 TPG_COLOR_75_CYAN
, TPG_COLOR_75_GREEN
,
725 TPG_COLOR_75_MAGENTA
, TPG_COLOR_75_RED
,
726 TPG_COLOR_75_BLUE
, TPG_COLOR_100_BLACK
, },
727 /* Standard ITU-R 100% color bar sequence */
728 { TPG_COLOR_100_WHITE
, TPG_COLOR_100_YELLOW
,
729 TPG_COLOR_100_CYAN
, TPG_COLOR_100_GREEN
,
730 TPG_COLOR_100_MAGENTA
, TPG_COLOR_100_RED
,
731 TPG_COLOR_100_BLUE
, TPG_COLOR_100_BLACK
, },
732 /* Color bar sequence suitable to test CSC */
733 { TPG_COLOR_CSC_WHITE
, TPG_COLOR_CSC_YELLOW
,
734 TPG_COLOR_CSC_CYAN
, TPG_COLOR_CSC_GREEN
,
735 TPG_COLOR_CSC_MAGENTA
, TPG_COLOR_CSC_RED
,
736 TPG_COLOR_CSC_BLUE
, TPG_COLOR_CSC_BLACK
, },
739 switch (tpg
->pattern
) {
740 case TPG_PAT_75_COLORBAR
:
741 case TPG_PAT_100_COLORBAR
:
742 case TPG_PAT_CSC_COLORBAR
:
743 return bars
[tpg
->pattern
][((x
* 8) / tpg
->src_width
) % 8];
744 case TPG_PAT_100_COLORSQUARES
:
745 return bars
[1][(pat_line
+ (x
* 8) / tpg
->src_width
) % 8];
746 case TPG_PAT_100_HCOLORBAR
:
747 return bars
[1][pat_line
];
749 return TPG_COLOR_100_BLACK
;
751 return TPG_COLOR_100_WHITE
;
753 return TPG_COLOR_100_RED
;
755 return TPG_COLOR_100_GREEN
;
757 return TPG_COLOR_100_BLUE
;
758 case TPG_PAT_CHECKERS_16X16
:
759 return (((x
>> 4) & 1) ^ (pat_line
& 1)) ?
760 TPG_COLOR_100_BLACK
: TPG_COLOR_100_WHITE
;
761 case TPG_PAT_CHECKERS_1X1
:
762 return ((x
& 1) ^ (pat_line
& 1)) ?
763 TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
764 case TPG_PAT_ALTERNATING_HLINES
:
765 return pat_line
? TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
766 case TPG_PAT_ALTERNATING_VLINES
:
767 return (x
& 1) ? TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
768 case TPG_PAT_CROSS_1_PIXEL
:
769 if (pat_line
|| (x
% tpg
->src_width
) == tpg
->src_width
/ 2)
770 return TPG_COLOR_100_BLACK
;
771 return TPG_COLOR_100_WHITE
;
772 case TPG_PAT_CROSS_2_PIXELS
:
773 if (pat_line
|| ((x
% tpg
->src_width
) + 1) / 2 == tpg
->src_width
/ 4)
774 return TPG_COLOR_100_BLACK
;
775 return TPG_COLOR_100_WHITE
;
776 case TPG_PAT_CROSS_10_PIXELS
:
777 if (pat_line
|| ((x
% tpg
->src_width
) + 10) / 20 == tpg
->src_width
/ 40)
778 return TPG_COLOR_100_BLACK
;
779 return TPG_COLOR_100_WHITE
;
780 case TPG_PAT_GRAY_RAMP
:
781 return TPG_COLOR_RAMP
+ ((x
% tpg
->src_width
) * 256) / tpg
->src_width
;
783 return TPG_COLOR_100_RED
;
788 * Given the pixel aspect ratio and video aspect ratio calculate the
789 * coordinates of a centered square and the coordinates of the border of
790 * the active video area. The coordinates are relative to the source
793 static void tpg_calculate_square_border(struct tpg_data
*tpg
)
795 unsigned w
= tpg
->src_width
;
796 unsigned h
= tpg
->src_height
;
799 sq_w
= (w
* 2 / 5) & ~1;
800 if (((w
- sq_w
) / 2) & 1)
803 tpg
->square
.width
= sq_w
;
804 if (tpg
->vid_aspect
== TPG_VIDEO_ASPECT_16X9_ANAMORPHIC
) {
805 unsigned ana_sq_w
= (sq_w
/ 4) * 3;
807 if (((w
- ana_sq_w
) / 2) & 1)
809 tpg
->square
.width
= ana_sq_w
;
811 tpg
->square
.left
= (w
- tpg
->square
.width
) / 2;
812 if (tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
)
813 sq_h
= sq_w
* 10 / 11;
814 else if (tpg
->pix_aspect
== TPG_PIXEL_ASPECT_PAL
)
815 sq_h
= sq_w
* 59 / 54;
816 tpg
->square
.height
= sq_h
;
817 tpg
->square
.top
= (h
- sq_h
) / 2;
818 tpg
->border
.left
= 0;
819 tpg
->border
.width
= w
;
821 tpg
->border
.height
= h
;
822 switch (tpg
->vid_aspect
) {
823 case TPG_VIDEO_ASPECT_4X3
:
826 if (3 * w
>= 4 * h
) {
827 tpg
->border
.width
= ((4 * h
) / 3) & ~1;
828 if (((w
- tpg
->border
.width
) / 2) & ~1)
829 tpg
->border
.width
-= 2;
830 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
833 tpg
->border
.height
= ((3 * w
) / 4) & ~1;
834 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
836 case TPG_VIDEO_ASPECT_14X9_CENTRE
:
837 if (tpg
->pix_aspect
) {
838 tpg
->border
.height
= tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
? 420 : 506;
839 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
842 if (9 * w
>= 14 * h
) {
843 tpg
->border
.width
= ((14 * h
) / 9) & ~1;
844 if (((w
- tpg
->border
.width
) / 2) & ~1)
845 tpg
->border
.width
-= 2;
846 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
849 tpg
->border
.height
= ((9 * w
) / 14) & ~1;
850 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
852 case TPG_VIDEO_ASPECT_16X9_CENTRE
:
853 if (tpg
->pix_aspect
) {
854 tpg
->border
.height
= tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
? 368 : 442;
855 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
858 if (9 * w
>= 16 * h
) {
859 tpg
->border
.width
= ((16 * h
) / 9) & ~1;
860 if (((w
- tpg
->border
.width
) / 2) & ~1)
861 tpg
->border
.width
-= 2;
862 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
865 tpg
->border
.height
= ((9 * w
) / 16) & ~1;
866 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
873 static void tpg_precalculate_line(struct tpg_data
*tpg
)
875 enum tpg_color contrast
;
880 switch (tpg
->pattern
) {
882 contrast
= TPG_COLOR_100_RED
;
884 case TPG_PAT_CSC_COLORBAR
:
885 contrast
= TPG_COLOR_CSC_GREEN
;
888 contrast
= TPG_COLOR_100_GREEN
;
892 for (pat
= 0; pat
< tpg_get_pat_lines(tpg
); pat
++) {
893 /* Coarse scaling with Bresenham */
894 unsigned int_part
= tpg
->src_width
/ tpg
->scaled_width
;
895 unsigned fract_part
= tpg
->src_width
% tpg
->scaled_width
;
899 for (x
= 0; x
< tpg
->scaled_width
* 2; x
+= 2) {
900 unsigned real_x
= src_x
;
901 enum tpg_color color1
, color2
;
902 u8 pix
[TPG_MAX_PLANES
][8];
904 real_x
= tpg
->hflip
? tpg
->src_width
* 2 - real_x
- 2 : real_x
;
905 color1
= tpg_get_color(tpg
, pat
, real_x
);
909 if (error
>= tpg
->scaled_width
) {
910 error
-= tpg
->scaled_width
;
915 real_x
= tpg
->hflip
? tpg
->src_width
* 2 - real_x
- 2 : real_x
;
916 color2
= tpg_get_color(tpg
, pat
, real_x
);
920 if (error
>= tpg
->scaled_width
) {
921 error
-= tpg
->scaled_width
;
925 gen_twopix(tpg
, pix
, tpg
->hflip
? color2
: color1
, 0);
926 gen_twopix(tpg
, pix
, tpg
->hflip
? color1
: color2
, 1);
927 for (p
= 0; p
< tpg
->planes
; p
++) {
928 unsigned twopixsize
= tpg
->twopixelsize
[p
];
929 u8
*pos
= tpg
->lines
[pat
][p
] + x
* twopixsize
/ 2;
931 memcpy(pos
, pix
[p
], twopixsize
);
935 for (x
= 0; x
< tpg
->scaled_width
; x
+= 2) {
936 u8 pix
[TPG_MAX_PLANES
][8];
938 gen_twopix(tpg
, pix
, contrast
, 0);
939 gen_twopix(tpg
, pix
, contrast
, 1);
940 for (p
= 0; p
< tpg
->planes
; p
++) {
941 unsigned twopixsize
= tpg
->twopixelsize
[p
];
942 u8
*pos
= tpg
->contrast_line
[p
] + x
* twopixsize
/ 2;
944 memcpy(pos
, pix
[p
], twopixsize
);
947 for (x
= 0; x
< tpg
->scaled_width
; x
+= 2) {
948 u8 pix
[TPG_MAX_PLANES
][8];
950 gen_twopix(tpg
, pix
, TPG_COLOR_100_BLACK
, 0);
951 gen_twopix(tpg
, pix
, TPG_COLOR_100_BLACK
, 1);
952 for (p
= 0; p
< tpg
->planes
; p
++) {
953 unsigned twopixsize
= tpg
->twopixelsize
[p
];
954 u8
*pos
= tpg
->black_line
[p
] + x
* twopixsize
/ 2;
956 memcpy(pos
, pix
[p
], twopixsize
);
959 for (x
= 0; x
< tpg
->scaled_width
* 2; x
+= 2) {
960 u8 pix
[TPG_MAX_PLANES
][8];
962 gen_twopix(tpg
, pix
, TPG_COLOR_RANDOM
, 0);
963 gen_twopix(tpg
, pix
, TPG_COLOR_RANDOM
, 1);
964 for (p
= 0; p
< tpg
->planes
; p
++) {
965 unsigned twopixsize
= tpg
->twopixelsize
[p
];
966 u8
*pos
= tpg
->random_line
[p
] + x
* twopixsize
/ 2;
968 memcpy(pos
, pix
[p
], twopixsize
);
971 gen_twopix(tpg
, tpg
->textbg
, TPG_COLOR_TEXTBG
, 0);
972 gen_twopix(tpg
, tpg
->textbg
, TPG_COLOR_TEXTBG
, 1);
973 gen_twopix(tpg
, tpg
->textfg
, TPG_COLOR_TEXTFG
, 0);
974 gen_twopix(tpg
, tpg
->textfg
, TPG_COLOR_TEXTFG
, 1);
977 /* need this to do rgb24 rendering */
978 typedef struct { u16 __
; u8 _
; } __packed x24
;
980 void tpg_gen_text(struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
981 int y
, int x
, char *text
)
984 unsigned step
= V4L2_FIELD_HAS_T_OR_B(tpg
->field
) ? 2 : 1;
987 unsigned len
= strlen(text
);
990 if (font8x16
== NULL
|| basep
== NULL
)
993 /* Checks if it is possible to show string */
994 if (y
+ 16 >= tpg
->compose
.height
|| x
+ 8 >= tpg
->compose
.width
)
997 if (len
> (tpg
->compose
.width
- x
) / 8)
998 len
= (tpg
->compose
.width
- x
) / 8;
1000 y
= tpg
->compose
.height
- y
- 16;
1002 x
= tpg
->compose
.width
- x
- 8;
1003 y
+= tpg
->compose
.top
;
1004 x
+= tpg
->compose
.left
;
1005 if (tpg
->field
== V4L2_FIELD_BOTTOM
)
1007 else if (tpg
->field
== V4L2_FIELD_SEQ_TB
|| tpg
->field
== V4L2_FIELD_SEQ_BT
)
1010 for (p
= 0; p
< tpg
->planes
; p
++) {
1011 /* Print stream time */
1012 #define PRINTSTR(PIXTYPE) do { \
1015 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1016 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1018 for (line = first; line < 16; line += step) { \
1019 int l = tpg->vflip ? 15 - line : line; \
1020 PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
1021 ((y * step + l) / div) * tpg->bytesperline[p] + \
1022 x * sizeof(PIXTYPE)); \
1025 for (s = 0; s < len; s++) { \
1026 u8 chr = font8x16[text[s] * 16 + line]; \
1029 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1030 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1031 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1032 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1033 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1034 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1035 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1036 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1038 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1039 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1040 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1041 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1042 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1043 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1044 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1045 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1048 pos += tpg->hflip ? -8 : 8; \
1053 switch (tpg
->twopixelsize
[p
]) {
1055 PRINTSTR(u8
); break;
1057 PRINTSTR(u16
); break;
1059 PRINTSTR(x24
); break;
1061 PRINTSTR(u32
); break;
1066 void tpg_update_mv_step(struct tpg_data
*tpg
)
1068 int factor
= tpg
->mv_hor_mode
> TPG_MOVE_NONE
? -1 : 1;
1072 switch (tpg
->mv_hor_mode
) {
1073 case TPG_MOVE_NEG_FAST
:
1074 case TPG_MOVE_POS_FAST
:
1075 tpg
->mv_hor_step
= ((tpg
->src_width
+ 319) / 320) * 4;
1079 tpg
->mv_hor_step
= ((tpg
->src_width
+ 639) / 640) * 4;
1081 case TPG_MOVE_NEG_SLOW
:
1082 case TPG_MOVE_POS_SLOW
:
1083 tpg
->mv_hor_step
= 2;
1086 tpg
->mv_hor_step
= 0;
1090 tpg
->mv_hor_step
= tpg
->src_width
- tpg
->mv_hor_step
;
1092 factor
= tpg
->mv_vert_mode
> TPG_MOVE_NONE
? -1 : 1;
1093 switch (tpg
->mv_vert_mode
) {
1094 case TPG_MOVE_NEG_FAST
:
1095 case TPG_MOVE_POS_FAST
:
1096 tpg
->mv_vert_step
= ((tpg
->src_width
+ 319) / 320) * 4;
1100 tpg
->mv_vert_step
= ((tpg
->src_width
+ 639) / 640) * 4;
1102 case TPG_MOVE_NEG_SLOW
:
1103 case TPG_MOVE_POS_SLOW
:
1104 tpg
->mv_vert_step
= 1;
1107 tpg
->mv_vert_step
= 0;
1111 tpg
->mv_vert_step
= tpg
->src_height
- tpg
->mv_vert_step
;
1114 /* Map the line number relative to the crop rectangle to a frame line number */
1115 static unsigned tpg_calc_frameline(struct tpg_data
*tpg
, unsigned src_y
,
1119 case V4L2_FIELD_TOP
:
1120 return tpg
->crop
.top
+ src_y
* 2;
1121 case V4L2_FIELD_BOTTOM
:
1122 return tpg
->crop
.top
+ src_y
* 2 + 1;
1124 return src_y
+ tpg
->crop
.top
;
1129 * Map the line number relative to the compose rectangle to a destination
1130 * buffer line number.
1132 static unsigned tpg_calc_buffer_line(struct tpg_data
*tpg
, unsigned y
,
1135 y
+= tpg
->compose
.top
;
1137 case V4L2_FIELD_SEQ_TB
:
1139 return tpg
->buf_height
/ 2 + y
/ 2;
1141 case V4L2_FIELD_SEQ_BT
:
1144 return tpg
->buf_height
/ 2 + y
/ 2;
1150 static void tpg_recalc(struct tpg_data
*tpg
)
1152 if (tpg
->recalc_colors
) {
1153 tpg
->recalc_colors
= false;
1154 tpg
->recalc_lines
= true;
1155 tpg_precalculate_colors(tpg
);
1157 if (tpg
->recalc_square_border
) {
1158 tpg
->recalc_square_border
= false;
1159 tpg_calculate_square_border(tpg
);
1161 if (tpg
->recalc_lines
) {
1162 tpg
->recalc_lines
= false;
1163 tpg_precalculate_line(tpg
);
1167 void tpg_calc_text_basep(struct tpg_data
*tpg
,
1168 u8
*basep
[TPG_MAX_PLANES
][2], unsigned p
, u8
*vbuf
)
1170 unsigned stride
= tpg
->bytesperline
[p
];
1176 if (tpg
->field
== V4L2_FIELD_SEQ_TB
)
1177 basep
[p
][1] += tpg
->buf_height
* stride
/ 2;
1178 else if (tpg
->field
== V4L2_FIELD_SEQ_BT
)
1179 basep
[p
][0] += tpg
->buf_height
* stride
/ 2;
1182 void tpg_fillbuffer(struct tpg_data
*tpg
, v4l2_std_id std
, unsigned p
, u8
*vbuf
)
1185 bool is_60hz
= is_tv
&& (std
& V4L2_STD_525_60
);
1186 unsigned mv_hor_old
= tpg
->mv_hor_count
% tpg
->src_width
;
1187 unsigned mv_hor_new
= (tpg
->mv_hor_count
+ tpg
->mv_hor_step
) % tpg
->src_width
;
1188 unsigned mv_vert_old
= tpg
->mv_vert_count
% tpg
->src_height
;
1189 unsigned mv_vert_new
= (tpg
->mv_vert_count
+ tpg
->mv_vert_step
) % tpg
->src_height
;
1192 int hmax
= (tpg
->compose
.height
* tpg
->perc_fill
) / 100;
1194 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1195 unsigned img_width
= tpg
->compose
.width
* twopixsize
/ 2;
1196 unsigned line_offset
;
1197 unsigned left_pillar_width
= 0;
1198 unsigned right_pillar_start
= img_width
;
1199 unsigned stride
= tpg
->bytesperline
[p
];
1200 unsigned factor
= V4L2_FIELD_HAS_T_OR_B(tpg
->field
) ? 2 : 1;
1201 u8
*orig_vbuf
= vbuf
;
1203 /* Coarse scaling with Bresenham */
1204 unsigned int_part
= (tpg
->crop
.height
/ factor
) / tpg
->compose
.height
;
1205 unsigned fract_part
= (tpg
->crop
.height
/ factor
) % tpg
->compose
.height
;
1211 mv_hor_old
= (mv_hor_old
* tpg
->scaled_width
/ tpg
->src_width
) & ~1;
1212 mv_hor_new
= (mv_hor_new
* tpg
->scaled_width
/ tpg
->src_width
) & ~1;
1213 wss_width
= tpg
->crop
.left
< tpg
->src_width
/ 2 ?
1214 tpg
->src_width
/ 2 - tpg
->crop
.left
: 0;
1215 if (wss_width
> tpg
->crop
.width
)
1216 wss_width
= tpg
->crop
.width
;
1217 wss_width
= wss_width
* tpg
->scaled_width
/ tpg
->src_width
;
1219 vbuf
+= tpg
->compose
.left
* twopixsize
/ 2;
1220 line_offset
= tpg
->crop
.left
* tpg
->scaled_width
/ tpg
->src_width
;
1221 line_offset
= (line_offset
& ~1) * twopixsize
/ 2;
1222 if (tpg
->crop
.left
< tpg
->border
.left
) {
1223 left_pillar_width
= tpg
->border
.left
- tpg
->crop
.left
;
1224 if (left_pillar_width
> tpg
->crop
.width
)
1225 left_pillar_width
= tpg
->crop
.width
;
1226 left_pillar_width
= (left_pillar_width
* tpg
->scaled_width
) / tpg
->src_width
;
1227 left_pillar_width
= (left_pillar_width
& ~1) * twopixsize
/ 2;
1229 if (tpg
->crop
.left
+ tpg
->crop
.width
> tpg
->border
.left
+ tpg
->border
.width
) {
1230 right_pillar_start
= tpg
->border
.left
+ tpg
->border
.width
- tpg
->crop
.left
;
1231 right_pillar_start
= (right_pillar_start
* tpg
->scaled_width
) / tpg
->src_width
;
1232 right_pillar_start
= (right_pillar_start
& ~1) * twopixsize
/ 2;
1233 if (right_pillar_start
> img_width
)
1234 right_pillar_start
= img_width
;
1237 f
= tpg
->field
== (is_60hz
? V4L2_FIELD_TOP
: V4L2_FIELD_BOTTOM
);
1239 for (h
= 0; h
< tpg
->compose
.height
; h
++) {
1241 bool fill_blank
= false;
1242 unsigned frame_line
;
1244 unsigned pat_line_old
;
1245 unsigned pat_line_new
;
1246 u8
*linestart_older
;
1247 u8
*linestart_newer
;
1249 u8
*linestart_bottom
;
1251 frame_line
= tpg_calc_frameline(tpg
, src_y
, tpg
->field
);
1252 even
= !(frame_line
& 1);
1253 buf_line
= tpg_calc_buffer_line(tpg
, h
, tpg
->field
);
1255 error
+= fract_part
;
1256 if (error
>= tpg
->compose
.height
) {
1257 error
-= tpg
->compose
.height
;
1262 if (hmax
== tpg
->compose
.height
)
1264 if (!tpg
->perc_fill_blank
)
1270 frame_line
= tpg
->src_height
- frame_line
- 1;
1273 linestart_older
= tpg
->contrast_line
[p
];
1274 linestart_newer
= tpg
->contrast_line
[p
];
1275 } else if (tpg
->qual
!= TPG_QUAL_NOISE
&&
1276 (frame_line
< tpg
->border
.top
||
1277 frame_line
>= tpg
->border
.top
+ tpg
->border
.height
)) {
1278 linestart_older
= tpg
->black_line
[p
];
1279 linestart_newer
= tpg
->black_line
[p
];
1280 } else if (tpg
->pattern
== TPG_PAT_NOISE
|| tpg
->qual
== TPG_QUAL_NOISE
) {
1281 linestart_older
= tpg
->random_line
[p
] +
1282 twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
1283 linestart_newer
= tpg
->random_line
[p
] +
1284 twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
1286 pat_line_old
= tpg_get_pat_line(tpg
,
1287 (frame_line
+ mv_vert_old
) % tpg
->src_height
);
1288 pat_line_new
= tpg_get_pat_line(tpg
,
1289 (frame_line
+ mv_vert_new
) % tpg
->src_height
);
1290 linestart_older
= tpg
->lines
[pat_line_old
][p
] +
1291 mv_hor_old
* twopixsize
/ 2;
1292 linestart_newer
= tpg
->lines
[pat_line_new
][p
] +
1293 mv_hor_new
* twopixsize
/ 2;
1294 linestart_older
+= line_offset
;
1295 linestart_newer
+= line_offset
;
1298 linestart_top
= linestart_newer
;
1299 linestart_bottom
= linestart_older
;
1301 linestart_top
= linestart_older
;
1302 linestart_bottom
= linestart_newer
;
1305 switch (tpg
->field
) {
1306 case V4L2_FIELD_INTERLACED
:
1307 case V4L2_FIELD_INTERLACED_TB
:
1308 case V4L2_FIELD_SEQ_TB
:
1309 case V4L2_FIELD_SEQ_BT
:
1311 memcpy(vbuf
+ buf_line
* stride
, linestart_top
, img_width
);
1313 memcpy(vbuf
+ buf_line
* stride
, linestart_bottom
, img_width
);
1315 case V4L2_FIELD_INTERLACED_BT
:
1317 memcpy(vbuf
+ buf_line
* stride
, linestart_bottom
, img_width
);
1319 memcpy(vbuf
+ buf_line
* stride
, linestart_top
, img_width
);
1321 case V4L2_FIELD_TOP
:
1322 memcpy(vbuf
+ buf_line
* stride
, linestart_top
, img_width
);
1324 case V4L2_FIELD_BOTTOM
:
1325 memcpy(vbuf
+ buf_line
* stride
, linestart_bottom
, img_width
);
1327 case V4L2_FIELD_NONE
:
1329 memcpy(vbuf
+ buf_line
* stride
, linestart_older
, img_width
);
1333 if (is_tv
&& !is_60hz
&& frame_line
== 0 && wss_width
) {
1335 * Replace the first half of the top line of a 50 Hz frame
1336 * with random data to simulate a WSS signal.
1338 u8
*wss
= tpg
->random_line
[p
] +
1339 twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
1341 memcpy(vbuf
+ buf_line
* stride
, wss
, wss_width
* twopixsize
/ 2);
1346 vbuf
+= tpg
->compose
.left
* twopixsize
/ 2;
1349 for (h
= 0; h
< tpg
->compose
.height
; h
++) {
1350 unsigned frame_line
= tpg_calc_frameline(tpg
, src_y
, tpg
->field
);
1351 unsigned buf_line
= tpg_calc_buffer_line(tpg
, h
, tpg
->field
);
1352 const struct v4l2_rect
*sq
= &tpg
->square
;
1353 const struct v4l2_rect
*b
= &tpg
->border
;
1354 const struct v4l2_rect
*c
= &tpg
->crop
;
1357 error
+= fract_part
;
1358 if (error
>= tpg
->compose
.height
) {
1359 error
-= tpg
->compose
.height
;
1363 if (tpg
->show_border
&& frame_line
>= b
->top
&&
1364 frame_line
< b
->top
+ b
->height
) {
1365 unsigned bottom
= b
->top
+ b
->height
- 1;
1366 unsigned left
= left_pillar_width
;
1367 unsigned right
= right_pillar_start
;
1369 if (frame_line
== b
->top
|| frame_line
== b
->top
+ 1 ||
1370 frame_line
== bottom
|| frame_line
== bottom
- 1) {
1371 memcpy(vbuf
+ buf_line
* stride
+ left
, tpg
->contrast_line
[p
],
1374 if (b
->left
>= c
->left
&&
1375 b
->left
< c
->left
+ c
->width
)
1376 memcpy(vbuf
+ buf_line
* stride
+ left
,
1377 tpg
->contrast_line
[p
], twopixsize
);
1378 if (b
->left
+ b
->width
> c
->left
&&
1379 b
->left
+ b
->width
<= c
->left
+ c
->width
)
1380 memcpy(vbuf
+ buf_line
* stride
+ right
- twopixsize
,
1381 tpg
->contrast_line
[p
], twopixsize
);
1384 if (tpg
->qual
!= TPG_QUAL_NOISE
&& frame_line
>= b
->top
&&
1385 frame_line
< b
->top
+ b
->height
) {
1386 memcpy(vbuf
+ buf_line
* stride
, tpg
->black_line
[p
], left_pillar_width
);
1387 memcpy(vbuf
+ buf_line
* stride
+ right_pillar_start
, tpg
->black_line
[p
],
1388 img_width
- right_pillar_start
);
1390 if (tpg
->show_square
&& frame_line
>= sq
->top
&&
1391 frame_line
< sq
->top
+ sq
->height
&&
1392 sq
->left
< c
->left
+ c
->width
&&
1393 sq
->left
+ sq
->width
>= c
->left
) {
1394 unsigned left
= sq
->left
;
1395 unsigned width
= sq
->width
;
1397 if (c
->left
> left
) {
1398 width
-= c
->left
- left
;
1401 if (c
->left
+ c
->width
< left
+ width
)
1402 width
-= left
+ width
- c
->left
- c
->width
;
1404 left
= (left
* tpg
->scaled_width
) / tpg
->src_width
;
1405 left
= (left
& ~1) * twopixsize
/ 2;
1406 width
= (width
* tpg
->scaled_width
) / tpg
->src_width
;
1407 width
= (width
& ~1) * twopixsize
/ 2;
1408 memcpy(vbuf
+ buf_line
* stride
+ left
, tpg
->contrast_line
[p
], width
);
1410 if (tpg
->insert_sav
) {
1411 unsigned offset
= (tpg
->compose
.width
/ 6) * twopixsize
;
1412 u8
*p
= vbuf
+ buf_line
* stride
+ offset
;
1413 unsigned vact
= 0, hact
= 0;
1418 p
[3] = 0x80 | (f
<< 6) | (vact
<< 5) | (hact
<< 4) |
1419 ((hact
^ vact
) << 3) |
1424 if (tpg
->insert_eav
) {
1425 unsigned offset
= (tpg
->compose
.width
/ 6) * 2 * twopixsize
;
1426 u8
*p
= vbuf
+ buf_line
* stride
+ offset
;
1427 unsigned vact
= 0, hact
= 1;
1432 p
[3] = 0x80 | (f
<< 6) | (vact
<< 5) | (hact
<< 4) |
1433 ((hact
^ vact
) << 3) |