Skip to content

Commit 370efec

Browse files
committed
drivers: video: sw_generator: add support for bayer and YUV formats
This refactors the pattern generator functions to also offer bayer formats as input. 4 variant of bayer formats are proposed. The pixel packing is also now split from the color selection: only a single RGB and single YUV array used by all the pattern generators. Signed-off-by: Josuah Demangeon <me@josuah.net>
1 parent d803873 commit 370efec

File tree

1 file changed

+125
-48
lines changed

1 file changed

+125
-48
lines changed

drivers/video/video_sw_generator.c

Lines changed: 125 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,25 +40,25 @@ struct video_sw_generator_data {
4040
uint32_t frame_rate;
4141
};
4242

43+
#define VIDEO_SW_GENERATOR_FORMAT_CAP(pixfmt) \
44+
{ \
45+
.pixelformat = pixfmt, \
46+
.width_min = 64, \
47+
.width_max = 1920, \
48+
.height_min = 64, \
49+
.height_max = 1080, \
50+
.width_step = 1, \
51+
.height_step = 1, \
52+
}
53+
4354
static const struct video_format_cap fmts[] = {
44-
{
45-
.pixelformat = VIDEO_PIX_FMT_RGB565,
46-
.width_min = 64,
47-
.width_max = 1920,
48-
.height_min = 64,
49-
.height_max = 1080,
50-
.width_step = 1,
51-
.height_step = 1,
52-
},
53-
{
54-
.pixelformat = VIDEO_PIX_FMT_XRGB32,
55-
.width_min = 64,
56-
.width_max = 1920,
57-
.height_min = 64,
58-
.height_max = 1080,
59-
.width_step = 1,
60-
.height_step = 1,
61-
},
55+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_YUYV),
56+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_RGB565),
57+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_XRGB32),
58+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_RGGB8),
59+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_GRBG8),
60+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_BGGR8),
61+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_GBRG8),
6262
{0},
6363
};
6464

@@ -85,6 +85,11 @@ static int video_sw_generator_set_fmt(const struct device *dev, enum video_endpo
8585
return -ENOTSUP;
8686
}
8787

88+
if (fmt->pitch != fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE) {
89+
LOG_ERR("The pitch is not consistent with the other parameters");
90+
return -EINVAL;
91+
}
92+
8893
data->fmt = *fmt;
8994

9095
return 0;
@@ -117,51 +122,123 @@ static int video_sw_generator_set_stream(const struct device *dev, bool enable)
117122
return 0;
118123
}
119124

