pipewire/spa/plugins/videotestsrc/draw.c

269 lines
5 KiB
C
Raw Normal View History

/* Spa Video Test Source */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#include <errno.h>
2017-05-26 09:09:31 +02:00
typedef enum {
GRAY = 0,
YELLOW,
CYAN,
GREEN,
MAGENTA,
RED,
BLUE,
BLACK,
NEG_I,
WHITE,
POS_Q,
DARK_BLACK,
LIGHT_BLACK,
N_COLORS
2016-11-21 09:05:42 +01:00
} Color;
typedef struct _Pixel Pixel;
2017-05-26 09:09:31 +02:00
struct _Pixel {
unsigned char R;
unsigned char G;
unsigned char B;
unsigned char Y;
unsigned char U;
unsigned char V;
};
2017-05-26 09:09:31 +02:00
static Pixel colors[N_COLORS] = {
{191, 191, 191, 0, 0, 0}, /* GRAY */
{191, 191, 0, 0, 0, 0}, /* YELLOW */
{0, 191, 191, 0, 0, 0}, /* CYAN */
{0, 191, 0, 0, 0, 0}, /* GREEN */
{191, 0, 191, 0, 0, 0}, /* MAGENTA */
{191, 0, 0, 0, 0, 0}, /* RED */
{0, 0, 191, 0, 0, 0}, /* BLUE */
{19, 19, 19, 0, 0, 0}, /* BLACK */
{0, 33, 76, 0, 0, 0}, /* NEGATIVE I */
{255, 255, 255, 0, 0, 0}, /* WHITE */
{49, 0, 107, 0, 0, 0}, /* POSITIVE Q */
{9, 9, 9, 0, 0, 0}, /* DARK BLACK */
{29, 29, 29, 0, 0, 0}, /* LIGHT BLACK */
};
2017-05-26 09:09:31 +02:00
2016-11-21 09:05:42 +01:00
/* YUV values are computed in init_colors() */
typedef struct _DrawingData DrawingData;
2017-05-26 09:09:31 +02:00
typedef void (*DrawPixelFunc) (DrawingData * dd, int x, Pixel * pixel);
2016-11-21 09:05:42 +01:00
struct _DrawingData {
2017-05-26 09:09:31 +02:00
char *line;
int width;
int height;
int stride;
DrawPixelFunc draw_pixel;
2016-11-21 09:05:42 +01:00
};
2017-05-26 09:09:31 +02:00
static inline void update_yuv(Pixel * pixel)
2016-11-21 09:05:42 +01:00
{
2017-05-26 09:09:31 +02:00
uint16_t y, u, v;
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
/* see https://en.wikipedia.org/wiki/YUV#Studio_swing_for_BT.601 */
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
y = 76 * pixel->R + 150 * pixel->G + 29 * pixel->B;
u = -43 * pixel->R - 84 * pixel->G + 127 * pixel->B;
v = 127 * pixel->R - 106 * pixel->G - 21 * pixel->B;
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
y = (y + 128) >> 8;
u = (u + 128) >> 8;
v = (v + 128) >> 8;
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
pixel->Y = y;
pixel->U = u + 128;
pixel->V = v + 128;
2016-11-21 09:05:42 +01:00
}
2017-05-26 09:09:31 +02:00
static void init_colors(void)
{
2017-05-26 09:09:31 +02:00
int i;
2017-05-26 09:09:31 +02:00
if (colors[WHITE].Y != 0) {
/* already computed */
return;
}
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
for (i = 0; i < N_COLORS; i++) {
update_yuv(&colors[i]);
}
}
2017-05-26 09:09:31 +02:00
static void draw_pixel_rgb(DrawingData * dd, int x, Pixel * color)
2016-11-21 09:05:42 +01:00
{
2017-05-26 09:09:31 +02:00
dd->line[3 * x + 0] = color->R;
dd->line[3 * x + 1] = color->G;
dd->line[3 * x + 2] = color->B;
2016-11-21 09:05:42 +01:00
}
2017-05-26 09:09:31 +02:00
static void draw_pixel_uyvy(DrawingData * dd, int x, Pixel * color)
2016-11-21 09:05:42 +01:00
{
2017-05-26 09:09:31 +02:00
if (x & 1) {
/* odd pixel */
dd->line[2 * (x - 1) + 3] = color->Y;
} else {
/* even pixel */
dd->line[2 * x + 0] = color->U;
dd->line[2 * x + 1] = color->Y;
dd->line[2 * x + 2] = color->V;
}
2016-11-21 09:05:42 +01:00
}
2017-05-26 09:09:31 +02:00
static int drawing_data_init(DrawingData * dd, struct impl *this, char *data)
2016-11-21 09:05:42 +01:00
{
struct port *port = &this->port;
struct spa_video_info *format = &port->current_format;
2017-05-26 09:09:31 +02:00
struct spa_rectangle *size = &format->info.raw.size;
if ((format->media_type != SPA_MEDIA_TYPE_video) ||
(format->media_subtype != SPA_MEDIA_SUBTYPE_raw))
return -ENOTSUP;
2017-05-26 09:09:31 +02:00
if (format->info.raw.format == SPA_VIDEO_FORMAT_RGB) {
2017-05-26 09:09:31 +02:00
dd->draw_pixel = draw_pixel_rgb;
} else if (format->info.raw.format == SPA_VIDEO_FORMAT_UYVY) {
2017-05-26 09:09:31 +02:00
dd->draw_pixel = draw_pixel_uyvy;
} else
return -ENOTSUP;
2017-05-26 09:09:31 +02:00
dd->line = data;
dd->width = size->width;
dd->height = size->height;
dd->stride = port->stride;
2017-05-26 09:09:31 +02:00
return 0;
2016-11-21 09:05:42 +01:00
}
2017-05-26 09:09:31 +02:00
static inline void draw_pixels(DrawingData * dd, int offset, Color color, int length)
2016-11-21 09:05:42 +01:00
{
2017-05-26 09:09:31 +02:00
int x;
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
for (x = offset; x < offset + length; x++) {
dd->draw_pixel(dd, x, &colors[color]);
}
2016-11-21 09:05:42 +01:00
}
2017-05-26 09:09:31 +02:00
static inline void next_line(DrawingData * dd)
2016-11-21 09:05:42 +01:00
{
2017-05-26 09:09:31 +02:00
dd->line += dd->stride;
2016-11-21 09:05:42 +01:00
}
2017-05-26 09:09:31 +02:00
static void draw_smpte_snow(DrawingData * dd)
{
2017-05-26 09:09:31 +02:00
int h, w;
int y1, y2;
int i, j;
w = dd->width;
h = dd->height;
y1 = 2 * h / 3;
y2 = 3 * h / 4;
for (i = 0; i < y1; i++) {
for (j = 0; j < 7; j++) {
int x1 = j * w / 7;
int x2 = (j + 1) * w / 7;
draw_pixels(dd, x1, j, x2 - x1);
}
next_line(dd);
}
for (i = y1; i < y2; i++) {
for (j = 0; j < 7; j++) {
int x1 = j * w / 7;
int x2 = (j + 1) * w / 7;
Color c = (j & 1) ? BLACK : BLUE - j;
draw_pixels(dd, x1, c, x2 - x1);
}
next_line(dd);
}
for (i = y2; i < h; i++) {
int x = 0;
/* negative I */
draw_pixels(dd, x, NEG_I, w / 6);
x += w / 6;
/* white */
draw_pixels(dd, x, WHITE, w / 6);
x += w / 6;
/* positive Q */
draw_pixels(dd, x, POS_Q, w / 6);
x += w / 6;
/* pluge */
draw_pixels(dd, x, DARK_BLACK, w / 12);
x += w / 12;
draw_pixels(dd, x, BLACK, w / 12);
x += w / 12;
draw_pixels(dd, x, LIGHT_BLACK, w / 12);
x += w / 12;
/* war of the ants (a.k.a. snow) */
for (j = x; j < w; j++) {
Pixel p;
unsigned char r = rand();
p.R = r;
p.G = r;
p.B = r;
update_yuv(&p);
dd->draw_pixel(dd, j, &p);
}
next_line(dd);
}
}
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
static void draw_snow(DrawingData * dd)
{
2017-05-26 09:09:31 +02:00
int x, y;
for (y = 0; y < dd->height; y++) {
for (x = 0; x < dd->width; x++) {
Pixel p;
unsigned char r = rand();
p.R = r;
p.G = r;
p.B = r;
update_yuv(&p);
dd->draw_pixel(dd, x, &p);
}
next_line(dd);
}
}
2017-05-26 09:09:31 +02:00
static int draw(struct impl *this, char *data)
2016-11-21 09:05:42 +01:00
{
2017-05-26 09:09:31 +02:00
DrawingData dd;
int res;
2016-11-21 09:05:42 +01:00
2017-05-26 09:09:31 +02:00
init_colors();
2016-11-21 09:05:42 +01:00
if ((res = drawing_data_init(&dd, this, data)) < 0)
2017-05-26 09:09:31 +02:00
return res;
2016-11-21 09:05:42 +01:00
switch (this->props.pattern) {
case PATTERN_SMPTE_SNOW:
2017-05-26 09:09:31 +02:00
draw_smpte_snow(&dd);
break;
case PATTERN_SNOW:
2017-05-26 09:09:31 +02:00
draw_snow(&dd);
break;
default:
return -ENOTSUP;
}
return 0;
2016-11-21 09:05:42 +01:00
}