Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 54 additions & 15 deletions examples/device/video_capture/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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, tud_video_payload_request_t* request)
{
static uint32_t frame_counter = 0;
(void)ctl_idx;
(void)stm_idx;

/* Offset will be zero at the start of a new frame */
if (!request->offset) frame_counter++;

for (size_t buf_pos = 0; buf_pos < request->length; buf_pos += 2) {

/* Position within the current line (pixel relative) */
int line_pos = ((request->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*)request->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.
Expand Down Expand Up @@ -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 */
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions examples/device/video_capture/src/tusb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@

//#define CFG_EXAMPLE_VIDEO_READONLY
//#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
//#define CFG_EXAMPLE_VIDEO_BUFFERLESS

#ifdef __cplusplus
}
Expand Down
21 changes: 18 additions & 3 deletions src/class/video/video_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@ TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
return VIDEO_ERROR_NONE;
}

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) {
(void) ctl_idx;
(void) stm_idx;
(void) request;
}

//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
Expand Down Expand Up @@ -860,7 +866,16 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm, uint
}
TU_ASSERT(pkt_len >= hdr_len);
uint_fast16_t data_len = pkt_len - hdr_len;
memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
if (stm->buffer) {
memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
} else {
tud_video_payload_request_t rqst = {
.buf = &ep_buf[hdr_len],
.length = data_len,
.offset = stm->offset
};
tud_video_prepare_payload_cb(stm->index_vc, stm->index_vs, &rqst);
}
stm->offset += data_len;
remaining -= data_len;
if (!remaining) {
Expand Down Expand Up @@ -1235,11 +1250,11 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);

if (!buffer || !bufsize) return false;
if (!bufsize) return false;
videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[ctl_idx];

if (!stm || !stm->desc.ep[0] || stm->buffer) return false;
if (!stm || !stm->desc.ep[0] || stm->bufsize) return false;
if (stm->state == VS_STATE_PROBING) return false;

/* Find EP address */
Expand Down
20 changes: 20 additions & 0 deletions src/class/video/video_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@
extern "C" {
#endif


//--------------------------------------------------------------------+
// Payload request
//--------------------------------------------------------------------+
typedef struct TU_ATTR_PACKED {
void* buf; /* Payload buffer to be filled */
size_t length; /* Length of the requested data in bytes */
size_t offset; /* Offset within the frame (in bytes) */
} tud_video_payload_request_t;

//--------------------------------------------------------------------+
// Application API (Multiple Ports)
// CFG_TUD_VIDEO > 1
Expand Down Expand Up @@ -83,6 +93,16 @@ int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod);
int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
video_probe_and_commit_control_t const *parameters);

/** Invoked if buffer is set to NULL (allows bufferless on the fly data generation)
*
* @param[in] ctl_idx Destination control interface index
* @param[in] stm_idx Destination streaming interface index
* @param[out] payload_buf Payload storage buffer (target buffer for requested data)
* @param[in] payload_size Size of payload_buf (requested data size)
* @param[in] offset Current byte offset relative to given bufsize from tud_video_n_frame_xfer (framesize)
* @return video_error_code_t */
void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request);

//--------------------------------------------------------------------+
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+
Expand Down
Loading