120-
/* Black, Blue, Red, Purple, Green, Aqua, Yellow, White */
121-
uint16_t rgb565_colorbar_value[] = {
122-
0x0000, 0x001F, 0xF800, 0xF81F, 0x07E0, 0x07FF, 0xFFE0, 0xFFFF,
125+
static const uint8_t pattern_rggb8_idx[] = {0, 1, 1, 2};
126+
static const uint8_t pattern_bggr8_idx[] = {2, 1, 1, 0};
127+
static const uint8_t pattern_gbrg8_idx[] = {1, 2, 0, 1};
128+
static const uint8_t pattern_grbg8_idx[] = {1, 0, 2, 1};
129+
130+
/* White, Yellow, Cyan, Green, Magenta, Red, Blue, Black */
131+
132+
static const uint16_t pattern_8bars_yuv_bt709[8][3] = {
133+
{0xFE, 0x80, 0x7F}, {0xEC, 0x00, 0x8B}, {0xC8, 0x9D, 0x00}, {0xB6, 0x1D, 0x0C},
134+
{0x48, 0xE2, 0xF3}, {0x36, 0x62, 0xFF}, {0x12, 0xFF, 0x74}, {0x00, 0x80, 0x80},
123135
};
124136

125-
uint32_t xrgb32_colorbar_value[] = {
126-
0xFF000000, 0xFF0000FF, 0xFFFF0000, 0xFFFF00FF,
127-
0xFF00FF00, 0xFF00FFFF, 0xFFFFFF00, 0xFFFFFFFF,
137+
static const uint16_t pattern_8bars_rgb[8][3] = {
138+
{0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0x00}, {0x00, 0xFF, 0xFF}, {0x00, 0xFF, 0x00},
139+
{0xFF, 0x00, 0xFF}, {0xFF, 0x00, 0x00}, {0x00, 0x00, 0xFF}, {0x00, 0x00, 0x00},
128140
};
129141

130-
static void video_sw_generator_fill_colorbar(struct video_sw_generator_data *data,
131-
struct video_buffer *vbuf)
142+
static int video_sw_generator_fill_yuyv(uint8_t *buffer, uint16_t width)
132143
{
133-
int bw = data->fmt.width / 8;
144+
for (size_t w = 0; w + 2 <= width; w += 2) {
145+
buffer[w * 2 + 0] = pattern_8bars_yuv_bt709[8 * w / width][0];
146+
buffer[w * 2 + 1] = pattern_8bars_yuv_bt709[8 * w / width][1];
147+
buffer[w * 2 + 2] = pattern_8bars_yuv_bt709[8 * w / width][0];
148+
buffer[w * 2 + 3] = pattern_8bars_yuv_bt709[8 * w / width][2];
149+
}
150+
return 1;
151+
}
134152

135-
vbuf->bytesused = 0;
153+
static int video_sw_generator_fill_xrgb32(uint8_t *buffer, uint16_t width)
154+
{
155+
for (size_t w = 0; w < width; w++) {
156+
buffer[w * 4 + 0] = 0xff;
157+
buffer[w * 4 + 1] = pattern_8bars_rgb[8 * w / width][0];
158+
buffer[w * 4 + 2] = pattern_8bars_rgb[8 * w / width][1];
159+
buffer[w * 4 + 3] = pattern_8bars_rgb[8 * w / width][2];
160+
}
161+
return 1;
162+
}
136163

137-
if (vbuf->size < data->fmt.pitch) {
138-
LOG_WRN("Buffer %p has only %u bytes, shorter than pitch %u",
164+
static int video_sw_generator_fill_rgb565(uint8_t *buffer, uint16_t width)
165+
{
166+
for (size_t w = 0; w < width; w++) {
167+
uint8_t r = pattern_8bars_rgb[8 * w / width][0] >> (8 - 5);
168+
uint8_t g = pattern_8bars_rgb[8 * w / width][1] >> (8 - 6);
169+
uint8_t b = pattern_8bars_rgb[8 * w / width][2] >> (8 - 5);
170+
171+
((uint16_t *)buffer)[w] = sys_cpu_to_le16((r << 11) | (g << 6) | (b << 0));
172+
}
173+
return 1;
174+
}
175+
176+
static int video_sw_generator_fill_bayer(uint8_t *buffer, uint16_t width, const uint8_t *idx)
177+
{
178+
uint8_t *row0 = buffer + 0;
179+
uint8_t *row1 = buffer + width;
180+
181+
for (size_t w = 0; w + 2 <= width; w += 2) {
182+
row0[w + 0] = pattern_8bars_rgb[8 * w / width][idx[0]];
183+
row0[w + 1] = pattern_8bars_rgb[8 * w / width][idx[1]];
184+
row1[w + 0] = pattern_8bars_rgb[8 * w / width][idx[2]];
185+
row1[w + 1] = pattern_8bars_rgb[8 * w / width][idx[3]];
186+
}
187+
return 2;
188+
}
189+
190+
static void video_sw_generator_fill(const struct device *const dev, struct video_buffer *vbuf)
191+
{
192+
struct video_sw_generator_data *data = dev->data;
193+
struct video_format *fmt = &data->fmt;
194+
int lines = 1;
195+
196+
if (vbuf->size < data->fmt.pitch * 2) {
197+
LOG_WRN("Buffer %p has only %u bytes, less than two lines (%u bytes)",
139198
vbuf, vbuf->size, data->fmt.pitch);
140199
return;
141200
}
142201

143-
/* Generate the first line of data */
144-
for (int w = 0, i = 0; w < data->fmt.width; w++) {
145-
int color_idx = data->ctrl_vflip ? 7 - w / bw : w / bw;
146-
147-
if (data->fmt.pixelformat == VIDEO_PIX_FMT_RGB565) {
148-
uint16_t *pixel = (uint16_t *)&vbuf->buffer[i];
149-
*pixel = sys_cpu_to_le16(rgb565_colorbar_value[color_idx]);
150-
} else if (data->fmt.pixelformat == VIDEO_PIX_FMT_XRGB32) {
151-
uint32_t *pixel = (uint32_t *)&vbuf->buffer[i];
152-
*pixel = sys_cpu_to_le32(xrgb32_colorbar_value[color_idx]);
153-
}
154-
i += video_bits_per_pixel(data->fmt.pixelformat) / BITS_PER_BYTE;
202+
/* Fill the first row of the emulated framebuffer */
203+
switch (data->fmt.pixelformat) {
204+
case VIDEO_PIX_FMT_YUYV:
205+
lines = video_sw_generator_fill_yuyv(vbuf->buffer, fmt->width);
206+
break;
207+
case VIDEO_PIX_FMT_XRGB32:
208+
lines = video_sw_generator_fill_xrgb32(vbuf->buffer, fmt->width);
209+
break;
210+
case VIDEO_PIX_FMT_RGB565:
211+
lines = video_sw_generator_fill_rgb565(vbuf->buffer, fmt->width);
212+
break;
213+
case VIDEO_PIX_FMT_RGGB8:
214+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, pattern_rggb8_idx);
215+
break;
216+
case VIDEO_PIX_FMT_GBRG8:
217+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, pattern_gbrg8_idx);
218+
break;
219+
case VIDEO_PIX_FMT_BGGR8:
220+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, pattern_bggr8_idx);
221+
break;
222+
case VIDEO_PIX_FMT_GRBG8:
223+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, pattern_grbg8_idx);
224+
break;
225+
default:
226+
LOG_WRN("Unsupported pixel format %x, filling with 0x55", data->fmt.pixelformat);
227+
memset(vbuf->buffer, 0x55, data->fmt.pitch);
228+
break;
155229
}
156230

231+
/* How much was filled insofar */
232+
vbuf->bytesused = data->fmt.pitch * lines;
233+
157234
/* Duplicate the first line all over the buffer */
158-
for (int h = 1; h < data->fmt.height; h++) {
159-
if (vbuf->size < vbuf->bytesused + data->fmt.pitch) {
235+
for (int h = lines; h < data->fmt.height; h += lines) {
236+
if (vbuf->size < vbuf->bytesused + data->fmt.pitch * lines) {
237+
LOG_WRN("Generation stopped early: buffer too small");
160238
break;
161239
}
162-
163-
memcpy(vbuf->buffer + h * data->fmt.pitch, vbuf->buffer, data->fmt.pitch);
164-
vbuf->bytesused += data->fmt.pitch;
240+
memcpy(vbuf->buffer + h * data->fmt.pitch, vbuf->buffer, data->fmt.pitch * lines);
241+
vbuf->bytesused += data->fmt.pitch * lines;
165242
}
166243

167244
vbuf->timestamp = k_uptime_get_32();
@@ -185,7 +262,7 @@ static void video_sw_generator_worker(struct k_work *work)
185262

186263
switch (data->pattern) {
187264
case VIDEO_PATTERN_COLOR_BAR:
188-
video_sw_generator_fill_colorbar(data, vbuf);
265+
video_sw_generator_fill(data->dev, vbuf);
189266
break;
190267
}
191268

0 commit comments

Comments
 (0)