Skip to content

Commit 63de992

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 d975f98 commit 63de992

File tree

1 file changed

+149
-46
lines changed

1 file changed

+149
-46
lines changed

drivers/video/video_sw_generator.c

Lines changed: 149 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,25 @@ struct video_sw_generator_data {
4646
uint32_t frame_rate;
4747
};
4848

49+
#define VIDEO_SW_GENERATOR_FORMAT_CAP(pixfmt) \
50+
{ \
51+
.pixelformat = pixfmt, \
52+
.width_min = 64, \
53+
.width_max = 1920, \
54+
.height_min = 64, \
55+
.height_max = 1080, \
56+
.width_step = 1, \
57+
.height_step = 1, \
58+
}
59+
4960
static const struct video_format_cap fmts[] = {
50-
{
51-
.pixelformat = VIDEO_PIX_FMT_RGB565,
52-
.width_min = 64,
53-
.width_max = 1920,
54-
.height_min = 64,
55-
.height_max = 1080,
56-
.width_step = 1,
57-
.height_step = 1,
58-
},
59-
{
60-
.pixelformat = VIDEO_PIX_FMT_XRGB32,
61-
.width_min = 64,
62-
.width_max = 1920,
63-
.height_min = 64,
64-
.height_max = 1080,
65-
.width_step = 1,
66-
.height_step = 1,
67-
},
61+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_YUYV),
62+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_RGB565),
63+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_XRGB32),
64+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_SRGGB8),
65+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_SGRBG8),
66+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_SBGGR8),
67+
VIDEO_SW_GENERATOR_FORMAT_CAP(VIDEO_PIX_FMT_SGBRG8),
6868
{0},
6969
};
7070

@@ -107,14 +107,21 @@ static int video_sw_generator_set_stream(const struct device *dev, bool enable,
107107
return 0;
108108
}
109109

