mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2026-07-31 07:16:21 -05:00
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
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:
parent
5f152f4913
commit
4bd8a189fb
|
|
@ -313,7 +313,7 @@ if(USE_LIBUSB_SUPPORT)
|
|||
endif()
|
||||
endif()
|
||||
if(IS_DEVICES_SUPPORT)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_communications.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_acquisition.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_capture.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_emulator.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_is_driver.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_libusb.cpp)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_communications.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_acquisition.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_capture.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_twl_acquisition_capture.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_emulator.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_is_driver.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_libusb.cpp ${TOOLS_DATA_DIR}/is_twl_0x81_packet.cpp)
|
||||
if(MSVC)
|
||||
list(APPEND EXTRA_CXX_FLAGS "/DUSE_IS_DEVICES_USB")
|
||||
else()
|
||||
|
|
@ -516,6 +516,13 @@ add_custom_command(
|
|||
DEPENDS ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_1.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${TOOLS_DATA_DIR}/is_twl_0x81_packet.cpp
|
||||
COMMENT "Convert binary to C - IS TWL Capture 0x81 Packet"
|
||||
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/is_twl_0x81_packet.bin ${TOOLS_DATA_DIR} is_twl_0x81_packet is_twl_0x81_packet
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/bin/is_twl_0x81_packet.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp
|
||||
COMMENT "Convert fw binary to C - FTD2 NDS 2"
|
||||
|
|
|
|||
1
bin/is_twl_0x81_packet.bin
Normal file
1
bin/is_twl_0x81_packet.bin
Normal file
|
|
@ -0,0 +1 @@
|
|||
›"’R¤ŠÅJV1åiTÁE•ªè<C2AA>$‹°bÄÌÍÔ.§÷î‡L7mçªf€Ö«rVÄöå&65™'Eö´¥eYºôð@»´BØ<dý<64>>»x?óþ£¼;}Ûº‚àÒ»:sš$ò1¹x<C2B9>Ga÷Ý´¹…]©ðð\˸c@
œ!?H_Oÿï_Œ?mÞ©~À+>žþåѽHѧ}—ÙÂAeYòÓH<O_Nø÷‚
|
||||
|
|
@ -27,6 +27,7 @@ int EndAcquisition(const is_device_usb_device* usb_device_desc, is_device_device
|
|||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ struct is_device_usb_device {
|
|||
InputVideoDataType video_data_type;
|
||||
size_t max_usb_packet_size;
|
||||
bool do_pipe_clear_reset;
|
||||
bool audio_enabled;
|
||||
size_t max_audio_samples_size;
|
||||
};
|
||||
|
||||
struct is_device_device_handlers {
|
||||
|
|
@ -96,6 +98,9 @@ int ReadPowerButtonState(is_device_device_handlers* handlers, bool* out, const i
|
|||
int ResetCPUStart(is_device_device_handlers* handlers, const is_device_usb_device* device_desc);
|
||||
int ResetCPUEnd(is_device_device_handlers* handlers, const is_device_usb_device* device_desc);
|
||||
int ResetFullHardware(is_device_device_handlers* handlers, const is_device_usb_device* device_desc);
|
||||
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);
|
||||
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);
|
||||
int ReadFrame(is_device_device_handlers* handlers, uint8_t* buf, uint32_t address, uint32_t length, const is_device_usb_device* device_desc);
|
||||
int ReadFrame(is_device_device_handlers* handlers, uint8_t* buf, int length, const is_device_usb_device* device_desc);
|
||||
void ReadFrameAsync(is_device_device_handlers* handlers, uint8_t* buf, int length, const is_device_usb_device* device_desc, isd_async_callback_data* cb_data);
|
||||
void CloseAsyncRead(is_device_device_handlers* handlers, isd_async_callback_data* cb_data);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef __USB_IS_TWL_ACQUISITION_CAPTURE_HPP
|
||||
#define __USB_IS_TWL_ACQUISITION_CAPTURE_HPP
|
||||
|
||||
#include "usb_is_device_communications.hpp"
|
||||
#include "capture_structs.hpp"
|
||||
|
||||
int initial_cleanup_twl_capture(const is_device_usb_device* usb_device_desc, is_device_device_handlers* handlers);
|
||||
int EndAcquisitionTWLCapture(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_twl_capture_recv_data);
|
||||
int EndAcquisitionTWLCapture(const is_device_usb_device* usb_device_desc, is_device_device_handlers* handlers);
|
||||
void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_twl_capture_recv_data);
|
||||
|
||||
#endif
|
||||
|
|
@ -146,6 +146,7 @@ union CaptureReceived {
|
|||
FTD2OldDSCaptureReceived ftd2_received_old_ds;
|
||||
FTD2OldDSCaptureReceivedRaw ftd2_received_old_ds_raw;
|
||||
ISNitroCaptureReceived is_nitro_capture_received;
|
||||
ISTWLCaptureReceived is_twl_capture_received;
|
||||
};
|
||||
|
||||
struct CaptureDevice {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -25,6 +25,32 @@ struct deinterleaved_ds_pixels_le {
|
|||
uint64_t fourth : 16;
|
||||
};
|
||||
|
||||
struct twl_16bit_pixels {
|
||||
uint16_t first_r : 5;
|
||||
uint16_t first_g : 6;
|
||||
uint16_t first_b : 5;
|
||||
uint16_t second_r : 5;
|
||||
uint16_t second_g : 6;
|
||||
uint16_t second_b : 5;
|
||||
uint16_t third_r : 5;
|
||||
uint16_t third_g : 6;
|
||||
uint16_t third_b : 5;
|
||||
uint16_t fourth_r : 5;
|
||||
uint16_t fourth_g : 6;
|
||||
uint16_t fourth_b : 5;
|
||||
};
|
||||
|
||||
struct twl_2bit_pixels {
|
||||
uint8_t first_r : 1;
|
||||
uint8_t first_b : 1;
|
||||
uint8_t second_r : 1;
|
||||
uint8_t second_b : 1;
|
||||
uint8_t third_r : 1;
|
||||
uint8_t third_b : 1;
|
||||
uint8_t fourth_r : 1;
|
||||
uint8_t fourth_b : 1;
|
||||
};
|
||||
|
||||
static inline void convertVideoToOutputChunk(RGB83DSVideoInputData *p_in, VideoOutputData *p_out, int iters, int start_in, int start_out) {
|
||||
memcpy(&p_out->screen_data[start_out], &p_in->screen_data[start_in], iters * 3);
|
||||
}
|
||||
|
|
@ -171,17 +197,63 @@ static void usb_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_o
|
|||
usb_oldDSconvertVideoToOutput(&p_in->usb_received_old_ds, p_out, is_big_endian);
|
||||
}
|
||||
|
||||
inline static uint8_t to_8_bit_6(uint8_t data) {
|
||||
return (data << 2) | (data >> 4);
|
||||
}
|
||||
|
||||
inline static void to_8_bit_6(uint8_t* out, uint8_t* in) {
|
||||
out[0] = to_8_bit_6(in[0]);
|
||||
out[1] = to_8_bit_6(in[1]);
|
||||
out[2] = to_8_bit_6(in[2]);
|
||||
}
|
||||
|
||||
static void usb_is_device_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureStatus* status, CaptureScreensType capture_type) {
|
||||
int num_pixels = usb_is_device_get_video_in_size(status) / 3;
|
||||
int out_start_pos = 0;
|
||||
int out_clear_pos = num_pixels;
|
||||
if(capture_type == CAPTURE_SCREENS_BOTTOM) {
|
||||
out_start_pos = num_pixels;
|
||||
out_clear_pos = 0;
|
||||
bool is_nitro = true;
|
||||
#ifdef USE_IS_DEVICES_USB
|
||||
is_nitro = is_device_is_nitro(&status->device);
|
||||
#endif
|
||||
if(is_nitro) {
|
||||
int num_pixels = usb_is_device_get_video_in_size(status) / 3;
|
||||
int out_start_pos = 0;
|
||||
int out_clear_pos = num_pixels;
|
||||
if(capture_type == CAPTURE_SCREENS_BOTTOM) {
|
||||
out_start_pos = num_pixels;
|
||||
out_clear_pos = 0;
|
||||
}
|
||||
if((capture_type == CAPTURE_SCREENS_BOTTOM) || (capture_type == CAPTURE_SCREENS_TOP))
|
||||
memset(p_out->screen_data[out_clear_pos], 0, num_pixels * 3);
|
||||
memcpy(p_out->screen_data[out_start_pos], p_in->is_nitro_capture_received.video_in.screen_data, num_pixels * 3);
|
||||
return;
|
||||
}
|
||||
ISTWLCaptureVideoInputData* data = &p_in->is_twl_capture_received.video_capture_in.video_in;
|
||||
twl_16bit_pixels* data_16_bit = (twl_16bit_pixels*)data->screen_data;
|
||||
twl_2bit_pixels* data_2_bit = (twl_2bit_pixels*)data->bit_6_rb_screen_data;
|
||||
int num_pixels = IN_VIDEO_SIZE_DS;
|
||||
const int num_pixels_struct = sizeof(twl_16bit_pixels) / sizeof(uint16_t);
|
||||
const int num_screens = 2;
|
||||
for(int i = 0; i < HEIGHT_DS; i++) {
|
||||
for(int j = 0; j < num_screens; j++) {
|
||||
size_t out_pos = ((num_screens - 1 - j) * (WIDTH_DS * HEIGHT_DS)) + (i * WIDTH_DS);
|
||||
for(int u = 0; u < (WIDTH_DS / num_pixels_struct); u++) {
|
||||
uint8_t pixels[num_pixels_struct][3];
|
||||
size_t index = (((i * num_screens * WIDTH_DS) + (j * WIDTH_DS)) / num_pixels_struct) + u;
|
||||
pixels[0][0] = (data_16_bit[index].first_r << 1) | (data_2_bit[index].first_r);
|
||||
pixels[0][1] = data_16_bit[index].first_g;
|
||||
pixels[0][2] = (data_16_bit[index].first_b << 1) | (data_2_bit[index].first_b);
|
||||
pixels[1][0] = (data_16_bit[index].second_r << 1) | (data_2_bit[index].second_r);
|
||||
pixels[1][1] = data_16_bit[index].second_g;
|
||||
pixels[1][2] = (data_16_bit[index].second_b << 1) | (data_2_bit[index].second_b);
|
||||
pixels[2][0] = (data_16_bit[index].third_r << 1) | (data_2_bit[index].third_r);
|
||||
pixels[2][1] = data_16_bit[index].third_g;
|
||||
pixels[2][2] = (data_16_bit[index].third_b << 1) | (data_2_bit[index].third_b);
|
||||
pixels[3][0] = (data_16_bit[index].fourth_r << 1) | (data_2_bit[index].fourth_r);
|
||||
pixels[3][1] = data_16_bit[index].fourth_g;
|
||||
pixels[3][2] = (data_16_bit[index].fourth_b << 1) | (data_2_bit[index].fourth_b);
|
||||
for(int k = 0; k < num_pixels_struct; k++)
|
||||
to_8_bit_6(p_out->screen_data[out_pos + (u * num_pixels_struct) + k], pixels[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if((capture_type == CAPTURE_SCREENS_BOTTOM) || (capture_type == CAPTURE_SCREENS_TOP))
|
||||
memset(p_out->screen_data[out_clear_pos], 0, num_pixels * 3);
|
||||
memcpy(p_out->screen_data[out_start_pos], p_in->is_nitro_capture_received.video_in.screen_data, num_pixels * 3);
|
||||
}
|
||||
|
||||
bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) {
|
||||
|
|
@ -240,6 +312,16 @@ bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, const bool i
|
|||
base_ptr = (uint8_t*)p_in->usb_received_3ds_3d.audio_data;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_IS_DEVICES_USB
|
||||
if(status->device.cc_type == CAPTURE_CONN_IS_NITRO) {
|
||||
base_ptr = (uint8_t*)p_in->is_twl_capture_received.audio_capture_in;
|
||||
size_t size_real = n_samples * 2;
|
||||
size_t size_packet_converted = sizeof(ISTWLCaptureAudioReceived) - sizeof(uint32_t);
|
||||
size_t num_packets = size_real / size_packet_converted;
|
||||
for(int i = 0; i < num_packets; i++)
|
||||
memcpy(base_ptr + (i * size_packet_converted), ((uint8_t*)&p_in->is_twl_capture_received.audio_capture_in[i]) + sizeof(uint32_t), size_packet_converted);
|
||||
}
|
||||
#endif
|
||||
if(base_ptr == NULL)
|
||||
return false;
|
||||
if(!is_big_endian)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user