mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
videotestsrc: add support for UYVY
This commit is contained in:
parent
ddcbca3c4b
commit
5c56fbdfc2
2 changed files with 196 additions and 69 deletions
|
|
@ -17,12 +17,7 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PIXEL_SIZE 3
|
typedef enum
|
||||||
|
|
||||||
#define GET_IMAGE_WIDTH(this) this->current_format.info.raw.size.width
|
|
||||||
#define GET_IMAGE_HEIGHT(this) this->current_format.info.raw.size.height
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
{
|
||||||
GRAY = 0,
|
GRAY = 0,
|
||||||
YELLOW,
|
YELLOW,
|
||||||
|
|
@ -38,56 +33,168 @@ enum
|
||||||
DARK_BLACK,
|
DARK_BLACK,
|
||||||
LIGHT_BLACK,
|
LIGHT_BLACK,
|
||||||
N_COLORS
|
N_COLORS
|
||||||
|
} Color;
|
||||||
|
|
||||||
|
typedef struct _Pixel Pixel;
|
||||||
|
|
||||||
|
struct _Pixel
|
||||||
|
{
|
||||||
|
unsigned char R;
|
||||||
|
unsigned char G;
|
||||||
|
unsigned char B;
|
||||||
|
unsigned char Y;
|
||||||
|
unsigned char U;
|
||||||
|
unsigned char V;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pixel
|
static Pixel colors[N_COLORS] =
|
||||||
{
|
{
|
||||||
char R;
|
{191, 191, 191, 0, 0, 0}, /* GRAY */
|
||||||
char G;
|
{191, 191, 0, 0, 0, 0}, /* YELLOW */
|
||||||
char B;
|
{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 */
|
||||||
|
};
|
||||||
|
/* YUV values are computed in init_colors() */
|
||||||
|
|
||||||
|
typedef struct _DrawingData DrawingData;
|
||||||
|
|
||||||
|
typedef void (*DrawPixelFunc) (DrawingData *dd,
|
||||||
|
int x,
|
||||||
|
Pixel *pixel);
|
||||||
|
|
||||||
|
struct _DrawingData {
|
||||||
|
char* line;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int stride;
|
||||||
|
DrawPixelFunc draw_pixel;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pixel colors[N_COLORS] =
|
static inline void
|
||||||
|
update_yuv (Pixel *pixel)
|
||||||
{
|
{
|
||||||
{191, 191, 191}, /* GRAY */
|
uint16_t y, u, v;
|
||||||
{191, 191, 0}, /* YELLOW */
|
|
||||||
{0, 191, 191}, /* CYAN */
|
/* see https://en.wikipedia.org/wiki/YUV#Studio_swing_for_BT.601 */
|
||||||
{0, 191, 0}, /* GREEN */
|
|
||||||
{191, 0, 191}, /* MAGENTA */
|
y = 76 * pixel->R + 150 * pixel->G + 29 * pixel->B;
|
||||||
{191, 0, 0}, /* RED */
|
u = -43 * pixel->R - 84 * pixel->G + 127 * pixel->B;
|
||||||
{0, 0, 191}, /* BLUE */
|
v = 127 * pixel->R - 106 * pixel->G - 21 * pixel->B;
|
||||||
{19, 19, 19}, /* BLACK */
|
|
||||||
{0, 33, 76}, /* NEGATIVE I */
|
y = (y + 128) >> 8;
|
||||||
{255, 255, 255}, /* WHITE */
|
u = (u + 128) >> 8;
|
||||||
{49, 0, 107}, /* POSITIVE Q */
|
v = (v + 128) >> 8;
|
||||||
{9, 9, 9}, /* DARK BLACK */
|
|
||||||
{29, 29, 29}, /* LIGHT BLACK */
|
pixel->Y = y;
|
||||||
};
|
pixel->U = u + 128;
|
||||||
|
pixel->V = v + 128;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_line (char *data, struct pixel *c, int w)
|
init_colors (void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < w; i++) {
|
if (colors[WHITE].Y != 0) {
|
||||||
data[i * PIXEL_SIZE + 0] = c->R;
|
/* already computed */
|
||||||
data[i * PIXEL_SIZE + 1] = c->G;
|
return;
|
||||||
data[i * PIXEL_SIZE + 2] = c->B;
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < N_COLORS; i++) {
|
||||||
|
update_yuv (&colors[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DRAW_LINE(data,line,offset,color,width) \
|
static void
|
||||||
draw_line (data + (line * w + offset) * PIXEL_SIZE, colors + color, width);
|
draw_pixel_rgb (DrawingData *dd, int x, Pixel *color)
|
||||||
|
{
|
||||||
|
dd->line[3 * x + 0] = color->R;
|
||||||
|
dd->line[3 * x + 1] = color->G;
|
||||||
|
dd->line[3 * x + 2] = color->B;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_smpte_snow (SpaVideoTestSrc *this, char *data)
|
draw_pixel_uyvy (DrawingData *dd, int x, Pixel *color)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpaResult
|
||||||
|
drawing_data_init (DrawingData *dd,
|
||||||
|
SpaVideoTestSrc *this,
|
||||||
|
char* data)
|
||||||
|
{
|
||||||
|
SpaFormatVideo *format = &this->current_format;
|
||||||
|
SpaRectangle *size = &format->info.raw.size;
|
||||||
|
|
||||||
|
if (format->format.media_type != SPA_MEDIA_TYPE_VIDEO ||
|
||||||
|
format->format.media_subtype != SPA_MEDIA_SUBTYPE_RAW)
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
switch (format->info.raw.format) {
|
||||||
|
case SPA_VIDEO_FORMAT_RGB:
|
||||||
|
dd->draw_pixel = draw_pixel_rgb;
|
||||||
|
break;
|
||||||
|
case SPA_VIDEO_FORMAT_UYVY:
|
||||||
|
dd->draw_pixel = draw_pixel_uyvy;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd->line = data;
|
||||||
|
dd->width = size->width;
|
||||||
|
dd->height = size->height;
|
||||||
|
dd->stride = this->param_buffers.stride;
|
||||||
|
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
draw_pixels (DrawingData *dd,
|
||||||
|
int offset,
|
||||||
|
Color color,
|
||||||
|
int length)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = offset; x < offset + length; x++) {
|
||||||
|
dd->draw_pixel (dd, x, &colors[color]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
next_line (DrawingData *dd)
|
||||||
|
{
|
||||||
|
dd->line += dd->stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_smpte_snow (DrawingData *dd)
|
||||||
{
|
{
|
||||||
int h, w;
|
int h, w;
|
||||||
int y1, y2;
|
int y1, y2;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
w = GET_IMAGE_WIDTH (this);
|
w = dd->width;
|
||||||
h = GET_IMAGE_HEIGHT (this);
|
h = dd->height;
|
||||||
y1 = 2 * h / 3;
|
y1 = 2 * h / 3;
|
||||||
y2 = 3 * h / 4;
|
y2 = 3 * h / 4;
|
||||||
|
|
||||||
|
|
@ -95,49 +202,66 @@ draw_smpte_snow (SpaVideoTestSrc *this, char *data)
|
||||||
for (j = 0; j < 7; j++) {
|
for (j = 0; j < 7; j++) {
|
||||||
int x1 = j * w / 7;
|
int x1 = j * w / 7;
|
||||||
int x2 = (j + 1) * w / 7;
|
int x2 = (j + 1) * w / 7;
|
||||||
DRAW_LINE (data, i, x1, j, x2 - x1);
|
draw_pixels (dd, x1, j, x2 - x1);
|
||||||
}
|
}
|
||||||
|
next_line (dd);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = y1; i < y2; i++) {
|
for (i = y1; i < y2; i++) {
|
||||||
for (j = 0; j < 7; j++) {
|
for (j = 0; j < 7; j++) {
|
||||||
int x1 = j * w / 7;
|
int x1 = j * w / 7;
|
||||||
int x2 = (j + 1) * w / 7;
|
int x2 = (j + 1) * w / 7;
|
||||||
int c = (j & 1) ? BLACK : BLUE - j;
|
Color c = (j & 1) ? BLACK : BLUE - j;
|
||||||
|
|
||||||
DRAW_LINE (data, i, x1, c, x2 - x1);
|
draw_pixels (dd, x1, c, x2 - x1);
|
||||||
}
|
}
|
||||||
|
next_line (dd);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = y2; i < h; i++) {
|
for (i = y2; i < h; i++) {
|
||||||
int x = 0;
|
|
||||||
|
|
||||||
/* negative I */
|
/* negative I */
|
||||||
DRAW_LINE (data, i, x, NEG_I, w / 6);
|
draw_pixels (dd, 0 * w / 6, NEG_I, w / 6);
|
||||||
x += w / 6;
|
|
||||||
|
|
||||||
/* white */
|
/* white */
|
||||||
DRAW_LINE (data, i, x, WHITE, w / 6);
|
draw_pixels (dd, 1 * w / 6, WHITE, w / 6);
|
||||||
x += w / 6;
|
|
||||||
|
|
||||||
/* positive Q */
|
/* positive Q */
|
||||||
DRAW_LINE (data, i, x, POS_Q, w / 6);
|
draw_pixels (dd, 2 * w / 6, POS_Q, w / 6);
|
||||||
x += w / 6;
|
|
||||||
|
|
||||||
/* pluge */
|
/* pluge */
|
||||||
DRAW_LINE (data, i, x, DARK_BLACK, w / 12);
|
draw_pixels (dd, 6 * w / 12, DARK_BLACK, w / 12);
|
||||||
x += w / 12;
|
draw_pixels (dd, 7 * w / 12, BLACK, w / 12);
|
||||||
DRAW_LINE (data, i, x, BLACK, w / 12);
|
draw_pixels (dd, 8 * w / 12, LIGHT_BLACK, w / 12);
|
||||||
x += w / 12;
|
|
||||||
DRAW_LINE (data, i, x, LIGHT_BLACK, w / 12);
|
|
||||||
x += w / 12;
|
|
||||||
|
|
||||||
/* war of the ants (a.k.a. snow) */
|
/* war of the ants (a.k.a. snow) */
|
||||||
for (j = x; j < w; j++) {
|
for (j = 9 * w / 12; j < w; j++) {
|
||||||
|
Pixel p;
|
||||||
unsigned char r = rand ();
|
unsigned char r = rand ();
|
||||||
data[(i * w + j) * PIXEL_SIZE + 0] = r;
|
|
||||||
data[(i * w + j) * PIXEL_SIZE + 1] = r;
|
p.R = r;
|
||||||
data[(i * w + j) * PIXEL_SIZE + 2] = r;
|
p.G = r;
|
||||||
|
p.B = r;
|
||||||
|
update_yuv (&p);
|
||||||
|
dd->draw_pixel (dd, j, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_line (dd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SpaResult
|
||||||
|
draw (SpaVideoTestSrc *this, char *data)
|
||||||
|
{
|
||||||
|
DrawingData dd;
|
||||||
|
SpaResult res;
|
||||||
|
|
||||||
|
init_colors ();
|
||||||
|
|
||||||
|
res = drawing_data_init (&dd, this, data);
|
||||||
|
if (res != SPA_RESULT_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
draw_smpte_snow (&dd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,6 @@
|
||||||
#define FRAMES_TO_TIME(this,f) ((this->current_format.info.raw.framerate.denom * (f) * SPA_NSEC_PER_SEC) / \
|
#define FRAMES_TO_TIME(this,f) ((this->current_format.info.raw.framerate.denom * (f) * SPA_NSEC_PER_SEC) / \
|
||||||
(this->current_format.info.raw.framerate.num))
|
(this->current_format.info.raw.framerate.num))
|
||||||
|
|
||||||
#define STATE_GET_IMAGE_WIDTH(this) this->current_format.info.raw.size.width
|
|
||||||
#define STATE_GET_IMAGE_HEIGHT(this) this->current_format.info.raw.size.height
|
|
||||||
|
|
||||||
#define STATE_GET_IMAGE_SIZE(this) \
|
|
||||||
(this->bpp * STATE_GET_IMAGE_WIDTH(this) * STATE_GET_IMAGE_HEIGHT(this))
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t node;
|
uint32_t node;
|
||||||
uint32_t clock;
|
uint32_t clock;
|
||||||
|
|
@ -200,9 +194,7 @@ send_have_output (SpaVideoTestSrc *this)
|
||||||
static SpaResult
|
static SpaResult
|
||||||
fill_buffer (SpaVideoTestSrc *this, VTSBuffer *b)
|
fill_buffer (SpaVideoTestSrc *this, VTSBuffer *b)
|
||||||
{
|
{
|
||||||
draw_smpte_snow (this, b->ptr);
|
return draw (this, b->ptr);
|
||||||
|
|
||||||
return SPA_RESULT_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SpaResult update_loop_enabled (SpaVideoTestSrc *this, bool enabled);
|
static SpaResult update_loop_enabled (SpaVideoTestSrc *this, bool enabled);
|
||||||
|
|
@ -505,18 +497,29 @@ spa_videotestsrc_node_port_set_format (SpaNode *node,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->have_format) {
|
if (this->have_format) {
|
||||||
|
SpaVideoInfoRaw *raw_info = &this->current_format.info.raw;
|
||||||
|
|
||||||
|
switch (raw_info->format) {
|
||||||
|
case SPA_VIDEO_FORMAT_RGB:
|
||||||
|
this->bpp = 3;
|
||||||
|
break;
|
||||||
|
case SPA_VIDEO_FORMAT_UYVY:
|
||||||
|
this->bpp = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
this->info.maxbuffering = -1;
|
this->info.maxbuffering = -1;
|
||||||
this->info.latency = 0;
|
this->info.latency = 0;
|
||||||
|
|
||||||
this->bpp = 3;
|
|
||||||
|
|
||||||
this->info.n_params = 2;
|
this->info.n_params = 2;
|
||||||
this->info.params = this->params;
|
this->info.params = this->params;
|
||||||
this->params[0] = &this->param_buffers.param;
|
this->params[0] = &this->param_buffers.param;
|
||||||
this->param_buffers.param.type = SPA_ALLOC_PARAM_TYPE_BUFFERS;
|
this->param_buffers.param.type = SPA_ALLOC_PARAM_TYPE_BUFFERS;
|
||||||
this->param_buffers.param.size = sizeof (this->param_buffers);
|
this->param_buffers.param.size = sizeof (this->param_buffers);
|
||||||
this->param_buffers.minsize = STATE_GET_IMAGE_SIZE (this);
|
this->param_buffers.stride = this->bpp * raw_info->size.width;
|
||||||
this->param_buffers.stride = this->bpp * STATE_GET_IMAGE_WIDTH (this);
|
this->param_buffers.minsize = this->param_buffers.stride * raw_info->size.height;
|
||||||
this->param_buffers.min_buffers = 2;
|
this->param_buffers.min_buffers = 2;
|
||||||
this->param_buffers.max_buffers = 32;
|
this->param_buffers.max_buffers = 32;
|
||||||
this->param_buffers.align = 16;
|
this->param_buffers.align = 16;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue