Really basic frame read implementation for IS TWL Capture
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
2024-12-14 23:38:05 +01:00
parent 5f152f4913
commit 4bd8a189fb
10 changed files with 388 additions and 22 deletions

View File

@@ -7,6 +7,7 @@
#include "usb_is_device_acquisition_general.hpp"
#include "usb_is_nitro_acquisition_capture.hpp"
#include "usb_is_nitro_acquisition_emulator.hpp"
#include "usb_is_twl_acquisition_capture.hpp"
#include "usb_generic.hpp"
#include <libusb.h>
@@ -44,6 +45,8 @@ static bool initial_cleanup(const is_device_usb_device* usb_device_desc, is_devi
return initial_cleanup_emulator(usb_device_desc, handlers) != LIBUSB_SUCCESS;
case IS_NITRO_CAPTURE_DEVICE:
return initial_cleanup_capture(usb_device_desc, handlers) != LIBUSB_SUCCESS;
case IS_TWL_CAPTURE_DEVICE:
return initial_cleanup_twl_capture(usb_device_desc, handlers) != LIBUSB_SUCCESS;
default:
return false;
}
@@ -67,11 +70,11 @@ std::string get_serial(const is_device_usb_device* usb_device_desc, is_device_de
}
void is_device_insert_device(std::vector<CaptureDevice>& devices_list, is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, int& curr_serial_extra_id_is_device, std::string path) {
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, usb_device_desc->audio_enabled, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, usb_device_desc->max_audio_samples_size, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
}
void is_device_insert_device(std::vector<CaptureDevice>& devices_list, is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, int& curr_serial_extra_id_is_device) {
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, usb_device_desc->audio_enabled, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, usb_device_desc->max_audio_samples_size, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
}
static is_device_device_handlers* usb_find_by_serial_number(const is_device_usb_device* usb_device_desc, CaptureDevice* device) {
@@ -135,6 +138,8 @@ bool is_device_connect_usb(bool print_failed, CaptureData* capture_data, Capture
}
uint64_t usb_is_device_get_video_in_size(CaptureScreensType capture_type, is_device_type device_type) {
if(device_type == IS_TWL_CAPTURE_DEVICE)
return sizeof(ISTWLCaptureVideoInputData) + (sizeof(uint32_t) * 2);
if((capture_type == CAPTURE_SCREENS_TOP) || (capture_type == CAPTURE_SCREENS_BOTTOM))
return sizeof(ISNitroEmulatorVideoInputData) / 2;
return sizeof(ISNitroEmulatorVideoInputData);
@@ -185,6 +190,8 @@ int EndAcquisition(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_de
return EndAcquisitionEmulator(capture_data, is_device_capture_recv_data, do_drain_frames, start_frames, capture_type);
case IS_NITRO_CAPTURE_DEVICE:
return EndAcquisitionCapture(capture_data, is_device_capture_recv_data);
case IS_TWL_CAPTURE_DEVICE:
return EndAcquisitionTWLCapture(capture_data, is_device_capture_recv_data);
default:
return 0;
}
@@ -196,18 +203,20 @@ int EndAcquisition(const is_device_usb_device* usb_device_desc, is_device_device
return EndAcquisitionEmulator(usb_device_desc, handlers, do_drain_frames, start_frames, capture_type);
case IS_NITRO_CAPTURE_DEVICE:
return EndAcquisitionCapture(usb_device_desc, handlers);
case IS_TWL_CAPTURE_DEVICE:
return EndAcquisitionTWLCapture(usb_device_desc, handlers);
default:
return 0;
}
}
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) {
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) {
// 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;
capture_data->data_buffers.WriteToBuffer(capture_buf, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type), diff.count(), &capture_data->status.device, curr_capture_type);
capture_data->data_buffers.WriteToBuffer(capture_buf, read_size, diff.count(), &capture_data->status.device, curr_capture_type);
if (capture_data->status.cooldown_curr_in)
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
@@ -215,6 +224,11 @@ static void output_to_thread(CaptureData* capture_data, CaptureReceived* capture
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) {
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));
}
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) {
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);
@@ -428,6 +442,9 @@ void is_device_acquisition_main_loop(CaptureData* capture_data) {
case IS_NITRO_CAPTURE_DEVICE:
is_nitro_acquisition_capture_main_loop(capture_data, is_device_capture_recv_data);
break;
case IS_TWL_CAPTURE_DEVICE:
is_twl_acquisition_capture_main_loop(capture_data, is_device_capture_recv_data);
break;
default:
break;
}

