1 // Intensity Shuttle USB3 prototype capture driver, v0.3
2 // Can download 8-bit and 10-bit UYVY/v210 frames from HDMI, quite stable
3 // (can do captures for hours at a time with no drops), except during startup
4 // 576p60/720p60/1080i60 works, 1080p60 does not work (firmware limitation)
5 // Audio comes out as 8-channel 24-bit raw audio.
10 #include <netinet/in.h>
17 #include <immintrin.h>
23 #include <condition_variable>
34 using namespace std::placeholders;
37 #define HEIGHT 750 /* 30 lines ancillary data? */
39 //#define HEIGHT 1125 /* ??? lines ancillary data? */
40 #define HEADER_SIZE 44
41 //#define HEADER_SIZE 0
42 #define AUDIO_HEADER_SIZE 4
44 //#define FRAME_SIZE (WIDTH * HEIGHT * 2 + HEADER_SIZE) // UYVY
45 //#define FRAME_SIZE (WIDTH * HEIGHT * 2 * 4 / 3 + HEADER_SIZE) // v210
46 #define FRAME_SIZE (8 << 20)
51 atomic<bool> should_quit;
53 FrameAllocator::~FrameAllocator() {}
55 #define NUM_QUEUED_FRAMES 8
56 class MallocFrameAllocator : public FrameAllocator {
58 MallocFrameAllocator(size_t frame_size);
59 Frame alloc_frame() override;
60 void release_frame(Frame frame) override;
66 stack<unique_ptr<uint8_t[]>> freelist; // All of size <frame_size>.
69 MallocFrameAllocator::MallocFrameAllocator(size_t frame_size)
70 : frame_size(frame_size)
72 for (int i = 0; i < NUM_QUEUED_FRAMES; ++i) {
73 freelist.push(unique_ptr<uint8_t[]>(new uint8_t[frame_size]));
77 FrameAllocator::Frame MallocFrameAllocator::alloc_frame()
82 unique_lock<mutex> lock(freelist_mutex); // Meh.
83 if (freelist.empty()) {
84 printf("Frame overrun (no more spare frames of size %ld), dropping frame!\n",
87 vf.data = freelist.top().release();
89 freelist.pop(); // Meh.
94 void MallocFrameAllocator::release_frame(Frame frame)
96 unique_lock<mutex> lock(freelist_mutex);
97 freelist.push(unique_ptr<uint8_t[]>(frame.data));
100 bool uint16_less_than_with_wraparound(uint16_t a, uint16_t b)
105 return (b - a < 0x8000);
107 int wrap_b = 0x10000 + int(b);
108 return (wrap_b - a < 0x8000);
112 void BMUSBCapture::queue_frame(uint16_t format, uint16_t timecode, FrameAllocator::Frame frame, deque<QueuedFrame> *q)
114 if (!q->empty() && !uint16_less_than_with_wraparound(q->back().timecode, timecode)) {
115 printf("Blocks going backwards: prev=0x%04x, cur=0x%04x (dropped)\n",
116 q->back().timecode, timecode);
117 frame.owner->release_frame(frame);
123 qf.timecode = timecode;
127 unique_lock<mutex> lock(queue_lock);
128 q->push_back(move(qf));
130 queues_not_empty.notify_one(); // might be spurious
133 void dump_frame(const char *filename, uint8_t *frame_start, size_t frame_len)
135 FILE *fp = fopen(filename, "wb");
136 if (fwrite(frame_start + HEADER_SIZE, frame_len - HEADER_SIZE, 1, fp) != 1) {
137 printf("short write!\n");
142 void dump_audio_block(uint8_t *audio_start, size_t audio_len)
144 fwrite(audio_start + AUDIO_HEADER_SIZE, 1, audio_len - AUDIO_HEADER_SIZE, audiofp);
147 void BMUSBCapture::dequeue_thread()
150 unique_lock<mutex> lock(queue_lock);
151 queues_not_empty.wait(lock, [this]{ return !pending_video_frames.empty() && !pending_audio_frames.empty(); });
153 uint16_t video_timecode = pending_video_frames.front().timecode;
154 uint16_t audio_timecode = pending_audio_frames.front().timecode;
155 if (video_timecode < audio_timecode) {
156 printf("Video block 0x%04x without corresponding audio block, dropping.\n",
158 video_frame_allocator->release_frame(pending_video_frames.front().frame);
159 pending_video_frames.pop_front();
160 } else if (audio_timecode < video_timecode) {
161 printf("Audio block 0x%04x without corresponding video block, dropping.\n",
163 audio_frame_allocator->release_frame(pending_audio_frames.front().frame);
164 pending_audio_frames.pop_front();
166 QueuedFrame video_frame = pending_video_frames.front();
167 QueuedFrame audio_frame = pending_audio_frames.front();
168 pending_audio_frames.pop_front();
169 pending_video_frames.pop_front();
174 snprintf(filename, sizeof(filename), "%04x%04x.uyvy", video_frame.format, video_timecode);
175 dump_frame(filename, video_frame.frame.data, video_frame.data_len);
176 dump_audio_block(audio_frame.frame.data, audio_frame.data_len);
179 frame_callback(video_timecode,
180 video_frame.frame, HEADER_SIZE, video_frame.format,
181 audio_frame.frame, AUDIO_HEADER_SIZE, audio_frame.format);
186 void BMUSBCapture::start_new_frame(const uint8_t *start)
188 uint16_t format = (start[3] << 8) | start[2];
189 uint16_t timecode = (start[1] << 8) | start[0];
191 if (current_video_frame.len > 0) {
193 queue_frame(format, timecode, current_video_frame, &pending_video_frames);
195 //printf("Found frame start, format 0x%04x timecode 0x%04x, previous frame length was %d/%d\n",
197 // //start[7], start[6], start[5], start[4],
198 // read_current_frame, FRAME_SIZE);
200 current_video_frame = video_frame_allocator->alloc_frame();
201 //if (current_video_frame.data == nullptr) {
202 // read_current_frame = -1;
204 // read_current_frame = 0;
208 void BMUSBCapture::start_new_audio_block(const uint8_t *start)
210 uint16_t format = (start[3] << 8) | start[2];
211 uint16_t timecode = (start[1] << 8) | start[0];
212 if (current_audio_frame.len > 0) {
213 //dump_audio_block();
214 queue_frame(format, timecode, current_audio_frame, &pending_audio_frames);
216 //printf("Found audio block start, format 0x%04x timecode 0x%04x, previous block length was %d\n",
217 // format, timecode, read_current_audio_block);
218 current_audio_frame = audio_frame_allocator->alloc_frame();
222 static void dump_pack(const libusb_transfer *xfr, int offset, const libusb_iso_packet_descriptor *pack)
224 // printf("ISO pack%u length:%u, actual_length:%u, offset:%u\n", i, pack->length, pack->actual_length, offset);
225 for (unsigned j = 0; j < pack->actual_length; j++) {
226 //for (int j = 0; j < min(pack->actual_length, 16u); j++) {
227 printf("%02x", xfr->buffer[j + offset]);
230 else if ((j % 8) == 7)
238 void memcpy_interleaved(uint8_t *dest1, uint8_t *dest2, const uint8_t *src, size_t n)
241 uint8_t *dptr1 = dest1;
242 uint8_t *dptr2 = dest2;
244 for (size_t i = 0; i < n; i += 2) {
250 void add_to_frame(FrameAllocator::Frame *current_frame, const char *frame_type_name, const uint8_t *start, const uint8_t *end)
252 if (current_frame->data == nullptr ||
253 current_frame->len > current_frame->size ||
258 int bytes = end - start;
259 if (current_frame->len + bytes > current_frame->size) {
260 printf("%d bytes overflow after last %s frame\n",
261 int(current_frame->len + bytes - current_frame->size), frame_type_name);
264 if (current_frame->interleaved) {
265 uint8_t *data = current_frame->data + current_frame->len / 2;
266 uint8_t *data2 = current_frame->data2 + current_frame->len / 2;
267 if (current_frame->len % 2 == 1) {
271 if (bytes % 2 == 1) {
274 ++current_frame->len;
277 memcpy_interleaved(data, data2, start, bytes);
278 current_frame->len += bytes;
280 memcpy(current_frame->data + current_frame->len, start, bytes);
281 current_frame->len += bytes;
289 void avx2_dump(const char *name, __m256i n)
291 printf("%-10s:", name);
292 printf(" %02x", _mm256_extract_epi8(n, 0));
293 printf(" %02x", _mm256_extract_epi8(n, 1));
294 printf(" %02x", _mm256_extract_epi8(n, 2));
295 printf(" %02x", _mm256_extract_epi8(n, 3));
296 printf(" %02x", _mm256_extract_epi8(n, 4));
297 printf(" %02x", _mm256_extract_epi8(n, 5));
298 printf(" %02x", _mm256_extract_epi8(n, 6));
299 printf(" %02x", _mm256_extract_epi8(n, 7));
301 printf(" %02x", _mm256_extract_epi8(n, 8));
302 printf(" %02x", _mm256_extract_epi8(n, 9));
303 printf(" %02x", _mm256_extract_epi8(n, 10));
304 printf(" %02x", _mm256_extract_epi8(n, 11));
305 printf(" %02x", _mm256_extract_epi8(n, 12));
306 printf(" %02x", _mm256_extract_epi8(n, 13));
307 printf(" %02x", _mm256_extract_epi8(n, 14));
308 printf(" %02x", _mm256_extract_epi8(n, 15));
310 printf(" %02x", _mm256_extract_epi8(n, 16));
311 printf(" %02x", _mm256_extract_epi8(n, 17));
312 printf(" %02x", _mm256_extract_epi8(n, 18));
313 printf(" %02x", _mm256_extract_epi8(n, 19));
314 printf(" %02x", _mm256_extract_epi8(n, 20));
315 printf(" %02x", _mm256_extract_epi8(n, 21));
316 printf(" %02x", _mm256_extract_epi8(n, 22));
317 printf(" %02x", _mm256_extract_epi8(n, 23));
319 printf(" %02x", _mm256_extract_epi8(n, 24));
320 printf(" %02x", _mm256_extract_epi8(n, 25));
321 printf(" %02x", _mm256_extract_epi8(n, 26));
322 printf(" %02x", _mm256_extract_epi8(n, 27));
323 printf(" %02x", _mm256_extract_epi8(n, 28));
324 printf(" %02x", _mm256_extract_epi8(n, 29));
325 printf(" %02x", _mm256_extract_epi8(n, 30));
326 printf(" %02x", _mm256_extract_epi8(n, 31));
331 // Does a memcpy and memchr in one to reduce processing time.
332 // Note that the benefit is somewhat limited if your L3 cache is small,
333 // as you'll (unfortunately) spend most of the time loading the data
336 // Complicated cases are left to the slow path; it basically stops copying
337 // up until the first instance of "sync_char" (usually a bit before, actually).
338 // This is fine, since 0x00 bytes shouldn't really show up in normal picture
339 // data, and what we really need this for is the 00 00 ff ff marker in video data.
340 const uint8_t *add_to_frame_fastpath(FrameAllocator::Frame *current_frame, const uint8_t *start, const uint8_t *limit, const char sync_char)
342 if (current_frame->data == nullptr ||
343 current_frame->len > current_frame->size ||
347 size_t orig_bytes = limit - start;
348 if (orig_bytes < 128) {
353 // Don't read more bytes than we can write.
354 limit = min(limit, start + (current_frame->size - current_frame->len));
356 // Align end to 32 bytes.
357 limit = (const uint8_t *)(intptr_t(limit) & ~31);
359 if (start >= limit) {
363 // Process [0,31] bytes, such that start gets aligned to 32 bytes.
364 const uint8_t *aligned_start = (const uint8_t *)(intptr_t(start + 31) & ~31);
365 if (aligned_start != start) {
366 const uint8_t *sync_start = (const uint8_t *)memchr(start, sync_char, aligned_start - start);
367 if (sync_start == nullptr) {
368 add_to_frame(current_frame, "", start, aligned_start);
370 add_to_frame(current_frame, "", start, sync_start);
375 // Make the length a multiple of 64.
376 if (current_frame->interleaved) {
377 if (((limit - aligned_start) % 64) != 0) {
380 assert(((limit - aligned_start) % 64) == 0);
384 const __m256i needle = _mm256_set1_epi8(sync_char);
386 const __restrict __m256i *in = (const __m256i *)aligned_start;
387 if (current_frame->interleaved) {
388 __restrict __m256i *out1 = (__m256i *)(current_frame->data + (current_frame->len + 1) / 2);
389 __restrict __m256i *out2 = (__m256i *)(current_frame->data2 + current_frame->len / 2);
390 if (current_frame->len % 2 == 1) {
394 __m256i shuffle_cw = _mm256_set_epi8(
395 15, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 0,
396 15, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 0);
397 while (in < (const __m256i *)limit) {
398 // Note: For brevity, comments show lanes as if they were 2x64-bit (they're actually 2x128).
399 __m256i data1 = _mm256_stream_load_si256(in); // AaBbCcDd EeFfGgHh
400 __m256i data2 = _mm256_stream_load_si256(in + 1); // IiJjKkLl MmNnOoPp
402 __m256i found1 = _mm256_cmpeq_epi8(data1, needle);
403 __m256i found2 = _mm256_cmpeq_epi8(data2, needle);
404 __m256i found = _mm256_or_si256(found1, found2);
406 data1 = _mm256_shuffle_epi8(data1, shuffle_cw); // ABCDabcd EFGHefgh
407 data2 = _mm256_shuffle_epi8(data2, shuffle_cw); // IJKLijkl MNOPmnop
409 data1 = _mm256_permute4x64_epi64(data1, 0b11011000); // ABCDEFGH abcdefgh
410 data2 = _mm256_permute4x64_epi64(data2, 0b11011000); // IJKLMNOP ijklmnop
412 __m256i lo = _mm256_permute2x128_si256(data1, data2, 0b00100000);
413 __m256i hi = _mm256_permute2x128_si256(data1, data2, 0b00110001);
415 _mm256_storeu_si256(out1, lo); // Store as early as possible, even if the data isn't used.
416 _mm256_storeu_si256(out2, hi);
418 if (!_mm256_testz_si256(found, found)) {
426 current_frame->len += (uint8_t *)in - aligned_start;
428 __m256i *out = (__m256i *)(current_frame->data + current_frame->len);
429 while (in < (const __m256i *)limit) {
430 __m256i data = _mm256_load_si256(in);
431 _mm256_storeu_si256(out, data); // Store as early as possible, even if the data isn't used.
432 __m256i found = _mm256_cmpeq_epi8(data, needle);
433 if (!_mm256_testz_si256(found, found)) {
440 current_frame->len = (uint8_t *)out - current_frame->data;
443 const __m128i needle = _mm_set1_epi8(sync_char);
445 const __m128i *in = (const __m128i *)aligned_start;
446 if (current_frame->interleaved) {
447 __m128i *out1 = (__m128i *)(current_frame->data + (current_frame->len + 1) / 2);
448 __m128i *out2 = (__m128i *)(current_frame->data2 + current_frame->len / 2);
449 if (current_frame->len % 2 == 1) {
453 __m128i mask_lower_byte = _mm_set1_epi16(0x00ff);
454 while (in < (const __m128i *)limit) {
455 __m128i data1 = _mm_load_si128(in);
456 __m128i data2 = _mm_load_si128(in + 1);
457 __m128i data1_lo = _mm_and_si128(data1, mask_lower_byte);
458 __m128i data2_lo = _mm_and_si128(data2, mask_lower_byte);
459 __m128i data1_hi = _mm_srli_epi16(data1, 8);
460 __m128i data2_hi = _mm_srli_epi16(data2, 8);
461 __m128i lo = _mm_packus_epi16(data1_lo, data2_lo);
462 _mm_storeu_si128(out1, lo); // Store as early as possible, even if the data isn't used.
463 __m128i hi = _mm_packus_epi16(data1_hi, data2_hi);
464 _mm_storeu_si128(out2, hi);
465 __m128i found1 = _mm_cmpeq_epi8(data1, needle);
466 __m128i found2 = _mm_cmpeq_epi8(data2, needle);
467 if (!_mm_testz_si128(found1, found1) ||
468 !_mm_testz_si128(found2, found2)) {
476 current_frame->len += (uint8_t *)in - aligned_start;
478 __m128i *out = (__m128i *)(current_frame->data + current_frame->len);
479 while (in < (const __m128i *)limit) {
480 __m128i data = _mm_load_si128(in);
481 _mm_storeu_si128(out, data); // Store as early as possible, even if the data isn't used.
482 __m128i found = _mm_cmpeq_epi8(data, needle);
483 if (!_mm_testz_si128(found, found)) {
490 current_frame->len = (uint8_t *)out - current_frame->data;
494 //printf("managed to fastpath %ld/%ld bytes\n", (const uint8_t *)in - (const uint8_t *)aligned_start, orig_bytes);
496 return (const uint8_t *)in;
500 void decode_packs(const libusb_transfer *xfr,
501 const char *sync_pattern,
503 FrameAllocator::Frame *current_frame,
504 const char *frame_type_name,
505 function<void(const uint8_t *start)> start_callback)
508 for (int i = 0; i < xfr->num_iso_packets; i++) {
509 const libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
511 if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
512 fprintf(stderr, "Error: pack %u/%u status %d\n", i, xfr->num_iso_packets, pack->status);
517 const uint8_t *start = xfr->buffer + offset;
518 const uint8_t *limit = start + pack->actual_length;
519 while (start < limit) { // Usually runs only one iteration.
521 start = add_to_frame_fastpath(current_frame, start, limit, sync_pattern[0]);
522 if (start == limit) break;
523 assert(start < limit);
526 const unsigned char* start_next_frame = (const unsigned char *)memmem(start, limit - start, sync_pattern, sync_length);
527 if (start_next_frame == nullptr) {
528 // add the rest of the buffer
529 add_to_frame(current_frame, frame_type_name, start, limit);
532 add_to_frame(current_frame, frame_type_name, start, start_next_frame);
533 start = start_next_frame + sync_length; // skip sync
534 start_callback(start);
538 dump_pack(xfr, offset, pack);
540 offset += pack->length;
544 void BMUSBCapture::cb_xfr(struct libusb_transfer *xfr)
546 if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {
547 fprintf(stderr, "transfer status %d\n", xfr->status);
548 libusb_free_transfer(xfr);
552 assert(xfr->user_data != nullptr);
553 BMUSBCapture *usb = static_cast<BMUSBCapture *>(xfr->user_data);
555 if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
556 if (xfr->endpoint == 0x84) {
557 decode_packs(xfr, "DeckLinkAudioResyncT", 20, &usb->current_audio_frame, "audio", bind(&BMUSBCapture::start_new_audio_block, usb, _1));
559 decode_packs(xfr, "\x00\x00\xff\xff", 4, &usb->current_video_frame, "video", bind(&BMUSBCapture::start_new_frame, usb, _1));
562 if (xfr->type == LIBUSB_TRANSFER_TYPE_CONTROL) {
563 //const libusb_control_setup *setup = libusb_control_transfer_get_setup(xfr);
564 uint8_t *buf = libusb_control_transfer_get_data(xfr);
566 if (setup->wIndex == 44) {
567 printf("read timer register: 0x%02x%02x%02x%02x\n", buf[0], buf[1], buf[2], buf[3]);
569 printf("read register %2d: 0x%02x%02x%02x%02x\n",
570 setup->wIndex, buf[0], buf[1], buf[2], buf[3]);
573 memcpy(usb->register_file + usb->current_register, buf, 4);
574 usb->current_register = (usb->current_register + 4) % NUM_BMUSB_REGISTERS;
575 if (usb->current_register == 0) {
576 // read through all of them
577 printf("register dump:");
578 for (int i = 0; i < NUM_BMUSB_REGISTERS; i += 4) {
579 printf(" 0x%02x%02x%02x%02x", usb->register_file[i], usb->register_file[i + 1], usb->register_file[i + 2], usb->register_file[i + 3]);
583 libusb_fill_control_setup(xfr->buffer,
584 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, /*request=*/214, /*value=*/0,
585 /*index=*/usb->current_register, /*length=*/4);
590 printf("length:%u, actual_length:%u\n", xfr->length, xfr->actual_length);
591 for (i = 0; i < xfr->actual_length; i++) {
592 printf("%02x", xfr->buffer[i]);
602 if (libusb_submit_transfer(xfr) < 0) {
603 fprintf(stderr, "error re-submitting URB\n");
608 void BMUSBCapture::usb_thread_func()
611 memset(¶m, 0, sizeof(param));
612 param.sched_priority = 1;
613 if (sched_setscheduler(0, SCHED_RR, ¶m) == -1) {
614 printf("couldn't set realtime priority for USB thread: %s\n", strerror(errno));
616 while (!should_quit) {
617 int rc = libusb_handle_events(nullptr);
618 if (rc != LIBUSB_SUCCESS)
623 void BMUSBCapture::configure_card()
625 if (video_frame_allocator == nullptr) {
626 set_video_frame_allocator(new MallocFrameAllocator(FRAME_SIZE)); // FIXME: leak.
628 if (audio_frame_allocator == nullptr) {
629 set_audio_frame_allocator(new MallocFrameAllocator(65536)); // FIXME: leak.
631 thread(&BMUSBCapture::dequeue_thread, this).detach();
634 struct libusb_transfer *xfr;
636 rc = libusb_init(nullptr);
638 fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
642 //struct libusb_device_handle *devh = libusb_open_device_with_vid_pid(nullptr, 0x1edb, 0xbd3b);
643 //struct libusb_device_handle *devh = libusb_open_device_with_vid_pid(nullptr, 0x1edb, 0xbd4f);
644 struct libusb_device_handle *devh = libusb_open_device_with_vid_pid(nullptr, vid, pid);
646 fprintf(stderr, "Error finding USB device\n");
650 libusb_config_descriptor *config;
651 rc = libusb_get_config_descriptor(libusb_get_device(devh), /*config_index=*/0, &config);
653 fprintf(stderr, "Error getting configuration: %s\n", libusb_error_name(rc));
656 printf("%d interface\n", config->bNumInterfaces);
657 for (int interface_number = 0; interface_number < config->bNumInterfaces; ++interface_number) {
658 printf(" interface %d\n", interface_number);
659 const libusb_interface *interface = &config->interface[interface_number];
660 for (int altsetting = 0; altsetting < interface->num_altsetting; ++altsetting) {
661 const libusb_interface_descriptor *interface_desc = &interface->altsetting[altsetting];
662 printf(" alternate setting %d\n", interface_desc->bAlternateSetting);
663 for (int endpoint_number = 0; endpoint_number < interface_desc->bNumEndpoints; ++endpoint_number) {
664 const libusb_endpoint_descriptor *endpoint = &interface_desc->endpoint[endpoint_number];
665 printf(" endpoint address 0x%02x\n", endpoint->bEndpointAddress);
670 rc = libusb_set_configuration(devh, /*configuration=*/1);
672 fprintf(stderr, "Error setting configuration 1: %s\n", libusb_error_name(rc));
676 rc = libusb_claim_interface(devh, 0);
678 fprintf(stderr, "Error claiming interface 0: %s\n", libusb_error_name(rc));
682 // Alternate setting 1 is output, alternate setting 2 is input.
683 // Card is reset when switching alternates, so the driver uses
684 // this “double switch” when it wants to reset.
686 // There's also alternate settings 3 and 4, which seem to be
687 // like 1 and 2 except they advertise less bandwidth needed.
688 rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/1);
690 fprintf(stderr, "Error setting alternate 1: %s\n", libusb_error_name(rc));
693 rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/2);
695 fprintf(stderr, "Error setting alternate 1: %s\n", libusb_error_name(rc));
699 rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/1);
701 fprintf(stderr, "Error setting alternate 1: %s\n", libusb_error_name(rc));
707 rc = libusb_claim_interface(devh, 3);
709 fprintf(stderr, "Error claiming interface 3: %s\n", libusb_error_name(rc));
715 // 44 is some kind of timer register (first 16 bits count upwards)
716 // 24 is some sort of watchdog?
717 // you can seemingly set it to 0x73c60001 and that bit will eventually disappear
718 // (or will go to 0x73c60010?), also seen 0x73c60100
719 // 12 also changes all the time, unclear why
720 // 16 seems to be autodetected mode somehow
721 // -- this is e00115e0 after reset?
722 // ed0115e0 after mode change [to output?]
723 // 2d0015e0 after more mode change [to input]
724 // ed0115e0 after more mode change
725 // 2d0015e0 after more mode change
727 // 390115e0 seems to indicate we have signal
728 // changes to 200115e0 when resolution changes/we lose signal, driver resets after a while
730 // 200015e0 on startup
731 // changes to 250115e0 when we sync to the signal
733 // so only first 16 bits count, and 0x0100 is a mask for ok/stable signal?
735 // Bottom 16 bits of this register seem to be firmware version number (possibly not all all of them).
737 // 28 and 32 seems to be analog audio input levels (one byte for each of the eight channels).
738 // however, if setting 32 with HDMI embedded audio, it is immediately overwritten back (to 0xe137002a).
740 // 4, 8, 20 are unclear. seem to be some sort of bitmask, but we can set them to 0 with no apparent effect.
741 // perhaps some of them are related to analog output?
743 // 36 can be set to 0 with no apparent effect (all of this tested on both video and audio),
744 // but the driver sets it to 0x8036802a at some point.
746 // all of this is on request 214/215. other requests (192, 219,
747 // 222, 223, 224) are used for firmware upgrade. Probably best to
748 // stay out of it unless you know what you're doing.
752 // first byte is 0x39 for a stable 576p60 signal, 0x2d for a stable 720p60 signal, 0x20 for no signal
755 // 0x01 - stable signal
757 // 0x08 - unknown (audio??)
767 static const ctrl ctrls[] = {
768 { LIBUSB_ENDPOINT_IN, 214, 16, 0 },
769 { LIBUSB_ENDPOINT_IN, 214, 0, 0 },
771 // seems to capture on HDMI, clearing the 0x20000000 bit seems to activate 10-bit
773 // clearing the 0x08000000 bit seems to change the capture format (other source?)
774 // 0x10000000 = analog audio instead of embedded audio, it seems
775 // 0x3a000000 = component video? (analog audio)
776 // 0x3c000000 = composite video? (analog audio)
777 // 0x3e000000 = s-video? (analog audio)
778 { LIBUSB_ENDPOINT_OUT, 215, 0, 0x29000000 },
779 //{ LIBUSB_ENDPOINT_OUT, 215, 0, 0x80000100 },
780 //{ LIBUSB_ENDPOINT_OUT, 215, 0, 0x09000000 },
781 { LIBUSB_ENDPOINT_OUT, 215, 24, 0x73c60001 }, // latch for frame start?
782 { LIBUSB_ENDPOINT_IN, 214, 24, 0 }, //
785 for (unsigned req = 0; req < sizeof(ctrls) / sizeof(ctrls[0]); ++req) {
786 uint32_t flipped = htonl(ctrls[req].data);
787 static uint8_t value[4];
788 memcpy(value, &flipped, sizeof(flipped));
789 int size = sizeof(value);
790 //if (ctrls[req].request == 215) size = 0;
791 rc = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | ctrls[req].endpoint,
792 /*request=*/ctrls[req].request, /*value=*/0, /*index=*/ctrls[req].index, value, size, /*timeout=*/0);
794 fprintf(stderr, "Error on control %d: %s\n", ctrls[req].index, libusb_error_name(rc));
798 printf("rc=%d: ep=%d@%d %d -> 0x", rc, ctrls[req].endpoint, ctrls[req].request, ctrls[req].index);
799 for (int i = 0; i < rc; ++i) {
800 printf("%02x", value[i]);
808 static int my_index = 0;
809 static uint8_t value[4];
810 int size = sizeof(value);
811 rc = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
812 /*request=*/214, /*value=*/0, /*index=*/my_index, value, size, /*timeout=*/0);
814 fprintf(stderr, "Error on control\n");
817 printf("rc=%d index=%d: 0x", rc, my_index);
818 for (int i = 0; i < rc; ++i) {
819 printf("%02x", value[i]);
826 // set up an asynchronous transfer of the timer register
827 static uint8_t cmdbuf[LIBUSB_CONTROL_SETUP_SIZE + 4];
828 static int completed = 0;
830 xfr = libusb_alloc_transfer(0);
831 libusb_fill_control_setup(cmdbuf,
832 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, /*request=*/214, /*value=*/0,
833 /*index=*/44, /*length=*/4);
834 libusb_fill_control_transfer(xfr, devh, cmdbuf, cb_xfr, &completed, 0);
835 xfr->user_data = this;
836 libusb_submit_transfer(xfr);
838 // set up an asynchronous transfer of register 24
839 static uint8_t cmdbuf2[LIBUSB_CONTROL_SETUP_SIZE + 4];
840 static int completed2 = 0;
842 xfr = libusb_alloc_transfer(0);
843 libusb_fill_control_setup(cmdbuf2,
844 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, /*request=*/214, /*value=*/0,
845 /*index=*/24, /*length=*/4);
846 libusb_fill_control_transfer(xfr, devh, cmdbuf2, cb_xfr, &completed2, 0);
847 xfr->user_data = this;
848 libusb_submit_transfer(xfr);
851 // set up an asynchronous transfer of the register dump
852 static uint8_t cmdbuf3[LIBUSB_CONTROL_SETUP_SIZE + 4];
853 static int completed3 = 0;
855 xfr = libusb_alloc_transfer(0);
856 libusb_fill_control_setup(cmdbuf3,
857 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, /*request=*/214, /*value=*/0,
858 /*index=*/current_register, /*length=*/4);
859 libusb_fill_control_transfer(xfr, devh, cmdbuf3, cb_xfr, &completed3, 0);
860 xfr->user_data = this;
861 //libusb_submit_transfer(xfr);
863 audiofp = fopen("audio.raw", "wb");
865 // set up isochronous transfers for audio and video
866 for (int e = 3; e <= 4; ++e) {
867 //int num_transfers = (e == 3) ? 6 : 6;
868 int num_transfers = 6;
869 for (int i = 0; i < num_transfers; ++i) {
870 int num_iso_pack, size;
872 // Video seems to require isochronous packets scaled with the width;
873 // seemingly six lines is about right, rounded up to the required 1kB
875 size = WIDTH * 2 * 6;
876 // Note that for 10-bit input, you'll need to increase size accordingly.
877 //size = size * 4 / 3;
878 if (size % 1024 != 0) {
882 num_iso_pack = (2 << 18) / size; // 512 kB.
883 printf("Picking %d packets of 0x%x bytes each\n", num_iso_pack, size);
888 int num_bytes = num_iso_pack * size;
889 uint8_t *buf = new uint8_t[num_bytes];
891 xfr = libusb_alloc_transfer(num_iso_pack);
893 fprintf(stderr, "oom\n");
897 int ep = LIBUSB_ENDPOINT_IN | e;
898 libusb_fill_iso_transfer(xfr, devh, ep, buf, num_bytes,
899 num_iso_pack, cb_xfr, nullptr, 0);
900 libusb_set_iso_packet_lengths(xfr, size);
901 xfr->user_data = this;
902 iso_xfrs.push_back(xfr);
907 void BMUSBCapture::start_bm_capture()
909 printf("starting capture\n");
911 for (libusb_transfer *xfr : iso_xfrs) {
912 printf("submitting transfer...\n");
913 int rc = libusb_submit_transfer(xfr);
916 //printf("num_bytes=%d\n", num_bytes);
917 fprintf(stderr, "Error submitting iso to endpoint 0x%02x, number %d: %s\n",
918 xfr->endpoint, i, libusb_error_name(rc));
925 libusb_release_interface(devh, 0);
929 libusb_exit(nullptr);
934 void BMUSBCapture::start_bm_thread()
937 usb_thread = thread(&BMUSBCapture::usb_thread_func);
940 void BMUSBCapture::stop_bm_thread()