videotestsrc: add support for UYVY

This commit is contained in:
David Svensson Fors 2016-11-21 09:05:42 +01:00 committed by Wim Taymans
parent ddcbca3c4b
commit 5c56fbdfc2
2 changed files with 196 additions and 69 deletions

View file

@ -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;
}

View file

@ -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;