// 576p60/720p60/1080i60 works, 1080p60 does not work (firmware limitation)
// Audio comes out as 8-channel 24-bit raw audio.
+#include <assert.h>
+#include <errno.h>
+#include <libusb.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <libusb.h>
-#include <arpa/inet.h>
-#include <unistd.h>
#include <string.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <assert.h>
-#ifdef __SSE2__
+#ifdef __SSE4_1__
#include <immintrin.h>
#endif
+#include "bmusb.h"
+
#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <cstddef>
+#include <cstdint>
+#include <deque>
#include <functional>
#include <memory>
-#include <deque>
-#include <utility>
#include <mutex>
-#include <condition_variable>
-#include <thread>
#include <stack>
-#include <atomic>
-#include "bmusb.h"
+#include <thread>
using namespace std;
using namespace std::placeholders;
fwrite(audio_start + AUDIO_HEADER_SIZE, 1, audio_len - AUDIO_HEADER_SIZE, audiofp);
}
-void BMUSBCapture::dequeue_thread()
+void BMUSBCapture::dequeue_thread_func()
{
- for ( ;; ) {
+ if (has_dequeue_callbacks) {
+ dequeue_init_callback();
+ }
+ while (!dequeue_thread_should_quit) {
unique_lock<mutex> lock(queue_lock);
- queues_not_empty.wait(lock, [this]{ return !pending_video_frames.empty() && !pending_audio_frames.empty(); });
+ queues_not_empty.wait(lock, [this]{ return dequeue_thread_should_quit || (!pending_video_frames.empty() && !pending_audio_frames.empty()); });
uint16_t video_timecode = pending_video_frames.front().timecode;
uint16_t audio_timecode = pending_audio_frames.front().timecode;
audio_frame.frame, AUDIO_HEADER_SIZE, audio_frame.format);
}
}
+ if (has_dequeue_callbacks) {
+ dequeue_cleanup_callback();
+ }
}
void BMUSBCapture::start_new_frame(const uint8_t *start)
}
}
-#ifdef __SSE2__
+#ifdef __SSE4_1__
#if 0
-void dump(const char *name, __m256i n)
+void avx2_dump(const char *name, __m256i n)
{
printf("%-10s:", name);
printf(" %02x", _mm256_extract_epi8(n, 0));
const uint8_t *start = xfr->buffer + offset;
const uint8_t *limit = start + pack->actual_length;
while (start < limit) { // Usually runs only one iteration.
-#ifdef __SSE2__
+#ifdef __SSE4_1__
start = add_to_frame_fastpath(current_frame, start, limit, sync_pattern[0]);
if (start == limit) break;
assert(start < limit);
if (audio_frame_allocator == nullptr) {
set_audio_frame_allocator(new MallocFrameAllocator(65536)); // FIXME: leak.
}
- thread(&BMUSBCapture::dequeue_thread, this).detach();
+ dequeue_thread_should_quit = false;
+ dequeue_thread = thread(&BMUSBCapture::dequeue_thread_func, this);
int rc;
struct libusb_transfer *xfr;
}
}
-#if 0
rc = libusb_set_configuration(devh, /*configuration=*/1);
if (rc < 0) {
fprintf(stderr, "Error setting configuration 1: %s\n", libusb_error_name(rc));
exit(1);
}
-#endif
rc = libusb_claim_interface(devh, 0);
if (rc < 0) {
exit(1);
}
+ // Alternate setting 1 is output, alternate setting 2 is input.
+ // Card is reset when switching alternates, so the driver uses
+ // this “double switch” when it wants to reset.
+ //
+ // There's also alternate settings 3 and 4, which seem to be
+ // like 1 and 2 except they advertise less bandwidth needed.
+ 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));
+ exit(1);
+ }
+ rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/2);
+ if (rc < 0) {
+ fprintf(stderr, "Error setting alternate 1: %s\n", libusb_error_name(rc));
+ exit(1);
+ }
#if 0
rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/1);
if (rc < 0) {
//
// so only first 16 bits count, and 0x0100 is a mask for ok/stable signal?
//
+ // Bottom 16 bits of this register seem to be firmware version number (possibly not all all of them).
+ //
// 28 and 32 seems to be analog audio input levels (one byte for each of the eight channels).
// however, if setting 32 with HDMI embedded audio, it is immediately overwritten back (to 0xe137002a).
//
// 36 can be set to 0 with no apparent effect (all of this tested on both video and audio),
// but the driver sets it to 0x8036802a at some point.
//
+ // all of this is on request 214/215. other requests (192, 219,
+ // 222, 223, 224) are used for firmware upgrade. Probably best to
+ // stay out of it unless you know what you're doing.
+ //
+ //
// register 16:
// first byte is 0x39 for a stable 576p60 signal, 0x2d for a stable 720p60 signal, 0x20 for no signal
//
printf("\n");
}
- // Alternate setting 1 is output, alternate setting 2 is input.
- // Card is reset when switching alternates, so the driver uses
- // this “double switch” when it wants to reset.
-#if 0
- 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));
- exit(1);
- }
-#endif
- rc = libusb_set_interface_alt_setting(devh, /*interface=*/0, /*alternate_setting=*/4);
- if (rc < 0) {
- fprintf(stderr, "Error setting alternate 4: %s\n", libusb_error_name(rc));
- exit(1);
- }
-
#if 0
// DEBUG
for ( ;; ) {
// set up isochronous transfers for audio and video
for (int e = 3; e <= 4; ++e) {
//int num_transfers = (e == 3) ? 6 : 6;
- int num_transfers = 2;
+ int num_transfers = 6;
for (int i = 0; i < num_transfers; ++i) {
int num_iso_pack, size;
if (e == 3) {
size &= ~1023;
size += 1024;
}
- num_iso_pack = (2 << 20) / size; // 512 kB.
+ num_iso_pack = (2 << 18) / size; // 512 kB.
printf("Picking %d packets of 0x%x bytes each\n", num_iso_pack, size);
} else {
size = 0xc0;
#endif
}
+void BMUSBCapture::stop_dequeue_thread()
+{
+ dequeue_thread_should_quit = true;
+ queues_not_empty.notify_all();
+ dequeue_thread.join();
+}
+
void BMUSBCapture::start_bm_thread()
{
should_quit = false;