Switch to buffer requests without memcpy
Some checks are pending
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux32 flags:32 name:Linux GCC 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux64 flags:64 name:Linux GCC x64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm32 flags:arm32 name:Linux GCC ARM 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm64 flags:arm64 name:Linux GCC ARM 64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:macos name:macOS Apple Silicon os:macos-14]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win32 flags:-A Win32 name:Windows VS2022 Win32 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win64 flags:-A x64 name:Windows VS2022 x64 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:winarm64 flags:-A ARM64 name:Windows VS2022 ARM os:windows-2022]) (push) Waiting to run
CD / Create Pi Mono Setup (push) Blocked by required conditions
CD / Publishing (push) Blocked by required conditions

This commit is contained in:
Lorenzooone 2025-03-13 03:11:55 +01:00
parent 365c0625bd
commit fb6de81c52
21 changed files with 274 additions and 309 deletions

View File

@ -4,7 +4,7 @@
#include "capture_structs.hpp"
#include "devicecapture.hpp"
#define FTD3_CONCURRENT_BUFFERS 4
#define FTD3_CONCURRENT_BUFFERS NUM_CONCURRENT_DATA_BUFFER_WRITERS
struct ftd3_device_device_handlers {
void* usb_handle = NULL;

View File

@ -13,7 +13,6 @@ struct ftd3_async_callback_data {
void* actual_user_data;
void* transfer_data;
std::mutex transfer_data_access;
int internal_index;
};
int ftd3_libusb_ctrl_in(ftd3_device_device_handlers* handlers, uint32_t timeout, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred);

View File

@ -8,6 +8,6 @@
uint64_t ftd3_get_capture_size(CaptureData* capture_data);
std::string ftd3_get_serial(std::string serial_string, int &curr_serial_extra_id);
void ftd3_insert_device(std::vector<CaptureDevice> &devices_list, std::string serial_string, int &curr_serial_extra_id, bool is_driver);
void data_output_update(CaptureReceived* received_buffer, size_t read_data, CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time);
void data_output_update(int inner_index, size_t read_data, CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time);
#endif

View File

@ -8,14 +8,11 @@
#include <chrono>
// Sometimes the CC returns a 2 length packet, if you're too fast
#define BASE_NUM_CAPTURE_RECEIVED_DATA_BUFFERS 4
#define NUM_CAPTURE_RECEIVED_DATA_0_MULTIPLIER 2
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS (BASE_NUM_CAPTURE_RECEIVED_DATA_BUFFERS * NUM_CAPTURE_RECEIVED_DATA_0_MULTIPLIER)
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS NUM_CONCURRENT_DATA_BUFFER_WRITERS
typedef void (*fdt2_async_callback_function)(void* user_data, int transfer_length, int transfer_status);
struct ftd2_async_callback_data {
FTD2OldDSCaptureReceivedRaw buffer_raw;
fdt2_async_callback_function function;
void* actual_user_data;
void* transfer_data;
@ -34,6 +31,8 @@ struct FTD2CaptureReceivedData {
int* status;
uint32_t index;
uint32_t* last_used_index;
uint8_t* buffer_raw;
uint32_t* buffer_target;
size_t* curr_offset;
CaptureData* capture_data;
std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start;

View File

@ -6,12 +6,11 @@
#include "capture_structs.hpp"
#include "display_structs.hpp"
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS 4
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS NUM_CONCURRENT_DATA_BUFFER_WRITERS
struct ISDeviceCaptureReceivedData {
volatile bool in_use;
uint32_t index;
CaptureReceived buffer;
SharedConsumerMutex* is_buffer_free_shared_mutex;
int* status;
uint32_t* last_index;
@ -24,10 +23,10 @@ struct ISDeviceCaptureReceivedData {
int set_acquisition_mode(is_device_device_handlers* handlers, CaptureScreensType capture_type, CaptureSpeedsType capture_speed, const is_device_usb_device* usb_device_desc);
int EndAcquisition(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data, bool do_drain_frames, int start_frames, CaptureScreensType capture_type);
int EndAcquisition(const is_device_usb_device* usb_device_desc, is_device_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type);
int is_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start);
int is_device_read_frame_and_output(CaptureData* capture_data, int internal_index, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start);
void is_device_read_frame_request(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index);
uint64_t usb_is_device_get_video_in_size(CaptureScreensType capture_type, is_device_type device_type);
void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size);
void output_to_thread(CaptureData* capture_data, int internal_index, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size);
ISDeviceCaptureReceivedData* is_device_get_free_buffer(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data);
bool is_device_are_buffers_all_free(ISDeviceCaptureReceivedData* is_device_capture_recv_data);

View File

@ -3,12 +3,11 @@
#include "cypress_nisetro_communications.hpp"
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS 4
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS NUM_CONCURRENT_DATA_BUFFER_WRITERS
struct CypressDeviceCaptureReceivedData {
volatile bool in_use;
uint32_t index;
CaptureReceived buffer;
SharedConsumerMutex* is_buffer_free_shared_mutex;
size_t* scheduled_special_read;
uint32_t* active_special_read_index;
@ -20,7 +19,6 @@ struct CypressDeviceCaptureReceivedData {
int* consecutive_output_to_thread;
CaptureData* capture_data;
std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start;
CaptureScreensType curr_capture_type;
cyni_async_callback_data cb_data;
};

View File

@ -26,12 +26,13 @@ enum CaptureScreensType { CAPTURE_SCREENS_BOTH, CAPTURE_SCREENS_TOP, CAPTURE_SCR
enum CaptureSpeedsType { CAPTURE_SPEEDS_FULL, CAPTURE_SPEEDS_HALF, CAPTURE_SPEEDS_THIRD, CAPTURE_SPEEDS_QUARTER, CAPTURE_SPEEDS_ENUM_END };
// Readers are Audio and Video. So 2.
// Use 2 extra buffers. One for writing in case the other 2 are busy,
// Use 6 extra buffers. 5 for async writing in case the other 2 are busy,
// and the other for writing without overwriting the latest stuff in
// a worst case scenario...
enum CaptureReaderType { CAPTURE_READER_VIDEO, CAPTURE_READER_AUDIO, CAPTURE_READER_ENUM_END };
#define NUM_CONCURRENT_DATA_BUFFER_WRITERS 5
#define NUM_CONCURRENT_DATA_BUFFER_READERS ((int)CAPTURE_READER_ENUM_END)
#define NUM_CONCURRENT_DATA_BUFFERS (NUM_CONCURRENT_DATA_BUFFER_READERS + 2)
#define NUM_CONCURRENT_DATA_BUFFERS (NUM_CONCURRENT_DATA_BUFFER_READERS + 1 + NUM_CONCURRENT_DATA_BUFFER_WRITERS)
#pragma pack(push, 1)
@ -149,6 +150,11 @@ struct ALIGNED(16) PACKED ISTWLCaptureReceived {
#pragma pack(pop)
struct ALIGNED(16) FTD2OldDSCaptureReceivedNormalPlusRaw {
FTD2OldDSCaptureReceived data;
FTD2OldDSCaptureReceivedRaw raw_data;
};
union CaptureReceived {
FTD3_3DSCaptureReceived ftd3_received;
FTD3_3DSCaptureReceived_3D ftd3_received_3d;
@ -156,7 +162,7 @@ union CaptureReceived {
USB3DSCaptureReceived_3D usb_received_3ds_3d;
USBOldDSCaptureReceived usb_received_old_ds;
FTD2OldDSCaptureReceived ftd2_received_old_ds;
FTD2OldDSCaptureReceivedRaw ftd2_received_old_ds_raw;
FTD2OldDSCaptureReceivedNormalPlusRaw ftd2_received_old_ds_normal_plus_raw;
ISNitroCaptureReceived is_nitro_capture_received;
ISTWLCaptureReceived is_twl_capture_received;
CypressNisetroDSCaptureReceived cypress_nisetro_capture_received;
@ -215,6 +221,7 @@ struct CaptureStatus {
struct CaptureDataSingleBuffer {
CaptureScreensType capture_type;
uint64_t read;
size_t unused_offset;
CaptureReceived capture_buf;
double time_in_buf;
uint32_t inner_index;
@ -225,16 +232,18 @@ public:
CaptureDataBuffers();
CaptureDataSingleBuffer* GetReaderBuffer(CaptureReaderType reader_type);
void ReleaseReaderBuffer(CaptureReaderType reader_type);
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type = CAPTURE_SCREENS_BOTH, size_t offset = 0);
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, size_t offset);
CaptureDataSingleBuffer* GetWriterBuffer();
void ReleaseWriterBuffer();
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type, size_t offset, int index);
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type, int index);
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, size_t offset, int index);
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, int index);
CaptureDataSingleBuffer* GetWriterBuffer(int index = 0);
void ReleaseWriterBuffer(int index = 0, bool update_last_curr_in = true);
private:
uint32_t inner_index = 0;
std::mutex access_mutex;
int last_curr_in;
int curr_writer_pos;
int curr_writer_pos[NUM_CONCURRENT_DATA_BUFFER_WRITERS];
int curr_reader_pos[NUM_CONCURRENT_DATA_BUFFER_READERS];
bool is_being_written_to[NUM_CONCURRENT_DATA_BUFFERS];
int num_readers[NUM_CONCURRENT_DATA_BUFFERS];
bool has_read_data[NUM_CONCURRENT_DATA_BUFFERS][NUM_CONCURRENT_DATA_BUFFER_READERS];
CaptureDataSingleBuffer buffers[NUM_CONCURRENT_DATA_BUFFERS];

View File

@ -3,7 +3,10 @@
CaptureDataBuffers::CaptureDataBuffers() {
last_curr_in = 0;
curr_writer_pos = -1;
for(int i = 0; i < NUM_CONCURRENT_DATA_BUFFER_WRITERS; i++) {
curr_writer_pos[i] = -1;
is_being_written_to[i] = false;
}
for(int i = 0; i < NUM_CONCURRENT_DATA_BUFFER_READERS; i++)
curr_reader_pos[i] = -1;
for(int i = 0; i < NUM_CONCURRENT_DATA_BUFFERS; i++) {
@ -24,13 +27,19 @@ static int reader_to_index(CaptureReaderType reader_type) {
}
}
static bool is_writer_index_valid(int index) {
if((index < 0) || (index >= NUM_CONCURRENT_DATA_BUFFER_WRITERS))
return false;
return true;
}
CaptureDataSingleBuffer* CaptureDataBuffers::GetReaderBuffer(CaptureReaderType reader_type) {
int index = reader_to_index(reader_type);
CaptureDataSingleBuffer* retval = NULL;
access_mutex.lock();
if(curr_reader_pos[index] != -1)
retval = &buffers[curr_reader_pos[index]];
else if(!has_read_data[last_curr_in][index]) {
return &buffers[curr_reader_pos[index]];
access_mutex.lock();
if(!has_read_data[last_curr_in][index]) {
has_read_data[last_curr_in][index] = true;
num_readers[last_curr_in] += 1;
retval = &buffers[last_curr_in];
@ -40,61 +49,84 @@ CaptureDataSingleBuffer* CaptureDataBuffers::GetReaderBuffer(CaptureReaderType r
return retval;
}
CaptureDataSingleBuffer* CaptureDataBuffers::GetWriterBuffer() {
CaptureDataSingleBuffer* CaptureDataBuffers::GetWriterBuffer(int index) {
if(!is_writer_index_valid(index))
return NULL;
if(curr_writer_pos[index] != -1)
return &buffers[curr_writer_pos[index]];
CaptureDataSingleBuffer* retval = NULL;
access_mutex.lock();
if(curr_writer_pos != -1)
retval = &buffers[curr_writer_pos];
else
for(int i = 0; i < NUM_CONCURRENT_DATA_BUFFERS; i++)
if((num_readers[i] == 0) && (i != last_curr_in)) {
retval = &buffers[i];
curr_writer_pos = i;
for(int j = 0; j < NUM_CONCURRENT_DATA_BUFFER_READERS; j++)
has_read_data[i][j] = false;
break;
}
for(int i = 0; i < NUM_CONCURRENT_DATA_BUFFERS; i++)
if((num_readers[i] == 0) && (i != last_curr_in) && (!is_being_written_to[i])) {
retval = &buffers[i];
is_being_written_to[i] = true;
curr_writer_pos[index] = i;
for(int j = 0; j < NUM_CONCURRENT_DATA_BUFFER_READERS; j++)
has_read_data[i][j] = true;
break;
}
access_mutex.unlock();
return retval;
}
void CaptureDataBuffers::ReleaseReaderBuffer(CaptureReaderType reader_type) {
int index = reader_to_index(reader_type);
if(curr_reader_pos[index] == -1)
return;
access_mutex.lock();
if(curr_reader_pos[index] != -1) {
num_readers[curr_reader_pos[index]] -= 1;
curr_reader_pos[index] = -1;
}
num_readers[curr_reader_pos[index]] -= 1;
curr_reader_pos[index] = -1;
access_mutex.unlock();
}
void CaptureDataBuffers::ReleaseWriterBuffer() {
void CaptureDataBuffers::ReleaseWriterBuffer(int index, bool update_last_curr_in) {
if(!is_writer_index_valid(index))
return;
if(curr_writer_pos[index] == -1)
return;
access_mutex.lock();
if(curr_writer_pos != -1) {
buffers[curr_writer_pos].inner_index = inner_index++;
last_curr_in = curr_writer_pos;
curr_writer_pos = -1;
if(update_last_curr_in) {
for(int j = 0; j < NUM_CONCURRENT_DATA_BUFFER_READERS; j++)
has_read_data[curr_writer_pos[index]][j] = false;
last_curr_in = curr_writer_pos[index];
}
is_being_written_to[curr_writer_pos[index]] = false;
curr_writer_pos[index] = -1;
access_mutex.unlock();
}
void CaptureDataBuffers::WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type, size_t offset) {
void CaptureDataBuffers::WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type, size_t offset, int index) {
if(offset >= read)
return;
CaptureDataSingleBuffer* target = this->GetWriterBuffer();
if(!is_writer_index_valid(index))
return;
CaptureDataSingleBuffer* target = this->GetWriterBuffer(index);
// How did we end here?!
if(target == NULL)
return;
memcpy(&target->capture_buf, ((uint8_t*)buffer) + offset, read - offset);
// Make sure to also copy the extra needed data, if any
if((device->cc_type == CAPTURE_CONN_USB) && (!device->is_3ds))
memcpy(&target->capture_buf.usb_received_old_ds.frameinfo, &buffer->usb_received_old_ds.frameinfo, sizeof(buffer->usb_received_old_ds.frameinfo));
target->read = read;
if(buffer != NULL) {
memcpy(&target->capture_buf, ((uint8_t*)buffer) + offset, read - offset);
// Make sure to also copy the extra needed data, if any
if((device->cc_type == CAPTURE_CONN_USB) && (!device->is_3ds))
memcpy(&target->capture_buf.usb_received_old_ds.frameinfo, &buffer->usb_received_old_ds.frameinfo, sizeof(buffer->usb_received_old_ds.frameinfo));
target->unused_offset = 0;
}
else
target->unused_offset = offset;
target->read = read - offset;
target->time_in_buf = time_in_buf;
target->capture_type = capture_type;
this->ReleaseWriterBuffer();
this->ReleaseWriterBuffer(index);
}
void CaptureDataBuffers::WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, size_t offset) {
return this->WriteToBuffer(buffer, read, time_in_buf, device, CAPTURE_SCREENS_BOTH, offset);
void CaptureDataBuffers::WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type, int index) {
return this->WriteToBuffer(buffer, read, time_in_buf, device, capture_type, 0, index);
}
void CaptureDataBuffers::WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, size_t offset, int index) {
return this->WriteToBuffer(buffer, read, time_in_buf, device, CAPTURE_SCREENS_BOTH, offset, index);
}
void CaptureDataBuffers::WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, int index) {
return this->WriteToBuffer(buffer, read, time_in_buf, device, CAPTURE_SCREENS_BOTH, 0, index);
}

View File

@ -17,7 +17,6 @@
#include <chrono>
struct FTD3XXReceivedDataBuffer {
CaptureReceived capture_buf;
OVERLAPPED overlap;
ULONG read_buffer;
};
@ -35,7 +34,9 @@ static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, Capture
}
for (inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS - 1; ++inner_curr_in) {
ftStatus = FT_ASYNC_CALL(handle, fifo_channel, (UCHAR*)&received_buffer[inner_curr_in].capture_buf, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(inner_curr_in);
uint8_t* buffer = (uint8_t*)&data_buf->capture_buf;
ftStatus = FT_ASYNC_CALL(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
if(ftStatus != FT_IO_PENDING) {
capture_error_print(true, capture_data, "Disconnected: Read failed");
return;
@ -47,8 +48,9 @@ static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, Capture
auto clock_start = std::chrono::high_resolution_clock::now();
while (capture_data->status.connected && capture_data->status.running) {
ftStatus = FT_ASYNC_CALL(handle, fifo_channel, (UCHAR*)&received_buffer[inner_curr_in].capture_buf, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(inner_curr_in);
uint8_t* buffer = (uint8_t*)&data_buf->capture_buf;
ftStatus = FT_ASYNC_CALL(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
if(ftStatus != FT_IO_PENDING) {
capture_error_print(true, capture_data, "Disconnected: Read failed");
return;
@ -62,7 +64,7 @@ static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, Capture
return;
}
data_output_update(&received_buffer[inner_curr_in].capture_buf, received_buffer[inner_curr_in].read_buffer, capture_data, clock_start);
data_output_update(inner_curr_in, received_buffer[inner_curr_in].read_buffer, capture_data, clock_start);
}
}
@ -72,17 +74,19 @@ static bool safe_capture_call(FTD3XXReceivedDataBuffer* received_buffer, Capture
while(capture_data->status.connected && capture_data->status.running) {
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(0);
uint8_t* buffer = (uint8_t*)&data_buf->capture_buf;
#ifdef _WIN32
FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, (UCHAR*)&received_buffer->capture_buf, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, NULL);
FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, NULL);
#else
FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, (UCHAR*)&received_buffer->capture_buf, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, 1000);
FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, 1000);
#endif
if(FT_FAILED(ftStatus)) {
capture_error_print(true, capture_data, "Disconnected: Read failed");
return true;
}
data_output_update(&received_buffer->capture_buf, received_buffer->read_buffer, capture_data, clock_start);
data_output_update(0, received_buffer->read_buffer, capture_data, clock_start);
}
return false;
@ -97,6 +101,7 @@ static FTD3XXReceivedDataBuffer* init_received_buffer() {
static void close_received_buffer(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data) {
if(ftd3_driver_get_is_bad()) {
capture_data->data_buffers.ReleaseWriterBuffer(0, false);
delete received_buffer;
return;
}
@ -107,6 +112,7 @@ static void close_received_buffer(FTD3XXReceivedDataBuffer* received_buffer, Cap
if(FT_ReleaseOverlapped(handle, &received_buffer[inner_curr_in].overlap)) {
capture_error_print(true, capture_data, "Disconnected: Release failed");
}
capture_data->data_buffers.ReleaseWriterBuffer(inner_curr_in, false);
}
delete []received_buffer;
}

View File

@ -23,8 +23,8 @@
struct FTD3LibusbCaptureReceivedData {
bool in_use;
uint32_t index;
int internal_index;
CaptureData* capture_data;
CaptureReceived buffer;
uint32_t* last_index;
std::chrono::time_point<std::chrono::high_resolution_clock> *clock_start;
SharedConsumerMutex *is_buffer_free_shared_mutex;
@ -78,31 +78,35 @@ static void ftd3_libusb_read_frame_request(CaptureData* capture_data, FTD3Libusb
return;
ftd3_libusb_capture_recv_data->index = index;
ftd3_libusb_capture_recv_data->cb_data.function = ftd3_libusb_read_frame_cb;
ftd3_libusb_async_in_start((ftd3_device_device_handlers*)capture_data->handle, pipe, MAX_TIME_WAIT * 1000, (uint8_t*)&ftd3_libusb_capture_recv_data->buffer, ftd3_get_capture_size(capture_data), &ftd3_libusb_capture_recv_data->cb_data);
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(ftd3_libusb_capture_recv_data->internal_index);
uint8_t* buffer = (uint8_t*)&data_buf->capture_buf;
ftd3_libusb_async_in_start((ftd3_device_device_handlers*)capture_data->handle, pipe, MAX_TIME_WAIT * 1000, buffer, ftd3_get_capture_size(capture_data), &ftd3_libusb_capture_recv_data->cb_data);
}
static void end_ftd3_libusb_read_frame_cb(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
static void end_ftd3_libusb_read_frame_cb(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, bool early_release) {
if(early_release)
ftd3_libusb_capture_recv_data->capture_data->data_buffers.ReleaseWriterBuffer(ftd3_libusb_capture_recv_data->internal_index, false);
ftd3_libusb_capture_recv_data->in_use = false;
ftd3_libusb_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(ftd3_libusb_capture_recv_data->cb_data.internal_index);
ftd3_libusb_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(ftd3_libusb_capture_recv_data->internal_index);
}
static void ftd3_libusb_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data = (FTD3LibusbCaptureReceivedData*)user_data;
if((*ftd3_libusb_capture_recv_data->status) < 0)
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true);
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
*ftd3_libusb_capture_recv_data->status = LIBUSB_ERROR_OTHER;
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true);
}
if(((int32_t)(ftd3_libusb_capture_recv_data->index - (*ftd3_libusb_capture_recv_data->last_index))) <= 0) {
//*ftd3_libusb_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED;
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true);
}
*ftd3_libusb_capture_recv_data->last_index = ftd3_libusb_capture_recv_data->index;
data_output_update(&ftd3_libusb_capture_recv_data->buffer, transfer_length, ftd3_libusb_capture_recv_data->capture_data, *ftd3_libusb_capture_recv_data->clock_start);
end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
data_output_update(ftd3_libusb_capture_recv_data->internal_index, transfer_length, ftd3_libusb_capture_recv_data->capture_data, *ftd3_libusb_capture_recv_data->clock_start);
end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, false);
}
static int ftd3_libusb_get_num_free_buffers(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
@ -216,6 +220,7 @@ void ftd3_libusb_capture_main_loop(CaptureData* capture_data, int pipe) {
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) {
ftd3_libusb_capture_recv_data[i].in_use = false;
ftd3_libusb_capture_recv_data[i].index = i;
ftd3_libusb_capture_recv_data[i].internal_index = i;
ftd3_libusb_capture_recv_data[i].capture_data = capture_data;
ftd3_libusb_capture_recv_data[i].last_index = &last_index;
ftd3_libusb_capture_recv_data[i].clock_start = &clock_start;
@ -223,7 +228,6 @@ void ftd3_libusb_capture_main_loop(CaptureData* capture_data, int pipe) {
ftd3_libusb_capture_recv_data[i].status = &status;
ftd3_libusb_capture_recv_data[i].cb_data.actual_user_data = &ftd3_libusb_capture_recv_data[i];
ftd3_libusb_capture_recv_data[i].cb_data.transfer_data = NULL;
ftd3_libusb_capture_recv_data[i].cb_data.internal_index = i;
}
ftd3_libusb_start_thread(&async_processing_thread, &is_done_thread);
ftd3_libusb_capture_main_loop_processing(ftd3_libusb_capture_recv_data, pipe);

View File

@ -32,11 +32,11 @@ void list_devices_ftd3(std::vector<CaptureDevice> &devices_list, std::vector<no_
ftd3_list_devices_compat(devices_list, no_access_list, valid_3dscapture_descriptions);
}
void data_output_update(CaptureReceived* received_buffer, size_t read_data, CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time) {
void data_output_update(int inner_index, size_t read_data, CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - base_time;
base_time = curr_time;
capture_data->data_buffers.WriteToBuffer(received_buffer, read_data, diff.count(), &capture_data->status.device);
capture_data->data_buffers.WriteToBuffer(NULL, read_data, diff.count(), &capture_data->status.device, inner_index);
if(capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;

View File

@ -71,13 +71,15 @@ static size_t get_initial_offset_buffer(uint16_t* in_u16, size_t real_length) {
return ignored_halfwords * 2;
}
static void data_output_update(CaptureReceived* buffer, CaptureData* capture_data, int read_amount, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time) {
static void data_output_update(int curr_data_buffer_index, CaptureData* capture_data, int read_amount, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - base_time;
base_time = curr_time;
CaptureDataSingleBuffer* curr_full_data_buf = capture_data->data_buffers.GetWriterBuffer(curr_data_buffer_index);
CaptureReceived* buffer = &curr_full_data_buf->capture_buf;
size_t buffer_real_len = remove_synch_from_final_length((uint32_t*)buffer, read_amount);
size_t initial_offset = get_initial_offset_buffer((uint16_t*) buffer, buffer_real_len);
capture_data->data_buffers.WriteToBuffer(buffer, buffer_real_len, diff.count(), &capture_data->status.device, initial_offset);
capture_data->data_buffers.WriteToBuffer(NULL, buffer_real_len, diff.count(), &capture_data->status.device, initial_offset, curr_data_buffer_index);
if(capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
@ -96,28 +98,30 @@ void ftd2_capture_main_loop_driver(CaptureData* capture_data) {
int inner_curr_in = 0;
int retval = 0;
auto clock_start = std::chrono::high_resolution_clock::now();
CaptureReceived* data_buffer = new CaptureReceived[NUM_CAPTURE_RECEIVED_DATA_BUFFERS];
int curr_data_buffer = 0;
int next_data_buffer = 0;
int curr_data_buffer_index = 0;
int next_data_buffer_index = 0;
const size_t full_size = get_capture_size(capture_data->status.device.is_rgb_888);
size_t next_size = full_size;
size_t bytesIn;
while (capture_data->status.connected && capture_data->status.running) {
curr_data_buffer = next_data_buffer;
retval = ftd2_read(capture_data->handle, is_libftdi, ((uint8_t*)(&data_buffer[curr_data_buffer]) + (full_size - next_size)), next_size, &bytesIn);
curr_data_buffer_index = next_data_buffer_index;
CaptureDataSingleBuffer* curr_full_data_buf = capture_data->data_buffers.GetWriterBuffer(curr_data_buffer_index);
CaptureReceived* curr_data_buffer = &curr_full_data_buf->capture_buf;
retval = ftd2_read(capture_data->handle, is_libftdi, ((uint8_t*)curr_data_buffer) + (full_size - next_size), next_size, &bytesIn);
if(ftd2_is_error(retval, is_libftdi)) {
capture_error_print(true, capture_data, "Disconnected: Read failed");
break;
}
if(bytesIn < next_size)
continue;
next_data_buffer = (curr_data_buffer + 1) % NUM_CAPTURE_RECEIVED_DATA_BUFFERS;
bool has_synch_failed = !synchronization_check((uint16_t*)(&data_buffer[curr_data_buffer]), full_size, (uint16_t*)(&data_buffer[next_data_buffer]), &next_size, true);
next_data_buffer_index = (curr_data_buffer_index + 1) % NUM_CAPTURE_RECEIVED_DATA_BUFFERS;
CaptureDataSingleBuffer* next_full_data_buf = capture_data->data_buffers.GetWriterBuffer(next_data_buffer_index);
CaptureReceived* next_data_buffer = &next_full_data_buf->capture_buf;
bool has_synch_failed = !synchronization_check((uint16_t*)curr_data_buffer, full_size, (uint16_t*)next_data_buffer, &next_size, true);
if(has_synch_failed) {
continue;
}
data_output_update(&data_buffer[curr_data_buffer], capture_data, full_size, clock_start);
data_output_update(curr_data_buffer_index, capture_data, full_size, clock_start);
}
delete []data_buffer;
}

View File

@ -375,10 +375,16 @@ bool synchronization_check(uint16_t* data_buffer, size_t size, uint16_t* next_da
size_t remove_synch_from_final_length(uint32_t* out_buffer, size_t real_length) {
// Ignore synch for final length
const uint32_t check_value = FTD2_OLDDS_SYNCH_VALUES | (FTD2_OLDDS_SYNCH_VALUES << 16);
while((real_length >= 4) && ((out_buffer)[(real_length / 4) - 1] == check_value))
real_length -= 4;
if((real_length < 4) && (out_buffer[0] == check_value))
uint32_t check_value = FTD2_OLDDS_SYNCH_VALUES | (FTD2_OLDDS_SYNCH_VALUES << 16);
size_t check_size = sizeof(uint32_t);
while((real_length >= check_size) && (out_buffer[(real_length / check_size) - 1] == check_value))
real_length -= check_size;
check_value = FTD2_OLDDS_SYNCH_VALUES;
uint16_t* u16_buffer = (uint16_t*)out_buffer;
check_size = sizeof(uint16_t);
while((real_length >= check_size) && (u16_buffer[(real_length / check_size) - 1] == check_value))
real_length -= check_size;
if((real_length < check_size) && (u16_buffer[0] == check_value))
real_length = 0;
return real_length;
}
@ -393,6 +399,8 @@ void ftd2_capture_main_loop_shared(CaptureData* capture_data) {
}
void ftd2_capture_cleanup_shared(CaptureData* capture_data) {
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
capture_data->data_buffers.ReleaseWriterBuffer(i, false);
bool is_libftdi = capture_data->status.device.descriptor != NULL;
if(ftd2_close(capture_data->handle, is_libftdi)) {
capture_error_print(true, capture_data, "Disconnected: Close failed");

View File

@ -309,7 +309,7 @@ static void STDCALL libftdi_read_callback(libusb_transfer* transfer) {
}
// Read from bulk
static void libftdi_schedule_read(ftd2_async_callback_data* cb_data, int length) {
static void libftdi_schedule_read(ftd2_async_callback_data* cb_data, uint8_t* buffer_raw, int length) {
const int max_packet_size = MAX_PACKET_SIZE_USB2;
libusb_transfer *transfer_in = libusb_alloc_transfer(0);
if(!transfer_in)
@ -320,7 +320,7 @@ static void libftdi_schedule_read(ftd2_async_callback_data* cb_data, int length)
length += ((length + (max_packet_size - FTD2_INTRA_PACKET_HEADER_SIZE) - 1) / (max_packet_size - FTD2_INTRA_PACKET_HEADER_SIZE)) * FTD2_INTRA_PACKET_HEADER_SIZE;
cb_data->requested_length = length;
ftdi_context* in_handle = (ftdi_context*)cb_data->handle;
libusb_fill_bulk_transfer(transfer_in, in_handle->usb_dev, in_handle->out_ep, (uint8_t*)&cb_data->buffer_raw, length, libftdi_read_callback, (void*)cb_data, in_handle->usb_read_timeout * NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
libusb_fill_bulk_transfer(transfer_in, in_handle->usb_dev, in_handle->out_ep, buffer_raw, length, libftdi_read_callback, (void*)cb_data, in_handle->usb_read_timeout * NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
transfer_in->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
libusb_submit_transfer(transfer_in);
cb_data->transfer_data_access.unlock();
@ -391,6 +391,7 @@ static int libftdi_full_read(void* handle, uint8_t* buffer_raw, uint8_t* buffer_
static void libftdi_copy_buffer_to_target_and_skip(uint8_t* buffer_written, uint8_t* buffer_target, const int max_packet_size, size_t length, size_t header_packet_size, size_t ignored_bytes) {
// This could be made faster for small "ignored_bytes", however this scales well...
// Plus, most of the time is used up by the memcpy routine, so...
// Remove the small headers every 512 bytes...
// The "- header_packet_size" instead of "-1" covers for partial header transfers...
@ -511,11 +512,17 @@ static FTD2CaptureReceivedData* libftdi_get_free_buffer(FTD2CaptureReceivedData*
static void libftdi_start_read(FTD2CaptureReceivedData* received_data_buffer, int index, size_t size) {
if(received_data_buffer == NULL)
return;
CaptureDataSingleBuffer* full_data_buf = received_data_buffer->capture_data->data_buffers.GetWriterBuffer(received_data_buffer->cb_data.internal_index);
CaptureReceived* data_buffer = &full_data_buf->capture_buf;
received_data_buffer->buffer_raw = (uint8_t*)&data_buffer->ftd2_received_old_ds_normal_plus_raw.raw_data;
received_data_buffer->buffer_target = (uint32_t*)data_buffer;
received_data_buffer->index = index;
libftdi_schedule_read(&received_data_buffer->cb_data, size);
libftdi_schedule_read(&received_data_buffer->cb_data, received_data_buffer->buffer_raw, size);
}
static void end_libftdi_read_frame_cb(FTD2CaptureReceivedData* received_data_buffer) {
static void end_libftdi_read_frame_cb(FTD2CaptureReceivedData* received_data_buffer, bool has_succeded) {
if(!has_succeded)
received_data_buffer->capture_data->data_buffers.ReleaseWriterBuffer(received_data_buffer->cb_data.internal_index, false);
received_data_buffer->in_use = false;
received_data_buffer->is_buffer_free_shared_mutex->specific_unlock(received_data_buffer->cb_data.internal_index);
}
@ -528,10 +535,8 @@ static size_t libftdi_copy_buffer_to_target_and_skip_synch(uint8_t* in_buffer, u
while((ignored_halfwords < (real_length / 2)) && (in_u16[ignored_halfwords + 1 + (ignored_halfwords / (MAX_PACKET_SIZE_USB2 / 2))] == FTD2_OLDDS_SYNCH_VALUES))
ignored_halfwords++;
size_t copy_offset = ignored_halfwords * 2;
if(ignored_halfwords >= ((MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE) / 2))
copy_offset = 0;
libftdi_copy_buffer_to_target_and_skip(in_buffer, (uint8_t*)out_buffer, MAX_PACKET_SIZE_USB2, read_length, FTD2_INTRA_PACKET_HEADER_SIZE, copy_offset);
if(copy_offset == 0) {
if((copy_offset == 0) || (copy_offset >= (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE))) {
size_t internal_sync_offset = 0;
bool is_synced = synchronization_check((uint16_t*)out_buffer, real_length, NULL, &internal_sync_offset);
if(!is_synced) {
@ -549,18 +554,15 @@ static size_t libftdi_copy_buffer_to_target_and_skip_synch(uint8_t* in_buffer, u
return remove_synch_from_final_length(out_buffer, real_length);
}
static void output_to_thread(CaptureData* capture_data, uint8_t* buffer, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time, int read_length, size_t* sync_offset) {
static void output_to_thread(CaptureData* capture_data, int internal_index, uint8_t* buffer_raw, uint32_t* buffer_target, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time, int read_length, size_t* sync_offset) {
// For some reason, there is usually one.
// Though make this generic enough
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - base_time;
base_time = curr_time;
CaptureDataSingleBuffer* target = capture_data->data_buffers.GetWriterBuffer();
// Copy data to buffer, with special memcpy which accounts for ftd2 header data and skips synch bytes
size_t real_length = libftdi_copy_buffer_to_target_and_skip_synch(buffer, (uint32_t*)&target->capture_buf, read_length, sync_offset);
target->read = real_length;
target->time_in_buf = diff.count();
capture_data->data_buffers.ReleaseWriterBuffer();
size_t real_length = libftdi_copy_buffer_to_target_and_skip_synch(buffer_raw, buffer_target, read_length, sync_offset);
capture_data->data_buffers.WriteToBuffer(NULL, real_length, diff.count(), &capture_data->status.device, internal_index);
if(capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
@ -574,21 +576,24 @@ static void libftdi_capture_process_data(void* in_user_data, int transfer_length
// It's because the code is too fast...
FTD2CaptureReceivedData* user_data = (FTD2CaptureReceivedData*)in_user_data;
if((*user_data->status) < 0)
return end_libftdi_read_frame_cb(user_data);
return end_libftdi_read_frame_cb(user_data, false);
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
*user_data->status = LIBUSB_ERROR_OTHER;
return end_libftdi_read_frame_cb(user_data);
return end_libftdi_read_frame_cb(user_data, false);
}
if(transfer_length < user_data->cb_data.requested_length)
return end_libftdi_read_frame_cb(user_data);
return end_libftdi_read_frame_cb(user_data, false);
if(((int32_t)(user_data->index - (*user_data->last_used_index))) <= 0) {
//*user_data->status = LIBUSB_ERROR_INTERRUPTED;
return end_libftdi_read_frame_cb(user_data);
return end_libftdi_read_frame_cb(user_data, false);
}
*user_data->last_used_index = user_data->index;
output_to_thread(user_data->capture_data, (uint8_t*)&user_data->cb_data.buffer_raw, *user_data->clock_start, transfer_length, user_data->curr_offset);
end_libftdi_read_frame_cb(user_data);
// For some reason, saving the raw buffer and then passing it
// like this is way faster than loading it.
// Even if it's still needed to get the writer buffer...
output_to_thread(user_data->capture_data, user_data->cb_data.internal_index, user_data->buffer_raw, user_data->buffer_target, *user_data->clock_start, transfer_length, user_data->curr_offset);
end_libftdi_read_frame_cb(user_data, true);
}
static void resync_offset(FTD2CaptureReceivedData* received_data_buffers, uint32_t &index, size_t full_size) {
@ -676,6 +681,7 @@ void ftd2_capture_main_loop_libftdi(CaptureData* capture_data) {
received_data_buffers[i].cb_data.transfer_data = NULL;
received_data_buffers[i].cb_data.handle = capture_data->handle;
received_data_buffers[i].cb_data.is_transfer_done_mutex = &is_transfer_done_mutex;
received_data_buffers[i].cb_data.internal_index = i;
received_data_buffers[i].cb_data.requested_length = 0;
}

View File

@ -210,27 +210,13 @@ int EndAcquisition(const is_device_usb_device* usb_device_desc, is_device_device
}
}
void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size) {
void output_to_thread(CaptureData* capture_data, int internal_index, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size) {
// Output to the other threads...
const is_device_usb_device* usb_device_info = (const is_device_usb_device*)capture_data->status.device.descriptor;
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - (*clock_start);
*clock_start = curr_time;
if(usb_device_info->device_type == IS_TWL_CAPTURE_DEVICE) {
CaptureDataSingleBuffer* target = capture_data->data_buffers.GetWriterBuffer();
// Copy data to buffer, with special memcpy which accounts for ftd2 header data and skips synch bytes
size_t video_size = usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type);
memcpy(&target->capture_buf.is_twl_capture_received.video_capture_in, &capture_buf->is_twl_capture_received.video_capture_in, video_size);
if(read_size > video_size) {
size_t audio_size = ((read_size - video_size) / sizeof(ISTWLCaptureSoundData)) * sizeof(ISTWLCaptureAudioReceived);
memcpy(&target->capture_buf.is_twl_capture_received.audio_capture_in, &capture_buf->is_twl_capture_received.audio_capture_in, audio_size);
}
target->read = read_size;
target->time_in_buf = diff.count();
capture_data->data_buffers.ReleaseWriterBuffer();
}
else
capture_data->data_buffers.WriteToBuffer(capture_buf, read_size, diff.count(), &capture_data->status.device, curr_capture_type);
capture_data->data_buffers.WriteToBuffer(NULL, read_size, diff.count(), &capture_data->status.device, curr_capture_type, internal_index);
if (capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
@ -238,17 +224,21 @@ void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, C
capture_data->status.audio_wait.unlock();
}
static void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start) {
static void output_to_thread(CaptureData* capture_data, int internal_index, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start) {
const is_device_usb_device* usb_device_info = (const is_device_usb_device*)capture_data->status.device.descriptor;
output_to_thread(capture_data, capture_buf, curr_capture_type, clock_start, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type));
output_to_thread(capture_data, internal_index, curr_capture_type, clock_start, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type));
}
int is_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start) {
int is_device_read_frame_and_output(CaptureData* capture_data, int internal_index, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start) {
const is_device_usb_device* usb_device_info = (const is_device_usb_device*)capture_data->status.device.descriptor;
int ret = ReadFrame((is_device_device_handlers*)capture_data->handle, (uint8_t*)capture_buf, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type), usb_device_info);
if (ret < 0)
CaptureDataSingleBuffer* target = capture_data->data_buffers.GetWriterBuffer(internal_index);
CaptureReceived* buffer = &target->capture_buf;
int ret = ReadFrame((is_device_device_handlers*)capture_data->handle, (uint8_t*)buffer, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type), usb_device_info);
if (ret < 0) {
capture_data->data_buffers.ReleaseWriterBuffer(internal_index, false);
return ret;
output_to_thread(capture_data, capture_buf, curr_capture_type, &clock_start);
}
output_to_thread(capture_data, internal_index, curr_capture_type, &clock_start);
return ret;
}
@ -261,10 +251,14 @@ void is_device_read_frame_request(CaptureData* capture_data, ISDeviceCaptureRece
is_device_capture_recv_data->index = index;
is_device_capture_recv_data->curr_capture_type = curr_capture_type;
is_device_capture_recv_data->cb_data.function = is_device_read_frame_cb;
ReadFrameAsync((is_device_device_handlers*)capture_data->handle, (uint8_t*)&is_device_capture_recv_data->buffer, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type), usb_device_info, &is_device_capture_recv_data->cb_data);
CaptureDataSingleBuffer* target = capture_data->data_buffers.GetWriterBuffer(is_device_capture_recv_data->cb_data.internal_index);
CaptureReceived* buffer = &target->capture_buf;
ReadFrameAsync((is_device_device_handlers*)capture_data->handle, (uint8_t*)buffer, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type), usb_device_info, &is_device_capture_recv_data->cb_data);
}
static void end_is_device_read_frame_cb(ISDeviceCaptureReceivedData* is_device_capture_recv_data) {
static void end_is_device_read_frame_cb(ISDeviceCaptureReceivedData* is_device_capture_recv_data, bool pre_release) {
if(pre_release)
is_device_capture_recv_data->capture_data->data_buffers.ReleaseWriterBuffer(is_device_capture_recv_data->cb_data.internal_index, false);
is_device_capture_recv_data->in_use = false;
is_device_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(is_device_capture_recv_data->cb_data.internal_index);
}
@ -272,20 +266,20 @@ static void end_is_device_read_frame_cb(ISDeviceCaptureReceivedData* is_device_c
static void is_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
ISDeviceCaptureReceivedData* is_device_capture_recv_data = (ISDeviceCaptureReceivedData*)user_data;
if((*is_device_capture_recv_data->status) < 0)
return end_is_device_read_frame_cb(is_device_capture_recv_data);
return end_is_device_read_frame_cb(is_device_capture_recv_data, true);
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
*is_device_capture_recv_data->status = LIBUSB_ERROR_OTHER;
return end_is_device_read_frame_cb(is_device_capture_recv_data);
return end_is_device_read_frame_cb(is_device_capture_recv_data, true);
}
if(((int32_t)(is_device_capture_recv_data->index - (*is_device_capture_recv_data->last_index))) <= 0) {
//*is_device_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED;
return end_is_device_read_frame_cb(is_device_capture_recv_data);
return end_is_device_read_frame_cb(is_device_capture_recv_data, true);
}
*is_device_capture_recv_data->last_index = is_device_capture_recv_data->index;
output_to_thread(is_device_capture_recv_data->capture_data, &is_device_capture_recv_data->buffer, is_device_capture_recv_data->curr_capture_type, is_device_capture_recv_data->clock_start);
end_is_device_read_frame_cb(is_device_capture_recv_data);
output_to_thread(is_device_capture_recv_data->capture_data, is_device_capture_recv_data->cb_data.internal_index, is_device_capture_recv_data->curr_capture_type, is_device_capture_recv_data->clock_start);
end_is_device_read_frame_cb(is_device_capture_recv_data, false);
}
int is_device_get_num_free_buffers(ISDeviceCaptureReceivedData* is_device_capture_recv_data) {
@ -467,6 +461,8 @@ void is_device_acquisition_main_loop(CaptureData* capture_data) {
void usb_is_device_acquisition_cleanup(CaptureData* capture_data) {
if(!usb_is_initialized())
return;
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
capture_data->data_buffers.ReleaseWriterBuffer(i, false);
is_device_connection_end((is_device_device_handlers*)capture_data->handle, (const is_device_usb_device*)capture_data->status.device.descriptor);
capture_data->handle = NULL;
}

View File

@ -15,18 +15,18 @@
#define AUDIO_ADDRESS_RING_BUFFER_END 0x01880000
#define VIDEO_ADDRESS_RING_BUFFER_END 0x01000000
static void output_to_thread_reset_processed_data(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t video_processed_size, size_t &video_length_processed, size_t &audio_length_processed) {
output_to_thread(capture_data, capture_buf, curr_capture_type, clock_start, video_processed_size + ((audio_length_processed / sizeof(ISTWLCaptureAudioReceived)) * sizeof(ISTWLCaptureSoundData)));
static void output_to_thread_reset_processed_data(CaptureData* capture_data, int internal_index, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t video_processed_size, size_t &video_length_processed, size_t &audio_length_processed) {
output_to_thread(capture_data, internal_index, curr_capture_type, clock_start, video_processed_size + ((audio_length_processed / sizeof(ISTWLCaptureAudioReceived)) * sizeof(ISTWLCaptureSoundData)));
video_length_processed = 0;
audio_length_processed = 0;
}
static int process_frame_and_read(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, CaptureSpeedsType curr_capture_speed, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, uint32_t &last_read_frame_index, uint32_t video_address, uint32_t video_length, size_t &video_length_processed, uint32_t audio_address, uint32_t audio_length, size_t &audio_length_processed, bool &processed, float &last_frame_length, bool &reprocess) {
static int process_frame_and_read(CaptureData* capture_data, int internal_index, CaptureScreensType curr_capture_type, CaptureSpeedsType curr_capture_speed, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, uint32_t &last_read_frame_index, uint32_t video_address, uint32_t video_length, size_t &video_length_processed, uint32_t audio_address, uint32_t audio_length, size_t &audio_length_processed, bool &processed, float &last_frame_length, bool &reprocess) {
const size_t video_processed_size = usb_is_device_get_video_in_size(curr_capture_type, IS_TWL_CAPTURE_DEVICE);
processed = false;
if((video_length == 0) && (audio_length == 0)) {
if(reprocess)
output_to_thread_reset_processed_data(capture_data, capture_buf, curr_capture_type, clock_start, video_processed_size, video_length_processed, audio_length_processed);
output_to_thread_reset_processed_data(capture_data, internal_index, curr_capture_type, clock_start, video_processed_size, video_length_processed, audio_length_processed);
reprocess = false;
return 0;
}
@ -63,6 +63,8 @@ static int process_frame_and_read(CaptureData* capture_data, CaptureReceived* ca
audio_processed_diff_from_max = 0;
else
audio_length_processed = max_audio_length - audio_length;
CaptureDataSingleBuffer* target = capture_data->data_buffers.GetWriterBuffer(internal_index);
CaptureReceived* capture_buf = &target->capture_buf;
int ret = ReadFrame(handlers, ((uint8_t*)&capture_buf->is_twl_capture_received.audio_capture_in) + audio_length_processed, audio_address, audio_length, usb_device_desc);
if(ret < 0)
return ret;
@ -91,7 +93,7 @@ static int process_frame_and_read(CaptureData* capture_data, CaptureReceived* ca
reprocess = true;
return 0;
}
output_to_thread_reset_processed_data(capture_data, capture_buf, curr_capture_type, clock_start, video_processed_size, video_length_processed, audio_length_processed);
output_to_thread_reset_processed_data(capture_data, internal_index, curr_capture_type, clock_start, video_processed_size, video_length_processed, audio_length_processed);
return 0;
}
@ -227,10 +229,10 @@ void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCap
capture_error_print(true, capture_data, "Frame Info Read: Failed");
return;
}
ret = process_frame_and_read(capture_data, &is_device_capture_recv_data[0].buffer, curr_capture_type, curr_capture_speed, &clock_last_frame, last_read_frame_index, video_address, video_length, video_length_processed, audio_address, audio_length, audio_length_processed, processed, last_frame_length, reprocess);
ret = process_frame_and_read(capture_data, 0, curr_capture_type, curr_capture_speed, &clock_last_frame, last_read_frame_index, video_address, video_length, video_length_processed, audio_address, audio_length, audio_length_processed, processed, last_frame_length, reprocess);
if(ret < 0) {
capture_error_print(true, capture_data, "Frame Read: Error " + std::to_string(ret));
return;
capture_error_print(true, capture_data, "Frame Read: Error " + std::to_string(ret));
return;
}
if(processed) {
curr_capture_speed = capture_data->status.capture_speed;

View File

@ -175,44 +175,48 @@ static int find_first_vsync_byte(CaptureReceived* capture_buf, size_t read_size)
return pos;
}
void cypress_output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size, size_t* scheduled_special_read, bool* recalibration_request) {
void cypress_output_to_thread(CaptureData* capture_data, int internal_index, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size, size_t* scheduled_special_read, bool* recalibration_request) {
// Output to the other threads...
int offset = find_first_vsync_byte(capture_buf, read_size);
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(internal_index);
int offset = find_first_vsync_byte(&data_buf->capture_buf, read_size);
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
if(offset) {
if(offset % usb_device_info->max_usb_packet_size)
*recalibration_request = true;
else
*scheduled_special_read = offset;
capture_data->data_buffers.ReleaseWriterBuffer(internal_index, false);
return;
}
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - (*clock_start);
*clock_start = curr_time;
capture_data->data_buffers.WriteToBuffer(capture_buf, read_size, diff.count(), &capture_data->status.device, curr_capture_type);
capture_data->data_buffers.WriteToBuffer(NULL, read_size, diff.count(), &capture_data->status.device, internal_index);
if (capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
capture_data->status.video_wait.unlock();
capture_data->status.audio_wait.unlock();
}
int cypress_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start, size_t* scheduled_special_read, bool* recalibration_request) {
int cypress_device_read_frame_and_output(CaptureData* capture_data, int internal_index, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start, size_t* scheduled_special_read, bool* recalibration_request) {
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
size_t read_size = cyni_device_get_video_in_size(usb_device_info->device_type);
if(*scheduled_special_read)
read_size = *scheduled_special_read;
int ret = ReadFrame((cyni_device_device_handlers*)capture_data->handle, (uint8_t*)capture_buf, read_size, usb_device_info);
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(internal_index);
uint8_t* buffer = (uint8_t*)&data_buf->capture_buf;
int ret = ReadFrame((cyni_device_device_handlers*)capture_data->handle, buffer, read_size, usb_device_info);
if (ret < 0)
return ret;
if(*scheduled_special_read) {
*scheduled_special_read = 0;
return ret;
}
cypress_output_to_thread(capture_data, capture_buf, curr_capture_type, &clock_start, read_size, scheduled_special_read, recalibration_request);
cypress_output_to_thread(capture_data, internal_index, &clock_start, read_size, scheduled_special_read, recalibration_request);
return ret;
}
int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index) {
int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, uint32_t index) {
if(cypress_device_capture_recv_data == NULL)
return LIBUSB_SUCCESS;
if((*cypress_device_capture_recv_data->status) < 0) {
@ -221,7 +225,6 @@ int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCa
}
const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
cypress_device_capture_recv_data->index = index;
cypress_device_capture_recv_data->curr_capture_type = curr_capture_type;
cypress_device_capture_recv_data->cb_data.function = cypress_device_read_frame_cb;
size_t read_size = cyni_device_get_video_in_size(usb_device_info->device_type);
if(*cypress_device_capture_recv_data->scheduled_special_read) {
@ -230,10 +233,14 @@ int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCa
*cypress_device_capture_recv_data->is_active_special_read = true;
*cypress_device_capture_recv_data->scheduled_special_read = 0;
}
return ReadFrameAsync((cyni_device_device_handlers*)capture_data->handle, (uint8_t*)&cypress_device_capture_recv_data->buffer, read_size, usb_device_info, &cypress_device_capture_recv_data->cb_data);
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(cypress_device_capture_recv_data->cb_data.internal_index);
uint8_t* buffer = (uint8_t*)&data_buf->capture_buf;
return ReadFrameAsync((cyni_device_device_handlers*)capture_data->handle, buffer, read_size, usb_device_info, &cypress_device_capture_recv_data->cb_data);
}
static void end_cypress_device_read_frame_cb(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
static void end_cypress_device_read_frame_cb(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool early_release) {
if(early_release)
cypress_device_capture_recv_data->capture_data->data_buffers.ReleaseWriterBuffer(cypress_device_capture_recv_data->cb_data.internal_index, false);
cypress_device_capture_recv_data->in_use = false;
cypress_device_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data->cb_data.internal_index);
}
@ -241,7 +248,7 @@ static void end_cypress_device_read_frame_cb(CypressDeviceCaptureReceivedData* c
static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data = (CypressDeviceCaptureReceivedData*)user_data;
if((*cypress_device_capture_recv_data->status) < 0)
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true);
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
int error = LIBUSB_ERROR_OTHER;
if(transfer_status == LIBUSB_TRANSFER_TIMED_OUT)
@ -251,12 +258,12 @@ static void cypress_device_read_frame_cb(void* user_data, int transfer_length, i
*cypress_device_capture_recv_data->consecutive_output_to_thread = 0;
}
*cypress_device_capture_recv_data->status = error;
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true);
}
if(((int32_t)(cypress_device_capture_recv_data->index - (*cypress_device_capture_recv_data->last_index))) <= 0) {
//*cypress_device_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED;
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true);
}
*cypress_device_capture_recv_data->consecutive_output_to_thread += 1;
if((*cypress_device_capture_recv_data->consecutive_output_to_thread) > NUM_CONSECUTIVE_NEEDED_OUTPUT)
@ -266,14 +273,14 @@ static void cypress_device_read_frame_cb(void* user_data, int transfer_length, i
// Realign, with multiple of max_usb_packet_size
if((*cypress_device_capture_recv_data->is_active_special_read) && (((int32_t)(cypress_device_capture_recv_data->index - (*cypress_device_capture_recv_data->active_special_read_index))) >= 0)) {
*cypress_device_capture_recv_data->is_active_special_read = false;
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true);
}
if((*cypress_device_capture_recv_data->scheduled_special_read) || (*cypress_device_capture_recv_data->is_active_special_read) || (*cypress_device_capture_recv_data->recalibration_request))
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true);
cypress_output_to_thread(cypress_device_capture_recv_data->capture_data, &cypress_device_capture_recv_data->buffer, cypress_device_capture_recv_data->curr_capture_type, cypress_device_capture_recv_data->clock_start, transfer_length, cypress_device_capture_recv_data->scheduled_special_read, cypress_device_capture_recv_data->recalibration_request);
end_cypress_device_read_frame_cb(cypress_device_capture_recv_data);
cypress_output_to_thread(cypress_device_capture_recv_data->capture_data, cypress_device_capture_recv_data->cb_data.internal_index, cypress_device_capture_recv_data->clock_start, transfer_length, cypress_device_capture_recv_data->scheduled_special_read, cypress_device_capture_recv_data->recalibration_request);
end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, false);
}
int cypress_device_get_num_free_buffers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
@ -395,7 +402,7 @@ void reset_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_devic
error_cypress_device_status(cypress_device_capture_recv_data, 0);
}
void recalibration_reads(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CypressDeviceCaptureReceivedData* chosen_buffer, uint32_t &index, CaptureScreensType curr_capture_type) {
void recalibration_reads(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CypressDeviceCaptureReceivedData* chosen_buffer, uint32_t &index) {
// Enforce properly synchronized reads.
// Reduces complexity and latency, at the cost of some extra
// time between lid reopening and visible video output.
@ -415,12 +422,12 @@ void recalibration_reads(cyni_device_device_handlers* handlers, const cyni_devic
default_sleep();
*chosen_buffer->recalibration_request = false;
chosen_buffer->in_use = true;
int ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++);
int ret = cypress_device_read_frame_request(capture_data, chosen_buffer, index++);
if(ret < 0) {
error_cypress_device_status(cypress_device_capture_recv_data, ret);
return;
}
ret = cypress_device_read_frame_request(capture_data, next_buffer, curr_capture_type, index++);
ret = cypress_device_read_frame_request(capture_data, next_buffer, index++);
if(ret < 0) {
next_buffer->in_use = false;
error_cypress_device_status(cypress_device_capture_recv_data, ret);
@ -437,8 +444,6 @@ static bool cyni_device_acquisition_loop(CaptureData* capture_data, CypressDevic
cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle;
const cyni_device_usb_device* usb_device_desc = (const cyni_device_usb_device*)capture_data->status.device.descriptor;
uint32_t index = 0;
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
CaptureSpeedsType curr_capture_speed = capture_data->status.capture_speed;
int ret = capture_start(handlers, usb_device_desc);
if (ret < 0) {
capture_error_print(true, capture_data, "Capture Start: Failed");
@ -448,7 +453,7 @@ static bool cyni_device_acquisition_loop(CaptureData* capture_data, CypressDevic
auto clock_last_reset = std::chrono::high_resolution_clock::now();
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
CypressDeviceCaptureReceivedData* chosen_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data);
ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++);
ret = cypress_device_read_frame_request(capture_data, chosen_buffer, index++);
if(ret < 0) {
chosen_buffer->in_use = false;
error_cypress_device_status(cypress_device_capture_recv_data, ret);
@ -478,9 +483,9 @@ static bool cyni_device_acquisition_loop(CaptureData* capture_data, CypressDevic
error_cypress_device_status(cypress_device_capture_recv_data, LIBUSB_ERROR_TIMEOUT);
if(chosen_buffer && (*chosen_buffer->recalibration_request)) {
*chosen_buffer->recalibration_request = false;
recalibration_reads(handlers, usb_device_desc, cypress_device_capture_recv_data, chosen_buffer, index, curr_capture_type);
recalibration_reads(handlers, usb_device_desc, cypress_device_capture_recv_data, chosen_buffer, index);
}
ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++);
ret = cypress_device_read_frame_request(capture_data, chosen_buffer, index++);
if(ret < 0) {
chosen_buffer->in_use = false;
error_cypress_device_status(cypress_device_capture_recv_data, ret);
@ -549,6 +554,8 @@ void cyni_device_acquisition_main_loop(CaptureData* capture_data) {
void usb_cyni_device_acquisition_cleanup(CaptureData* capture_data) {
if(!usb_is_initialized())
return;
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
capture_data->data_buffers.ReleaseWriterBuffer(i, false);
cypress_nisetro_connection_end((cyni_device_device_handlers*)capture_data->handle, (const cyni_device_usb_device*)capture_data->status.device.descriptor);
capture_data->handle = NULL;
}

View File

@ -16,9 +16,6 @@
#define FIRST_3D_VERSION 6
#define CAPTURE_SKIP_TIMEOUT_SECONDS 1.0
#define NUM_DS_3DS_CONCURRENT_DATA_BUFFERS 4
#define NUM_DS_3DS_CONCURRENT_REQUESTS 4
enum usb_capture_status {
USB_CAPTURE_SUCCESS = 0,
USB_CAPTURE_SKIP,
@ -46,25 +43,6 @@ struct usb_device {
int bitstream_3dscfg_ver;
};
struct usb_ds_status {
uint32_t framecount;
uint8_t lcd_on;
uint8_t capture_in_progress;
};
struct usb_ds_3ds_general_data {
SharedConsumerMutex* is_there_ready_buffer;
SharedConsumerMutex* is_buffer_usage_done;
uint32_t index;
uint32_t* last_index;
int real_index;
bool in_use;
CaptureData* capture_data;
CaptureReceived capture_buf;
size_t read_amount;
double time_in;
};
static const usb_device usb_3ds_desc = {
.is_3ds = true,
.vid = 0x16D0, .pid = 0x06A3,
@ -94,51 +72,6 @@ static const usb_device* usb_devices_desc_list[] = {
&usb_old_ds_desc,
};
static void unlock_buffer(usb_ds_3ds_general_data* buffer_data) {
buffer_data->in_use = false;
buffer_data->is_buffer_usage_done->specific_unlock(buffer_data->real_index);
}
static void ds_3ds_usb_thread_function(bool* usb_thread_run, usb_ds_3ds_general_data* buffer_data) {
if(!usb_is_initialized())
return;
while(*usb_thread_run) {
int processing_index = *buffer_data[0].last_index;
int dummy = 0;
for(int i = 0; i < NUM_DS_3DS_CONCURRENT_DATA_BUFFERS; i++) {
if(!buffer_data[i].in_use)
continue;
int diff = (int)(processing_index - buffer_data[i].index);
if(diff > 0)
unlock_buffer(&buffer_data[i]);
else if(diff == 0) {
buffer_data[i].capture_data->data_buffers.WriteToBuffer(&buffer_data[i].capture_buf, buffer_data[i].read_amount, buffer_data[i].time_in, &buffer_data[i].capture_data->status.device);
if(buffer_data[i].capture_data->status.cooldown_curr_in)
buffer_data[i].capture_data->status.cooldown_curr_in = buffer_data[i].capture_data->status.cooldown_curr_in - 1;
buffer_data[i].capture_data->status.video_wait.unlock();
buffer_data[i].capture_data->status.audio_wait.unlock();
unlock_buffer(&buffer_data[i]);
}
}
buffer_data[0].is_there_ready_buffer->general_timed_lock(&dummy);
}
}
static void ds_3ds_start_thread(std::thread* thread_ptr, bool* usb_thread_run, usb_ds_3ds_general_data* buffer_data) {
if(!usb_is_initialized())
return;
*usb_thread_run = true;
*thread_ptr = std::thread(ds_3ds_usb_thread_function, usb_thread_run, buffer_data);
}
static void ds_3ds_close_thread(std::thread* thread_ptr, bool* usb_thread_run, usb_ds_3ds_general_data* buffer_data) {
if(!usb_is_initialized())
return;
*usb_thread_run = false;
buffer_data[0].is_there_ready_buffer->specific_unlock(0);
thread_ptr->join();
}
// Read vendor request from control endpoint. Returns bytes transferred (<0 = libusb error)
static int vend_in(libusb_device_handle *handle, const usb_device* usb_device_desc, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *buf) {
return libusb_control_transfer(handle, ((uint8_t)LIBUSB_REQUEST_TYPE_VENDOR | (uint8_t)LIBUSB_ENDPOINT_IN), bRequest, wValue, wIndex, buf, wLength, usb_device_desc->control_timeout);
@ -278,9 +211,10 @@ static uint64_t get_capture_size(const usb_device* usb_device_desc, bool enabled
return sizeof(USB3DSCaptureReceived) - EXTRA_DATA_BUFFER_USB_SIZE;
}
static usb_capture_status capture_read_oldds_3ds(usb_ds_3ds_general_data* chosen_buffer) {
CaptureData* capture_data = chosen_buffer->capture_data;
CaptureReceived* data_buffer = &chosen_buffer->capture_buf;
static usb_capture_status capture_read_oldds_3ds(CaptureData* capture_data, size_t *read_amount) {
*read_amount = 0;
CaptureDataSingleBuffer* full_data_buf = capture_data->data_buffers.GetWriterBuffer(0);
CaptureReceived* data_buffer = &full_data_buf->capture_buf;
libusb_device_handle* handle = (libusb_device_handle*)capture_data->handle;
const usb_device* usb_device_desc = get_usb_device_desc(capture_data);
const bool enabled_3d = capture_data->status.enabled_3d;
@ -332,73 +266,49 @@ static usb_capture_status capture_read_oldds_3ds(usb_ds_3ds_general_data* chosen
#endif
}
chosen_buffer->read_amount = bytesIn;
*read_amount = bytesIn;
return USB_CAPTURE_SUCCESS;
}
static void process_usb_capture_result(usb_capture_status result, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, bool* done, usb_ds_3ds_general_data* chosen_buffer) {
static void process_usb_capture_result(usb_capture_status result, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, bool* done, CaptureData* capture_data, size_t read_amount) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - (*clock_start);
bool wrote_to_buffer = false;
switch(result) {
case USB_CAPTURE_SKIP:
/*
if(diff.count() >= CAPTURE_SKIP_TIMEOUT_SECONDS) {
capture_error_print(true, chosen_buffer->capture_data, "Disconnected: Too long since last read");
capture_error_print(true, capture_data, "Disconnected: Too long since last read");
done = true;
}
*/
break;
case USB_CAPTURE_PIPE_ERROR:
capture_error_print(true, chosen_buffer->capture_data, "Disconnected: Pipe error");
capture_error_print(true, capture_data, "Disconnected: Pipe error");
*done = true;
break;
case USB_CAPTURE_FRAMEINFO_ERROR:
capture_error_print(true, chosen_buffer->capture_data, "Disconnected: Frameinfo error");
capture_error_print(true, capture_data, "Disconnected: Frameinfo error");
*done = true;
break;
case USB_CAPTURE_SUCCESS:
*clock_start = curr_time;
chosen_buffer->time_in = diff.count();
chosen_buffer->index = (*chosen_buffer->last_index) + 1;
chosen_buffer->is_buffer_usage_done->specific_try_lock(chosen_buffer->real_index);
chosen_buffer->in_use = true;
(*chosen_buffer->last_index) += 1;
chosen_buffer->is_there_ready_buffer->specific_unlock(chosen_buffer->real_index);
wrote_to_buffer = true;
if(capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
capture_data->data_buffers.WriteToBuffer(NULL, read_amount, diff.count(), &capture_data->status.device, 0);
capture_data->status.video_wait.unlock();
capture_data->status.audio_wait.unlock();
break;
default:
capture_error_print(true, chosen_buffer->capture_data, "Disconnected: Error");
capture_error_print(true, capture_data, "Disconnected: Error");
*done = true;
break;
}
}
static usb_ds_3ds_general_data* get_free_buffer(usb_ds_3ds_general_data* buffer_data) {
usb_ds_3ds_general_data* out_data = NULL;
int dummy = 0;
while(!out_data) {
for(int i = 0; i < NUM_DS_3DS_CONCURRENT_DATA_BUFFERS; i++) {
if(!buffer_data[i].in_use) {
buffer_data[i].is_there_ready_buffer->specific_try_lock(i);
out_data = &buffer_data[i];
break;
}
}
if(!out_data)
buffer_data[0].is_buffer_usage_done->general_timed_lock(&dummy);
}
return out_data;
}
static void wait_all_free_buffer(usb_ds_3ds_general_data* buffer_data) {
for(int i = 0; i < NUM_DS_3DS_CONCURRENT_DATA_BUFFERS; i++)
buffer_data[i].index = (*buffer_data[0].last_index) - 1;
for(int i = 0; i < NUM_DS_3DS_CONCURRENT_DATA_BUFFERS; i++) {
while(buffer_data[i].in_use) {
buffer_data[i].is_there_ready_buffer->specific_unlock(i);
buffer_data[i].is_buffer_usage_done->specific_timed_lock(i);
}
}
if(!wrote_to_buffer)
capture_data->data_buffers.ReleaseWriterBuffer(0, false);
}
void list_devices_usb_ds_3ds(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list) {
@ -477,38 +387,20 @@ void usb_capture_main_loop(CaptureData* capture_data) {
std::chrono::time_point<std::chrono::high_resolution_clock> clock_start = std::chrono::high_resolution_clock::now();
bool done = false;
usb_ds_3ds_general_data* general_data = new usb_ds_3ds_general_data[NUM_DS_3DS_CONCURRENT_DATA_BUFFERS];
SharedConsumerMutex is_there_ready_buffer(NUM_DS_3DS_CONCURRENT_DATA_BUFFERS);
SharedConsumerMutex is_buffer_usage_done(NUM_DS_3DS_CONCURRENT_DATA_BUFFERS);
uint32_t last_index = -1;
for(int i = 0; i < NUM_DS_3DS_CONCURRENT_DATA_BUFFERS; i++) {
general_data[i].is_there_ready_buffer = &is_there_ready_buffer;
general_data[i].is_buffer_usage_done = &is_buffer_usage_done;
general_data[i].last_index = &last_index;
general_data[i].capture_data = capture_data;
general_data[i].in_use = false;
general_data[i].real_index = i;
}
bool usb_thread_run;
std::thread processing_thread;
ds_3ds_start_thread(&processing_thread, &usb_thread_run, general_data);
size_t read_amount = 0;
usb_ds_3ds_general_data* chosen_buffer = get_free_buffer(general_data);
while((!done) && capture_data->status.connected && capture_data->status.running) {
usb_capture_status result = capture_read_oldds_3ds(chosen_buffer);
usb_capture_status result = capture_read_oldds_3ds(capture_data, &read_amount);
process_usb_capture_result(result, &clock_start, &done, chosen_buffer);
if(!done)
chosen_buffer = get_free_buffer(general_data);
process_usb_capture_result(result, &clock_start, &done, capture_data, read_amount);
}
wait_all_free_buffer(general_data);
ds_3ds_close_thread(&processing_thread, &usb_thread_run, general_data);
delete []general_data;
}
void usb_capture_cleanup(CaptureData* capture_data) {
if(!usb_is_initialized())
return;
capture_data->data_buffers.ReleaseWriterBuffer(0, false);
const usb_device* usb_device_desc = get_usb_device_desc(capture_data);
capture_end((libusb_device_handle*)capture_data->handle, usb_device_desc);
}

View File

@ -94,6 +94,9 @@ bool Audio::onGetData(sf::SoundStream::Chunk &data) {
}
loaded_samples = samples.size();
if((loaded_samples <= 0) && this->hasTooMuchTimeElapsedInside()) {
// This is needed by MacOS...
// But it also causes some trailing noise when
// closing the lid on the devices.
inside_onGetData = false;
return false;
}

View File

@ -577,10 +577,11 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data,
if(no_data_consecutive > NO_DATA_CONSECUTIVE_THRESHOLD)
no_data_consecutive = NO_DATA_CONSECUTIVE_THRESHOLD;
capture_data->status.video_wait.update_time_multiplier(get_time_multiplier(capture_data, no_data_consecutive >= NO_DATA_CONSECUTIVE_THRESHOLD));
bool timed_out = !capture_data->status.video_wait.timed_lock();
bool data_processed = false;
CaptureDataSingleBuffer* data_buffer = capture_data->data_buffers.GetReaderBuffer(CAPTURE_READER_VIDEO);
if(data_buffer != NULL) {
last_frame_time = data_buffer->time_in_buf;
if(data_buffer->read >= get_video_in_size(capture_data)) {

View File

@ -271,7 +271,7 @@ static void usb_is_device_convertVideoToOutput(CaptureReceived *p_in, VideoOutpu
}
bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) {
CaptureReceived *p_in = &data_buffer->capture_buf;
CaptureReceived* p_in = (CaptureReceived*)(((uint8_t*)&data_buffer->capture_buf) + data_buffer->unused_offset);
bool converted = false;
CaptureDevice* chosen_device = &status->device;
#ifdef USE_FTD3
@ -310,7 +310,7 @@ bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, Capt
bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) {
if(!status->device.has_audio)
return true;
CaptureReceived *p_in = &data_buffer->capture_buf;
CaptureReceived* p_in = (CaptureReceived*)(((uint8_t*)&data_buffer->capture_buf) + data_buffer->unused_offset);
uint8_t* base_ptr = NULL;
#ifdef USE_FTD3
if(status->device.cc_type == CAPTURE_CONN_FTD3) {