mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04: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.
|
||||
*/
|
||||
|
||||
#define PIXEL_SIZE 3
|
||||
|
||||
#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
|
||||
typedef enum
|
||||
{
|
||||
GRAY = 0,
|
||||
YELLOW,
|
||||
|
|
@ -38,56 +33,168 @@ enum
|
|||
DARK_BLACK,
|
||||
LIGHT_BLACK,
|
||||
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;
|
||||
char G;
|
||||
char B;
|
||||
{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 */
|
||||
};
|
||||
/* 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 */
|
||||
{191, 191, 0}, /* YELLOW */
|
||||
{0, 191, 191}, /* CYAN */
|
||||
{0, 191, 0}, /* GREEN */
|
||||
{191, 0, 191}, /* MAGENTA */
|
||||
{191, 0, 0}, /* RED */
|
||||
{0, 0, 191}, /* BLUE */
|
||||
{19, 19, 19}, /* BLACK */
|
||||
{0, 33, 76}, /* NEGATIVE I */
|
||||
{255, 255, 255}, /* WHITE */
|
||||
{49, 0, 107}, /* POSITIVE Q */
|
||||
{9, 9, 9}, /* DARK BLACK */
|
||||
{29, 29, 29}, /* LIGHT BLACK */
|
||||
};
|
||||
uint16_t y, u, v;
|
||||
|
||||
/* see https://en.wikipedia.org/wiki/YUV#Studio_swing_for_BT.601 */
|
||||
|
||||
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;
|
||||
|
||||
y = (y + 128) >> 8;
|
||||
u = (u + 128) >> 8;
|
||||
v = (v + 128) >> 8;
|
||||
|
||||
pixel->Y = y;
|
||||
pixel->U = u + 128;
|
||||
pixel->V = v + 128;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_line (char *data, struct pixel *c, int w)
|
||||
init_colors (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < w; i++) {
|
||||
data[i * PIXEL_SIZE + 0] = c->R;
|
||||
data[i * PIXEL_SIZE + 1] = c->G;
|
||||
data[i * PIXEL_SIZE + 2] = c->B;
|
||||
if (colors[WHITE].Y != 0) {
|
||||
/* already computed */
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < N_COLORS; i++) {
|
||||
update_yuv (&colors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#define DRAW_LINE(data,line,offset,color,width) \
|
||||
draw_line (data + (line * w + offset) * PIXEL_SIZE, colors + color, width);
|
||||
static void
|
||||
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
|
||||
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 y1, y2;
|
||||
int i, j;
|
||||
|
||||
w = GET_IMAGE_WIDTH (this);
|
||||
h = GET_IMAGE_HEIGHT (this);
|
||||
w = dd->width;
|
||||
h = dd->height;
|
||||
y1 = 2 * h / 3;
|
||||
y2 = 3 * h / 4;
|
||||
|
||||
|
|
@ -95,49 +202,66 @@ draw_smpte_snow (SpaVideoTestSrc *this, char *data)
|
|||
for (j = 0; j < 7; j++) {
|
||||
int x1 = j * 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 (j = 0; j < 7; j++) {
|
||||
int x1 = j * 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++) {
|
||||
int x = 0;
|
||||
|
||||
/* negative I */
|
||||
DRAW_LINE (data, i, x, NEG_I, w / 6);
|
||||
x += w / 6;
|
||||
draw_pixels (dd, 0 * w / 6, NEG_I, w / 6);
|
||||
|
||||
/* white */
|
||||
DRAW_LINE (data, i, x, WHITE, w / 6);
|
||||
x += w / 6;
|
||||
draw_pixels (dd, 1 * w / 6, WHITE, w / 6);
|
||||
|
||||
/* positive Q */
|
||||
DRAW_LINE (data, i, x, POS_Q, w / 6);
|
||||
x += w / 6;
|
||||
draw_pixels (dd, 2 * w / 6, POS_Q, w / 6);
|
||||
|
||||
/* pluge */
|
||||
DRAW_LINE (data, i, x, DARK_BLACK, w / 12);
|
||||
x += w / 12;
|
||||
DRAW_LINE (data, i, x, BLACK, w / 12);
|
||||
x += w / 12;
|
||||
DRAW_LINE (data, i, x, LIGHT_BLACK, w / 12);
|
||||
x += w / 12;
|
||||
draw_pixels (dd, 6 * w / 12, DARK_BLACK, w / 12);
|
||||
draw_pixels (dd, 7 * w / 12, BLACK, w / 12);
|
||||
draw_pixels (dd, 8 * w / 12, LIGHT_BLACK, w / 12);
|
||||
|
||||
/* 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 ();
|
||||
data[(i * w + j) * PIXEL_SIZE + 0] = r;
|
||||
data[(i * w + j) * PIXEL_SIZE + 1] = r;
|
||||
data[(i * w + j) * PIXEL_SIZE + 2] = r;
|
||||
|
||||
p.R = 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) / \
|
||||
(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 {
|
||||
uint32_t node;
|
||||
uint32_t clock;
|
||||
|
|
@ -200,9 +194,7 @@ send_have_output (SpaVideoTestSrc *this)
|
|||
static SpaResult
|
||||
fill_buffer (SpaVideoTestSrc *this, VTSBuffer *b)
|
||||
{
|
||||
draw_smpte_snow (this, b->ptr);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
return draw (this, b->ptr);
|
||||
}
|
||||
|
||||
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) {
|
||||
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.latency = 0;
|
||||
|
||||
this->bpp = 3;
|
||||
|
||||
this->info.n_params = 2;
|
||||
this->info.params = this->params;
|
||||
this->params[0] = &this->param_buffers.param;
|
||||
this->param_buffers.param.type = SPA_ALLOC_PARAM_TYPE_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 * STATE_GET_IMAGE_WIDTH (this);
|
||||
this->param_buffers.stride = this->bpp * raw_info->size.width;
|
||||
this->param_buffers.minsize = this->param_buffers.stride * raw_info->size.height;
|
||||
this->param_buffers.min_buffers = 2;
|
||||
this->param_buffers.max_buffers = 32;
|
||||
this->param_buffers.align = 16;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue