#include "common/abi.h" #include "libs/errno.h" #include "libs/libs.h" #include "loader/symbolDatabase.h" #include #include #include #include namespace Libs { LIB_VERSION("Videodec2", 1, "Videodec2", 1, 1); namespace VideoDec2 { constexpr int32_t VIDEODEC2_ERROR_STRUCT_SIZE = -2128805631; // 0x811d0101 constexpr int32_t VIDEODEC2_ERROR_ARGUMENT_POINTER = -2128805630; // 0x811d0102 constexpr int32_t VIDEODEC2_ERROR_DECODER_INSTANCE = -2128805629; // 0x811d0103 constexpr int32_t VIDEODEC2_ERROR_MEMORY_SIZE = -2128805628; // 0x811d0104 constexpr int32_t VIDEODEC2_ERROR_MEMORY_POINTER = -2128805627; // 0x811d0105 constexpr int32_t VIDEODEC2_ERROR_FRAME_BUFFER_SIZE = -2128805626; // 0x811d0106 constexpr int32_t VIDEODEC2_ERROR_FRAME_BUFFER_POINTER = -2128805625; // 0x811d0107 constexpr int32_t VIDEODEC2_ERROR_CONFIG_INFO = -2128805376; // 0x811d0200 constexpr int32_t VIDEODEC2_ERROR_COMPUTE_PIPE_ID = -2128805375; // 0x811d0201 constexpr int32_t VIDEODEC2_ERROR_COMPUTE_QUEUE_ID = -2128805374; // 0x811d0202 constexpr int32_t VIDEODEC2_ERROR_RESOURCE_TYPE = -2128805373; // 0x811d0203 constexpr int32_t VIDEODEC2_ERROR_INPUT_QUEUE_DEPTH = -2128805370; // 0x811d0206 constexpr int32_t VIDEODEC2_ERROR_DPB_FRAME_COUNT = -2128805367; // 0x811d0209 constexpr int32_t VIDEODEC2_ERROR_FRAME_WIDTH_HEIGHT = -2128805366; // 0x811d020a constexpr uint32_t VIDEODEC2_RESOURCE_TYPE_COMPUTE = 1; constexpr size_t VIDEODEC2_MIN_MEMORY_SIZE = 16ull * 1024ull * 1024ull; constexpr uint32_t VIDEODEC2_FRAME_FORMAT_DEFAULT = 0; using Videodec2Decoder = void*; using Videodec2ComputeQueue = void*; struct Videodec2DecoderConfigInfo { size_t this_size; uint32_t resource_type; uint32_t codec_type; uint32_t profile; uint32_t max_level; int32_t max_frame_width; int32_t max_frame_height; int32_t max_dpb_frame_count; uint32_t decode_input_queue_depth; Videodec2ComputeQueue compute_queue; uint64_t cpu_affinity_mask; int32_t cpu_thread_priority; bool optimize_progressive_video; bool check_memory_type; uint8_t reserved0; uint8_t reserved1; void* extra_config_info; }; struct Videodec2DecoderMemoryInfo { size_t this_size; size_t cpu_memory_size; void* cpu_memory; size_t gpu_memory_size; void* gpu_memory; size_t cpu_gpu_memory_size; void* cpu_gpu_memory; size_t max_frame_buffer_size; uint32_t frame_buffer_alignment; uint32_t reserved0; }; struct Videodec2InputData { size_t this_size; void* au_data; size_t au_size; uint64_t pts_data; uint64_t dts_data; uint64_t attached_data; }; struct Videodec2OutputInfo { size_t this_size; bool is_valid; bool is_error_frame; uint8_t picture_count; bool is_discarded_frame; uint32_t codec_type; uint32_t frame_width; uint32_t frame_pitch; uint32_t frame_height; void* frame_buffer; size_t frame_buffer_size; uint32_t frame_format; uint32_t frame_pitch_in_bytes; }; struct Videodec2FrameBuffer { size_t this_size; void* frame_buffer; size_t frame_buffer_size; bool is_accepted; }; struct Videodec2ComputeMemoryInfo { size_t this_size; size_t cpu_gpu_memory_size; void* cpu_gpu_memory; }; struct Videodec2ComputeConfigInfo { size_t this_size; uint16_t compute_pipe_id; uint16_t compute_queue_id; bool check_memory_type; uint8_t reserved0; uint16_t reserved1; }; struct DecoderState { uint64_t magic; uint32_t codec_type; }; static_assert(sizeof(Videodec2ComputeMemoryInfo) == 24); static_assert(sizeof(Videodec2ComputeConfigInfo) == 16); static_assert(sizeof(Videodec2DecoderConfigInfo) == 72); static_assert(sizeof(Videodec2DecoderMemoryInfo) == 72); static_assert(sizeof(Videodec2InputData) == 48); static_assert(sizeof(Videodec2OutputInfo) == 56); static_assert(sizeof(Videodec2FrameBuffer) == 32); constexpr uint64_t DECODER_MAGIC = 0x4b59545956444543ull; // KYTYVDEC static std::mutex g_decoder_mutex; static std::unordered_set g_decoders; static bool IsOutputInfoSizeValid(size_t this_size) { return this_size == sizeof(Videodec2OutputInfo) || (this_size | 8u) == sizeof(Videodec2OutputInfo); } static DecoderState* GetDecoder(Videodec2Decoder decoder) { std::scoped_lock lock(g_decoder_mutex); return g_decoders.contains(decoder) ? static_cast(decoder) : nullptr; } static void FillNoPictureOutput(const Videodec2FrameBuffer* frame_buffer, Videodec2OutputInfo* output_info, uint32_t codec_type) { output_info->is_valid = false; output_info->is_error_frame = false; output_info->picture_count = 0; output_info->is_discarded_frame = false; output_info->codec_type = codec_type; output_info->frame_width = 0; output_info->frame_pitch = 0; output_info->frame_height = 0; output_info->frame_buffer = frame_buffer != nullptr ? frame_buffer->frame_buffer : nullptr; output_info->frame_buffer_size = frame_buffer != nullptr ? frame_buffer->frame_buffer_size : 0; output_info->frame_format = VIDEODEC2_FRAME_FORMAT_DEFAULT; output_info->frame_pitch_in_bytes = 0; } static int32_t ValidateDecoderConfig(const Videodec2DecoderConfigInfo* config) { if (config->resource_type != VIDEODEC2_RESOURCE_TYPE_COMPUTE) { return VIDEODEC2_ERROR_RESOURCE_TYPE; } if (config->reserved0 != 0 || config->reserved1 != 0) { return VIDEODEC2_ERROR_CONFIG_INFO; } if (config->decode_input_queue_depth == 0) { return VIDEODEC2_ERROR_INPUT_QUEUE_DEPTH; } if (config->max_dpb_frame_count < -1 || config->max_dpb_frame_count == 0) { return VIDEODEC2_ERROR_DPB_FRAME_COUNT; } if (config->max_frame_width < -1 || config->max_frame_height < -1 || config->max_frame_width == 0 || config->max_frame_height == 0) { return VIDEODEC2_ERROR_FRAME_WIDTH_HEIGHT; } if (config->compute_queue == nullptr) { return VIDEODEC2_ERROR_CONFIG_INFO; } return OK; } static int32_t KYTY_SYSV_ABI QueryComputeMemoryInfo(Videodec2ComputeMemoryInfo* compute_memory_info) { PRINT_NAME(); if (compute_memory_info == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (compute_memory_info->this_size != sizeof(Videodec2ComputeMemoryInfo)) { return VIDEODEC2_ERROR_STRUCT_SIZE; } compute_memory_info->cpu_gpu_memory_size = VIDEODEC2_MIN_MEMORY_SIZE; compute_memory_info->cpu_gpu_memory = nullptr; return OK; } static int32_t KYTY_SYSV_ABI AllocateComputeQueue( const Videodec2ComputeConfigInfo* compute_config_info, const Videodec2ComputeMemoryInfo* compute_memory_info, Videodec2ComputeQueue* compute_queue) { PRINT_NAME(); if (compute_config_info == nullptr || compute_memory_info == nullptr || compute_queue == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (compute_config_info->this_size != sizeof(Videodec2ComputeConfigInfo) || compute_memory_info->this_size != sizeof(Videodec2ComputeMemoryInfo)) { return VIDEODEC2_ERROR_STRUCT_SIZE; } if (compute_config_info->reserved0 != 0 || compute_config_info->reserved1 != 0) { return VIDEODEC2_ERROR_CONFIG_INFO; } if (compute_config_info->compute_pipe_id > 4) { return VIDEODEC2_ERROR_COMPUTE_PIPE_ID; } if (compute_config_info->compute_queue_id > 7) { return VIDEODEC2_ERROR_COMPUTE_QUEUE_ID; } if (compute_memory_info->cpu_gpu_memory_size < VIDEODEC2_MIN_MEMORY_SIZE) { return VIDEODEC2_ERROR_MEMORY_SIZE; } if (compute_memory_info->cpu_gpu_memory == nullptr) { return VIDEODEC2_ERROR_MEMORY_POINTER; } *compute_queue = compute_memory_info->cpu_gpu_memory; return OK; } static int32_t KYTY_SYSV_ABI ReleaseComputeQueue(Videodec2ComputeQueue compute_queue) { PRINT_NAME(); return compute_queue != nullptr ? OK : VIDEODEC2_ERROR_COMPUTE_QUEUE_ID; } static int32_t KYTY_SYSV_ABI QueryDecoderMemoryInfo(const Videodec2DecoderConfigInfo* config, Videodec2DecoderMemoryInfo* memory_info) { PRINT_NAME(); if (config == nullptr || memory_info == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (config->this_size != sizeof(Videodec2DecoderConfigInfo) || memory_info->this_size != sizeof(Videodec2DecoderMemoryInfo)) { return VIDEODEC2_ERROR_STRUCT_SIZE; } const auto validation_result = ValidateDecoderConfig(config); if (validation_result != OK) { return validation_result; } memory_info->cpu_memory_size = VIDEODEC2_MIN_MEMORY_SIZE; memory_info->cpu_memory = nullptr; memory_info->gpu_memory_size = VIDEODEC2_MIN_MEMORY_SIZE; memory_info->gpu_memory = nullptr; memory_info->cpu_gpu_memory_size = VIDEODEC2_MIN_MEMORY_SIZE; memory_info->cpu_gpu_memory = nullptr; memory_info->max_frame_buffer_size = VIDEODEC2_MIN_MEMORY_SIZE; memory_info->frame_buffer_alignment = 0x100; memory_info->reserved0 = 0; return OK; } static int32_t KYTY_SYSV_ABI CreateDecoder(const Videodec2DecoderConfigInfo* config, const Videodec2DecoderMemoryInfo* memory_info, Videodec2Decoder* decoder) { PRINT_NAME(); if (config == nullptr || memory_info == nullptr || decoder == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (config->this_size != sizeof(Videodec2DecoderConfigInfo) || memory_info->this_size != sizeof(Videodec2DecoderMemoryInfo)) { return VIDEODEC2_ERROR_STRUCT_SIZE; } const auto validation_result = ValidateDecoderConfig(config); if (validation_result != OK) { return validation_result; } if (memory_info->cpu_memory_size < VIDEODEC2_MIN_MEMORY_SIZE || memory_info->gpu_memory_size < VIDEODEC2_MIN_MEMORY_SIZE || memory_info->cpu_gpu_memory_size < VIDEODEC2_MIN_MEMORY_SIZE || memory_info->max_frame_buffer_size < VIDEODEC2_MIN_MEMORY_SIZE) { return VIDEODEC2_ERROR_MEMORY_SIZE; } if (memory_info->cpu_memory == nullptr || memory_info->gpu_memory == nullptr || memory_info->cpu_gpu_memory == nullptr) { return VIDEODEC2_ERROR_MEMORY_POINTER; } auto* state = new DecoderState {}; state->magic = DECODER_MAGIC; state->codec_type = config->codec_type; { std::scoped_lock lock(g_decoder_mutex); g_decoders.insert(state); } *decoder = state; return OK; } static int32_t KYTY_SYSV_ABI DeleteDecoder(Videodec2Decoder decoder) { PRINT_NAME(); DecoderState* state = nullptr; { std::scoped_lock lock(g_decoder_mutex); auto it = g_decoders.find(decoder); if (it == g_decoders.end()) { return VIDEODEC2_ERROR_DECODER_INSTANCE; } state = static_cast(*it); g_decoders.erase(it); } delete state; return OK; } static int32_t KYTY_SYSV_ABI Decode(Videodec2Decoder decoder, const Videodec2InputData* input_data, Videodec2FrameBuffer* frame_buffer, Videodec2OutputInfo* output_info) { PRINT_NAME(); const auto* state = GetDecoder(decoder); if (state == nullptr || state->magic != DECODER_MAGIC) { return VIDEODEC2_ERROR_DECODER_INSTANCE; } if (input_data == nullptr || frame_buffer == nullptr || output_info == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (input_data->this_size != sizeof(Videodec2InputData) || frame_buffer->this_size != sizeof(Videodec2FrameBuffer) || !IsOutputInfoSizeValid(output_info->this_size)) { return VIDEODEC2_ERROR_STRUCT_SIZE; } if (input_data->au_size != 0 && input_data->au_data == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (frame_buffer->frame_buffer_size == 0) { return VIDEODEC2_ERROR_FRAME_BUFFER_SIZE; } if (frame_buffer->frame_buffer == nullptr) { return VIDEODEC2_ERROR_FRAME_BUFFER_POINTER; } frame_buffer->is_accepted = false; FillNoPictureOutput(frame_buffer, output_info, state->codec_type); return OK; } static int32_t KYTY_SYSV_ABI Flush(Videodec2Decoder decoder, Videodec2FrameBuffer* frame_buffer, Videodec2OutputInfo* output_info) { PRINT_NAME(); const auto* state = GetDecoder(decoder); if (state == nullptr || state->magic != DECODER_MAGIC) { return VIDEODEC2_ERROR_DECODER_INSTANCE; } if (frame_buffer == nullptr || output_info == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (frame_buffer->this_size != sizeof(Videodec2FrameBuffer) || !IsOutputInfoSizeValid(output_info->this_size)) { return VIDEODEC2_ERROR_STRUCT_SIZE; } frame_buffer->is_accepted = false; FillNoPictureOutput(frame_buffer, output_info, state->codec_type); return OK; } static int32_t KYTY_SYSV_ABI Reset(Videodec2Decoder decoder) { PRINT_NAME(); const auto* state = GetDecoder(decoder); return state != nullptr && state->magic == DECODER_MAGIC ? OK : VIDEODEC2_ERROR_DECODER_INSTANCE; } static int32_t KYTY_SYSV_ABI GetPictureInfo(const Videodec2OutputInfo* output_info, void* /*first_picture_info*/, void* /*second_picture_info*/) { PRINT_NAME(); if (output_info == nullptr) { return VIDEODEC2_ERROR_ARGUMENT_POINTER; } if (!IsOutputInfoSizeValid(output_info->this_size)) { return VIDEODEC2_ERROR_STRUCT_SIZE; } return OK; } LIB_DEFINE(InitVideoDec2_1) { PRINT_NAME_ENABLE(true); LIB_FUNC("RnDibcGCPKw", QueryComputeMemoryInfo); LIB_FUNC("eD+X2SmxUt4", AllocateComputeQueue); LIB_FUNC("UvtA3FAiF4Y", ReleaseComputeQueue); LIB_FUNC("qqMCwlULR+E", QueryDecoderMemoryInfo); LIB_FUNC("CNNRoRYd8XI", CreateDecoder); LIB_FUNC("jwImxXRGSKA", DeleteDecoder); LIB_FUNC("852F5+q6+iM", Decode); LIB_FUNC("l1hXwscLuCY", Flush); LIB_FUNC("wJXikG6QFN8", Reset); LIB_FUNC("NtXRa3dRzU0", GetPictureInfo); LIB_FUNC("kjrLbcyhEiw", GetPictureInfo); } } // namespace VideoDec2 } // namespace Libs