View File

@@ -2,6 +2,7 @@
#include "usb_is_device_communications.hpp"
#include "usb_is_device_libusb.hpp"
#include "usb_is_device_is_driver.hpp"
#include "is_twl_0x81_packet.h"
#include <libusb.h>
#include <cstring>
@@ -36,6 +37,9 @@
#define REG_USB_DMA_CONTROL_2 0x0C000028
#define REG_USB_BIU_CONTROL_2 0x0C0000A4
#define DEFAULT_MAX_LENGTH_IS_TWL_VIDEO 0x00040000
#define DEFAULT_MAX_LENGTH_IS_TWL_AUDIO 0x00007800
enum is_nitro_packet_emulator_dir {
IS_NITRO_PACKET_EMU_DIR_WRITE = 0x10,
IS_NITRO_PACKET_EMU_DIR_READ = 0x11
@@ -59,7 +63,8 @@ enum is_device_packet_type {
IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL = 2,
IS_NITRO_PACKET_TYPE_CAPTURE = 3,
IS_NITRO_PACKET_TYPE_AGB_CART_ROM = 4,
IS_NITRO_PACKET_TYPE_AGB_BUS2 = 5
IS_NITRO_PACKET_TYPE_AGB_BUS2 = 5,
IS_TWL_PACKET_TYPE_FRAME = 7,
};
enum is_nitro_emulator_command {
@@ -88,8 +93,17 @@ enum is_nitro_capture_command {
};
enum is_twl_capture_command {
IS_TWL_CAP_CMD_GET_CAP = 0x00,
IS_TWL_CAP_CMD_GET_SERIAL = 0x13,
IS_TWL_CAP_CMD_UNLOCK_COMMS = 0x1C,
IS_TWL_CAP_CMD_ENABLE_CAP_PRE_3 = 0x80,
IS_TWL_CAP_CMD_ENABLE_CAP_PRE_1 = 0x81,
IS_TWL_CAP_CMD_ASK_CAPTURE_INFORMATION = 0x83,
IS_TWL_CAP_CMD_ENABLE_CAP = 0x84,
IS_TWL_CAP_CMD_ENABLE_CAP_PRE_2 = 0x85,
IS_TWL_CAP_CMD_STOP_FRAME_READS = 0x88,
IS_TWL_CAP_CMD_SET_LAST_FRAME_INFORMATION = 0x8B,
IS_TWL_CAP_CMD_ENABLE_CAP_PART_2 = 0x8C,
};
enum is_nitro_emulator_forward_bits {
@@ -126,6 +140,26 @@ struct PACKED is_device_rw_packet_header {
uint32_t length_w;
uint32_t length_r;
};
struct PACKED is_twl_ask_capture_information_packet {
uint32_t unk[2];
uint32_t max_length_video;
uint32_t unk2[2];
uint32_t max_length_audio;
uint32_t unk3[0x10];
};
// These two are probably the same struct, with different fields used for
// different packets...
// I say probably, that's why I keep them separate.
struct PACKED is_twl_capture_information_packet {
uint32_t available_video_length;
uint32_t video_start_address;
uint32_t unk;
uint32_t available_audio_length;
uint32_t audio_start_address;
uint32_t unk2;
uint32_t unk3[0x10];
};
#pragma pack(pop)
static const is_device_usb_device usb_is_nitro_emu_rare_desc = {
@@ -137,7 +171,7 @@ static const is_device_usb_device usb_is_nitro_emu_rare_desc = {
.write_pipe = "Pipe00", .read_pipe = "Pipe01",
.product_id = 2, .manufacturer_id = 1, .device_type = IS_NITRO_EMULATOR_DEVICE,
.video_data_type = VIDEO_DATA_BGR, .max_usb_packet_size = IS_NITRO_USB_PACKET_LIMIT,
.do_pipe_clear_reset = true
.do_pipe_clear_reset = true, .audio_enabled = false, .max_audio_samples_size = 0
};
static const is_device_usb_device usb_is_nitro_emu_common_desc = {
@@ -149,7 +183,7 @@ static const is_device_usb_device usb_is_nitro_emu_common_desc = {
.write_pipe = "Pipe00", .read_pipe = "Pipe01",
.product_id = 2, .manufacturer_id = 1, .device_type = IS_NITRO_EMULATOR_DEVICE,
.video_data_type = VIDEO_DATA_BGR, .max_usb_packet_size = IS_NITRO_USB_PACKET_LIMIT,
.do_pipe_clear_reset = true
.do_pipe_clear_reset = true, .audio_enabled = false, .max_audio_samples_size = 0
};
static const is_device_usb_device usb_is_nitro_cap_desc = {
@@ -161,11 +195,11 @@ static const is_device_usb_device usb_is_nitro_cap_desc = {
.write_pipe = "Pipe00", .read_pipe = "Pipe01",
.product_id = 2, .manufacturer_id = 1, .device_type = IS_NITRO_CAPTURE_DEVICE,
.video_data_type = VIDEO_DATA_BGR, .max_usb_packet_size = IS_NITRO_USB_PACKET_LIMIT,
.do_pipe_clear_reset = true
.do_pipe_clear_reset = true, .audio_enabled = false, .max_audio_samples_size = 0
};
static const is_device_usb_device usb_is_twl_cap_desc = {
.name = "ISTC", .long_name = "IS TWL Capture",
.name = "ISTCD", .long_name = "IS TWL Capture (Dev)",
.vid = 0x0f6e, .pid = 0x0501,
.default_config = 1, .default_interface = 0,
.bulk_timeout = 500,
@@ -173,11 +207,11 @@ static const is_device_usb_device usb_is_twl_cap_desc = {
.write_pipe = "Pipe01", .read_pipe = "Pipe03",
.product_id = 2, .manufacturer_id = 1, .device_type = IS_TWL_CAPTURE_DEVICE,
.video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = IS_TWL_USB_PACKET_LIMIT,
.do_pipe_clear_reset = false
.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureAudioReceived) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM
};
static const is_device_usb_device usb_is_twl_cap_desc_2 = {
.name = "ISTC", .long_name = "IS TWL Capture",
.name = "ISTCR", .long_name = "IS TWL Capture (Retail)",
.vid = 0x0f6e, .pid = 0x0502,
.default_config = 1, .default_interface = 0,
.bulk_timeout = 500,
@@ -185,7 +219,7 @@ static const is_device_usb_device usb_is_twl_cap_desc_2 = {
.write_pipe = "Pipe01", .read_pipe = "Pipe03",
.product_id = 2, .manufacturer_id = 1, .device_type = IS_TWL_CAPTURE_DEVICE,
.video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = IS_TWL_USB_PACKET_LIMIT,
.do_pipe_clear_reset = false
.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureAudioReceived) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM
};
static const is_device_usb_device* all_usb_is_device_devices_desc[] = {
@@ -510,6 +544,10 @@ int SendWriteCommand(is_device_device_handlers* handlers, uint16_t command, uint
return SendWritePacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc);
}
int SendReadWriteCommand(is_device_device_handlers* handlers, uint16_t command, uint8_t* out_buf, int out_length, uint8_t* in_buf, int in_length, const is_device_usb_device* device_desc) {
return SendReadWritePacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, out_buf, out_length, in_buf, in_length, device_desc);
}
int SendReadCommandU32(is_device_device_handlers* handlers, uint16_t command, uint32_t* out, const is_device_usb_device* device_desc) {
uint32_t buffer;
int ret = SendReadCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc);
@@ -617,6 +655,9 @@ int DisableLca2(is_device_device_handlers* handlers, const is_device_usb_device*
int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_device* device_desc) {
int ret = 0;
uint8_t buffer[0x200];
uint8_t is_twl_handshake_buffer[0x10] = {0x39, 0xC5, 0x5E, 0xC1, 0xA3, 0x02, 0x1D, 0xA1, 0x1E, 0xE9, 0x2F, 0x35, 0x29, 0x98, 0x63, 0x6C};
uint8_t is_twl_handshake_buffer_pre2[0x10] = {0x0C, 0xF7, 0x48, 0x2B, 0xE9, 0x5A, 0xA2, 0x3C, 0xE5, 0x0E, 0x1F, 0xEB, 0x1C, 0x71, 0xB8, 0xAE};
switch(device_desc->device_type) {
case IS_NITRO_EMULATOR_DEVICE:
ret = WriteNecMemU16(handlers, REG_USB_DMA_CONTROL_2, 2, device_desc);
@@ -625,6 +666,24 @@ int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 1, device_desc);
case IS_NITRO_CAPTURE_DEVICE:
return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 1, device_desc, false);
case IS_TWL_CAPTURE_DEVICE:
ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PART_2, NULL, 0, device_desc);
if(ret < 0)
return ret;
ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_1, is_twl_0x81_packet, is_twl_0x81_packet_len, buffer, is_twl_0x81_packet_len, device_desc);
if(ret < 0)
return ret;
ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_2, is_twl_handshake_buffer_pre2, 0x10, device_desc);
if(ret < 0)
return ret;
ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_3, buffer, 0x200, device_desc);
if(ret < 0)
return ret;
ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP, buffer, 0x10, device_desc);
if(ret < 0)
return ret;
ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PART_2, is_twl_handshake_buffer, sizeof(is_twl_handshake_buffer), buffer, 8, device_desc);
return ret;
default:
return 0;
}
@@ -640,6 +699,8 @@ int StopUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_d
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 0, device_desc);
case IS_NITRO_CAPTURE_DEVICE:
return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 0, device_desc);
case IS_TWL_CAPTURE_DEVICE:
return SendWriteCommand(handlers, IS_TWL_CAP_CMD_STOP_FRAME_READS, NULL, 0, device_desc);
default:
return 0;
}
@@ -798,6 +859,46 @@ int ResetFullHardware(is_device_device_handlers* handlers, const is_device_usb_d
}
}
int AskFrameLengthPos(is_device_device_handlers* handlers, uint32_t* video_address, uint32_t* video_length, bool video_enabled, uint32_t* audio_address, uint32_t* audio_length, bool audio_enabled, const is_device_usb_device* device_desc) {
if(device_desc->device_type != IS_TWL_CAPTURE_DEVICE)
return 0;
is_twl_ask_capture_information_packet out_packet;
is_twl_capture_information_packet in_packet;
memset(&out_packet, 0, sizeof(out_packet));
if(video_enabled)
out_packet.max_length_video = to_le((uint32_t)DEFAULT_MAX_LENGTH_IS_TWL_VIDEO);
if(audio_enabled)
out_packet.max_length_audio = to_le((uint32_t)DEFAULT_MAX_LENGTH_IS_TWL_AUDIO);
int ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_ASK_CAPTURE_INFORMATION, (uint8_t*)&out_packet, sizeof(out_packet), (uint8_t*)&in_packet, sizeof(in_packet), device_desc);
if(ret < 0)
return ret;
*video_length = from_le(in_packet.available_video_length);
*video_address = from_le(in_packet.video_start_address);
*audio_length = from_le(in_packet.available_audio_length);
*audio_address = from_le(in_packet.audio_start_address);
return ret;
}
int SetLastFrameInfo(is_device_device_handlers* handlers, uint32_t video_address, uint32_t video_length, uint32_t audio_address, uint32_t audio_length, const is_device_usb_device* device_desc) {
if(device_desc->device_type != IS_TWL_CAPTURE_DEVICE)
return 0;
is_twl_capture_information_packet out_packet;
memset(&out_packet, 0, sizeof(out_packet));
out_packet.available_video_length = to_le(video_length);
out_packet.video_start_address = to_le(video_address);
out_packet.available_audio_length = to_le(audio_length);
out_packet.audio_start_address = to_le(audio_address);
return SendWriteCommand(handlers, IS_TWL_CAP_CMD_SET_LAST_FRAME_INFORMATION, (uint8_t*)&out_packet, sizeof(out_packet), device_desc);
}
int ReadFrame(is_device_device_handlers* handlers, uint8_t* buf, uint32_t address, uint32_t length, const is_device_usb_device* device_desc) {
if(device_desc->device_type != IS_TWL_CAPTURE_DEVICE)
return 0;
if(length == 0)
return 0;
return SendReadPacket(handlers, IS_TWL_CAP_CMD_GET_CAP, IS_TWL_PACKET_TYPE_FRAME, address, buf, length, device_desc);
}
int ReadFrame(is_device_device_handlers* handlers, uint8_t* buf, int length, const is_device_usb_device* device_desc) {
// Maybe making this async would be better for lower end hardware...
int num_bytes = 0;

View File

@@ -0,0 +1,139 @@
#include "devicecapture.hpp"
#include "usb_is_device_communications.hpp"
#include "usb_is_device_acquisition_general.hpp"
#include "usb_is_twl_acquisition_capture.hpp"
// Code created by analyzing the USB packets sent and received by the IS TWL Capture device.
#define RESET_TIMEOUT 4.0
#define SLEEP_RESET_TIME_MS 2000
#define DEFAULT_FRAME_TIME_MS 16.7
#define SLEEP_FRAME_DIVIDER 4
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, uint32_t audio_address, uint32_t audio_length, bool &processed, float &last_frame_length) {
processed = false;
int multiplier = 1;
switch(curr_capture_speed) {
case CAPTURE_SPEEDS_HALF:
multiplier = 2;
break;
case CAPTURE_SPEEDS_THIRD:
multiplier = 3;
break;
case CAPTURE_SPEEDS_QUARTER:
multiplier = 4;
break;
default:
break;
}
int num_available_frames = multiplier;
if(num_available_frames < multiplier)
return 0;
processed = true;
int frame_next = num_available_frames - 1;
last_read_frame_index += num_available_frames;
video_address = video_address + (frame_next * sizeof(ISTWLCaptureVideoReceived));
is_device_device_handlers* handlers = (is_device_device_handlers*)capture_data->handle;
const is_device_usb_device* usb_device_desc = (const is_device_usb_device*)capture_data->status.device.descriptor;
size_t video_processed_size = usb_is_device_get_video_in_size(curr_capture_type, IS_TWL_CAPTURE_DEVICE);
int ret = ReadFrame(handlers, (uint8_t*)&capture_buf->is_twl_capture_received.video_capture_in, 0, video_processed_size, usb_device_desc);
if(ret < 0)
return ret;
int audio_diff_from_max = usb_device_desc->max_audio_samples_size - audio_length;
if(audio_diff_from_max >= 0)
audio_diff_from_max = 0;
else {
audio_address -= audio_diff_from_max;
audio_length = usb_device_desc->max_audio_samples_size;
}
ret = ReadFrame(handlers, (uint8_t*)&capture_buf->is_twl_capture_received.audio_capture_in, audio_address, audio_length, usb_device_desc);
if(ret < 0)
return ret;
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - (*clock_start);
last_frame_length = diff.count();
output_to_thread(capture_data, capture_buf, curr_capture_type, clock_start, video_processed_size + (audio_length / sizeof(ISTWLCaptureAudioReceived)) * (sizeof(ISTWLCaptureAudioReceived) - sizeof(uint32_t)));
return 0;
}
int initial_cleanup_twl_capture(const is_device_usb_device* usb_device_desc, is_device_device_handlers* handlers) {
//EndAcquisition(handlers, usb_device_desc, false, 0, CAPTURE_SCREENS_BOTH);
return LIBUSB_SUCCESS;
}
int EndAcquisitionTWLCapture(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data) {
wait_all_is_device_transfers_done(capture_data, is_device_capture_recv_data);
return EndAcquisitionTWLCapture((const is_device_usb_device*)capture_data->status.device.descriptor, (is_device_device_handlers*)capture_data->handle);
}
int EndAcquisitionTWLCapture(const is_device_usb_device* usb_device_desc, is_device_device_handlers* handlers) {
return StopUsbCaptureDma(handlers, usb_device_desc);
}
void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data) {
is_device_device_handlers* handlers = (is_device_device_handlers*)capture_data->handle;
const is_device_usb_device* usb_device_desc = (const is_device_usb_device*)capture_data->status.device.descriptor;
bool is_acquisition_off = true;
uint32_t last_read_frame_index = 0;
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
CaptureSpeedsType curr_capture_speed = capture_data->status.capture_speed;
bool audio_enabled = true;
std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_frame = std::chrono::high_resolution_clock::now();
float last_frame_length = 0.0;
int ret = 0;
uint32_t video_address = 0;
uint32_t video_length = 0;
uint32_t audio_address = 0;
uint32_t audio_length = 0;
ret = StartUsbCaptureDma(handlers, usb_device_desc);
if(ret < 0) {
capture_error_print(true, capture_data, "Capture Start: Failed");
return;
}
/*
ret = AskFrameLengthPos(handlers, &video_address, &video_length, true, &audio_address, &audio_length, audio_enabled, usb_device_desc);
if(ret < 0) {
capture_error_print(true, capture_data, "Initial Frame Info Read: Failed");
return;
}
ret = SetLastFrameInfo(handlers, video_address, video_length, audio_address, audio_length, usb_device_desc);
if(ret < 0) {
capture_error_print(true, capture_data, "Initial Frame Info Set: Failed");
return;
}
*/
default_sleep(DEFAULT_FRAME_TIME_MS / SLEEP_FRAME_DIVIDER);
while(capture_data->status.connected && capture_data->status.running) {
bool processed = false;
/*
ret = AskFrameLengthPos(handlers, &video_address, &video_length, true, &audio_address, &audio_length, audio_enabled, usb_device_desc);
if(ret < 0) {
capture_error_print(true, capture_data, "Frame Info Read: Failed");
return;
}
if(video_length > 0) {
*/
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, audio_address, audio_length, processed, last_frame_length);
if(ret < 0) {
capture_error_print(true, capture_data, "Frame Read: Error " + std::to_string(ret));
return;
}
/*
if(processed) {
ret = SetLastFrameInfo(handlers, video_address, video_length, audio_address, audio_length, usb_device_desc);
if(ret < 0) {
capture_error_print(true, capture_data, "Frame Info Set: Failed");
return;
}
}
}
*/
if(last_frame_length > 0)
default_sleep((last_frame_length * 1000) / SLEEP_FRAME_DIVIDER);
else
default_sleep(DEFAULT_FRAME_TIME_MS / SLEEP_FRAME_DIVIDER);
}
if(!is_acquisition_off)
EndAcquisition(capture_data, is_device_capture_recv_data, true, 0, curr_capture_type);
}