Skip to content

Commit 20c3644

Browse files
authored
Merge pull request #3322 from embedded-ideas/master
Bufferless (on the fly) video data generation for the video device class
2 parents fc5415b + ac903db commit 20c3644

File tree

4 files changed

+93
-17
lines changed

4 files changed

+93
-17
lines changed

examples/device/video_capture/src/main.c

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ void video_task(void* param);
5656
void freertos_init(void);
5757
#endif
5858

59+
#if !defined(CFG_EXAMPLE_VIDEO_READONLY) || defined(CFG_EXAMPLE_VIDEO_BUFFERLESS)
60+
/* EBU color bars: https://stackoverflow.com/questions/6939422 */
61+
static uint8_t const bar_color[8][4] = {
62+
/* Y, U, Y, V */
63+
{ 235, 128, 235, 128}, /* 100% White */
64+
{ 219, 16, 219, 138}, /* Yellow */
65+
{ 188, 154, 188, 16}, /* Cyan */
66+
{ 173, 42, 173, 26}, /* Green */
67+
{ 78, 214, 78, 230}, /* Magenta */
68+
{ 63, 102, 63, 240}, /* Red */
69+
{ 32, 240, 32, 118}, /* Blue */
70+
{ 16, 128, 16, 128}, /* Black */
71+
};
72+
#endif
5973

6074
//--------------------------------------------------------------------+
6175
// Main
@@ -111,12 +125,43 @@ void tud_resume_cb(void) {
111125
blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
112126
}
113127

128+
#ifdef CFG_EXAMPLE_VIDEO_BUFFERLESS
129+
130+
#ifndef CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
131+
#error Demo only supports YUV2 please define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
132+
#endif
133+
134+
void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request)
135+
{
136+
static uint32_t frame_counter = 0;
137+
(void)ctl_idx;
138+
(void)stm_idx;
139+
140+
/* Offset will be zero at the start of a new frame */
141+
if (!request->offset) frame_counter++;
142+
143+
for (size_t buf_pos = 0; buf_pos < request->length; buf_pos += 2) {
144+
145+
/* Position within the current line (pixel relative) */
146+
int line_pos = ((request->offset + buf_pos)>>1) % FRAME_WIDTH;
147+
148+
/* Choose color based on the position and change the table offset every 4 frames */
149+
const uint8_t* color = bar_color[(line_pos/(FRAME_WIDTH / 8) + (frame_counter>>2)) % 8];
150+
151+
/* Copy pixel data for odd or even pixels */
152+
memcpy(&((uint8_t*)request->buf)[buf_pos], &color[(line_pos & 1) ? 2 : 0], 2);
153+
}
154+
155+
}
156+
#endif
157+
114158
//--------------------------------------------------------------------+
115159
// USB Video
116160
//--------------------------------------------------------------------+
117161
static unsigned frame_num = 0;
118162
static unsigned tx_busy = 0;
119163
static unsigned interval_ms = 1000 / FRAME_RATE;
164+
#ifndef CFG_EXAMPLE_VIDEO_BUFFERLESS
120165

121166
#ifdef CFG_EXAMPLE_VIDEO_READONLY
122167
// For mcus that does not have enough SRAM for frame buffer, we use fixed frame data.
@@ -145,18 +190,6 @@ static struct {
145190
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8];
146191

