|
12 | 12 | #include "Adafruit_TinyUSB.h"
|
13 | 13 | #include "usb_descriptors.h"
|
14 | 14 |
|
| 15 | +//--------------------------------------------------------------------+ |
| 16 | +// |
| 17 | +//--------------------------------------------------------------------+ |
15 | 18 | #define FRAME_WIDTH 128
|
16 | 19 | #define FRAME_HEIGHT 96
|
17 | 20 | #define FRAME_RATE 10
|
18 | 21 |
|
19 | 22 | uint8_t const desc_video[] = {
|
20 |
| - TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(4, 0x80, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, 64) |
| 23 | + TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(0, 0x80, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, 64) |
21 | 24 | };
|
22 | 25 |
|
23 | 26 | Adafruit_USBD_Video usb_video(desc_video, sizeof(desc_video));
|
24 | 27 |
|
| 28 | +// YUY2 frame buffer |
| 29 | +static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8]; |
| 30 | + |
| 31 | +static unsigned frame_num = 0; |
| 32 | +static unsigned tx_busy = 0; |
| 33 | +static unsigned interval_ms = 1000 / FRAME_RATE; |
| 34 | +static unsigned start_ms = 0; |
| 35 | +static unsigned already_sent = 0; |
| 36 | + |
| 37 | +//--------------------------------------------------------------------+ |
| 38 | +// |
| 39 | +//--------------------------------------------------------------------+ |
| 40 | +static void fill_color_bar(uint8_t* buffer, unsigned start_position); |
| 41 | + |
25 | 42 | void setup() {
|
26 | 43 | Serial.begin(115200);
|
| 44 | +// Serial.end(); |
27 | 45 | usb_video.begin();
|
28 | 46 | }
|
29 | 47 |
|
30 | 48 | void loop() {
|
| 49 | + if (!tud_video_n_streaming(0, 0)) { |
| 50 | + already_sent = 0; |
| 51 | + frame_num = 0; |
| 52 | + return; |
| 53 | + } |
| 54 | + |
| 55 | + if (!already_sent) { |
| 56 | + already_sent = 1; |
| 57 | + start_ms = millis(); |
| 58 | + fill_color_bar(frame_buffer, frame_num); |
| 59 | + tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); |
| 60 | + } |
| 61 | + |
| 62 | + unsigned cur = millis(); |
| 63 | + if (cur - start_ms < interval_ms) return; // not enough time |
| 64 | + if (tx_busy) return; |
| 65 | + start_ms += interval_ms; |
| 66 | + |
| 67 | + fill_color_bar(frame_buffer, frame_num); |
| 68 | + tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); |
| 69 | +} |
| 70 | + |
| 71 | +void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) { |
| 72 | + (void) ctl_idx; |
| 73 | + (void) stm_idx; |
| 74 | + tx_busy = 0; |
| 75 | + /* flip buffer */ |
| 76 | + ++frame_num; |
| 77 | +} |
| 78 | + |
| 79 | +int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, |
| 80 | + video_probe_and_commit_control_t const* parameters) { |
| 81 | + (void) ctl_idx; |
| 82 | + (void) stm_idx; |
| 83 | + /* convert unit to ms from 100 ns */ |
| 84 | + interval_ms = parameters->dwFrameInterval / 10000; |
| 85 | + return VIDEO_ERROR_NONE; |
| 86 | +} |
| 87 | + |
| 88 | +//------------- Helper -------------// |
| 89 | +static void fill_color_bar(uint8_t* buffer, unsigned start_position) { |
| 90 | + /* EBU color bars |
| 91 | + * See also https://stackoverflow.com/questions/6939422 */ |
| 92 | + static uint8_t const bar_color[8][4] = { |
| 93 | + /* Y, U, Y, V */ |
| 94 | + { 235, 128, 235, 128}, /* 100% White */ |
| 95 | + { 219, 16, 219, 138}, /* Yellow */ |
| 96 | + { 188, 154, 188, 16}, /* Cyan */ |
| 97 | + { 173, 42, 173, 26}, /* Green */ |
| 98 | + { 78, 214, 78, 230}, /* Magenta */ |
| 99 | + { 63, 102, 63, 240}, /* Red */ |
| 100 | + { 32, 240, 32, 118}, /* Blue */ |
| 101 | + { 16, 128, 16, 128}, /* Black */ |
| 102 | + }; |
| 103 | + uint8_t* p; |
| 104 | + |
| 105 | + /* Generate the 1st line */ |
| 106 | + uint8_t* end = &buffer[FRAME_WIDTH * 2]; |
| 107 | + unsigned idx = (FRAME_WIDTH / 2 - 1) - (start_position % (FRAME_WIDTH / 2)); |
| 108 | + p = &buffer[idx * 4]; |
| 109 | + for (unsigned i = 0; i < 8; ++i) { |
| 110 | + for (int j = 0; j < FRAME_WIDTH / (2 * 8); ++j) { |
| 111 | + memcpy(p, &bar_color[i], 4); |
| 112 | + p += 4; |
| 113 | + if (end <= p) { |
| 114 | + p = buffer; |
| 115 | + } |
| 116 | + } |
| 117 | + } |
31 | 118 |
|
| 119 | + /* Duplicate the 1st line to the others */ |
| 120 | + p = &buffer[FRAME_WIDTH * 2]; |
| 121 | + for (unsigned i = 1; i < FRAME_HEIGHT; ++i) { |
| 122 | + memcpy(p, buffer, FRAME_WIDTH * 2); |
| 123 | + p += FRAME_WIDTH * 2; |
| 124 | + } |
32 | 125 | }
|
0 commit comments