-// Intensity Shuttle USB3 capture driver, v0.6.0
+// Intensity Shuttle USB3 capture driver, v0.7.5
// Can download 8-bit and 10-bit UYVY/v210-ish 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)
constexpr VideoFormatEntry entries[] = {
{ 0x01f1, 720, 480, 0, 40, 5, 60000, 1001, false }, // 480p59.94 (believed).
{ 0x0131, 720, 576, 0, 44, 5, 50, 1, false }, // 576p50.
+ { 0x0151, 720, 576, 0, 44, 5, 50, 1, false }, // 576p50.
{ 0x0011, 720, 576, 0, 44, 5, 50, 1, false }, // 576p50 (5:4).
{ 0x0143, 1280, 720, 0, 25, 5, 50, 1, false }, // 720p50.
+ { 0x0161, 1280, 720, 0, 25, 5, 50, 1, false }, // 720p50.
{ 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.
// See if we match or are very close to any of the mandatory HDMI sample rates.
const int candidate_sample_rates[] = { 32000, 44100, 48000 };
for (int rate : candidate_sample_rates) {
- if (abs(int(num_samples_per_second) - rate) < 50) {
+ if (abs(int(num_samples_per_second) - rate) <= 100) {
return rate;
}
}
void dump_audio_block(uint8_t *audio_start, size_t audio_len)
{
- fwrite(audio_start + AUDIO_HEADER_SIZE, 1, audio_len - AUDIO_HEADER_SIZE, audiofp);
+ if (audiofp != nullptr) {
+ fwrite(audio_start + AUDIO_HEADER_SIZE, 1, audio_len - AUDIO_HEADER_SIZE, audiofp);
+ }
}
void BMUSBCapture::dequeue_thread_func()
video_frame.frame, HEADER_SIZE, video_format,
audio_frame.frame, AUDIO_HEADER_SIZE, audio_format);
} else {
+ video_frame_allocator->release_frame(video_frame.frame);
audio_format.sample_rate = last_sample_rate;
frame_callback(video_timecode,
FrameAllocator::Frame(), 0, video_format,
}
//dump_frame();
} else {
+ if (current_frame->data_copy != nullptr) {
+ memcpy(current_frame->data_copy + current_frame->len, start, bytes);
+ }
if (current_frame->interleaved) {
uint8_t *data = current_frame->data + current_frame->len / 2;
uint8_t *data2 = current_frame->data2 + current_frame->len / 2;
{
const __m256i needle = _mm256_set1_epi8(sync_char);
+ size_t bytes_copied;
const __restrict __m256i *in = (const __m256i *)aligned_start;
if (current_frame->interleaved) {
__restrict __m256i *out1 = (__m256i *)(current_frame->data + (current_frame->len + 1) / 2);
++out1;
++out2;
}
- current_frame->len += (uint8_t *)in - aligned_start;
+ bytes_copied = (uint8_t *)in - aligned_start;
} else {
- __m256i *out = (__m256i *)(current_frame->data + current_frame->len);
+ uint8_t *old_end = current_frame->data + current_frame->len;
+ __m256i *out = (__m256i *)old_end;
while (in < (const __m256i *)limit) {
__m256i data = _mm256_load_si256(in);
_mm256_storeu_si256(out, data); // Store as early as possible, even if the data isn't used.
++in;
++out;
}
- current_frame->len = (uint8_t *)out - current_frame->data;
+ bytes_copied = (uint8_t *)out - old_end;
}
+ if (current_frame->data_copy != nullptr) {
+ // TODO: It would be somewhat more cache-efficient to write this in the
+ // same loop as above. However, it might not be worth the extra complexity.
+ memcpy(current_frame->data_copy + current_frame->len, aligned_start, bytes_copied);
+ }
+ current_frame->len += bytes_copied;
//printf("managed to fastpath %ld/%ld bytes\n", (const uint8_t *)in - (const uint8_t *)aligned_start, orig_bytes);
return (const uint8_t *)in;
const __m128i needle = _mm_set1_epi8(sync_char);
const __m128i *in = (const __m128i *)aligned_start;
+ size_t bytes_copied;
if (current_frame->interleaved) {
__m128i *out1 = (__m128i *)(current_frame->data + (current_frame->len + 1) / 2);
__m128i *out2 = (__m128i *)(current_frame->data2 + current_frame->len / 2);
++out1;
++out2;
}
- current_frame->len += (uint8_t *)in - aligned_start;
+ bytes_copied = (uint8_t *)in - aligned_start;
} else {
- __m128i *out = (__m128i *)(current_frame->data + current_frame->len);
+ uint8_t *old_end = current_frame->data + current_frame->len;
+ __m128i *out = (__m128i *)old_end;
while (in < (const __m128i *)limit) {
__m128i data = _mm_load_si128(in);
_mm_storeu_si128(out, data); // Store as early as possible, even if the data isn't used.
++in;
++out;
}
- current_frame->len = (uint8_t *)out - current_frame->data;
+ bytes_copied = (uint8_t *)out - old_end;
+ }
+ if (current_frame->data_copy != nullptr) {
+ // TODO: It would be somewhat more cache-efficient to write this in the
+ // same loop as above. However, it might not be worth the extra complexity.
+ memcpy(current_frame->data_copy + current_frame->len, aligned_start, bytes_copied);
}
+ current_frame->len += bytes_copied;
//printf("managed to fastpath %ld/%ld bytes\n", (const uint8_t *)in - (const uint8_t *)aligned_start, orig_bytes);
return (const uint8_t *)in;
void BMUSBCapture::stop_bm_thread()
{
should_quit = true;
+ libusb_interrupt_event_handler(nullptr);
usb_thread.join();
}