Added bufferless operation to the video capture example. Can be tested with e.g. nanoCH32V305 board with the following settings:

- tusb_config.h
  - #define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE  1024
  - #define CFG_TUD_VIDEO_STREAMING_BULK 1
  - #define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
  - #define CFG_EXAMPLE_VIDEO_BUFFERLESS

and

- usb_descriptor.h
  - #define FRAME_RATE    60
This commit is contained in:
Tobi
2025-10-30 14:06:17 +01:00
parent 032de0b0df
commit b8cea4ad76
2 changed files with 55 additions and 15 deletions

View File

@ -56,6 +56,20 @@ void video_task(void* param);
void freertos_init_task(void);
#endif
#if !defined(CFG_EXAMPLE_VIDEO_READONLY) || defined(CFG_EXAMPLE_VIDEO_BUFFERLESS)
/* EBU color bars: https://stackoverflow.com/questions/6939422 */
static uint8_t const bar_color[8][4] = {
/* Y, U, Y, V */
{ 235, 128, 235, 128}, /* 100% White */
{ 219, 16, 219, 138}, /* Yellow */
{ 188, 154, 188, 16}, /* Cyan */
{ 173, 42, 173, 26}, /* Green */
{ 78, 214, 78, 230}, /* Magenta */
{ 63, 102, 63, 240}, /* Red */
{ 32, 240, 32, 118}, /* Blue */
{ 16, 128, 16, 128}, /* Black */
};
#endif
//--------------------------------------------------------------------+
// Main
@ -111,12 +125,43 @@ void tud_resume_cb(void) {
blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
#ifdef CFG_EXAMPLE_VIDEO_BUFFERLESS
#ifndef CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
#error Demo only supports YUV2 please define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
#endif
void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void* payload_buf, size_t payload_size, size_t offset)
{
static uint32_t frame_counter = 0;
(void)ctl_idx;
(void)stm_idx;
/* Offset will be zero at the start of a new frame */
if (!offset) frame_counter++;
for (size_t buf_pos = 0; buf_pos < payload_size; buf_pos += 2) {
/* Position within the current line (pixel relative) */
int line_pos = ((offset + buf_pos)>>1) % FRAME_WIDTH;
/* Choose color based on the position and change the table offset every 4 frames */
const uint8_t* color = bar_color[(line_pos/(FRAME_WIDTH / 8) + (frame_counter>>2)) % 8];
/* Copy pixel data for odd or even pixels */
memcpy(&((uint8_t*)payload_buf)[buf_pos], &color[(line_pos & 1) ? 2 : 0], 2);
}
}
#endif
//--------------------------------------------------------------------+
// USB Video
//--------------------------------------------------------------------+
static unsigned frame_num = 0;
static unsigned tx_busy = 0;
static unsigned interval_ms = 1000 / FRAME_RATE;
#ifndef CFG_EXAMPLE_VIDEO_BUFFERLESS
#ifdef CFG_EXAMPLE_VIDEO_READONLY
// For mcus that does not have enough SRAM for frame buffer, we use fixed frame data.
@ -145,18 +190,6 @@ static struct {
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8];
static void fill_color_bar(uint8_t* buffer, unsigned start_position) {
/* EBU color bars: https://stackoverflow.com/questions/6939422 */
static uint8_t const bar_color[8][4] = {
/* Y, U, Y, V */
{ 235, 128, 235, 128}, /* 100% White */
{ 219, 16, 219, 138}, /* Yellow */
{ 188, 154, 188, 16}, /* Cyan */
{ 173, 42, 173, 26}, /* Green */
{ 78, 214, 78, 230}, /* Magenta */
{ 63, 102, 63, 240}, /* Red */
{ 32, 240, 32, 118}, /* Blue */
{ 16, 128, 16, 128}, /* Black */
};
uint8_t* p;
/* Generate the 1st line */
@ -183,6 +216,8 @@ static void fill_color_bar(uint8_t* buffer, unsigned start_position) {
#endif
#endif /* NDEF CFG_EXAMPLE_VIDEO_BUFFERLESS */
static void video_send_frame(void) {
static unsigned start_ms = 0;
static unsigned already_sent = 0;
@ -197,7 +232,9 @@ static void video_send_frame(void) {
already_sent = 1;
tx_busy = 1;
start_ms = board_millis();
#ifdef CFG_EXAMPLE_VIDEO_READONLY
#if defined(CFG_EXAMPLE_VIDEO_BUFFERLESS)
tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
#elif defined (CFG_EXAMPLE_VIDEO_READONLY)
#if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
@ -216,13 +253,15 @@ static void video_send_frame(void) {
start_ms += interval_ms;
tx_busy = 1;
#ifdef CFG_EXAMPLE_VIDEO_READONLY
#if defined(CFG_EXAMPLE_VIDEO_BUFFERLESS)
tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
#elif defined(CFG_EXAMPLE_VIDEO_READONLY)
#if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
#else
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size);
#endif
#endif
#else
fill_color_bar(frame_buffer, frame_num);
tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);

View File

@ -110,6 +110,7 @@
//#define CFG_EXAMPLE_VIDEO_READONLY
//#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
//#define CFG_EXAMPLE_VIDEO_BUFFERLESS
#ifdef __cplusplus
}