@@ -40,25 +40,25 @@ struct video_sw_generator_data {
4040 uint32_t frame_rate ;
4141};
4242
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+
4354static 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 ),
6262 {0 },
6363};
6464
@@ -117,47 +117,120 @@ static int video_sw_generator_set_stream(const struct device *dev, bool enable)
117117 return 0 ;
118118}
119119
120- /* Black, Blue, Red, Purple, Green, Aqua, Yellow, White */
121- uint16_t rgb565_colorbar_value [] = {
122- 0x0000 , 0x001F , 0xF800 , 0xF81F , 0x07E0 , 0x07FF , 0xFFE0 , 0xFFFF ,
120+ static const uint8_t pattern_rggb8_idx [] = {0 , 1 , 1 , 2 };
121+ static const uint8_t pattern_bggr8_idx [] = {2 , 1 , 1 , 0 };
122+ static const uint8_t pattern_gbrg8_idx [] = {1 , 2 , 0 , 1 };
123+ static const uint8_t pattern_grbg8_idx [] = {1 , 0 , 2 , 1 };
124+
125+ /* White, Yellow, Cyan, Green, Magenta, Red, Blue, Black */
126+
127+ static const uint16_t pattern_8bars_yuv_bt709 [8 ][3 ] = {
128+ {0xFE , 0x80 , 0x7F }, {0xEC , 0x00 , 0x8B }, {0xC8 , 0x9D , 0x00 }, {0xB6 , 0x1D , 0x0C },
129+ {0x48 , 0xE2 , 0xF3 }, {0x36 , 0x62 , 0xFF }, {0x12 , 0xFF , 0x74 }, {0x00 , 0x80 , 0x80 },
123130};
124131
125- uint32_t xrgb32_colorbar_value [ ] = {
126- 0xFF000000 , 0xFF0000FF , 0xFFFF0000 , 0xFFFF00FF ,
127- 0xFF00FF00 , 0xFF00FFFF , 0xFFFFFF00 , 0xFFFFFFFF ,
132+ static const uint16_t pattern_8bars_rgb [ 8 ][ 3 ] = {
133+ { 0xFF , 0xFF , 0xFF }, { 0xFF , 0xFF , 0x00 }, { 0x00 , 0xFF , 0xFF }, { 0x00 , 0xFF , 0x00 } ,
134+ { 0xFF , 0x00 , 0xFF }, { 0xFF , 0x00 , 0x00 }, { 0x00 , 0x00 , 0xFF }, { 0x00 , 0x00 , 0x00 } ,
128135};
129136
130- static void video_sw_generator_fill_colorbar (struct video_sw_generator_data * data ,
131- struct video_buffer * vbuf )
137+ static int video_sw_generator_fill_yuyv (uint8_t * buffer , uint16_t width )
138+ {
139+ for (size_t w = 0 ; w + 2 <= width ; w += 2 ) {
140+ buffer [w * 2 + 0 ] = pattern_8bars_yuv_bt709 [8 * w / width ][0 ];
141+ buffer [w * 2 + 1 ] = pattern_8bars_yuv_bt709 [8 * w / width ][1 ];
142+ buffer [w * 2 + 2 ] = pattern_8bars_yuv_bt709 [8 * w / width ][0 ];
143+ buffer [w * 2 + 3 ] = pattern_8bars_yuv_bt709 [8 * w / width ][2 ];
144+ }
145+ return 1 ;
146+ }
147+
148+ static int video_sw_generator_fill_xrgb32 (uint8_t * buffer , uint16_t width )
149+ {
150+ for (size_t w = 0 ; w < width ; w ++ ) {
151+ buffer [w * 4 + 0 ] = 0xff ;
152+ buffer [w * 4 + 1 ] = pattern_8bars_rgb [8 * w / width ][0 ];
153+ buffer [w * 4 + 2 ] = pattern_8bars_rgb [8 * w / width ][1 ];
154+ buffer [w * 4 + 3 ] = pattern_8bars_rgb [8 * w / width ][2 ];
155+ }
156+ return 1 ;
157+ }
158+
159+ static int video_sw_generator_fill_rgb565 (uint8_t * buffer , uint16_t width )
132160{
133- int bw = data -> fmt .width / 8 ;
161+ for (size_t w = 0 ; w < width ; w ++ ) {
162+ uint8_t r = pattern_8bars_rgb [8 * w / width ][0 ] >> (8 - 5 );
163+ uint8_t g = pattern_8bars_rgb [8 * w / width ][1 ] >> (8 - 6 );
164+ uint8_t b = pattern_8bars_rgb [8 * w / width ][2 ] >> (8 - 5 );
165+
166+ ((uint16_t * )buffer )[w ] = sys_cpu_to_le16 ((r << 11 ) | (g << 6 ) | (b << 0 ));
167+ }
168+ return 1 ;
169+ }
170+
171+ static int video_sw_generator_fill_bayer (uint8_t * buffer , uint16_t width , const uint8_t * idx )
172+ {
173+ uint8_t * row0 = buffer + 0 ;
174+ uint8_t * row1 = buffer + width ;
175+
176+ for (size_t w = 0 ; w + 2 <= width ; w += 2 ) {
177+ row0 [w + 0 ] = pattern_8bars_rgb [8 * w / width ][idx [0 ]];
178+ row0 [w + 1 ] = pattern_8bars_rgb [8 * w / width ][idx [1 ]];
179+ row1 [w + 0 ] = pattern_8bars_rgb [8 * w / width ][idx [2 ]];
180+ row1 [w + 1 ] = pattern_8bars_rgb [8 * w / width ][idx [3 ]];
181+ }
182+ return 2 ;
183+ }
184+
185+ static void video_sw_generator_fill (const struct device * const dev , struct video_buffer * vbuf )
186+ {
187+ struct video_sw_generator_data * data = dev -> data ;
134188 struct video_format * fmt = & data -> fmt ;
135189 size_t pitch = fmt -> width * video_bits_per_pixel (fmt -> pixelformat ) / BITS_PER_BYTE ;
190+ int lines = 1 ;
136191
137- vbuf -> bytesused = 0 ;
138-
139- /* Generate the first line of data */
140- for (int w = 0 , i = 0 ; w < data -> fmt .width ; w ++ ) {
141- int color_idx = data -> ctrl_vflip ? 7 - w / bw : w / bw ;
192+ __ASSERT (vbuf -> size >= pitch * 2 , "At least 2 lines needed for bayer formats support" );
142193
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 ;
194+ /* Fill the first row of the emulated framebuffer */
195+ switch (data -> fmt .pixelformat ) {
196+ case VIDEO_PIX_FMT_YUYV :
197+ lines = video_sw_generator_fill_yuyv (vbuf -> buffer , fmt -> width );
198+ break ;
199+ case VIDEO_PIX_FMT_XRGB32 :
200+ lines = video_sw_generator_fill_xrgb32 (vbuf -> buffer , fmt -> width );
201+ break ;
202+ case VIDEO_PIX_FMT_RGB565 :
203+ lines = video_sw_generator_fill_rgb565 (vbuf -> buffer , fmt -> width );
204+ break ;
205+ case VIDEO_PIX_FMT_RGGB8 :
206+ lines = video_sw_generator_fill_bayer (vbuf -> buffer , fmt -> width , pattern_rggb8_idx );
207+ break ;
208+ case VIDEO_PIX_FMT_GBRG8 :
209+ lines = video_sw_generator_fill_bayer (vbuf -> buffer , fmt -> width , pattern_gbrg8_idx );
210+ break ;
211+ case VIDEO_PIX_FMT_BGGR8 :
212+ lines = video_sw_generator_fill_bayer (vbuf -> buffer , fmt -> width , pattern_bggr8_idx );
213+ break ;
214+ case VIDEO_PIX_FMT_GRBG8 :
215+ lines = video_sw_generator_fill_bayer (vbuf -> buffer , fmt -> width , pattern_grbg8_idx );
216+ break ;
217+ default :
218+ LOG_WRN ("Unsupported pixel format %x, filling with 0x55" , data -> fmt .pixelformat );
219+ memset (vbuf -> buffer , 0x55 , data -> fmt .pitch );
220+ break ;
151221 }
152222
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 ) {
223+ /* How much was filled insofar */
224+ vbuf -> bytesused = data -> fmt .pitch * lines ;
225+
226+ /* Duplicate the first line(s) all over the buffer */
227+ for (int h = lines ; h < data -> fmt .height ; h += lines ) {
228+ if (vbuf -> size < vbuf -> bytesused + pitch * lines ) {
229+ LOG_WRN ("Generation stopped early: buffer too small" );
156230 break ;
157231 }
158-
159- memcpy (vbuf -> buffer + h * pitch , vbuf -> buffer , pitch );
160- vbuf -> bytesused += pitch ;
232+ memcpy (vbuf -> buffer + h * pitch , vbuf -> buffer , pitch * lines );
233+ vbuf -> bytesused += pitch * lines ;
161234 }
162235
163236 vbuf -> timestamp = k_uptime_get_32 ();
@@ -181,7 +254,7 @@ static void video_sw_generator_worker(struct k_work *work)
181254
182255 switch (data -> pattern ) {
183256 case VIDEO_PATTERN_COLOR_BAR :
184- video_sw_generator_fill_colorbar (data , vbuf );
257+ video_sw_generator_fill (data -> dev , vbuf );
185258 break ;
186259 }
187260
0 commit comments