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;
}
y >>= 4;
cb >>= 4;
cr >>= 4; /* *XV601/709usetheheader/footermarginstoencodeR',G' *andB'valuesoutsidetherange[0-1].Sodonotclamp *XV601/709values.
*/ 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: /* *Ideallybothbytesshouldbesettor_y_h,butthenyouwon't *beabletodetectendianproblems.Sokeepit0exceptfor *thecornercasewherer_y_his0xffsowhitereallywillbe *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(const struct 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. */
static unsigned tpg_get_pat_lines(const struct 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. */
static unsigned tpg_get_pat_line(const struct 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.
*/
static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
unsigned pat_line, unsigned x)
{
/* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
should be modified */
static const enum 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.
*/
static void 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(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, const char *text, unsigned len)
{
PRINTSTR(u8);
}
static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, const char *text, unsigned len)
{
PRINTSTR(u16);
}
static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, const char *text, unsigned len)
{
PRINTSTR(x24);
}
static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, const char *text, unsigned len)
{
PRINTSTR(u32);
}
void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
int y, int x, const char *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;
else if (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);
const char *tpg_g_color_order(const struct 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 */
static unsigned tpg_calc_frameline(const struct 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.
*/
static unsigned tpg_calc_buffer_line(const struct 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;
if (params->is_tv && !params->is_60hz &&
frame_line == 0 && params->wss_width) {
/*
* Replace the first half of the top line of a 50 Hz frame
* with random data to simulate a WSS signal.
*/
u8 *wss = tpg->random_line[p] + params->wss_random_offset;
memcpy(vbuf, wss, params->wss_width);
}
if (tpg->show_border && frame_line >= b->top &&
frame_line < b->top + b->height) {
unsigned bottom = b->top + b->height - 1;
unsigned left = params->left_pillar_width;
unsigned right = params->right_pillar_start;
if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
int avg_pat;
/*
* Now decide whether we need to use downsampled_lines[].
* That's necessary if the two lines use different patterns.
*/
pat_line_next_old = tpg_get_pat_line(tpg,
(frame_line_next + mv_vert_old) % tpg->src_height);
pat_line_next_new = tpg_get_pat_line(tpg,
(frame_line_next + mv_vert_new) % tpg->src_height);
switch (tpg->field) {
case V4L2_FIELD_INTERLACED:
case V4L2_FIELD_INTERLACED_BT:
case V4L2_FIELD_INTERLACED_TB:
avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
if (avg_pat < 0)
break;
linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
linestart_newer = linestart_older;
break;
case V4L2_FIELD_NONE:
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_SEQ_BT:
case V4L2_FIELD_SEQ_TB:
avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
if (avg_pat >= 0)
linestart_older = tpg->downsampled_lines[avg_pat][p] +
mv_hor_old;
avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
if (avg_pat >= 0)
linestart_newer = tpg->downsampled_lines[avg_pat][p] +
mv_hor_new;
break;
}
}
linestart_older += line_offset;
linestart_newer += line_offset;
}
if (tpg->field_alternate) {
linestart_top = linestart_bottom = linestart_older;
} else if (params->is_60hz) {
linestart_top = linestart_newer;
linestart_bottom = linestart_older;
} else {
linestart_top = linestart_older;
linestart_bottom = linestart_newer;
}
switch (tpg->field) {
case V4L2_FIELD_INTERLACED:
case V4L2_FIELD_INTERLACED_TB:
case V4L2_FIELD_SEQ_TB:
case V4L2_FIELD_SEQ_BT:
if (even)
memcpy(vbuf, linestart_top, img_width);
else
memcpy(vbuf, linestart_bottom, img_width);
break;
case V4L2_FIELD_INTERLACED_BT:
if (even)
memcpy(vbuf, linestart_bottom, img_width);
else
memcpy(vbuf, linestart_top, img_width);
break;
case V4L2_FIELD_TOP:
memcpy(vbuf, linestart_top, img_width);
break;
case V4L2_FIELD_BOTTOM:
memcpy(vbuf, linestart_bottom, img_width);
break;
case V4L2_FIELD_NONE:
default:
memcpy(vbuf, linestart_older, img_width);
break;
}
}
/*
* For line-interleaved formats determine the 'plane'
* based on the buffer line.
*/
if (tpg_g_interleaved(tpg))
p = tpg_g_interleaved_plane(tpg, buf_line);
if (tpg->vdownsampling[p] > 1) {
/*
* When doing vertical downsampling the field setting
* matters: for SEQ_BT/TB we downsample each field
* separately (i.e. lines 0+2 are combined, as are
* lines 1+3), for the other field settings we combine
* odd and even lines. Doing that for SEQ_BT/TB would
* be really weird.
*/
if (tpg->field == V4L2_FIELD_SEQ_BT ||
tpg->field == V4L2_FIELD_SEQ_TB) {
unsigned next_src_y = src_y;
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.