mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2025-06-18 16:45:39 -04:00
344 lines
14 KiB
C++
Executable File
344 lines
14 KiB
C++
Executable File
#ifndef __CAPTURESTRUCTS_HPP
|
|
#define __CAPTURESTRUCTS_HPP
|
|
|
|
#include "utils.hpp"
|
|
#include "hw_defs.hpp"
|
|
#include <mutex>
|
|
#include <string>
|
|
|
|
// It may happen that a frame is lost.
|
|
// This value prevents showing a black frame for that.
|
|
// Shouldn't happen with recent updates, though...
|
|
#define MAX_ALLOWED_BLANKS 1
|
|
|
|
#define FIX_PARTIAL_FIRST_FRAME_NUM 3
|
|
|
|
#define MAX_PACKET_SIZE_USB2 (1 << 9)
|
|
#define EXTRA_DATA_BUFFER_USB_SIZE MAX_PACKET_SIZE_USB2
|
|
#define EXTRA_DATA_BUFFER_FTD3XX_SIZE (1 << 10)
|
|
|
|
#define FTD2_INTRA_PACKET_HEADER_SIZE 2
|
|
#define MAX_PACKET_SIZE_FTD2 (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE)
|
|
|
|
#define OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE 0x200
|
|
|
|
enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO, CAPTURE_CONN_CYPRESS_NISETRO, CAPTURE_CONN_CYPRESS_NEW_OPTIMIZE };
|
|
enum InputVideoDataType { VIDEO_DATA_RGB, VIDEO_DATA_BGR, VIDEO_DATA_RGB16, VIDEO_DATA_BGR16 };
|
|
enum CaptureScreensType { CAPTURE_SCREENS_BOTH, CAPTURE_SCREENS_TOP, CAPTURE_SCREENS_BOTTOM, CAPTURE_SCREENS_ENUM_END };
|
|
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 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 + 1 + NUM_CONCURRENT_DATA_BUFFER_WRITERS)
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct PACKED RGB83DSVideoInputData {
|
|
uint8_t screen_data[IN_VIDEO_SIZE_3DS][3];
|
|
};
|
|
|
|
struct PACKED RGB83DSVideoInputData_3D {
|
|
uint8_t screen_data[IN_VIDEO_SIZE_3DS_3D][3];
|
|
};
|
|
|
|
#define OLD_DS_PIXEL_B_BITS 5
|
|
#define OLD_DS_PIXEL_G_BITS 6
|
|
#define OLD_DS_PIXEL_R_BITS 5
|
|
|
|
struct PACKED USBOldDSPixelData {
|
|
uint16_t b : OLD_DS_PIXEL_B_BITS;
|
|
uint16_t g : OLD_DS_PIXEL_G_BITS;
|
|
uint16_t r : OLD_DS_PIXEL_R_BITS;
|
|
};
|
|
|
|
struct PACKED USBOldDSVideoInputData {
|
|
USBOldDSPixelData screen_data[IN_VIDEO_SIZE_DS];
|
|
};
|
|
|
|
#define OPTIMIZE_NEW_3DS_PIXEL_R_BITS 5
|
|
#define OPTIMIZE_NEW_3DS_PIXEL_G_BITS 6
|
|
#define OPTIMIZE_NEW_3DS_PIXEL_B_BITS 5
|
|
|
|
struct PACKED USB565New3DSOptimizePixelData {
|
|
uint16_t r : OPTIMIZE_NEW_3DS_PIXEL_R_BITS;
|
|
uint16_t g : OPTIMIZE_NEW_3DS_PIXEL_G_BITS;
|
|
uint16_t b : OPTIMIZE_NEW_3DS_PIXEL_B_BITS;
|
|
};
|
|
|
|
struct PACKED USB888New3DSOptimizePixelData {
|
|
uint8_t r;
|
|
uint8_t g;
|
|
uint8_t b;
|
|
};
|
|
|
|
struct PACKED USBNew3DSOptimizeSingleSoundData {
|
|
uint16_t sample_index;
|
|
uint16_t sample_l;
|
|
uint16_t sample_r;
|
|
};
|
|
|
|
struct PACKED USBNew3DSOptimizeHeaderSoundData {
|
|
// Order is Little Endian
|
|
uint16_t magic;
|
|
uint16_t unk_fixed_1 : 1;
|
|
uint16_t buffer_num : 1;
|
|
uint16_t unk : 5;
|
|
uint16_t column_index : 9;
|
|
USBNew3DSOptimizeSingleSoundData samples[2];
|
|
};
|
|
|
|
struct PACKED USB565New3DSOptimizeInputColumnData {
|
|
USBNew3DSOptimizeHeaderSoundData header_sound;
|
|
USB565New3DSOptimizePixelData pixel[HEIGHT_3DS][2];
|
|
};
|
|
|
|
struct PACKED USB565New3DSOptimizeInputColumnData3D {
|
|
USBNew3DSOptimizeHeaderSoundData header_sound;
|
|
USB565New3DSOptimizePixelData pixel[HEIGHT_3DS][3];
|
|
};
|
|
|
|
struct PACKED USB888New3DSOptimizeInputColumnData {
|
|
USBNew3DSOptimizeHeaderSoundData header_sound;
|
|
USB888New3DSOptimizePixelData pixel[HEIGHT_3DS][2];
|
|
};
|
|
|
|
struct PACKED USB888New3DSOptimizeInputColumnData3D {
|
|
USBNew3DSOptimizeHeaderSoundData header_sound;
|
|
USB888New3DSOptimizePixelData pixel[HEIGHT_3DS][3];
|
|
};
|
|
|
|
struct PACKED ISNitroEmulatorVideoInputData {
|
|
uint8_t screen_data[IN_VIDEO_SIZE_DS][3];
|
|
};
|
|
|
|
struct PACKED ISTWLCaptureVideoInputData {
|
|
USBOldDSPixelData screen_data[IN_VIDEO_SIZE_DS];
|
|
uint8_t bit_6_rb_screen_data[(IN_VIDEO_SIZE_DS >> 3) * 2];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED FTD3_3DSCaptureReceived {
|
|
RGB83DSVideoInputData video_in;
|
|
uint16_t audio_data[N3DSXL_SAMPLES_IN];
|
|
uint8_t unused_buffer[EXTRA_DATA_BUFFER_FTD3XX_SIZE];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED FTD3_3DSCaptureReceived_3D {
|
|
RGB83DSVideoInputData_3D video_in;
|
|
uint16_t audio_data[N3DSXL_SAMPLES_IN];
|
|
uint8_t unused_buffer[EXTRA_DATA_BUFFER_FTD3XX_SIZE];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED USB3DSCaptureReceived {
|
|
RGB83DSVideoInputData video_in;
|
|
uint16_t audio_data[O3DS_SAMPLES_IN];
|
|
uint8_t unused_buffer[EXTRA_DATA_BUFFER_USB_SIZE];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED USB3DSCaptureReceived_3D {
|
|
RGB83DSVideoInputData_3D video_in;
|
|
uint16_t audio_data[O3DS_SAMPLES_IN];
|
|
uint8_t unused_buffer[EXTRA_DATA_BUFFER_USB_SIZE];
|
|
};
|
|
|
|
struct PACKED USBOldDSFrameInfo {
|
|
uint8_t half_line_flags[(HEIGHT_DS >> 3) << 1];
|
|
uint32_t frame;
|
|
uint8_t valid;
|
|
uint8_t unused[11];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED USBOldDSCaptureReceived {
|
|
USBOldDSVideoInputData video_in;
|
|
uint8_t unused_buffer[EXTRA_DATA_BUFFER_USB_SIZE];
|
|
USBOldDSFrameInfo frameinfo;
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED FTD2OldDSCaptureReceived {
|
|
USBOldDSVideoInputData video_in;
|
|
uint16_t audio_data[DS_SAMPLES_IN];
|
|
uint8_t unused_buffer[EXTRA_DATA_BUFFER_USB_SIZE];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED FTD2OldDSCaptureReceivedRaw {
|
|
FTD2OldDSCaptureReceived data;
|
|
uint8_t extra_ftd2_buffer[((sizeof(FTD2OldDSCaptureReceived) + MAX_PACKET_SIZE_FTD2 - 1) / MAX_PACKET_SIZE_FTD2) * FTD2_INTRA_PACKET_HEADER_SIZE];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED ISNitroCaptureReceived {
|
|
ISNitroEmulatorVideoInputData video_in;
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED CypressNisetroDSCaptureReceived {
|
|
ISNitroEmulatorVideoInputData video_in;
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED ISTWLCaptureVideoReceived {
|
|
ISTWLCaptureVideoInputData video_in;
|
|
uint32_t time;
|
|
uint32_t frame;
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED ISTWLCaptureVideoInternalReceived {
|
|
ISTWLCaptureVideoReceived real_video_in;
|
|
uint8_t unknown[0x40000 - sizeof(ISTWLCaptureVideoReceived)];
|
|
};
|
|
|
|
struct ALIGNED(4) PACKED ISTWLCaptureSoundData {
|
|
uint16_t data[TWL_CAPTURE_SAMPLES_IN];
|
|
};
|
|
|
|
struct ALIGNED(4) PACKED ISTWLCaptureAudioReceived {
|
|
uint32_t time;
|
|
ISTWLCaptureSoundData sound_data;
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED ISTWLCaptureReceived {
|
|
ISTWLCaptureVideoReceived video_capture_in;
|
|
ISTWLCaptureAudioReceived audio_capture_in[TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED USB565New3DSOptimizeCaptureReceived {
|
|
USB565New3DSOptimizeInputColumnData columns_data[TOP_WIDTH_3DS];
|
|
USB565New3DSOptimizePixelData bottom_only_column[HEIGHT_3DS][2];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED USB565New3DSOptimizeCaptureReceived_3D {
|
|
USB565New3DSOptimizeInputColumnData3D columns_data[TOP_WIDTH_3DS];
|
|
USB565New3DSOptimizePixelData bottom_only_column[HEIGHT_3DS][3];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED USB888New3DSOptimizeCaptureReceived {
|
|
USB888New3DSOptimizeInputColumnData columns_data[TOP_WIDTH_3DS];
|
|
USB888New3DSOptimizePixelData bottom_only_column[HEIGHT_3DS][2];
|
|
};
|
|
|
|
struct ALIGNED(16) PACKED USB888New3DSOptimizeCaptureReceived_3D {
|
|
USB888New3DSOptimizeInputColumnData3D columns_data[TOP_WIDTH_3DS];
|
|
USB888New3DSOptimizePixelData bottom_only_column[HEIGHT_3DS][3];
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
struct ALIGNED(16) FTD2OldDSCaptureReceivedNormalPlusRaw {
|
|
FTD2OldDSCaptureReceived data;
|
|
FTD2OldDSCaptureReceivedRaw raw_data;
|
|
};
|
|
|
|
union CaptureReceived {
|
|
FTD3_3DSCaptureReceived ftd3_received;
|
|
FTD3_3DSCaptureReceived_3D ftd3_received_3d;
|
|
USB3DSCaptureReceived usb_received_3ds;
|
|
USB3DSCaptureReceived_3D usb_received_3ds_3d;
|
|
USBOldDSCaptureReceived usb_received_old_ds;
|
|
FTD2OldDSCaptureReceived ftd2_received_old_ds;
|
|
FTD2OldDSCaptureReceivedNormalPlusRaw ftd2_received_old_ds_normal_plus_raw;
|
|
ISNitroCaptureReceived is_nitro_capture_received;
|
|
ISTWLCaptureReceived is_twl_capture_received;
|
|
CypressNisetroDSCaptureReceived cypress_nisetro_capture_received;
|
|
USB565New3DSOptimizeCaptureReceived cypress_new_optimize_received_565;
|
|
USB565New3DSOptimizeCaptureReceived_3D cypress_new_optimize_received_565_3d;
|
|
USB888New3DSOptimizeCaptureReceived cypress_new_optimize_received_888;
|
|
USB888New3DSOptimizeCaptureReceived_3D cypress_new_optimize_received_888_3d;
|
|
};
|
|
|
|
struct CaptureDevice {
|
|
// This is so messy... Wish there was a clearer way...
|
|
CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, uint64_t max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), video_data_type(video_data_type), long_name(name) {}
|
|
CaptureDevice(std::string serial_number, std::string name, std::string long_name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, uint64_t max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type, std::string path = "") : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), video_data_type(video_data_type), path(path), long_name(long_name) {}
|
|
CaptureDevice(std::string serial_number, std::string name, std::string long_name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, uint64_t max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type, int firmware_id, bool is_rgb_888, std::string path = "") : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(path), video_data_type(video_data_type), firmware_id(firmware_id), is_rgb_888(is_rgb_888), long_name(long_name) {}
|
|
CaptureDevice(std::string serial_number, std::string name, std::string long_name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int width_3d, int height_3d, uint64_t max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int second_top_screen_x, int second_top_screen_y, int bot_screen_x, int bot_screen_y, bool is_second_top_screen_right, InputVideoDataType video_data_type, uint32_t usb_speed, std::string path = "") : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), video_data_type(video_data_type), long_name(long_name), usb_speed(usb_speed), second_top_screen_x(second_top_screen_x), second_top_screen_y(second_top_screen_y), width_3d(width_3d), height_3d(height_3d), is_second_top_screen_right(is_second_top_screen_right), path(path) {}
|
|
CaptureDevice() : usb_speed(0) {}
|
|
|
|
std::string serial_number = "";
|
|
std::string name = "";
|
|
std::string long_name = "";
|
|
std::string path = "";
|
|
CaptureConnectionType cc_type = CAPTURE_CONN_USB;
|
|
InputVideoDataType video_data_type = VIDEO_DATA_RGB;
|
|
const void* descriptor = NULL;
|
|
bool is_3ds = false;
|
|
bool has_3d = false;
|
|
bool has_audio = false;
|
|
int width = 0;
|
|
int height = 0;
|
|
int width_3d = 0;
|
|
int height_3d = 0;
|
|
uint64_t max_samples_in = 0;
|
|
int base_rotation = 0;
|
|
int top_screen_x = 0;
|
|
int top_screen_y = 0;
|
|
int second_top_screen_x = 0;
|
|
int second_top_screen_y = 0;
|
|
bool is_second_top_screen_right = false;
|
|
int bot_screen_x = 0;
|
|
int bot_screen_y = 0;
|
|
int firmware_id = 0;
|
|
uint32_t usb_speed = 0x200;
|
|
bool is_rgb_888 = false;
|
|
};
|
|
|
|
struct CaptureStatus {
|
|
CaptureDevice device;
|
|
std::string graphical_error_text;
|
|
std::string detailed_error_text;
|
|
bool new_error_text;
|
|
volatile int cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM;
|
|
volatile bool connected = false;
|
|
volatile bool running = true;
|
|
volatile bool close_success = true;
|
|
volatile int curr_delay = 0;
|
|
volatile bool reset_hardware = false;
|
|
bool requested_3d = false;
|
|
CaptureScreensType capture_type;
|
|
CaptureSpeedsType capture_speed;
|
|
int battery_percentage;
|
|
bool ac_adapter_connected;
|
|
ConsumerMutex video_wait;
|
|
ConsumerMutex audio_wait;
|
|
};
|
|
|
|
struct CaptureDataSingleBuffer {
|
|
CaptureScreensType capture_type;
|
|
uint64_t read;
|
|
size_t unused_offset;
|
|
CaptureReceived capture_buf;
|
|
double time_in_buf;
|
|
uint32_t inner_index;
|
|
bool is_3d;
|
|
InputVideoDataType buffer_video_data_type;
|
|
};
|
|
|
|
class CaptureDataBuffers {
|
|
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, size_t offset, int index, bool is_3d = false);
|
|
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type, int index, bool is_3d = false);
|
|
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, size_t offset, int index, bool is_3d = false);
|
|
void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, int index, bool is_3d = false);
|
|
CaptureDataSingleBuffer* GetWriterBuffer(int index = 0);
|
|
void ReleaseWriterBuffer(int index = 0, bool update_last_curr_in = true);
|
|
private:
|
|
std::mutex access_mutex;
|
|
int last_curr_in;
|
|
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];
|
|
};
|
|
|
|
struct CaptureData {
|
|
void* handle;
|
|
CaptureDataBuffers data_buffers;
|
|
CaptureStatus status;
|
|
};
|
|
#endif
|