]> git.sesse.net Git - bmusb/blobdiff - bmusb.cpp
Release v0.5.3.
[bmusb] / bmusb.cpp
index c4758f5eaa7a0c9c5bb8fe1e74b81c17ee255c14..9c0ff26e7b767cf522ce5184f9be30130e5c61d9 100644 (file)
--- a/bmusb.cpp
+++ b/bmusb.cpp
@@ -1,4 +1,4 @@
-// Intensity Shuttle USB3 capture driver, v0.4
+// Intensity Shuttle USB3 capture driver, v0.5.3
 // Can download 8-bit and 10-bit UYVY/v210 frames from HDMI, quite stable
 // (can do captures for hours at a time with no drops), except during startup
 // 576p60/720p60/1080i60 works, 1080p60 does not work (firmware limitation)
 #if HAS_MULTIVERSIONING
 #include <immintrin.h>
 #endif
-#include "bmusb.h"
+#include "bmusb/bmusb.h"
 
 #include <algorithm>
 #include <atomic>
+#include <chrono>
 #include <condition_variable>
 #include <cstddef>
 #include <cstdint>
@@ -37,6 +38,7 @@
 #include <thread>
 
 using namespace std;
+using namespace std::chrono;
 using namespace std::placeholders;
 
 #define USB_VENDOR_BLACKMAGIC 0x1edb
@@ -51,6 +53,7 @@ using namespace std::placeholders;
 namespace bmusb {
 
 card_connected_callback_t BMUSBCapture::card_connected_callback = nullptr;
+bool BMUSBCapture::hotplug_existing_devices = false;
 
 namespace {
 
@@ -361,6 +364,8 @@ void BMUSBCapture::start_new_frame(const uint8_t *start)
        uint16_t timecode = (start[1] << 8) | start[0];
 
        if (current_video_frame.len > 0) {
+               current_video_frame.received_timestamp = steady_clock::now();
+
                // If format is 0x0800 (no signal), add a fake (empty) audio
                // frame to get it out of the queue.
                // TODO: Figure out if there are other formats that come with
@@ -404,6 +409,7 @@ void BMUSBCapture::start_new_audio_block(const uint8_t *start)
        uint16_t format = (start[3] << 8) | start[2];
        uint16_t timecode = (start[1] << 8) | start[0];
        if (current_audio_frame.len > 0) {
+               current_audio_frame.received_timestamp = steady_clock::now();
                //dump_audio_block();
                queue_frame(format, timecode, current_audio_frame, &pending_audio_frames);
        }
@@ -535,6 +541,10 @@ const uint8_t *add_to_frame_fastpath(FrameAllocator::Frame *current_frame, const
 
 #else  // defined(HAS_MULTIVERSIONING)
 
+__attribute__((target("sse4.1")))
+const uint8_t *add_to_frame_fastpath_core(FrameAllocator::Frame *current_frame, const uint8_t *aligned_start, const uint8_t *limit, const char sync_char);
+
+__attribute__((target("avx2")))
 const uint8_t *add_to_frame_fastpath_core(FrameAllocator::Frame *current_frame, const uint8_t *aligned_start, const uint8_t *limit, const char sync_char);
 
 // Does a memcpy and memchr in one to reduce processing time.
@@ -877,12 +887,15 @@ void BMUSBCapture::usb_thread_func()
                printf("couldn't set realtime priority for USB thread: %s\n", strerror(errno));
        }
        while (!should_quit) {
-               int rc = libusb_handle_events(nullptr);
+               timeval sec { 1, 0 };
+               int rc = libusb_handle_events_timeout(nullptr, &sec);
                if (rc != LIBUSB_SUCCESS)
                        break;
        }
 }
 
+namespace {
+
 struct USBCardDevice {
        uint16_t product;
        uint8_t bus, port;
@@ -911,7 +924,7 @@ string get_card_description(int id, uint8_t bus, uint8_t port, uint16_t product)
        return buf;
 }
 
-libusb_device_handle *open_card(int card_index, string *description)
+vector<USBCardDevice> find_all_cards()
 {
        libusb_device **devices;
        ssize_t num_devices = libusb_get_device_list(nullptr, &devices);
@@ -949,6 +962,13 @@ libusb_device_handle *open_card(int card_index, string *description)
                return a.port < b.port;
        });
 
+       return found_cards;
+}
+
+libusb_device_handle *open_card(int card_index, string *description)
+{
+       vector<USBCardDevice> found_cards = find_all_cards();
+
        for (size_t i = 0; i < found_cards.size(); ++i) {
                string tmp_description = get_card_description(i, found_cards[i].bus, found_cards[i].port, found_cards[i].product);
                fprintf(stderr, "%s\n", tmp_description.c_str());
@@ -999,6 +1019,24 @@ libusb_device_handle *open_card(unsigned card_index, libusb_device *dev, string
        return devh;
 }
 
+}  // namespace
+
+unsigned BMUSBCapture::num_cards()
+{
+       int rc = libusb_init(nullptr);
+       if (rc < 0) {
+               fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
+               exit(1);
+       }
+
+       vector<USBCardDevice> found_cards = find_all_cards();
+       unsigned ret = found_cards.size();
+       for (size_t i = 0; i < found_cards.size(); ++i) {
+               libusb_unref_device(found_cards[i].device);
+       }
+       return ret;
+}
+
 void BMUSBCapture::configure_card()
 {
        if (video_frame_allocator == nullptr) {
@@ -1076,6 +1114,11 @@ void BMUSBCapture::configure_card()
        rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/1);
        if (rc < 0) {
                fprintf(stderr, "Error setting alternate 1: %s\n", libusb_error_name(rc));
+               if (rc == LIBUSB_ERROR_NOT_FOUND) {
+                       fprintf(stderr, "This is usually because the card came up in USB2 mode.\n");
+                       fprintf(stderr, "In particular, this tends to happen if you boot up with the\n");
+                       fprintf(stderr, "card plugged in; just unplug and replug it, and it usually works.\n");
+               }
                exit(1);
        }
        rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/2);
@@ -1346,7 +1389,7 @@ void BMUSBCapture::start_bm_thread()
        // coming back with errors, so only care about devices joining.
        if (card_connected_callback != nullptr) {
                if (libusb_hotplug_register_callback(
-                       nullptr, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, LIBUSB_HOTPLUG_NO_FLAGS,
+                       nullptr, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, hotplug_existing_devices ? LIBUSB_HOTPLUG_ENUMERATE : LIBUSB_HOTPLUG_NO_FLAGS,
                        USB_VENDOR_BLACKMAGIC, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
                        &BMUSBCapture::cb_hotplug, nullptr, nullptr) < 0) {
                        fprintf(stderr, "libusb_hotplug_register_callback() failed\n");