#ifndef __CAPTURESTRUCTS_HPP #define __CAPTURESTRUCTS_HPP #include "utils.hpp" #include "hw_defs.hpp" #include #include // 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 EXTRA_DATA_BUFFER_USB_SIZE (1 << 9) #define EXTRA_DATA_BUFFER_FTD3XX_SIZE (1 << 10) enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO }; 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 2 extra buffers. One for 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_READERS ((int)CAPTURE_READER_ENUM_END) #define NUM_CONCURRENT_DATA_BUFFERS (NUM_CONCURRENT_DATA_BUFFER_READERS + 2) #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]; }; struct PACKED ISNitroEmulatorVideoInputData { uint8_t screen_data[IN_VIDEO_SIZE_DS][3]; }; 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 ISNitroCaptureReceived { ISNitroEmulatorVideoInputData video_in; }; #pragma pack(pop) 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; ISNitroCaptureReceived is_nitro_capture_received; }; struct CaptureDevice { 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, int 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), path(""), video_data_type(video_data_type), firmware_id(0), is_rgb_888(false) {} 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, int 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) : 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(""), video_data_type(video_data_type), firmware_id(firmware_id), is_rgb_888(is_rgb_888) {} CaptureDevice(std::string serial_number, std::string name, std::string path, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int 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), path(path), video_data_type(video_data_type), firmware_id(0), is_rgb_888(false) {} CaptureDevice(): serial_number(""), name(""), cc_type(CAPTURE_CONN_USB), descriptor(NULL), is_3ds(false), has_3d(false), has_audio(false), width(0), height(0), max_samples_in(0), base_rotation(0), top_screen_x(0), top_screen_y(0), bot_screen_x(0), bot_screen_y(0), path(""), firmware_id(0), video_data_type(VIDEO_DATA_RGB), is_rgb_888(false) {} std::string serial_number; std::string name; std::string path; CaptureConnectionType cc_type; InputVideoDataType video_data_type; const void* descriptor; bool is_3ds; bool has_3d; bool has_audio; int width; int height; int max_samples_in; int base_rotation; int top_screen_x; int top_screen_y; int bot_screen_x; int bot_screen_y; int firmware_id; bool is_rgb_888; }; 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 enabled_3d = false; CaptureScreensType capture_type; CaptureSpeedsType capture_speed; ConsumerMutex video_wait; ConsumerMutex audio_wait; }; struct CaptureDataSingleBuffer { CaptureScreensType capture_type; uint64_t read; CaptureReceived capture_buf; double time_in_buf; }; 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 = CAPTURE_SCREENS_BOTH); private: std::mutex access_mutex; int last_curr_in; int curr_writer_pos; int curr_reader_pos[NUM_CONCURRENT_DATA_BUFFER_READERS]; 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]; CaptureDataSingleBuffer* GetWriterBuffer(); void ReleaseWriterBuffer(); }; struct CaptureData { void* handle; CaptureDataBuffers data_buffers; CaptureStatus status; }; #endif