@@ -46,25 +46,25 @@ struct video_sw_generator_data {
46
46
uint32_t frame_rate ;
47
47
};
48
48
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
+
49
60
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 ),
68
68
{0 },
69
69
};
70
70
@@ -109,14 +109,21 @@ static int video_sw_generator_set_stream(const struct device *dev, bool enable,
109
109
return 0 ;
110
110
}
111
111
112
- /* Black, Blue, Red, Purple, Green, Aqua, Yellow, White */
113
- uint16_t rgb565_colorbar_value [] = {
114
- 0x0000 , 0x001F , 0xF800 , 0xF81F , 0x07E0 , 0x07FF , 0xFFE0 , 0xFFFF ,
112
+ static const uint8_t pattern_rggb_idx [] = {0 , 1 , 1 , 2 };
113
+ static const uint8_t pattern_bggr_idx [] = {2 , 1 , 1 , 0 };
114
+ static const uint8_t pattern_gbrg_idx [] = {1 , 2 , 0 , 1 };
115
+ static const uint8_t pattern_grbg_idx [] = {1 , 0 , 2 , 1 };
116
+
117
+ /* White, Yellow, Cyan, Green, Magenta, Red, Blue, Black */
118
+
119
+ static const uint16_t pattern_8bars_yuv_bt709 [8 ][3 ] = {
120
+ {0xFE , 0x80 , 0x7F }, {0xEC , 0x00 , 0x8B }, {0xC8 , 0x9D , 0x00 }, {0xB6 , 0x1D , 0x0C },
121
+ {0x48 , 0xE2 , 0xF3 }, {0x36 , 0x62 , 0xFF }, {0x12 , 0xFF , 0x74 }, {0x00 , 0x80 , 0x80 },
115
122
};
116
123
117
- uint32_t xrgb32_colorbar_value [ ] = {
118
- 0xFF000000 , 0xFF0000FF , 0xFFFF0000 , 0xFFFF00FF ,
119
- 0xFF00FF00 , 0xFF00FFFF , 0xFFFFFF00 , 0xFFFFFFFF ,
124
+ static const uint16_t pattern_8bars_rgb [ 8 ][ 3 ] = {
125
+ { 0xFF , 0xFF , 0xFF }, { 0xFF , 0xFF , 0x00 }, { 0x00 , 0xFF , 0xFF }, { 0x00 , 0xFF , 0x00 } ,
126
+ { 0xFF , 0x00 , 0xFF }, { 0xFF , 0x00 , 0x00 }, { 0x00 , 0x00 , 0xFF }, { 0x00 , 0x00 , 0x00 } ,
120
127
};
121
128
122
129
static inline int video_sw_generator_get_color_idx (uint16_t w , uint16_t width , bool hflip )
@@ -128,42 +135,138 @@ static inline int video_sw_generator_get_color_idx(uint16_t w, uint16_t width, b
128
135
return 8 * w / width ;
129
136
}
130
137
131
- static void video_sw_generator_fill_colorbar (struct video_sw_generator_data * data ,
132
- struct video_buffer * vbuf )
138
+ static uint16_t video_sw_generator_fill_yuyv (uint8_t * buffer , uint16_t width , bool hflip )
139
+ {
140
+ if (width % 2 != 0 ) {
141
+ LOG_ERR ("YUYV pixels always go by pairs" );
142
+ return 0 ;
143
+ }
144
+
145
+ for (size_t w = 0 ; w < width ; w += 2 ) {
146
+ int color_idx = video_sw_generator_get_color_idx (w , width , hflip );
147
+
148
+ buffer [w * 2 + 0 ] = pattern_8bars_yuv_bt709 [color_idx ][0 ];
149
+ buffer [w * 2 + 1 ] = pattern_8bars_yuv_bt709 [color_idx ][1 ];
150
+ buffer [w * 2 + 2 ] = pattern_8bars_yuv_bt709 [color_idx ][0 ];
151
+ buffer [w * 2 + 3 ] = pattern_8bars_yuv_bt709 [color_idx ][2 ];
152
+ }
153
+ return 1 ;
154
+ }
155
+
156
+ static uint16_t video_sw_generator_fill_xrgb32 (uint8_t * buffer , uint16_t width , bool hflip )
157
+ {
158
+ for (size_t w = 0 ; w < width ; w ++ ) {
159
+ int color_idx = video_sw_generator_get_color_idx (w , width , hflip );
160
+
161
+ buffer [w * 4 + 0 ] = 0xff ;
162
+ buffer [w * 4 + 1 ] = pattern_8bars_rgb [color_idx ][0 ];
163
+ buffer [w * 4 + 2 ] = pattern_8bars_rgb [color_idx ][1 ];
164
+ buffer [w * 4 + 3 ] = pattern_8bars_rgb [color_idx ][2 ];
165
+ }
166
+ return 1 ;
167
+ }
168
+
169
+ static uint16_t video_sw_generator_fill_rgb565 (uint8_t * buffer , uint16_t width , bool hflip )
170
+ {
171
+ for (size_t w = 0 ; w < width ; w ++ ) {
172
+ int color_idx = video_sw_generator_get_color_idx (w , width , hflip );
173
+ uint8_t r = pattern_8bars_rgb [color_idx ][0 ] >> (8 - 5 );
174
+ uint8_t g = pattern_8bars_rgb [color_idx ][1 ] >> (8 - 6 );
175
+ uint8_t b = pattern_8bars_rgb [color_idx ][2 ] >> (8 - 5 );
176
+
177
+ ((uint16_t * )buffer )[w ] = sys_cpu_to_le16 ((r << 11 ) | (g << 6 ) | (b << 0 ));
178
+ }
179
+ return 1 ;
180
+ }
181
+
182
+ static uint16_t video_sw_generator_fill_bayer8 (uint8_t * buffer , uint16_t width , bool hflip ,
183
+ const uint8_t * bayer_idx )
184
+ {
185
+ uint8_t * row0 = buffer + 0 ;
186
+ uint8_t * row1 = buffer + width ;
187
+
188
+ if (width % 2 != 0 ) {
189
+ LOG_ERR ("Bayer pixels always go by pairs (vertically and horizontally)" );
190
+ return 0 ;
191
+ }
192
+
193
+ for (size_t w = 0 ; w < width ; w += 2 ) {
194
+ int color_idx = video_sw_generator_get_color_idx (w , width , hflip );
195
+
196
+ row0 [w + 0 ] = pattern_8bars_rgb [color_idx ][bayer_idx [0 ]];
197
+ row0 [w + 1 ] = pattern_8bars_rgb [color_idx ][bayer_idx [1 ]];
198
+ row1 [w + 0 ] = pattern_8bars_rgb [color_idx ][bayer_idx [2 ]];
199
+ row1 [w + 1 ] = pattern_8bars_rgb [color_idx ][bayer_idx [3 ]];
200
+ }
201
+ return 2 ;
202
+ }
203
+
204
+ static int video_sw_generator_fill (const struct device * const dev , struct video_buffer * vbuf )
133
205
{
134
- int bw = data -> fmt . width / 8 ;
206
+ struct video_sw_generator_data * data = dev -> data ;
135
207
struct video_format * fmt = & data -> fmt ;
136
208
size_t pitch = fmt -> width * video_bits_per_pixel (fmt -> pixelformat ) / BITS_PER_BYTE ;
137
209
bool hflip = data -> ctrls .hflip .val ;
210
+ uint16_t lines = 0 ;
138
211
139
- vbuf -> bytesused = 0 ;
212
+ if (vbuf -> size < pitch * 2 ) {
213
+ LOG_ERR ("At least 2 lines needed for bayer formats support" );
214
+ return - EINVAL ;
215
+ }
140
216
141
- /* Generate the first line of data */
142
- for (int w = 0 , i = 0 ; w < data -> fmt .width ; w ++ ) {
143
- int color_idx = video_sw_generator_get_color_idx (w , width , hflip );
217
+ /* Fill the first row of the emulated framebuffer */
218
+ switch (data -> fmt .pixelformat ) {
219
+ case VIDEO_PIX_FMT_YUYV :
220
+ lines = video_sw_generator_fill_yuyv (vbuf -> buffer , fmt -> width , hflip );
221
+ break ;
222
+ case VIDEO_PIX_FMT_XRGB32 :
223
+ lines = video_sw_generator_fill_xrgb32 (vbuf -> buffer , fmt -> width , hflip );
224
+ break ;
225
+ case VIDEO_PIX_FMT_RGB565 :
226
+ lines = video_sw_generator_fill_rgb565 (vbuf -> buffer , fmt -> width , hflip );
227
+ break ;
228
+ case VIDEO_PIX_FMT_SRGGB8 :
229
+ lines = video_sw_generator_fill_bayer8 (vbuf -> buffer , fmt -> width , hflip ,
230
+ pattern_rggb_idx );
231
+ break ;
232
+ case VIDEO_PIX_FMT_SGBRG8 :
233
+ lines = video_sw_generator_fill_bayer8 (vbuf -> buffer , fmt -> width , hflip ,
234
+ pattern_gbrg_idx );
235
+ break ;
236
+ case VIDEO_PIX_FMT_SBGGR8 :
237
+ lines = video_sw_generator_fill_bayer8 (vbuf -> buffer , fmt -> width , hflip ,
238
+ pattern_bggr_idx );
239
+ break ;
240
+ case VIDEO_PIX_FMT_SGRBG8 :
241
+ lines = video_sw_generator_fill_bayer8 (vbuf -> buffer , fmt -> width , hflip ,
242
+ pattern_grbg_idx );
243
+ break ;
244
+ default :
245
+ CODE_UNREACHABLE ;
246
+ break ;
247
+ }
144
248
145
- if (data -> fmt .pixelformat == VIDEO_PIX_FMT_RGB565 ) {
146
- uint16_t * pixel = (uint16_t * )& vbuf -> buffer [i ];
147
- * pixel = sys_cpu_to_le16 (rgb565_colorbar_value [color_idx ]);
148
- } else if (data -> fmt .pixelformat == VIDEO_PIX_FMT_XRGB32 ) {
149
- uint32_t * pixel = (uint32_t * )& vbuf -> buffer [i ];
150
- * pixel = sys_cpu_to_le32 (xrgb32_colorbar_value [color_idx ]);
151
- }
152
- i += video_bits_per_pixel (data -> fmt .pixelformat ) / BITS_PER_BYTE ;
249
+ if (lines == 0 ) {
250
+ return - EINVAL ;
153
251
}
154
252
155
- /* Duplicate the first line all over the buffer */
156
- for (int h = 1 ; h < data -> fmt .height ; h ++ ) {
157
- if (vbuf -> size < vbuf -> bytesused + pitch ) {
253
+ /* How much was filled in so far */
254
+ vbuf -> bytesused = data -> fmt .pitch * lines ;
255
+
256
+ /* Duplicate the first line(s) all over the buffer */
257
+ for (int h = lines ; h < data -> fmt .height ; h += lines ) {
258
+ if (vbuf -> size < vbuf -> bytesused + pitch * lines ) {
259
+ LOG_WRN ("Generation stopped early: buffer too small" );
158
260
break ;
159
261
}
160
-
161
- memcpy (vbuf -> buffer + h * pitch , vbuf -> buffer , pitch );
162
- vbuf -> bytesused += pitch ;
262
+ memcpy (vbuf -> buffer + h * pitch , vbuf -> buffer , pitch * lines );
263
+ vbuf -> bytesused += pitch * lines ;
163
264
}
164
265
165
266
vbuf -> timestamp = k_uptime_get_32 ();
166
267
vbuf -> line_offset = 0 ;
268
+
269
+ return 0 ;
167
270
}
168
271
169
272
static void video_sw_generator_worker (struct k_work * work )
@@ -183,7 +286,7 @@ static void video_sw_generator_worker(struct k_work *work)
183
286
184
287
switch (data -> pattern ) {
185
288
case VIDEO_PATTERN_COLOR_BAR :
186
- video_sw_generator_fill_colorbar (data , vbuf );
289
+ video_sw_generator_fill (data -> dev , vbuf );
187
290
break ;
188
291
}
189
292
0 commit comments