110-
/* Black, Blue, Red, Purple, Green, Aqua, Yellow, White */
111-
uint16_t rgb565_colorbar_value[] = {
112-
0x0000, 0x001F, 0xF800, 0xF81F, 0x07E0, 0x07FF, 0xFFE0, 0xFFFF,
110+
static const uint8_t pattern_rggb8_idx[] = {0, 1, 1, 2};
111+
static const uint8_t pattern_bggr8_idx[] = {2, 1, 1, 0};
112+
static const uint8_t pattern_gbrg8_idx[] = {1, 2, 0, 1};
113+
static const uint8_t pattern_grbg8_idx[] = {1, 0, 2, 1};
114+
115+
/* White, Yellow, Cyan, Green, Magenta, Red, Blue, Black */
116+
117+
static const uint16_t pattern_8bars_yuv_bt709[8][3] = {
118+
{0xFE, 0x80, 0x7F}, {0xEC, 0x00, 0x8B}, {0xC8, 0x9D, 0x00}, {0xB6, 0x1D, 0x0C},
119+
{0x48, 0xE2, 0xF3}, {0x36, 0x62, 0xFF}, {0x12, 0xFF, 0x74}, {0x00, 0x80, 0x80},
113120
};
114121

115-
uint32_t xrgb32_colorbar_value[] = {
116-
0xFF000000, 0xFF0000FF, 0xFFFF0000, 0xFFFF00FF,
117-
0xFF00FF00, 0xFF00FFFF, 0xFFFFFF00, 0xFFFFFFFF,
122+
static const uint16_t pattern_8bars_rgb[8][3] = {
123+
{0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0x00}, {0x00, 0xFF, 0xFF}, {0x00, 0xFF, 0x00},
124+
{0xFF, 0x00, 0xFF}, {0xFF, 0x00, 0x00}, {0x00, 0x00, 0xFF}, {0x00, 0x00, 0x00},
118125
};
119126

120127
static inline int video_sw_generator_get_color_idx(uint16_t w, uint16_t width, bool hflip)
@@ -126,42 +133,138 @@ static inline int video_sw_generator_get_color_idx(uint16_t w, uint16_t width, b
126133
return 8 * w / width;
127134
}
128135

129-
static void video_sw_generator_fill_colorbar(struct video_sw_generator_data *data,
130-
struct video_buffer *vbuf)
136+
static uint16_t video_sw_generator_fill_yuyv(uint8_t *buffer, uint16_t width, bool hflip)
137+
{
138+
if (width % 2 != 0) {
139+
LOG_ERR("YUYV pixels always go by pairs");
140+
return 0;
141+
}
142+
143+
for (size_t w = 0; w < width; w += 2) {
144+
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
145+
146+
buffer[w * 2 + 0] = pattern_8bars_yuv_bt709[color_idx][0];
147+
buffer[w * 2 + 1] = pattern_8bars_yuv_bt709[color_idx][1];
148+
buffer[w * 2 + 2] = pattern_8bars_yuv_bt709[color_idx][0];
149+
buffer[w * 2 + 3] = pattern_8bars_yuv_bt709[color_idx][2];
150+
}
151+
return 1;
152+
}
153+
154+
static uint16_t video_sw_generator_fill_xrgb32(uint8_t *buffer, uint16_t width, bool hflip)
155+
{
156+
for (size_t w = 0; w < width; w++) {
157+
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
158+
159+
buffer[w * 4 + 0] = 0xff;
160+
buffer[w * 4 + 1] = pattern_8bars_rgb[color_idx][0];
161+
buffer[w * 4 + 2] = pattern_8bars_rgb[color_idx][1];
162+
buffer[w * 4 + 3] = pattern_8bars_rgb[color_idx][2];
163+
}
164+
return 1;
165+
}
166+
167+
static uint16_t video_sw_generator_fill_rgb565(uint8_t *buffer, uint16_t width, bool hflip)
168+
{
169+
for (size_t w = 0; w < width; w++) {
170+
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
171+
uint8_t r = pattern_8bars_rgb[color_idx][0] >> (8 - 5);
172+
uint8_t g = pattern_8bars_rgb[color_idx][1] >> (8 - 6);
173+
uint8_t b = pattern_8bars_rgb[color_idx][2] >> (8 - 5);
174+
175+
((uint16_t *)buffer)[w] = sys_cpu_to_le16((r << 11) | (g << 6) | (b << 0));
176+
}
177+
return 1;
178+
}
179+
180+
static uint16_t video_sw_generator_fill_bayer(uint8_t *buffer, uint16_t width, bool hflip,
181+
const uint8_t *bayer_idx)
182+
{
183+
uint8_t *row0 = buffer + 0;
184+
uint8_t *row1 = buffer + width;
185+
186+
if (width % 2 != 0) {
187+
LOG_ERR("Bayer pixels always go by pairs (vertically and horizontally)");
188+
return 0;
189+
}
190+
191+
for (size_t w = 0; w < width; w += 2) {
192+
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
193+
194+
row0[w + 0] = pattern_8bars_rgb[color_idx][bayer_idx[0]];
195+
row0[w + 1] = pattern_8bars_rgb[color_idx][bayer_idx[1]];
196+
row1[w + 0] = pattern_8bars_rgb[color_idx][bayer_idx[2]];
197+
row1[w + 1] = pattern_8bars_rgb[color_idx][bayer_idx[3]];
198+
}
199+
return 2;
200+
}
201+
202+
static int video_sw_generator_fill(const struct device *const dev, struct video_buffer *vbuf)
131203
{
132-
int bw = data->fmt.width / 8;
204+
struct video_sw_generator_data *data = dev->data;
133205
struct video_format *fmt = &data->fmt;
134206
size_t pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE;
135207
bool hflip = data->ctrls.hflip.val;
208+
uint16_t lines = 0;
136209

137-
vbuf->bytesused = 0;
210+
if (vbuf->size < pitch * 2) {
211+
LOG_ERR("At least 2 lines needed for bayer formats support");
212+
return -EINVAL;
213+
}
138214

139-
/* Generate the first line of data */
140-
for (int w = 0, i = 0; w < data->fmt.width; w++) {
141-
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
215+
/* Fill the first row of the emulated framebuffer */
216+
switch (data->fmt.pixelformat) {
217+
case VIDEO_PIX_FMT_YUYV:
218+
lines = video_sw_generator_fill_yuyv(vbuf->buffer, fmt->width, hflip);
219+
break;
220+
case VIDEO_PIX_FMT_XRGB32:
221+
lines = video_sw_generator_fill_xrgb32(vbuf->buffer, fmt->width, hflip);
222+
break;
223+
case VIDEO_PIX_FMT_RGB565:
224+
lines = video_sw_generator_fill_rgb565(vbuf->buffer, fmt->width, hflip);
225+
break;
226+
case VIDEO_PIX_FMT_SRGGB8:
227+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
228+
pattern_rggb8_idx);
229+
break;
230+
case VIDEO_PIX_FMT_SGBRG8:
231+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
232+
pattern_gbrg8_idx);
233+
break;
234+
case VIDEO_PIX_FMT_SBGGR8:
235+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
236+
pattern_bggr8_idx);
237+
break;
238+
case VIDEO_PIX_FMT_SGRBG8:
239+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
240+
pattern_grbg8_idx);
241+
break;
242+
default:
243+
CODE_UNREACHABLE;
244+
break;
245+
}
142246

