1 /* 2 * v4l2-tpg.h - Test Pattern Generator 3 * 4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 5 * 6 * This program is free software; you may redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 11 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 12 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 13 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 14 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 15 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 * SOFTWARE. 18 */ 19 20 #ifndef _V4L2_TPG_H_ 21 #define _V4L2_TPG_H_ 22 23 #include <linux/types.h> 24 #include <linux/errno.h> 25 #include <linux/random.h> 26 #include <linux/slab.h> 27 #include <linux/vmalloc.h> 28 #include <linux/videodev2.h> 29 30 struct tpg_rbg_color8 { 31 unsigned char r, g, b; 32 }; 33 34 struct tpg_rbg_color16 { 35 __u16 r, g, b; 36 }; 37 38 enum tpg_color { 39 TPG_COLOR_CSC_WHITE, 40 TPG_COLOR_CSC_YELLOW, 41 TPG_COLOR_CSC_CYAN, 42 TPG_COLOR_CSC_GREEN, 43 TPG_COLOR_CSC_MAGENTA, 44 TPG_COLOR_CSC_RED, 45 TPG_COLOR_CSC_BLUE, 46 TPG_COLOR_CSC_BLACK, 47 TPG_COLOR_75_YELLOW, 48 TPG_COLOR_75_CYAN, 49 TPG_COLOR_75_GREEN, 50 TPG_COLOR_75_MAGENTA, 51 TPG_COLOR_75_RED, 52 TPG_COLOR_75_BLUE, 53 TPG_COLOR_100_WHITE, 54 TPG_COLOR_100_YELLOW, 55 TPG_COLOR_100_CYAN, 56 TPG_COLOR_100_GREEN, 57 TPG_COLOR_100_MAGENTA, 58 TPG_COLOR_100_RED, 59 TPG_COLOR_100_BLUE, 60 TPG_COLOR_100_BLACK, 61 TPG_COLOR_TEXTFG, 62 TPG_COLOR_TEXTBG, 63 TPG_COLOR_RANDOM, 64 TPG_COLOR_RAMP, 65 TPG_COLOR_MAX = TPG_COLOR_RAMP + 256 66 }; 67 68 extern const struct tpg_rbg_color8 tpg_colors[TPG_COLOR_MAX]; 69 extern const unsigned short tpg_rec709_to_linear[255 * 16 + 1]; 70 extern const unsigned short tpg_linear_to_rec709[255 * 16 + 1]; 71 extern const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1] 72 [V4L2_XFER_FUNC_SMPTE2084 + 1] 73 [TPG_COLOR_CSC_BLACK + 1]; 74 enum tpg_pattern { 75 TPG_PAT_75_COLORBAR, 76 TPG_PAT_100_COLORBAR, 77 TPG_PAT_CSC_COLORBAR, 78 TPG_PAT_100_HCOLORBAR, 79 TPG_PAT_100_COLORSQUARES, 80 TPG_PAT_BLACK, 81 TPG_PAT_WHITE, 82 TPG_PAT_RED, 83 TPG_PAT_GREEN, 84 TPG_PAT_BLUE, 85 TPG_PAT_CHECKERS_16X16, 86 TPG_PAT_CHECKERS_2X2, 87 TPG_PAT_CHECKERS_1X1, 88 TPG_PAT_COLOR_CHECKERS_2X2, 89 TPG_PAT_COLOR_CHECKERS_1X1, 90 TPG_PAT_ALTERNATING_HLINES, 91 TPG_PAT_ALTERNATING_VLINES, 92 TPG_PAT_CROSS_1_PIXEL, 93 TPG_PAT_CROSS_2_PIXELS, 94 TPG_PAT_CROSS_10_PIXELS, 95 TPG_PAT_GRAY_RAMP, 96 97 /* Must be the last pattern */ 98 TPG_PAT_NOISE, 99 }; 100 101 extern const char * const tpg_pattern_strings[]; 102 103 enum tpg_quality { 104 TPG_QUAL_COLOR, 105 TPG_QUAL_GRAY, 106 TPG_QUAL_NOISE 107 }; 108 109 enum tpg_video_aspect { 110 TPG_VIDEO_ASPECT_IMAGE, 111 TPG_VIDEO_ASPECT_4X3, 112 TPG_VIDEO_ASPECT_14X9_CENTRE, 113 TPG_VIDEO_ASPECT_16X9_CENTRE, 114 TPG_VIDEO_ASPECT_16X9_ANAMORPHIC, 115 }; 116 117 enum tpg_pixel_aspect { 118 TPG_PIXEL_ASPECT_SQUARE, 119 TPG_PIXEL_ASPECT_NTSC, 120 TPG_PIXEL_ASPECT_PAL, 121 }; 122 123 enum tpg_move_mode { 124 TPG_MOVE_NEG_FAST, 125 TPG_MOVE_NEG, 126 TPG_MOVE_NEG_SLOW, 127 TPG_MOVE_NONE, 128 TPG_MOVE_POS_SLOW, 129 TPG_MOVE_POS, 130 TPG_MOVE_POS_FAST, 131 }; 132 133 enum tgp_color_enc { 134 TGP_COLOR_ENC_RGB, 135 TGP_COLOR_ENC_YCBCR, 136 TGP_COLOR_ENC_HSV, 137 TGP_COLOR_ENC_LUMA, 138 }; 139 140 extern const char * const tpg_aspect_strings[]; 141 142 #define TPG_MAX_PLANES 3 143 #define TPG_MAX_PAT_LINES 8 144 145 struct tpg_data { 146 /* Source frame size */ 147 unsigned src_width, src_height; 148 /* Buffer height */ 149 unsigned buf_height; 150 /* Scaled output frame size */ 151 unsigned scaled_width; 152 u32 field; 153 bool field_alternate; 154 /* crop coordinates are frame-based */ 155 struct v4l2_rect crop; 156 /* compose coordinates are format-based */ 157 struct v4l2_rect compose; 158 /* border and square coordinates are frame-based */ 159 struct v4l2_rect border; 160 struct v4l2_rect square; 161 162 /* Color-related fields */ 163 enum tpg_quality qual; 164 unsigned qual_offset; 165 u8 alpha_component; 166 bool alpha_red_only; 167 u8 brightness; 168 u8 contrast; 169 u8 saturation; 170 s16 hue; 171 u32 fourcc; 172 enum tgp_color_enc color_enc; 173 u32 colorspace; 174 u32 xfer_func; 175 u32 ycbcr_enc; 176 u32 hsv_enc; 177 /* 178 * Stores the actual transfer function, i.e. will never be 179 * V4L2_XFER_FUNC_DEFAULT. 180 */ 181 u32 real_xfer_func; 182 /* 183 * Stores the actual Y'CbCr encoding, i.e. will never be 184 * V4L2_YCBCR_ENC_DEFAULT. 185 */ 186 u32 real_hsv_enc; 187 u32 real_ycbcr_enc; 188 u32 quantization; 189 /* 190 * Stores the actual quantization, i.e. will never be 191 * V4L2_QUANTIZATION_DEFAULT. 192 */ 193 u32 real_quantization; 194 enum tpg_video_aspect vid_aspect; 195 enum tpg_pixel_aspect pix_aspect; 196 unsigned rgb_range; 197 unsigned real_rgb_range; 198 unsigned buffers; 199 unsigned planes; 200 bool interleaved; 201 u8 vdownsampling[TPG_MAX_PLANES]; 202 u8 hdownsampling[TPG_MAX_PLANES]; 203 /* 204 * horizontal positions must be ANDed with this value to enforce 205 * correct boundaries for packed YUYV values. 206 */ 207 unsigned hmask[TPG_MAX_PLANES]; 208 /* Used to store the colors in native format, either RGB or YUV */ 209 u8 colors[TPG_COLOR_MAX][3]; 210 u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; 211 /* size in bytes for two pixels in each plane */ 212 unsigned twopixelsize[TPG_MAX_PLANES]; 213 unsigned bytesperline[TPG_MAX_PLANES]; 214 215 /* Configuration */ 216 enum tpg_pattern pattern; 217 bool hflip; 218 bool vflip; 219 unsigned perc_fill; 220 bool perc_fill_blank; 221 bool show_border; 222 bool show_square; 223 bool insert_sav; 224 bool insert_eav; 225 226 /* Test pattern movement */ 227 enum tpg_move_mode mv_hor_mode; 228 int mv_hor_count; 229 int mv_hor_step; 230 enum tpg_move_mode mv_vert_mode; 231 int mv_vert_count; 232 int mv_vert_step; 233 234 bool recalc_colors; 235 bool recalc_lines; 236 bool recalc_square_border; 237 238 /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ 239 unsigned max_line_width; 240 u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; 241 u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; 242 u8 *random_line[TPG_MAX_PLANES]; 243 u8 *contrast_line[TPG_MAX_PLANES]; 244 u8 *black_line[TPG_MAX_PLANES]; 245 }; 246 247 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h); 248 int tpg_alloc(struct tpg_data *tpg, unsigned max_w); 249 void tpg_free(struct tpg_data *tpg); 250 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, 251 u32 field); 252 void tpg_log_status(struct tpg_data *tpg); 253 254 void tpg_set_font(const u8 *f); 255 void tpg_gen_text(const struct tpg_data *tpg, 256 u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); 257 void tpg_calc_text_basep(struct tpg_data *tpg, 258 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); 259 unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line); 260 void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, 261 unsigned p, u8 *vbuf); 262 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, 263 unsigned p, u8 *vbuf); 264 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); 265 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, 266 const struct v4l2_rect *compose); 267 268 static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern) 269 { 270 if (tpg->pattern == pattern) 271 return; 272 tpg->pattern = pattern; 273 tpg->recalc_colors = true; 274 } 275 276 static inline void tpg_s_quality(struct tpg_data *tpg, 277 enum tpg_quality qual, unsigned qual_offset) 278 { 279 if (tpg->qual == qual && tpg->qual_offset == qual_offset) 280 return; 281 tpg->qual = qual; 282 tpg->qual_offset = qual_offset; 283 tpg->recalc_colors = true; 284 } 285 286 static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg) 287 { 288 return tpg->qual; 289 } 290 291 static inline void tpg_s_alpha_component(struct tpg_data *tpg, 292 u8 alpha_component) 293 { 294 if (tpg->alpha_component == alpha_component) 295 return; 296 tpg->alpha_component = alpha_component; 297 tpg->recalc_colors = true; 298 } 299 300 static inline void tpg_s_alpha_mode(struct tpg_data *tpg, 301 bool red_only) 302 { 303 if (tpg->alpha_red_only == red_only) 304 return; 305 tpg->alpha_red_only = red_only; 306 tpg->recalc_colors = true; 307 } 308 309 static inline void tpg_s_brightness(struct tpg_data *tpg, 310 u8 brightness) 311 { 312 if (tpg->brightness == brightness) 313 return; 314 tpg->brightness = brightness; 315 tpg->recalc_colors = true; 316 } 317 318 static inline void tpg_s_contrast(struct tpg_data *tpg, 319 u8 contrast) 320 { 321 if (tpg->contrast == contrast) 322 return; 323 tpg->contrast = contrast; 324 tpg->recalc_colors = true; 325 } 326 327 static inline void tpg_s_saturation(struct tpg_data *tpg, 328 u8 saturation) 329 { 330 if (tpg->saturation == saturation) 331 return; 332 tpg->saturation = saturation; 333 tpg->recalc_colors = true; 334 } 335 336 static inline void tpg_s_hue(struct tpg_data *tpg, 337 s16 hue) 338 { 339 if (tpg->hue == hue) 340 return; 341 tpg->hue = hue; 342 tpg->recalc_colors = true; 343 } 344 345 static inline void tpg_s_rgb_range(struct tpg_data *tpg, 346 unsigned rgb_range) 347 { 348 if (tpg->rgb_range == rgb_range) 349 return; 350 tpg->rgb_range = rgb_range; 351 tpg->recalc_colors = true; 352 } 353 354 static inline void tpg_s_real_rgb_range(struct tpg_data *tpg, 355 unsigned rgb_range) 356 { 357 if (tpg->real_rgb_range == rgb_range) 358 return; 359 tpg->real_rgb_range = rgb_range; 360 tpg->recalc_colors = true; 361 } 362 363 static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace) 364 { 365 if (tpg->colorspace == colorspace) 366 return; 367 tpg->colorspace = colorspace; 368 tpg->recalc_colors = true; 369 } 370 371 static inline u32 tpg_g_colorspace(const struct tpg_data *tpg) 372 { 373 return tpg->colorspace; 374 } 375 376 static inline void tpg_s_ycbcr_enc(struct tpg_data *tpg, u32 ycbcr_enc) 377 { 378 if (tpg->ycbcr_enc == ycbcr_enc) 379 return; 380 tpg->ycbcr_enc = ycbcr_enc; 381 tpg->recalc_colors = true; 382 } 383 384 static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg) 385 { 386 return tpg->ycbcr_enc; 387 } 388 389 static inline void tpg_s_hsv_enc(struct tpg_data *tpg, u32 hsv_enc) 390 { 391 if (tpg->hsv_enc == hsv_enc) 392 return; 393 tpg->hsv_enc = hsv_enc; 394 tpg->recalc_colors = true; 395 } 396 397 static inline u32 tpg_g_hsv_enc(const struct tpg_data *tpg) 398 { 399 return tpg->hsv_enc; 400 } 401 402 static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func) 403 { 404 if (tpg->xfer_func == xfer_func) 405 return; 406 tpg->xfer_func = xfer_func; 407 tpg->recalc_colors = true; 408 } 409 410 static inline u32 tpg_g_xfer_func(const struct tpg_data *tpg) 411 { 412 return tpg->xfer_func; 413 } 414 415 static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization) 416 { 417 if (tpg->quantization == quantization) 418 return; 419 tpg->quantization = quantization; 420 tpg->recalc_colors = true; 421 } 422 423 static inline u32 tpg_g_quantization(const struct tpg_data *tpg) 424 { 425 return tpg->quantization; 426 } 427 428 static inline unsigned tpg_g_buffers(const struct tpg_data *tpg) 429 { 430 return tpg->buffers; 431 } 432 433 static inline unsigned tpg_g_planes(const struct tpg_data *tpg) 434 { 435 return tpg->interleaved ? 1 : tpg->planes; 436 } 437 438 static inline bool tpg_g_interleaved(const struct tpg_data *tpg) 439 { 440 return tpg->interleaved; 441 } 442 443 static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) 444 { 445 return tpg->twopixelsize[plane]; 446 } 447 448 static inline unsigned tpg_hdiv(const struct tpg_data *tpg, 449 unsigned plane, unsigned x) 450 { 451 return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) * 452 tpg->twopixelsize[plane] / 2; 453 } 454 455 static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x) 456 { 457 return (x * tpg->scaled_width) / tpg->src_width; 458 } 459 460 static inline unsigned tpg_hscale_div(const struct tpg_data *tpg, 461 unsigned plane, unsigned x) 462 { 463 return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x)); 464 } 465 466 static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) 467 { 468 return tpg->bytesperline[plane]; 469 } 470 471 static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) 472 { 473 unsigned p; 474 475 if (tpg->buffers > 1) { 476 tpg->bytesperline[plane] = bpl; 477 return; 478 } 479 480 for (p = 0; p < tpg_g_planes(tpg); p++) { 481 unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; 482 483 tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p]; 484 } 485 if (tpg_g_interleaved(tpg)) 486 tpg->bytesperline[1] = tpg->bytesperline[0]; 487 } 488 489 490 static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane) 491 { 492 unsigned w = 0; 493 unsigned p; 494 495 if (tpg->buffers > 1) 496 return tpg_g_bytesperline(tpg, plane); 497 for (p = 0; p < tpg_g_planes(tpg); p++) { 498 unsigned plane_w = tpg_g_bytesperline(tpg, p); 499 500 w += plane_w / tpg->vdownsampling[p]; 501 } 502 return w; 503 } 504 505 static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, 506 unsigned plane, unsigned bpl) 507 { 508 unsigned w = 0; 509 unsigned p; 510 511 if (tpg->buffers > 1) 512 return bpl; 513 for (p = 0; p < tpg_g_planes(tpg); p++) { 514 unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; 515 516 plane_w /= tpg->hdownsampling[p]; 517 w += plane_w / tpg->vdownsampling[p]; 518 } 519 return w; 520 } 521 522 static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane) 523 { 524 if (plane >= tpg_g_planes(tpg)) 525 return 0; 526 527 return tpg_g_bytesperline(tpg, plane) * tpg->buf_height / 528 tpg->vdownsampling[plane]; 529 } 530 531 static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) 532 { 533 tpg->buf_height = h; 534 } 535 536 static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate) 537 { 538 tpg->field = field; 539 tpg->field_alternate = alternate; 540 } 541 542 static inline void tpg_s_perc_fill(struct tpg_data *tpg, 543 unsigned perc_fill) 544 { 545 tpg->perc_fill = perc_fill; 546 } 547 548 static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg) 549 { 550 return tpg->perc_fill; 551 } 552 553 static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg, 554 bool perc_fill_blank) 555 { 556 tpg->perc_fill_blank = perc_fill_blank; 557 } 558 559 static inline void tpg_s_video_aspect(struct tpg_data *tpg, 560 enum tpg_video_aspect vid_aspect) 561 { 562 if (tpg->vid_aspect == vid_aspect) 563 return; 564 tpg->vid_aspect = vid_aspect; 565 tpg->recalc_square_border = true; 566 } 567 568 static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg) 569 { 570 return tpg->vid_aspect; 571 } 572 573 static inline void tpg_s_pixel_aspect(struct tpg_data *tpg, 574 enum tpg_pixel_aspect pix_aspect) 575 { 576 if (tpg->pix_aspect == pix_aspect) 577 return; 578 tpg->pix_aspect = pix_aspect; 579 tpg->recalc_square_border = true; 580 } 581 582 static inline void tpg_s_show_border(struct tpg_data *tpg, 583 bool show_border) 584 { 585 tpg->show_border = show_border; 586 } 587 588 static inline void tpg_s_show_square(struct tpg_data *tpg, 589 bool show_square) 590 { 591 tpg->show_square = show_square; 592 } 593 594 static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav) 595 { 596 tpg->insert_sav = insert_sav; 597 } 598 599 static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav) 600 { 601 tpg->insert_eav = insert_eav; 602 } 603 604 void tpg_update_mv_step(struct tpg_data *tpg); 605 606 static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg, 607 enum tpg_move_mode mv_hor_mode) 608 { 609 tpg->mv_hor_mode = mv_hor_mode; 610 tpg_update_mv_step(tpg); 611 } 612 613 static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg, 614 enum tpg_move_mode mv_vert_mode) 615 { 616 tpg->mv_vert_mode = mv_vert_mode; 617 tpg_update_mv_step(tpg); 618 } 619 620 static inline void tpg_init_mv_count(struct tpg_data *tpg) 621 { 622 tpg->mv_hor_count = tpg->mv_vert_count = 0; 623 } 624 625 static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field) 626 { 627 tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2); 628 tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2); 629 } 630 631 static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip) 632 { 633 if (tpg->hflip == hflip) 634 return; 635 tpg->hflip = hflip; 636 tpg_update_mv_step(tpg); 637 tpg->recalc_lines = true; 638 } 639 640 static inline bool tpg_g_hflip(const struct tpg_data *tpg) 641 { 642 return tpg->hflip; 643 } 644 645 static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip) 646 { 647 tpg->vflip = vflip; 648 } 649 650 static inline bool tpg_g_vflip(const struct tpg_data *tpg) 651 { 652 return tpg->vflip; 653 } 654 655 static inline bool tpg_pattern_is_static(const struct tpg_data *tpg) 656 { 657 return tpg->pattern != TPG_PAT_NOISE && 658 tpg->mv_hor_mode == TPG_MOVE_NONE && 659 tpg->mv_vert_mode == TPG_MOVE_NONE; 660 } 661 662 #endif 663