// SPDX-License-Identifier: GPL-2.0-only /* * v4l2-tpg-core.c - Test Pattern Generator * * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the * vivi.c source for the copyright information of those functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
switch (fourcc) { case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: case V4L2_PIX_FMT_SBGGR10: case V4L2_PIX_FMT_SGBRG10: case V4L2_PIX_FMT_SGRBG10: case V4L2_PIX_FMT_SRGGB10: case V4L2_PIX_FMT_SBGGR12: case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SRGGB12: case V4L2_PIX_FMT_SBGGR16: case V4L2_PIX_FMT_SGBRG16: case V4L2_PIX_FMT_SGRBG16: case V4L2_PIX_FMT_SRGGB16:
tpg->interleaved = true;
tpg->vdownsampling[1] = 1;
tpg->hdownsampling[1] = 1;
tpg->planes = 2;
fallthrough; case V4L2_PIX_FMT_RGB332: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: case V4L2_PIX_FMT_RGBX444: case V4L2_PIX_FMT_RGBA444: case V4L2_PIX_FMT_XBGR444: case V4L2_PIX_FMT_ABGR444: case V4L2_PIX_FMT_BGRX444: case V4L2_PIX_FMT_BGRA444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGBX555: case V4L2_PIX_FMT_RGBA555: case V4L2_PIX_FMT_XBGR555: case V4L2_PIX_FMT_ABGR555: case V4L2_PIX_FMT_BGRX555: case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: case V4L2_PIX_FMT_BGR666: case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: case V4L2_PIX_FMT_RGBX32: case V4L2_PIX_FMT_BGRX32: case V4L2_PIX_FMT_RGBA32: case V4L2_PIX_FMT_BGRA32:
tpg->color_enc = TGP_COLOR_ENC_RGB; break; case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y10: case V4L2_PIX_FMT_Y12: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: case V4L2_PIX_FMT_Z16:
tpg->color_enc = TGP_COLOR_ENC_LUMA; break; case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_YUV565: case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_AYUV32: case V4L2_PIX_FMT_XYUV32: case V4L2_PIX_FMT_VUYA32: case V4L2_PIX_FMT_VUYX32: case V4L2_PIX_FMT_YUVA32: case V4L2_PIX_FMT_YUVX32:
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV420M: case V4L2_PIX_FMT_YVU420M:
tpg->buffers = 3;
fallthrough; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420:
tpg->vdownsampling[1] = 2;
tpg->vdownsampling[2] = 2;
tpg->hdownsampling[1] = 2;
tpg->hdownsampling[2] = 2;
tpg->planes = 3;
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV422M: case V4L2_PIX_FMT_YVU422M:
tpg->buffers = 3;
fallthrough; case V4L2_PIX_FMT_YUV422P:
tpg->vdownsampling[1] = 1;
tpg->vdownsampling[2] = 1;
tpg->hdownsampling[1] = 2;
tpg->hdownsampling[2] = 2;
tpg->planes = 3;
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M:
tpg->buffers = 2;
fallthrough; case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61:
tpg->vdownsampling[1] = 1;
tpg->hdownsampling[1] = 1;
tpg->hmask[1] = ~1;
tpg->planes = 2;
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_NV12M: case V4L2_PIX_FMT_NV21M:
tpg->buffers = 2;
fallthrough; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21:
tpg->vdownsampling[1] = 2;
tpg->hdownsampling[1] = 1;
tpg->hmask[1] = ~1;
tpg->planes = 2;
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV444M: case V4L2_PIX_FMT_YVU444M:
tpg->buffers = 3;
tpg->planes = 3;
tpg->vdownsampling[1] = 1;
tpg->vdownsampling[2] = 1;
tpg->hdownsampling[1] = 1;
tpg->hdownsampling[2] = 1;
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_NV24: case V4L2_PIX_FMT_NV42:
tpg->vdownsampling[1] = 1;
tpg->hdownsampling[1] = 1;
tpg->planes = 2;
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY:
tpg->hmask[0] = ~1;
tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_HSV24: case V4L2_PIX_FMT_HSV32:
tpg->color_enc = TGP_COLOR_ENC_HSV; break; default: returnfalse;
}
switch (fourcc) { case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_RGB332:
tpg->twopixelsize[0] = 2; break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: case V4L2_PIX_FMT_RGBX444: case V4L2_PIX_FMT_RGBA444: case V4L2_PIX_FMT_XBGR444: case V4L2_PIX_FMT_ABGR444: case V4L2_PIX_FMT_BGRX444: case V4L2_PIX_FMT_BGRA444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGBX555: case V4L2_PIX_FMT_RGBA555: case V4L2_PIX_FMT_XBGR555: case V4L2_PIX_FMT_ABGR555: case V4L2_PIX_FMT_BGRX555: case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_YUV565: case V4L2_PIX_FMT_Y10: case V4L2_PIX_FMT_Y12: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: case V4L2_PIX_FMT_Z16:
tpg->twopixelsize[0] = 2 * 2; break; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: case V4L2_PIX_FMT_HSV24:
tpg->twopixelsize[0] = 2 * 3; break; case V4L2_PIX_FMT_BGR666: case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: case V4L2_PIX_FMT_RGBX32: case V4L2_PIX_FMT_BGRX32: case V4L2_PIX_FMT_RGBA32: case V4L2_PIX_FMT_BGRA32: case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_AYUV32: case V4L2_PIX_FMT_XYUV32: case V4L2_PIX_FMT_VUYA32: case V4L2_PIX_FMT_VUYX32: case V4L2_PIX_FMT_YUVA32: case V4L2_PIX_FMT_YUVX32: case V4L2_PIX_FMT_HSV32:
tpg->twopixelsize[0] = 2 * 4; break; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV12M: case V4L2_PIX_FMT_NV21M: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8:
tpg->twopixelsize[0] = 2;
tpg->twopixelsize[1] = 2; break; case V4L2_PIX_FMT_SRGGB10: case V4L2_PIX_FMT_SGRBG10: case V4L2_PIX_FMT_SGBRG10: case V4L2_PIX_FMT_SBGGR10: case V4L2_PIX_FMT_SRGGB12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SBGGR12: case V4L2_PIX_FMT_SRGGB16: case V4L2_PIX_FMT_SGRBG16: case V4L2_PIX_FMT_SGBRG16: case V4L2_PIX_FMT_SBGGR16:
tpg->twopixelsize[0] = 4;
tpg->twopixelsize[1] = 4; break; case V4L2_PIX_FMT_YUV444M: case V4L2_PIX_FMT_YVU444M: case V4L2_PIX_FMT_YUV422M: case V4L2_PIX_FMT_YVU422M: case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_YUV420M: case V4L2_PIX_FMT_YVU420M:
tpg->twopixelsize[0] = 2;
tpg->twopixelsize[1] = 2;
tpg->twopixelsize[2] = 2; break; case V4L2_PIX_FMT_NV24: case V4L2_PIX_FMT_NV42:
tpg->twopixelsize[0] = 2;
tpg->twopixelsize[1] = 4; break;
} returntrue;
}
EXPORT_SYMBOL_GPL(tpg_s_fourcc);
staticvoid color_to_hsv(struct tpg_data *tpg, int r, int g, int b, int *h, int *s, int *v)
{ int max_rgb, min_rgb, diff_rgb; int aux; int third; int third_size;
/* Hue */ if (max_rgb == r) {
aux = g - b;
third = 0;
} elseif (max_rgb == g) {
aux = b - r;
third = third_size;
} else {
aux = r - g;
third = third_size * 2;
}
aux *= third_size / 2;
aux += diff_rgb / 2;
aux /= diff_rgb;
aux += third;
/* Clamp Hue */ if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) { if (aux < 0)
aux += 180; elseif (aux > 180)
aux -= 180;
} else {
aux = aux & 0xff;
}
*h = aux;
}
staticvoid rgb2ycbcr(constint m[3][3], int r, int g, int b, int y_offset, int *y, int *cb, int *cr)
{
*y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
*cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
*cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
}
staticvoid color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, int *y, int *cb, int *cr)
{ #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; unsigned y_offset = full ? 0 : 16; int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219); int lin_r, lin_g, lin_b, lin_y;
switch (tpg->real_ycbcr_enc) { case V4L2_YCBCR_ENC_601:
ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b); break; case V4L2_YCBCR_ENC_XV601: /* Ignore quantization range, there is only one possible
* Y'CbCr encoding. */
ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b); break; case V4L2_YCBCR_ENC_XV709: /* Ignore quantization range, there is only one possible
* Y'CbCr encoding. */
ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b); break; case V4L2_YCBCR_ENC_BT2020:
ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b); break; case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
y -= full ? 0 : 16 << 4;
cb -= 128 << 4;
cr -= 128 << 4;
/* precalculate color bar values to speed up rendering */ staticvoid precalculate_color(struct tpg_data *tpg, int k)
{ int col = k; int r = tpg_colors[col].r; int g = tpg_colors[col].g; int b = tpg_colors[col].b; int y, cb, cr; bool ycbcr_valid = false;
if (k == TPG_COLOR_TEXTBG) {
col = tpg_get_textbg_color(tpg);
r = tpg_colors[col].r;
g = tpg_colors[col].g;
b = tpg_colors[col].b;
} elseif (k == TPG_COLOR_TEXTFG) {
col = tpg_get_textfg_color(tpg);
r = tpg_colors[col].r;
g = tpg_colors[col].g;
b = tpg_colors[col].b;
} elseif (tpg->pattern == TPG_PAT_NOISE) {
r = g = b = get_random_u8();
} elseif (k == TPG_COLOR_RANDOM) {
r = g = b = tpg->qual_offset + get_random_u32_below(196);
} elseif (k >= TPG_COLOR_RAMP) {
r = g = b = k - TPG_COLOR_RAMP;
}
if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
} else {
r <<= 4;
g <<= 4;
b <<= 4;
}
if (tpg->qual == TPG_QUAL_GRAY ||
tpg->color_enc == TGP_COLOR_ENC_LUMA) { /* Rec. 709 Luma function */ /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
}
/* * The assumption is that the RGB output is always full range, * so only if the rgb_range overrides the 'real' rgb range do * we need to convert the RGB values. * * Remember that r, g and b are still in the 0 - 0xff0 range.
*/ if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL &&
tpg->color_enc == TGP_COLOR_ENC_RGB) { /* * Convert from full range (which is what r, g and b are) * to limited range (which is the 'real' RGB range), which * is then interpreted as full range.
*/
r = (r * 219) / 255 + (16 << 4);
g = (g * 219) / 255 + (16 << 4);
b = (b * 219) / 255 + (16 << 4);
} elseif (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
tpg->color_enc == TGP_COLOR_ENC_RGB) {
/* * Clamp r, g and b to the limited range and convert to full * range since that's what we deliver.
*/
r = clamp(r, 16 << 4, 235 << 4);
g = clamp(g, 16 << 4, 235 << 4);
b = clamp(b, 16 << 4, 235 << 4);
r = (r - (16 << 4)) * 255 / 219;
g = (g - (16 << 4)) * 255 / 219;
b = (b - (16 << 4)) * 255 / 219;
}
if ((tpg->brightness != 128 || tpg->contrast != 128 ||
tpg->saturation != 128 || tpg->hue) &&
tpg->color_enc != TGP_COLOR_ENC_LUMA) { /* Implement these operations */ int tmp_cb, tmp_cr;
y >>= 4;
cb >>= 4;
cr >>= 4; /* * XV601/709 use the header/footer margins to encode R', G' * and B' values outside the range [0-1]. So do not clamp * XV601/709 values.
*/ if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE &&
tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&
tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV709) {
y = clamp(y, 16, 235);
cb = clamp(cb, 16, 240);
cr = clamp(cr, 16, 240);
} else {
y = clamp(y, 1, 254);
cb = clamp(cb, 1, 254);
cr = clamp(cr, 1, 254);
} switch (tpg->fourcc) { case V4L2_PIX_FMT_YUV444:
y >>= 4;
cb >>= 4;
cr >>= 4; break; case V4L2_PIX_FMT_YUV555:
y >>= 3;
cb >>= 3;
cr >>= 3; break; case V4L2_PIX_FMT_YUV565:
y >>= 3;
cb >>= 2;
cr >>= 3; break;
}
tpg->colors[k][0] = y;
tpg->colors[k][1] = cb;
tpg->colors[k][2] = cr; break;
} case TGP_COLOR_ENC_LUMA:
{
tpg->colors[k][0] = r >> 4; break;
} case TGP_COLOR_ENC_RGB:
{ if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
r = (r * 219) / 255 + (16 << 4);
g = (g * 219) / 255 + (16 << 4);
b = (b * 219) / 255 + (16 << 4);
} switch (tpg->fourcc) { case V4L2_PIX_FMT_RGB332:
r >>= 9;
g >>= 9;
b >>= 10; break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X:
r >>= 7;
g >>= 6;
b >>= 7; break; case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: case V4L2_PIX_FMT_RGBX444: case V4L2_PIX_FMT_RGBA444: case V4L2_PIX_FMT_XBGR444: case V4L2_PIX_FMT_ABGR444: case V4L2_PIX_FMT_BGRX444: case V4L2_PIX_FMT_BGRA444:
r >>= 8;
g >>= 8;
b >>= 8; break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGBX555: case V4L2_PIX_FMT_RGBA555: case V4L2_PIX_FMT_XBGR555: case V4L2_PIX_FMT_ABGR555: case V4L2_PIX_FMT_BGRX555: case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X:
r >>= 7;
g >>= 7;
b >>= 7; break; case V4L2_PIX_FMT_BGR666:
r >>= 6;
g >>= 6;
b >>= 6; break; default:
r >>= 4;
g >>= 4;
b >>= 4; break;
}
staticvoid tpg_precalculate_colors(struct tpg_data *tpg)
{ int k;
for (k = 0; k < TPG_COLOR_MAX; k++)
precalculate_color(tpg, k);
}
/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */ staticvoid gen_twopix(struct tpg_data *tpg,
u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
{ unsigned offset = odd * tpg->twopixelsize[0] / 2;
u8 alpha = tpg->alpha_component;
u8 r_y_h, g_u_s, b_v;
if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
color != TPG_COLOR_100_RED &&
color != TPG_COLOR_75_RED)
alpha = 0; if (color == TPG_COLOR_RANDOM)
precalculate_color(tpg, color);
r_y_h = tpg->colors[color][0]; /* R or precalculated Y, H */
g_u_s = tpg->colors[color][1]; /* G or precalculated U, V */
b_v = tpg->colors[color][2]; /* B or precalculated V */
switch (tpg->fourcc) { case V4L2_PIX_FMT_GREY:
buf[0][offset] = r_y_h; break; case V4L2_PIX_FMT_Y10:
buf[0][offset] = (r_y_h << 2) & 0xff;
buf[0][offset+1] = r_y_h >> 6; break; case V4L2_PIX_FMT_Y12:
buf[0][offset] = (r_y_h << 4) & 0xff;
buf[0][offset+1] = r_y_h >> 4; break; case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Z16: /* * Ideally both bytes should be set to r_y_h, but then you won't * be able to detect endian problems. So keep it 0 except for * the corner case where r_y_h is 0xff so white really will be * white (0xffff).
*/
buf[0][offset] = r_y_h == 0xff ? r_y_h : 0;
buf[0][offset+1] = r_y_h; break; case V4L2_PIX_FMT_Y16_BE: /* See comment for V4L2_PIX_FMT_Y16 above */
buf[0][offset] = r_y_h;
buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0; break; case V4L2_PIX_FMT_YUV422M: case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV420M:
buf[0][offset] = r_y_h; if (odd) {
buf[1][0] = (buf[1][0] + g_u_s) / 2;
buf[2][0] = (buf[2][0] + b_v) / 2;
buf[1][1] = buf[1][0];
buf[2][1] = buf[2][0]; break;
}
buf[1][0] = g_u_s;
buf[2][0] = b_v; break; case V4L2_PIX_FMT_YVU422M: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_YVU420M:
buf[0][offset] = r_y_h; if (odd) {
buf[1][0] = (buf[1][0] + b_v) / 2;
buf[2][0] = (buf[2][0] + g_u_s) / 2;
buf[1][1] = buf[1][0];
buf[2][1] = buf[2][0]; break;
}
buf[1][0] = b_v;
buf[2][0] = g_u_s; break;
case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV16M:
buf[0][offset] = r_y_h; if (odd) {
buf[1][0] = (buf[1][0] + g_u_s) / 2;
buf[1][1] = (buf[1][1] + b_v) / 2; break;
}
buf[1][0] = g_u_s;
buf[1][1] = b_v; break; case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV21M: case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV61M:
buf[0][offset] = r_y_h; if (odd) {
buf[1][0] = (buf[1][0] + b_v) / 2;
buf[1][1] = (buf[1][1] + g_u_s) / 2; break;
}
buf[1][0] = b_v;
buf[1][1] = g_u_s; break;
unsigned tpg_g_interleaved_plane(conststruct tpg_data *tpg, unsigned buf_line)
{ switch (tpg->fourcc) { case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: case V4L2_PIX_FMT_SBGGR10: case V4L2_PIX_FMT_SGBRG10: case V4L2_PIX_FMT_SGRBG10: case V4L2_PIX_FMT_SRGGB10: case V4L2_PIX_FMT_SBGGR12: case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SRGGB12: case V4L2_PIX_FMT_SBGGR16: case V4L2_PIX_FMT_SGBRG16: case V4L2_PIX_FMT_SGRBG16: case V4L2_PIX_FMT_SRGGB16: return buf_line & 1; default: return 0;
}
}
EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);
/* Return how many pattern lines are used by the current pattern. */ staticunsigned tpg_get_pat_lines(conststruct tpg_data *tpg)
{ switch (tpg->pattern) { case TPG_PAT_CHECKERS_16X16: case TPG_PAT_CHECKERS_2X2: case TPG_PAT_CHECKERS_1X1: case TPG_PAT_COLOR_CHECKERS_2X2: case TPG_PAT_COLOR_CHECKERS_1X1: case TPG_PAT_ALTERNATING_HLINES: case TPG_PAT_CROSS_1_PIXEL: case TPG_PAT_CROSS_2_PIXELS: case TPG_PAT_CROSS_10_PIXELS: return 2; case TPG_PAT_100_COLORSQUARES: case TPG_PAT_100_HCOLORBAR: return 8; default: return 1;
}
}
/* Which pattern line should be used for the given frame line. */ staticunsigned tpg_get_pat_line(conststruct tpg_data *tpg, unsigned line)
{ switch (tpg->pattern) { case TPG_PAT_CHECKERS_16X16: return (line >> 4) & 1; case TPG_PAT_CHECKERS_1X1: case TPG_PAT_COLOR_CHECKERS_1X1: case TPG_PAT_ALTERNATING_HLINES: return line & 1; case TPG_PAT_CHECKERS_2X2: case TPG_PAT_COLOR_CHECKERS_2X2: return (line & 2) >> 1; case TPG_PAT_100_COLORSQUARES: case TPG_PAT_100_HCOLORBAR: return (line * 8) / tpg->src_height; case TPG_PAT_CROSS_1_PIXEL: return line == tpg->src_height / 2; case TPG_PAT_CROSS_2_PIXELS: return (line + 1) / 2 == tpg->src_height / 4; case TPG_PAT_CROSS_10_PIXELS: return (line + 10) / 20 == tpg->src_height / 40; default: return 0;
}
}
/* * Which color should be used for the given pattern line and X coordinate. * Note: x is in the range 0 to 2 * tpg->src_width.
*/ staticenum tpg_color tpg_get_color(conststruct tpg_data *tpg, unsigned pat_line, unsigned x)
{ /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
should be modified */ staticconstenum tpg_color bars[3][8] = { /* Standard ITU-R 75% color bar sequence */
{ TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, }, /* Standard ITU-R 100% color bar sequence */
{ TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, }, /* Color bar sequence suitable to test CSC */
{ TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
};
switch (tpg->pattern) { case TPG_PAT_75_COLORBAR: case TPG_PAT_100_COLORBAR: case TPG_PAT_CSC_COLORBAR: return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8]; case TPG_PAT_100_COLORSQUARES: return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8]; case TPG_PAT_100_HCOLORBAR: return bars[1][pat_line]; case TPG_PAT_BLACK: return TPG_COLOR_100_BLACK; case TPG_PAT_WHITE: return TPG_COLOR_100_WHITE; case TPG_PAT_RED: return TPG_COLOR_100_RED; case TPG_PAT_GREEN: return TPG_COLOR_100_GREEN; case TPG_PAT_BLUE: return TPG_COLOR_100_BLUE; case TPG_PAT_CHECKERS_16X16: return (((x >> 4) & 1) ^ (pat_line & 1)) ?
TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE; case TPG_PAT_CHECKERS_1X1: return ((x & 1) ^ (pat_line & 1)) ?
TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; case TPG_PAT_COLOR_CHECKERS_1X1: return ((x & 1) ^ (pat_line & 1)) ?
TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; case TPG_PAT_CHECKERS_2X2: return (((x >> 1) & 1) ^ (pat_line & 1)) ?
TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; case TPG_PAT_COLOR_CHECKERS_2X2: return (((x >> 1) & 1) ^ (pat_line & 1)) ?
TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; case TPG_PAT_ALTERNATING_HLINES: return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; case TPG_PAT_ALTERNATING_VLINES: return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; case TPG_PAT_CROSS_1_PIXEL: if (pat_line || (x % tpg->src_width) == tpg->src_width / 2) return TPG_COLOR_100_BLACK; return TPG_COLOR_100_WHITE; case TPG_PAT_CROSS_2_PIXELS: if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4) return TPG_COLOR_100_BLACK; return TPG_COLOR_100_WHITE; case TPG_PAT_CROSS_10_PIXELS: if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40) return TPG_COLOR_100_BLACK; return TPG_COLOR_100_WHITE; case TPG_PAT_GRAY_RAMP: return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width; default: return TPG_COLOR_100_RED;
}
}
/* * Given the pixel aspect ratio and video aspect ratio calculate the * coordinates of a centered square and the coordinates of the border of * the active video area. The coordinates are relative to the source * frame rectangle.
*/ staticvoid tpg_calculate_square_border(struct tpg_data *tpg)
{ unsigned w = tpg->src_width; unsigned h = tpg->src_height; unsigned sq_w, sq_h;
static noinline void tpg_print_str_2(conststruct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, unsigned first, unsigned div, unsigned step, int y, int x, constchar *text, unsigned len)
{
PRINTSTR(u8);
}
static noinline void tpg_print_str_4(conststruct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, unsigned first, unsigned div, unsigned step, int y, int x, constchar *text, unsigned len)
{
PRINTSTR(u16);
}
static noinline void tpg_print_str_6(conststruct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, unsigned first, unsigned div, unsigned step, int y, int x, constchar *text, unsigned len)
{
PRINTSTR(x24);
}
static noinline void tpg_print_str_8(conststruct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, unsigned first, unsigned div, unsigned step, int y, int x, constchar *text, unsigned len)
{
PRINTSTR(u32);
}
void tpg_gen_text(conststruct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], int y, int x, constchar *text)
{ unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; unsigned div = step; unsigned first = 0; unsigned len; unsigned p;
if (font8x16 == NULL || basep == NULL || text == NULL) return;
len = strlen(text);
/* Checks if it is possible to show string */ if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width) return;
if (len > (tpg->compose.width - x) / 8)
len = (tpg->compose.width - x) / 8; if (tpg->vflip)
y = tpg->compose.height - y - 16; if (tpg->hflip)
x = tpg->compose.width - x - 8;
y += tpg->compose.top;
x += tpg->compose.left; if (tpg->field == V4L2_FIELD_BOTTOM)
first = 1; elseif (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
div = 2;
for (p = 0; p < tpg->planes; p++) { /* Print text */ switch (tpg->twopixelsize[p]) { case 2:
tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
text, len); break; case 4:
tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
text, len); break; case 6:
tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
text, len); break; case 8:
tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
text, len); break;
}
}
}
EXPORT_SYMBOL_GPL(tpg_gen_text);
constchar *tpg_g_color_order(conststruct tpg_data *tpg)
{ switch (tpg->pattern) { case TPG_PAT_75_COLORBAR: case TPG_PAT_100_COLORBAR: case TPG_PAT_CSC_COLORBAR: case TPG_PAT_100_HCOLORBAR: return"White, yellow, cyan, green, magenta, red, blue, black"; case TPG_PAT_BLACK: return"Black"; case TPG_PAT_WHITE: return"White"; case TPG_PAT_RED: return"Red"; case TPG_PAT_GREEN: return"Green"; case TPG_PAT_BLUE: return"Blue"; default: return NULL;
}
}
EXPORT_SYMBOL_GPL(tpg_g_color_order);
if (tpg->hflip)
factor = -factor; switch (tpg->mv_hor_mode) { case TPG_MOVE_NEG_FAST: case TPG_MOVE_POS_FAST:
tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4; break; case TPG_MOVE_NEG: case TPG_MOVE_POS:
tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4; break; case TPG_MOVE_NEG_SLOW: case TPG_MOVE_POS_SLOW:
tpg->mv_hor_step = 2; break; case TPG_MOVE_NONE:
tpg->mv_hor_step = 0; break;
} if (factor < 0)
tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1; switch (tpg->mv_vert_mode) { case TPG_MOVE_NEG_FAST: case TPG_MOVE_POS_FAST:
tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4; break; case TPG_MOVE_NEG: case TPG_MOVE_POS:
tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4; break; case TPG_MOVE_NEG_SLOW: case TPG_MOVE_POS_SLOW:
tpg->mv_vert_step = 1; break; case TPG_MOVE_NONE:
tpg->mv_vert_step = 0; break;
} if (factor < 0)
tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
}
EXPORT_SYMBOL_GPL(tpg_update_mv_step);
/* Map the line number relative to the crop rectangle to a frame line number */ staticunsigned tpg_calc_frameline(conststruct tpg_data *tpg, unsigned src_y, unsigned field)
{ switch (field) { case V4L2_FIELD_TOP: return tpg->crop.top + src_y * 2; case V4L2_FIELD_BOTTOM: return tpg->crop.top + src_y * 2 + 1; default: return src_y + tpg->crop.top;
}
}
/* * Map the line number relative to the compose rectangle to a destination * buffer line number.
*/ staticunsigned tpg_calc_buffer_line(conststruct tpg_data *tpg, unsigned y, unsigned field)
{
y += tpg->compose.top; switch (field) { case V4L2_FIELD_SEQ_TB: if (y & 1) return tpg->buf_height / 2 + y / 2; return y / 2; case V4L2_FIELD_SEQ_BT: if (y & 1) return y / 2; return tpg->buf_height / 2 + y / 2; default: return y;
}
}
/* * This struct contains common parameters used by both the drawing of the * test pattern and the drawing of the extras (borders, square, etc.)
*/ struct tpg_draw_params { /* common data */ bool is_tv; bool is_60hz; unsigned twopixsize; unsigned img_width; unsigned stride; unsigned hmax; unsigned frame_line; unsigned frame_line_next;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.