143-
if (data->fmt.pixelformat == VIDEO_PIX_FMT_RGB565) {
144-
uint16_t *pixel = (uint16_t *)&vbuf->buffer[i];
145-
*pixel = sys_cpu_to_le16(rgb565_colorbar_value[color_idx]);
146-
} else if (data->fmt.pixelformat == VIDEO_PIX_FMT_XRGB32) {
147-
uint32_t *pixel = (uint32_t *)&vbuf->buffer[i];
148-
*pixel = sys_cpu_to_le32(xrgb32_colorbar_value[color_idx]);
149-
}
150-
i += video_bits_per_pixel(data->fmt.pixelformat) / BITS_PER_BYTE;
247+
if (lines == 0) {
248+
return -EINVAL;
151249
}
152250

153-
/* Duplicate the first line all over the buffer */
154-
for (int h = 1; h < data->fmt.height; h++) {
155-
if (vbuf->size < vbuf->bytesused + pitch) {
251+
/* How much was filled in so far */
252+
vbuf->bytesused = data->fmt.pitch * lines;
253+
254+
/* Duplicate the first line(s) all over the buffer */
255+
for (int h = lines; h < data->fmt.height; h += lines) {
256+
if (vbuf->size < vbuf->bytesused + pitch * lines) {
257+
LOG_WRN("Generation stopped early: buffer too small");
156258
break;
157259
}
158-
159-
memcpy(vbuf->buffer + h * pitch, vbuf->buffer, pitch);
160-
vbuf->bytesused += pitch;
260+
memcpy(vbuf->buffer + h * pitch, vbuf->buffer, pitch * lines);
261+
vbuf->bytesused += pitch * lines;
161262
}
162263

163264
vbuf->timestamp = k_uptime_get_32();
164265
vbuf->line_offset = 0;
266+
267+
return 0;
165268
}
166269

167270
static void video_sw_generator_worker(struct k_work *work)
@@ -181,7 +284,7 @@ static void video_sw_generator_worker(struct k_work *work)
181284

182285
switch (data->pattern) {
183286
case VIDEO_PATTERN_COLOR_BAR:
184-
video_sw_generator_fill_colorbar(data, vbuf);
287+
video_sw_generator_fill(data->dev, vbuf);
185288
break;
186289
}
187290

0 commit comments

Comments
 (0)