147192
static void fill_color_bar(uint8_t* buffer, unsigned start_position) {
148-
/* EBU color bars: https://stackoverflow.com/questions/6939422 */
149-
static uint8_t const bar_color[8][4] = {
150-
/* Y, U, Y, V */
151-
{ 235, 128, 235, 128}, /* 100% White */
152-
{ 219, 16, 219, 138}, /* Yellow */
153-
{ 188, 154, 188, 16}, /* Cyan */
154-
{ 173, 42, 173, 26}, /* Green */
155-
{ 78, 214, 78, 230}, /* Magenta */
156-
{ 63, 102, 63, 240}, /* Red */
157-
{ 32, 240, 32, 118}, /* Blue */
158-
{ 16, 128, 16, 128}, /* Black */
159-
};
160193
uint8_t* p;
161194

162195
/* Generate the 1st line */
@@ -183,6 +216,8 @@ static void fill_color_bar(uint8_t* buffer, unsigned start_position) {
183216

184217
#endif
185218

219+
#endif /* NDEF CFG_EXAMPLE_VIDEO_BUFFERLESS */
220+
186221
static void video_send_frame(void) {
187222
static unsigned start_ms = 0;
188223
static unsigned already_sent = 0;
@@ -197,7 +232,9 @@ static void video_send_frame(void) {
197232
already_sent = 1;
198233
tx_busy = 1;
199234
start_ms = board_millis();
200-
#ifdef CFG_EXAMPLE_VIDEO_READONLY
235+
#if defined(CFG_EXAMPLE_VIDEO_BUFFERLESS)
236+
tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
237+
#elif defined (CFG_EXAMPLE_VIDEO_READONLY)
201238
#if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
202239
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
203240
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
@@ -220,7 +257,9 @@ static void video_send_frame(void) {
220257
start_ms += interval_ms;
221258
tx_busy = 1;
222259

223-
#ifdef CFG_EXAMPLE_VIDEO_READONLY
260+
#if defined(CFG_EXAMPLE_VIDEO_BUFFERLESS)
261+
tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
262+
#elif defined(CFG_EXAMPLE_VIDEO_READONLY)
224263
#if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
225264
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
226265
FRAME_WIDTH * FRAME_HEIGHT * 16/8);

examples/device/video_capture/src/tusb_config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110

111111
//#define CFG_EXAMPLE_VIDEO_READONLY
112112
//#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
113+
//#define CFG_EXAMPLE_VIDEO_BUFFERLESS
113114

114115
#ifdef __cplusplus
115116
}

src/class/video/video_device.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
214214
return VIDEO_ERROR_NONE;
215215
}
216216

217+
TU_ATTR_WEAK void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request) {
218+
(void) ctl_idx;
219+
(void) stm_idx;
220+
(void) request;
221+
}
222+
217223
//--------------------------------------------------------------------+
218224
//
219225
//--------------------------------------------------------------------+
@@ -874,7 +880,16 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm, uint
874880
}
875881
TU_ASSERT(pkt_len >= hdr_len);
876882
uint_fast16_t data_len = pkt_len - hdr_len;
877-
memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
883+
if (stm->buffer) {
884+
memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
885+
} else {
886+
tud_video_payload_request_t rqst = {
887+
.buf = &ep_buf[hdr_len],
888+
.length = data_len,
889+
.offset = stm->offset
890+
};
891+
tud_video_prepare_payload_cb(stm->index_vc, stm->index_vs, &rqst);
892+
}
878893
stm->offset += data_len;
879894
remaining -= data_len;
880895
if (!remaining) {
@@ -1255,13 +1270,14 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
12551270
TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
12561271
TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
12571272

1258-
if (NULL == buffer || 0 == bufsize) {
1273+
if (0 == bufsize) {
12591274
return false;
12601275
}
1276+
12611277
videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
12621278
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[ctl_idx];
12631279

1264-
if (NULL == stm || 0 == stm->desc.ep[0] || stm->buffer) {
1280+
if (NULL == stm || 0 == stm->desc.ep[0] || stm->bufsize) {
12651281
return false;
12661282
}
12671283
if (stm->state == VS_STATE_PROBING) {

src/class/video/video_device.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@
3535
extern "C" {
3636
#endif
3737

38+
39+
//--------------------------------------------------------------------+
40+
// Payload request
41+
//--------------------------------------------------------------------+
42+
typedef struct TU_ATTR_PACKED {
43+
void* buf; /* Payload buffer to be filled */
44+
size_t length; /* Length of the requested data in bytes */
45+
size_t offset; /* Offset within the frame (in bytes) */
46+
} tud_video_payload_request_t;
47+
3848
//--------------------------------------------------------------------+
3949
// Application API (Multiple Ports)
4050
// CFG_TUD_VIDEO > 1
@@ -83,6 +93,16 @@ int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod);
8393
int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
8494
video_probe_and_commit_control_t const *parameters);
8595

96+
/** Invoked if buffer is set to NULL (allows bufferless on the fly data generation)
97+
*
98+
* @param[in] ctl_idx Destination control interface index
99+
* @param[in] stm_idx Destination streaming interface index
100+
* @param[out] payload_buf Payload storage buffer (target buffer for requested data)
101+
* @param[in] payload_size Size of payload_buf (requested data size)
102+
* @param[in] offset Current byte offset relative to given bufsize from tud_video_n_frame_xfer (framesize)
103+
* @return video_error_code_t */
104+
void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request);
105+
86106
//--------------------------------------------------------------------+
87107
// INTERNAL USBD-CLASS DRIVER API
88108
//--------------------------------------------------------------------+

0 commit comments

Comments
 (0)