summaryrefslogtreecommitdiff
path: root/examples/device/video_capture/src
diff options
context:
space:
mode:
authorTobi <[email protected]>2025-10-30 14:06:17 +0100
committerTobi <[email protected]>2025-10-30 14:06:17 +0100
commitb8cea4ad766ea40de88fdaa28c19e69f5bc25f9d (patch)
tree11472a8fde432e00fe3c52220047a2d67ef49662 /examples/device/video_capture/src
parent032de0b0df92162aa579eda986145e3756a29a6c (diff)
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
Diffstat (limited to 'examples/device/video_capture/src')
-rw-r--r--examples/device/video_capture/src/main.c69
-rw-r--r--examples/device/video_capture/src/tusb_config.h1
2 files changed, 55 insertions, 15 deletions
diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c
index 29656e944..b01830dfe 100644
--- a/examples/device/video_capture/src/main.c
+++ b/examples/device/video_capture/src/main.c
@@ -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);
diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h
index 390152e16..1aa1a5ce7 100644
--- a/examples/device/video_capture/src/tusb_config.h
+++ b/examples/device/video_capture/src/tusb_config.h
@@ -110,6 +110,7 @@
//#define CFG_EXAMPLE_VIDEO_READONLY
//#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
+//#define CFG_EXAMPLE_VIDEO_BUFFERLESS
#ifdef __cplusplus
}