@@ -40,25 +40,25 @@ struct video_sw_generator_data {
40
40
uint32_t frame_rate ;
41
41
};
42
42
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
+
43
54
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 ),
62
62
{0 },
63
63
};
64
64
@@ -85,6 +85,11 @@ static int video_sw_generator_set_fmt(const struct device *dev, enum video_endpo
85
85
return - ENOTSUP ;
86
86
}
87
87
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
+
88
93
data -> fmt = * fmt ;
89
94
90
95
return 0 ;
@@ -117,51 +122,123 @@ static int video_sw_generator_set_stream(const struct device *dev, bool enable)
117
122
return 0 ;
118
123
}
119
124
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 },
123
135
};
124
136
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 } ,
128
140
};
129
141
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 )
132
143
{
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
+ }
134
152
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
+ }
136
163
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)" ,
139
198
vbuf , vbuf -> size , data -> fmt .pitch );
140
199
return ;
141
200
}
142
201
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 ;
155
229
}
156
230
231
+ /* How much was filled insofar */
232
+ vbuf -> bytesused = data -> fmt .pitch * lines ;
233
+
157
234
/* 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" );
160
238
break ;
161
239
}
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 ;
165
242
}
166
243
167
244
vbuf -> timestamp = k_uptime_get_32 ();
@@ -185,7 +262,7 @@ static void video_sw_generator_worker(struct k_work *work)
185
262
186
263
switch (data -> pattern ) {
187
264
case VIDEO_PATTERN_COLOR_BAR :
188
- video_sw_generator_fill_colorbar (data , vbuf );
265
+ video_sw_generator_fill (data -> dev , vbuf );
189
266
break ;
190
267
}
191
268
0 commit comments