-// Intensity Shuttle USB3 capture driver, v0.5
+// Intensity Shuttle USB3 capture driver, v0.5.4
// 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)
#include <libusb.h>
#include <unistd.h>
#include <netinet/in.h>
+#include <pthread.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <algorithm>
#include <atomic>
+#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <thread>
using namespace std;
+using namespace std::chrono;
using namespace std::placeholders;
#define USB_VENDOR_BLACKMAGIC 0x1edb
// It's a strange thing, but what can you do.
decoded_video_format->width = 720;
decoded_video_format->height = 525;
+ decoded_video_format->stride = 720 * 2;
decoded_video_format->extra_lines_top = 0;
decoded_video_format->extra_lines_bottom = 0;
decoded_video_format->frame_rate_nom = 3013;
video_format);
decoded_video_format->width = 0;
decoded_video_format->height = 0;
+ decoded_video_format->stride = 0;
decoded_video_format->extra_lines_top = 0;
decoded_video_format->extra_lines_bottom = 0;
decoded_video_format->frame_rate_nom = 60;
if (video_format == 0xe901 || video_format == 0xe9c1 || video_format == 0xe801) {
decoded_video_format->width = 720;
decoded_video_format->height = 480;
+ decoded_video_format->stride = 720 * 2;
decoded_video_format->extra_lines_top = 17;
decoded_video_format->extra_lines_bottom = 28;
decoded_video_format->frame_rate_nom = 30000;
if (video_format == 0xe909 || video_format == 0xe9c9 || video_format == 0xe809 || video_format == 0xebe9 || video_format == 0xebe1) {
decoded_video_format->width = 720;
decoded_video_format->height = 576;
+ decoded_video_format->stride = 720 * 2;
decoded_video_format->extra_lines_top = 22;
decoded_video_format->extra_lines_bottom = 27;
decoded_video_format->frame_rate_nom = 25;
{ 0x0103, 1280, 720, 0, 25, 5, 60, 1, false }, // 720p60.
{ 0x0125, 1280, 720, 0, 25, 5, 60, 1, false }, // 720p60.
{ 0x0121, 1280, 720, 0, 25, 5, 60000, 1001, false }, // 720p59.94.
- { 0x01c3, 1920, 1080, 0, 0, 0, 30, 1, false }, // 1080p30.
+ { 0x01c3, 1920, 1080, 0, 41, 4, 30, 1, false }, // 1080p30.
{ 0x0003, 1920, 1080, 583, 20, 25, 30, 1, true }, // 1080i60.
- { 0x01e1, 1920, 1080, 0, 0, 0, 30000, 1001, false }, // 1080p29.97.
+ { 0x01e1, 1920, 1080, 0, 41, 4, 30000, 1001, false }, // 1080p29.97.
{ 0x0021, 1920, 1080, 583, 20, 25, 30000, 1001, true }, // 1080i59.94.
- { 0x0063, 1920, 1080, 0, 0, 0, 25, 1, false }, // 1080p25.
- { 0x0043, 1920, 1080, 0, 0, 0, 25, 1, true }, // 1080p50.
- { 0x008e, 1920, 1080, 0, 0, 0, 24, 1, false }, // 1080p24.
- { 0x00a1, 1920, 1080, 0, 0, 0, 24000, 1001, false }, // 1080p23.98.
+ { 0x0063, 1920, 1080, 0, 41, 4, 25, 1, false }, // 1080p25.
+ { 0x0043, 1920, 1080, 583, 20, 25, 25, 1, true }, // 1080i50.
+ { 0x0083, 1920, 1080, 0, 41, 4, 24, 1, false }, // 1080p24.
+ { 0x00a1, 1920, 1080, 0, 41, 4, 24000, 1001, false }, // 1080p23.98.
};
for (const VideoFormatEntry &entry : entries) {
if (normalized_video_format == entry.normalized_video_format) {
decoded_video_format->width = entry.width;
decoded_video_format->height = entry.height;
+ decoded_video_format->stride = entry.width * 2;
decoded_video_format->second_field_start = entry.second_field_start;
decoded_video_format->extra_lines_top = entry.extra_lines_top;
decoded_video_format->extra_lines_bottom = entry.extra_lines_bottom;
printf("Unknown video format 0x%04x (normalized 0x%04x). Assuming 720p60.\n", video_format, normalized_video_format);
decoded_video_format->width = 1280;
decoded_video_format->height = 720;
+ decoded_video_format->stride = 1280 * 2;
decoded_video_format->frame_rate_nom = 60;
decoded_video_format->frame_rate_den = 1;
return false;
void BMUSBCapture::dequeue_thread_func()
{
+ char thread_name[16];
+ snprintf(thread_name, sizeof(thread_name), "bmusb_dequeue_%d", card_index);
+ pthread_setname_np(pthread_self(), thread_name);
+
if (has_dequeue_callbacks) {
dequeue_init_callback();
}
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
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);
}
#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.
if (sched_setscheduler(0, SCHED_RR, ¶m) == -1) {
printf("couldn't set realtime priority for USB thread: %s\n", strerror(errno));
}
+ pthread_setname_np(pthread_self(), "bmusb_usb_drv");
while (!should_quit) {
timeval sec { 1, 0 };
int rc = libusb_handle_events_timeout(nullptr, &sec);
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);