@@ -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+
4960static 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
120127static 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
167270static 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