Skip to content

Commit 0eb3a59

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 152175b commit 0eb3a59

File tree

1 file changed

+136
-48
lines changed

1 file changed

+136
-48
lines changed

drivers/video/video_sw_generator.c

Lines changed: 136 additions & 48 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

@@ -114,14 +114,21 @@ static int video_sw_generator_set_stream(const struct device *dev, bool enable,
114114
return 0;
115115
}
116116

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

122-
uint32_t xrgb32_colorbar_value[] = {
123-
0xFF000000, 0xFF0000FF, 0xFFFF0000, 0xFFFF00FF,
124-
0xFF00FF00, 0xFF00FFFF, 0xFFFFFF00, 0xFFFFFFFF,
129+
static const uint16_t pattern_8bars_rgb[8][3] = {
130+
{0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0x00}, {0x00, 0xFF, 0xFF}, {0x00, 0xFF, 0x00},
131+
{0xFF, 0x00, 0xFF}, {0xFF, 0x00, 0x00}, {0x00, 0x00, 0xFF}, {0x00, 0x00, 0x00},
125132
};
126133

127134
static inline int video_sw_generator_get_color_idx(uint16_t w, uint16_t width, bool hflip)
@@ -133,38 +140,119 @@ static inline int video_sw_generator_get_color_idx(uint16_t w, uint16_t width, b
133140
return 8 * w / width;
134141
}
135142

136-
static void video_sw_generator_fill_colorbar(struct video_sw_generator_data *data,
137-
struct video_buffer *vbuf)
143+
static int video_sw_generator_fill_yuyv(uint8_t *buffer, uint16_t width, bool hflip)
138144
{
139-
int bw = data->fmt.width / 8;
140-
struct video_format *fmt = &data->fmt;
141-
size_t pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE;
142-
bool hflip = data->ctrls.hflip.val;
145+
__ASSERT(width % 2 == 0, "YUYV pixels always go by pairs");
146+
147+
for (size_t w = 0; w + 2 <= width; w += 2) {
148+
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
143149

144-
vbuf->bytesused = 0;
150+
buffer[w * 2 + 0] = pattern_8bars_yuv_bt709[color_idx][0];
151+
buffer[w * 2 + 1] = pattern_8bars_yuv_bt709[color_idx][1];
152+
buffer[w * 2 + 2] = pattern_8bars_yuv_bt709[color_idx][0];
153+
buffer[w * 2 + 3] = pattern_8bars_yuv_bt709[color_idx][2];
154+
}
155+
return 1;
156+
}
145157

146-
/* Generate the first line of data */
147-
for (int w = 0, i = 0; w < data->fmt.width; w++) {
158+
static int video_sw_generator_fill_xrgb32(uint8_t *buffer, uint16_t width, bool hflip)
159+
{
160+
for (size_t w = 0; w < width; w++) {
148161
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
149162

150-
if (data->fmt.pixelformat == VIDEO_PIX_FMT_RGB565) {
151-
uint16_t *pixel = (uint16_t *)&vbuf->buffer[i];
152-
*pixel = sys_cpu_to_le16(rgb565_colorbar_value[color_idx]);
153-
} else if (data->fmt.pixelformat == VIDEO_PIX_FMT_XRGB32) {
154-
uint32_t *pixel = (uint32_t *)&vbuf->buffer[i];
155-
*pixel = sys_cpu_to_le32(xrgb32_colorbar_value[color_idx]);
156-
}
157-
i += video_bits_per_pixel(data->fmt.pixelformat) / BITS_PER_BYTE;
163+
buffer[w * 4 + 0] = 0xff;
164+
buffer[w * 4 + 1] = pattern_8bars_rgb[color_idx][0];
165+
buffer[w * 4 + 2] = pattern_8bars_rgb[color_idx][1];
166+
buffer[w * 4 + 3] = pattern_8bars_rgb[color_idx][2];
167+
}
168+
return 1;
169+
}
170+
171+
static int video_sw_generator_fill_rgb565(uint8_t *buffer, uint16_t width, bool hflip)
172+
{
173+
for (size_t w = 0; w < width; w++) {
174+
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
175+
uint8_t r = pattern_8bars_rgb[color_idx][0] >> (8 - 5);
176+
uint8_t g = pattern_8bars_rgb[color_idx][1] >> (8 - 6);
177+
uint8_t b = pattern_8bars_rgb[color_idx][2] >> (8 - 5);
178+
179+
((uint16_t *)buffer)[w] = sys_cpu_to_le16((r << 11) | (g << 6) | (b << 0));
180+
}
181+
return 1;
182+
}
183+
184+
static int video_sw_generator_fill_bayer(uint8_t *buffer, uint16_t width, bool hflip,
185+
const uint8_t *bayer_idx)
186+
{
187+
uint8_t *row0 = buffer + 0;
188+
uint8_t *row1 = buffer + width;
189+
190+
__ASSERT(width % 2 == 0, "Bayer pixels always go by pairs (vertically and horizontally)");
191+
192+
for (size_t w = 0; w + 2 <= width; w += 2) {
193+
int color_idx = video_sw_generator_get_color_idx(w, width, hflip);
194+
195+
row0[w + 0] = pattern_8bars_rgb[color_idx][bayer_idx[0]];
196+
row0[w + 1] = pattern_8bars_rgb[color_idx][bayer_idx[1]];
197+
row1[w + 0] = pattern_8bars_rgb[color_idx][bayer_idx[2]];
198+
row1[w + 1] = pattern_8bars_rgb[color_idx][bayer_idx[3]];
158199
}
200+
return 2;
201+
}
202+
203+
static void video_sw_generator_fill(const struct device *const dev, struct video_buffer *vbuf)
204+
{
205+
struct video_sw_generator_data *data = dev->data;
206+
struct video_format *fmt = &data->fmt;
207+
size_t pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE;
208+
bool hflip = data->ctrls.hflip.val;
209+
int lines = 1;
159210

160-
/* Duplicate the first line all over the buffer */
161-
for (int h = 1; h < data->fmt.height; h++) {
162-
if (vbuf->size < vbuf->bytesused + pitch) {
211+
__ASSERT(vbuf->size >= pitch * 2, "At least 2 lines needed for bayer formats support");
212+
/* Fill the first row of the emulated framebuffer */
213+
switch (data->fmt.pixelformat) {
214+
case VIDEO_PIX_FMT_YUYV:
215+
lines = video_sw_generator_fill_yuyv(vbuf->buffer, fmt->width, hflip);
216+
break;
217+
case VIDEO_PIX_FMT_XRGB32:
218+
lines = video_sw_generator_fill_xrgb32(vbuf->buffer, fmt->width, hflip);
219+
break;
220+
case VIDEO_PIX_FMT_RGB565:
221+
lines = video_sw_generator_fill_rgb565(vbuf->buffer, fmt->width, hflip);
222+
break;
223+
case VIDEO_PIX_FMT_SRGGB8:
224+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
225+
pattern_rggb8_idx);
226+
break;
227+
case VIDEO_PIX_FMT_SGBRG8:
228+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
229+
pattern_gbrg8_idx);
230+
break;
231+
case VIDEO_PIX_FMT_SBGGR8:
232+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
233+
pattern_bggr8_idx);
234+
break;
235+
case VIDEO_PIX_FMT_SGRBG8:
236+
lines = video_sw_generator_fill_bayer(vbuf->buffer, fmt->width, hflip,
237+
pattern_grbg8_idx);
238+
break;
239+
default:
240+
LOG_WRN("Unsupported pixel format %x, filling with 0x55", data->fmt.pixelformat);
241+
memset(vbuf->buffer, 0x55, data->fmt.pitch);
242+
break;
243+
}
244+
245+
/* How much was filled insofar */
246+
vbuf->bytesused = data->fmt.pitch * lines;
247+
248+
/* Duplicate the first line(s) all over the buffer */
249+
for (int h = lines; h < data->fmt.height; h += lines) {
250+
if (vbuf->size < vbuf->bytesused + pitch * lines) {
251+
LOG_WRN("Generation stopped early: buffer too small");
163252
break;
164253
}
165-
166-
memcpy(vbuf->buffer + h * pitch, vbuf->buffer, pitch);
167-
vbuf->bytesused += pitch;
254+
memcpy(vbuf->buffer + h * pitch, vbuf->buffer, pitch * lines);
255+
vbuf->bytesused += pitch * lines;
168256
}
169257

170258
vbuf->timestamp = k_uptime_get_32();
@@ -188,7 +276,7 @@ static void video_sw_generator_worker(struct k_work *work)
188276

189277
switch (data->pattern) {
190278
case VIDEO_PATTERN_COLOR_BAR:
191-
video_sw_generator_fill_colorbar(data, vbuf);
279+
video_sw_generator_fill(data->dev, vbuf);
192280
break;
193281
}
194282

0 commit comments

Comments
 (0)