From 9a8ae4417bbfc79b1a43eb8a2eb0bb602148261e Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 3 Oct 2026 15:31:45 +0200 Subject: [PATCH] Camera code cleanup and fixes (#5211) * Split the HLE camera library into multiple source files for readability * copyright 2026 * calibration functions * Pull out camera config type table to a separate header * Do not assume the base format is always RGBA8888 for RAW8/RAW16 outputs If a game registers YUV422 for eye 1 and RAW16 for eye 2, that made the HLE library register YUY2 as the SDL format before, but then tried to use it as RGBA88888, which lead to overidexing and reading from unmapped pages * Cleanup Turtle's cleanup * copyright 2024-2026 * the loathsome clang-formatter * sir clang offnir, the all formatting --- CMakeLists.txt | 7 + src/core/libraries/camera/camera.cpp | 968 ++---------------- src/core/libraries/camera/camera.h | 188 +--- src/core/libraries/camera/camera_audio.cpp | 45 + .../libraries/camera/camera_calibration.cpp | 76 ++ src/core/libraries/camera/camera_config.cpp | 648 ++++++++++++ .../libraries/camera/camera_config_types.h | 187 ++++ src/core/libraries/camera/camera_device.cpp | 62 ++ src/core/libraries/camera/camera_error.h | 4 +- src/core/libraries/camera/camera_helpers.cpp | 204 ++++ src/core/libraries/camera/camera_helpers.h | 22 + src/main.cpp | 2 +- 12 files changed, 1322 insertions(+), 1091 deletions(-) create mode 100644 src/core/libraries/camera/camera_audio.cpp create mode 100644 src/core/libraries/camera/camera_calibration.cpp create mode 100644 src/core/libraries/camera/camera_config.cpp create mode 100644 src/core/libraries/camera/camera_config_types.h create mode 100644 src/core/libraries/camera/camera_device.cpp create mode 100644 src/core/libraries/camera/camera_helpers.cpp create mode 100644 src/core/libraries/camera/camera_helpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 279ce115e..98ee1dd7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -732,6 +732,13 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp set(CAMERA_LIBS src/core/libraries/camera/camera.cpp src/core/libraries/camera/camera.h + src/core/libraries/camera/camera_helpers.h + src/core/libraries/camera/camera_helpers.cpp + src/core/libraries/camera/camera_audio.cpp + src/core/libraries/camera/camera_calibration.cpp + src/core/libraries/camera/camera_config.cpp + src/core/libraries/camera/camera_config_types.h + src/core/libraries/camera/camera_device.cpp src/core/libraries/camera/camera_error.h ) diff --git a/src/core/libraries/camera/camera.cpp b/src/core/libraries/camera/camera.cpp index ae1745065..fe09bc0bd 100644 --- a/src/core/libraries/camera/camera.cpp +++ b/src/core/libraries/camera/camera.cpp @@ -1,11 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/elf_info.h" #include "common/logging/log.h" #include "core/emulator_settings.h" #include "core/libraries/camera/camera.h" -#include "core/libraries/camera/camera_error.h" +#include "core/libraries/camera/camera_helpers.h" #include "core/libraries/error_codes.h" #include "core/libraries/kernel/memory.h" #include "core/libraries/kernel/process.h" @@ -19,8 +19,9 @@ namespace Libraries::Camera { -static bool g_library_opened = false; -static s32 g_firmware_version = 0; +bool g_library_opened = false; +s32 g_firmware_version = 0; + static s32 g_handles = 0; static constexpr s32 c_width = 1280, c_height = 800; @@ -35,42 +36,6 @@ s32 PS4_SYSV_ABI sceCameraAccGetData() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceCameraAudioClose() { - LOG_DEBUG(Lib_Camera, "called"); - // Returns ORBIS_OK while internally failing - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraAudioGetData(void* data) { - LOG_DEBUG(Lib_Camera, "called"); - if (data == nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - // Returns ORBIS_OK while internally failing - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraAudioGetData2(void* data) { - LOG_DEBUG(Lib_Camera, "called"); - if (data == nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - // Returns ORBIS_OK while internally failing - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraAudioOpen() { - LOG_DEBUG(Lib_Camera, "called"); - // Returns error fatal as a side effect of not having a camera attached. - return ORBIS_CAMERA_ERROR_FATAL; -} - -s32 PS4_SYSV_ABI sceCameraAudioReset() { - LOG_DEBUG(Lib_Camera, "called"); - // Returns ORBIS_OK while internally failing - return ORBIS_OK; -} - s32 PS4_SYSV_ABI sceCameraChangeAppModuleState() { LOG_ERROR(Lib_Camera, "(STUBBED) called"); return ORBIS_OK; @@ -90,6 +55,11 @@ s32 PS4_SYSV_ABI sceCameraClose(s32 handle) { if (--g_handles == 0) { g_library_opened = false; } + + if (sdl_camera) { + SDL_CloseCamera(sdl_camera); + } + return ORBIS_OK; } @@ -110,346 +80,11 @@ s32 PS4_SYSV_ABI sceCameraCloseByHandle(s32 handle) { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceCameraDeviceOpen() { - // Stubbed on real hardware - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* attribute) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || attribute == nullptr || attribute->sizeThis != sizeof(OrbisCameraAttribute) || - attribute->channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - attribute->channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - auto channel = attribute->channel; - - // Set default attributes - memset(attribute, 0, sizeof(OrbisCameraAttribute)); - attribute->sizeThis = sizeof(OrbisCameraAttribute); - attribute->channel = channel; - attribute->exposureGain.exposure = 83; - attribute->exposureGain.gain = 100; - attribute->whiteBalance.gainRed = 768; - attribute->whiteBalance.gainBlue = 768; - attribute->whiteBalance.gainGreen = 512; - attribute->gamma.value = 4; - attribute->saturation = 64; - attribute->contrast = 32; - attribute->sharpness = 1; - attribute->hue = 1; - - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* enable, - OrbisCameraAutoExposureGainTarget* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (option != nullptr && (g_firmware_version < Common::ElfInfo::FW_300 || - option->sizeThis != sizeof(OrbisCameraAutoExposureGainTarget))) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *enable = 0; - if (option != nullptr) { - option->sizeThis = 0; - option->target = OrbisCameraAecAgcTarget::ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF; - } - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* enable, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *enable = 0; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetCalibData(s32 id, void* calib_data, void* maybe_reserved) { - LOG_WARNING(Lib_Camera, "(DUMMY) called, id: {}", id); - if (calib_data == nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (id != 1 && id != 2) { - return ORBIS_OK; - } - static constexpr u64 dumped_calib_data1[32]{ - 0x000000000b0b0200, 0x00000000bc128639, 0x000000003de79766, 0x00000000be6e2869, - 0x3ca0ce1f3e30521c, 0x4452d55e3d0160b6, 0x3cf7fdaa4453abf1, 0x000000003ce3f40f, - 0x000000003cdbcaa6, 0x000000003d635f4e, 0x00000000be299439, 0xbb98ddc23e1159b4, - 0x44523b6c3c87d83c, 0x3c8d1c46445308a2, 0xbbb83fe03c9bcc40, 0xbab0ed65b8fe93b0, - 0xba677004bb598091, 0x3c0eb61e3b49d173, 0xba1bac9f3c67af0b, 0x00000000b9d0e64d, - 0x0000000000000000, 0x0000000000000000, 0xb97653e400000000, 0x00000000ba95460e, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0xbab5330000000000, 0x000001013b07a47f, - }; - static constexpr u64 dumped_calib_data2[32]{ - 0x002d000000ff0009, 0x002d0ff70ffd0f14, 0x002d0efe00010008, 0x002f0ffe0f020008, - 0x002f000800060105, 0x002e00fc0001000a, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - }; - std::memcpy(calib_data, id == 1 ? dumped_calib_data1 : dumped_calib_data2, - sizeof(dumped_calib_data1)); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraGetCalibrationData(const OrbisCameraGetCalibrationDataParameter* param, - OrbisCameraCalibrationData* calibration_data) { - LOG_DEBUG(Lib_Camera, "called"); - if (param == nullptr || calibration_data == nullptr || - param->size != sizeof(OrbisCameraGetCalibrationDataParameter) || param->format_type != 0 || - param->function_type < - OrbisCameraCalibrationDataFunctionType:: - ORBIS_CAMERA_CALIBRATION_DATA_FUNCTION_TYPE_IMAGE_RECTIFICATION || - param->function_type > - OrbisCameraCalibrationDataFunctionType:: - ORBIS_CAMERA_CALIBRATION_DATA_FUNCTION_TYPE_IMAGE_INVERSE_RECTIFICATION) { - return ORBIS_CAMERA_ERROR_PARAM; - } - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* config) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - // Set default config - config->configType = ORBIS_CAMERA_CONFIG_TYPE1; - config->sizeThis = 0; - - OrbisCameraConfigExtention default_extension; - default_extension.format.formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422; - default_extension.format.formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8; - default_extension.format.formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8; - default_extension.format.formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8; - default_extension.resolution = ORBIS_CAMERA_RESOLUTION_1280X800; - default_extension.framerate = ORBIS_CAMERA_FRAMERATE_60; - default_extension.width = 0; - default_extension.height = 0; - default_extension.reserved1 = 0; - - memcpy(&config->configExtention[0], &default_extension, sizeof(OrbisCameraConfigExtention)); - memcpy(&config->configExtention[1], &default_extension, sizeof(OrbisCameraConfigExtention)); - - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* contrast, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || contrast == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *contrast = 32; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel, - u32* enable, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *enable = 0; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetDeviceConfig(s32 handle, OrbisCameraConfig* config) { - if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - memset(config, 0, sizeof(OrbisCameraConfig)); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle(OrbisCameraConfig* config) { - if (config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - memset(config, 0, sizeof(OrbisCameraConfig)); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetDeviceID() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* device_info) { - LOG_DEBUG(Lib_Camera, "called"); - if (reserved != 0 || device_info == nullptr || - device_info->sizeThis != sizeof(OrbisCameraDeviceInfo) || device_info->infoRevision != 1) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_INIT; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel, - OrbisCameraExposureGain* exposure_gain, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || exposure_gain == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - // Return default parameters - exposure_gain->exposureControl = 0; - exposure_gain->exposure = 20; - exposure_gain->gain = 100; - exposure_gain->mode = 0; - return ORBIS_OK; -} - -static void ConvertRGBA8888ToRAW16(const u8* src, u16* dst, int width, int height) { - for (int y = 0; y < height; ++y) { - const u8* row = src + y * width * 4; - u16* outRow = dst + y * width; - - for (int x = 0; x < width; ++x) { - const u8* px = row + x * 4; - - u16 b = u16(px[1]) << 4; - u16 g = u16(px[2]) << 4; - u16 r = u16(px[3]) << 4; - - // BGGR Bayer layout - // B G - // G R - bool evenRow = (y & 1) == 0; - bool evenCol = (x & 1) == 0; - - if (evenRow && evenCol) { - outRow[x] = b; - } else if (evenRow && !evenCol) { - outRow[x] = g; - } else if (!evenRow && evenCol) { - outRow[x] = g; - } else { - outRow[x] = r; - } - } - } -} - -static void ConvertRGBA8888ToRAW8(const u8* src, u8* dst, int width, int height) { - for (int y = 0; y < height; ++y) { - const u8* row = src + y * width * 4; - u8* outRow = dst + y * width; - - for (int x = 0; x < width; ++x) { - const u8* px = row + x * 4; - - u8 b = px[1]; - u8 g = px[2]; - u8 r = px[3]; - - // BGGR Bayer layout - // B G - // G R - bool evenRow = (y & 1) == 0; - bool evenCol = (x & 1) == 0; - - if (evenRow && evenCol) { - outRow[x] = b; - } else if (evenRow && !evenCol) { - outRow[x] = g; - } else if (!evenRow && evenCol) { - outRow[x] = g; - } else { - outRow[x] = r; - } - } - } -} - -static s32 SizeOfFormat(OrbisCameraBaseFormat const f) { - switch (f) { - case ORBIS_CAMERA_FORMAT_YUV422: - return 2; - case ORBIS_CAMERA_FORMAT_RAW16: - return 2; - case ORBIS_CAMERA_FORMAT_RAW8: - return 1; - case ORBIS_CAMERA_FORMAT_NO_USE: - return 0; - default: - UNREACHABLE(); - } -} - s32 PS4_SYSV_ABI sceCameraGetFrameData(s32 handle, OrbisCameraFrameData* frame_data) { - LOG_DEBUG(Lib_Camera, "called"); if (frame_data == nullptr) { return ORBIS_CAMERA_ERROR_PARAM; } + LOG_DEBUG(Lib_Camera, "called, read mode: {:#x}", frame_data->readMode); frame_data->status[0] = -1; frame_data->status[1] = -1; if (handle < 1 || frame_data->sizeThis > 584) { @@ -468,10 +103,36 @@ s32 PS4_SYSV_ABI sceCameraGetFrameData(s32 handle, OrbisCameraFrameData* frame_d } frame = SDL_AcquireCameraFrame(sdl_camera, ×tampNS); - frame_data->status[0] = frame != nullptr ? 0 : -1; - frame_data->status[1] = frame != nullptr ? 0 : -1; + frame_data->status[0] = frame != nullptr ? 1 : -1; + frame_data->status[1] = frame != nullptr ? 1 : -1; if (!frame) { - return ORBIS_CAMERA_ERROR_BUSY; + switch (output_config0.format.formatLevel0) { + case ORBIS_CAMERA_FORMAT_YUV422: + frame_data->pFramePointerList[0][0] = raw16_buffer1; + break; + case ORBIS_CAMERA_FORMAT_RAW16: + frame_data->pFramePointerList[0][0] = raw16_buffer1; + break; + case ORBIS_CAMERA_FORMAT_RAW8: + frame_data->pFramePointerList[0][0] = raw8_buffer1; + break; + default: + UNREACHABLE(); + } + switch (output_config1.format.formatLevel0) { + case ORBIS_CAMERA_FORMAT_YUV422: + frame_data->pFramePointerList[1][0] = raw16_buffer2; + break; + case ORBIS_CAMERA_FORMAT_RAW16: + frame_data->pFramePointerList[1][0] = raw16_buffer2; + break; + case ORBIS_CAMERA_FORMAT_RAW8: + frame_data->pFramePointerList[1][0] = raw8_buffer2; + break; + default: + UNREACHABLE(); + } + return frame_data->pFramePointerList[0][0] == nullptr ? ORBIS_CAMERA_ERROR_BUSY : ORBIS_OK; } switch (output_config0.format.formatLevel0) { @@ -480,11 +141,11 @@ s32 PS4_SYSV_ABI sceCameraGetFrameData(s32 handle, OrbisCameraFrameData* frame_d frame_data->pFramePointerList[0][0] = raw16_buffer1; break; case ORBIS_CAMERA_FORMAT_RAW16: - ConvertRGBA8888ToRAW16((u8*)frame->pixels, raw16_buffer1, c_width, c_height); + ConvertYUY2ToRAW16((u8*)frame->pixels, raw16_buffer1, c_width, c_height); frame_data->pFramePointerList[0][0] = raw16_buffer1; break; case ORBIS_CAMERA_FORMAT_RAW8: - ConvertRGBA8888ToRAW8((u8*)frame->pixels, raw8_buffer1, c_width, c_height); + ConvertYUY2ToRAW8((u8*)frame->pixels, raw8_buffer1, c_width, c_height); frame_data->pFramePointerList[0][0] = raw8_buffer1; break; default: @@ -496,11 +157,11 @@ s32 PS4_SYSV_ABI sceCameraGetFrameData(s32 handle, OrbisCameraFrameData* frame_d frame_data->pFramePointerList[1][0] = raw16_buffer2; break; case ORBIS_CAMERA_FORMAT_RAW16: - ConvertRGBA8888ToRAW16((u8*)frame->pixels, raw16_buffer2, c_width, c_height); + ConvertYUY2ToRAW16((u8*)frame->pixels, raw16_buffer2, c_width, c_height); frame_data->pFramePointerList[1][0] = raw16_buffer2; break; case ORBIS_CAMERA_FORMAT_RAW8: - ConvertRGBA8888ToRAW8((u8*)frame->pixels, raw8_buffer2, c_width, c_height); + ConvertYUY2ToRAW8((u8*)frame->pixels, raw8_buffer2, c_width, c_height); frame_data->pFramePointerList[1][0] = raw8_buffer2; break; default: @@ -509,9 +170,9 @@ s32 PS4_SYSV_ABI sceCameraGetFrameData(s32 handle, OrbisCameraFrameData* frame_d frame_data->meta.format[0][0] = output_config0.format.formatLevel0; frame_data->meta.format[1][0] = output_config1.format.formatLevel0; frame_data->frameSize[0][0] = - c_width * c_height * SizeOfFormat(output_config0.format.formatLevel0); + c_width * c_height * SizeOfBaseFormat(output_config0.format.formatLevel0); frame_data->frameSize[1][0] = - c_width * c_height * SizeOfFormat(output_config1.format.formatLevel0); + c_width * c_height * SizeOfBaseFormat(output_config1.format.formatLevel0); // on older firmwares, this wasn't present, and the original library also checks struct size // instead of the SDK version, and without this check, we'd smash the stack in those games @@ -523,162 +184,6 @@ s32 PS4_SYSV_ABI sceCameraGetFrameData(s32 handle, OrbisCameraFrameData* frame_d return ORBIS_OK; } -s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* gamma, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || gamma == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - // Return default parameters - memset(gamma, 0, sizeof(OrbisCameraGamma)); - gamma->value = 4; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* hue, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || hue == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *hue = 1; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* enable, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *enable = 0; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount(u32* count) { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - if (count == nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - - *count = 0; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetProductInfo(void* product_info) { - LOG_DEBUG(Lib_Camera, "(STUBBED) called"); - if (product_info == nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_INIT; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraGetRegister() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetRegistryInfo(void* registry_info) { - LOG_DEBUG(Lib_Camera, "(STUBBED) called"); - if (registry_info == nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_INIT; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* saturation, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || saturation == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *saturation = 64; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* sharpness, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || sharpness == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - *sharpness = 1; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel, - OrbisCameraWhiteBalance* white_balance, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || white_balance == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - // Set default parameters - white_balance->whiteBalanceControl = 0; - white_balance->gainRed = 768; - white_balance->gainBlue = 768; - white_balance->gainGreen = 512; - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_INIT; - } - return ORBIS_OK; -} - s32 PS4_SYSV_ABI sceCameraIsAttached(s32 index) { static bool first_log = true; if (first_log) { @@ -708,7 +213,7 @@ s32 PS4_SYSV_ABI sceCameraIsValidFrameData(s32 handle, OrbisCameraFrameData* fra return ORBIS_CAMERA_ERROR_NOT_OPEN; } - return frame_data->status[0] == 0 && frame_data->status[1] == 0; + return frame_data->status[0] == 1 && frame_data->status[1] == 1; } s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId user_id, s32 type, @@ -737,10 +242,14 @@ s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId us u8* remaining_camera_buf = (u8*)camera_garlic_pool; - raw8_buffer1 = remaining_camera_buf += raw8_buffer_size; - raw8_buffer2 = remaining_camera_buf += raw8_buffer_size; - raw16_buffer1 = (u16*)(remaining_camera_buf += raw16_buffer_size); - raw16_buffer2 = (u16*)(remaining_camera_buf += raw16_buffer_size); + raw8_buffer1 = remaining_camera_buf; + remaining_camera_buf += raw8_buffer_size; + raw8_buffer2 = remaining_camera_buf; + remaining_camera_buf += raw8_buffer_size; + raw16_buffer1 = (u16*)remaining_camera_buf; + remaining_camera_buf += raw16_buffer_size; + raw16_buffer2 = (u16*)remaining_camera_buf; + remaining_camera_buf += raw16_buffer_size; ASSERT(remaining_camera_buf <= (u8*)camera_garlic_pool + camera_system_mem_size); @@ -758,353 +267,16 @@ s32 PS4_SYSV_ABI sceCameraOpenByModuleId() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - s32 PS4_SYSV_ABI sceCameraSetAppModuleFocus() { LOG_ERROR(Lib_Camera, "(STUBBED) called"); return ORBIS_OK; } -s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* attribute) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || attribute == nullptr || attribute->sizeThis != sizeof(OrbisCameraAttribute) || - attribute->channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - attribute->channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetAttributeInternal() { - // Stubbed on real hardware - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable, - OrbisCameraAutoExposureGainTarget* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (option != nullptr) { - if (g_firmware_version < Common::ElfInfo::FW_300 || - option->sizeThis != sizeof(OrbisCameraAutoExposureGainTarget)) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (option->target % 2 == 1 || option->target < ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF || - option->target > ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_2_0) { - return ORBIS_CAMERA_ERROR_PARAM; - } - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetCalibData() { +s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus() { LOG_ERROR(Lib_Camera, "(STUBBED) called"); return ORBIS_OK; } -s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* config) { - LOG_INFO(Lib_Camera, "called"); - if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { - LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_PARAM"); - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_NOT_OPEN"); - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - if (EmulatorSettings.GetCameraId() == -1) { - LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_NOT_CONNECTED"); - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; - } - - switch (config->configType) { - case ORBIS_CAMERA_CONFIG_TYPE1: - case ORBIS_CAMERA_CONFIG_TYPE2: - case ORBIS_CAMERA_CONFIG_TYPE3: - case ORBIS_CAMERA_CONFIG_TYPE4: - output_config0 = camera_config_types[config->configType - 1][0]; - output_config1 = camera_config_types[config->configType - 1][1]; - break; - case ORBIS_CAMERA_CONFIG_TYPE5: - int sdk_ver; - Libraries::Kernel::sceKernelGetCompiledSdkVersion(&sdk_ver); - if (sdk_ver < Common::ElfInfo::FW_450) { - LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_UNKNOWN_CONFIG"); - return ORBIS_CAMERA_ERROR_UNKNOWN_CONFIG; - } - output_config0 = camera_config_types[config->configType - 1][0]; - output_config1 = camera_config_types[config->configType - 1][1]; - break; - case ORBIS_CAMERA_CONFIG_EXTENTION: - output_config0 = config->configExtention[0]; - output_config1 = config->configExtention[1]; - break; - default: - LOG_ERROR(Lib_Camera, "Invalid config type {}", std::to_underlying(config->configType)); - return ORBIS_CAMERA_ERROR_PARAM; - } - - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetConfigInternal(s32 handle, OrbisCameraConfig* config) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetDebugStop(u32 debug_stop_enable) { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - if (debug_stop_enable > 1) { - return ORBIS_CAMERA_ERROR_PARAM; - } - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel, - u32 enable, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 1 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal(s32 handle, - OrbisCameraChannel channel, - u32 enable, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 2 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel, - OrbisCameraExposureGain* exposure_gain, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || exposure_gain != nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetForceActivate() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* gamma, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || gamma != nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 1 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal(s32 handle, OrbisCameraChannel channel, - u32 enable, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 2 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetProcessFocus() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetRegister() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness, - void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (g_firmware_version >= Common::ElfInfo::FW_350 && sharpness > 10) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - -s32 PS4_SYSV_ABI sceCameraSetTrackerMode() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetUacModeInternal() { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* video_sync) { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - if (handle < 1 || video_sync == nullptr || - video_sync->sizeThis != sizeof(OrbisCameraVideoSyncParameter) || - video_sync->videoSyncMode > 1 || video_sync->pModeOption != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal(s32 handle, - OrbisCameraVideoSyncParameter* video_sync) { - LOG_ERROR(Lib_Camera, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel, - OrbisCameraWhiteBalance* white_balance, void* option) { - LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || - channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || white_balance == nullptr || - option != nullptr) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_CAMERA_ERROR_NOT_CONNECTED; -} - s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* param) { LOG_INFO(Lib_Camera, "called"); if (handle < 1 || param == nullptr || param->sizeThis != sizeof(OrbisCameraStartParameter)) { @@ -1137,22 +309,7 @@ s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* param) { return ORBIS_CAMERA_ERROR_NOT_CONNECTED; } SDL_CameraSpec cam_spec{}; - switch (output_config0.format.formatLevel0) { - case ORBIS_CAMERA_FORMAT_YUV422: - cam_spec.format = SDL_PIXELFORMAT_YUY2; - break; - case ORBIS_CAMERA_FORMAT_RAW8: - cam_spec.format = SDL_PIXELFORMAT_RGBA8888; // to be swizzled - break; - case ORBIS_CAMERA_FORMAT_RAW16: - cam_spec.format = SDL_PIXELFORMAT_RGBA8888; // to be swizzled - break; - - default: - LOG_ERROR(Lib_Camera, "Invalid format {}", - std::to_underlying(output_config0.format.formatLevel0)); - break; - } + cam_spec.format = SDL_PIXELFORMAT_YUY2; // to be swizzled cam_spec.height = c_height; cam_spec.width = c_width; cam_spec.framerate_numerator = 60; @@ -1208,7 +365,7 @@ s32 PS4_SYSV_ABI sceCameraStartByHandle(s32 handle, OrbisCameraStartParameter* p } s32 PS4_SYSV_ABI sceCameraStop(s32 handle) { - LOG_DEBUG(Lib_Camera, "called"); + LOG_INFO(Lib_Camera, "called, handle: {}", handle); if (handle < 1) { return ORBIS_CAMERA_ERROR_PARAM; } @@ -1221,14 +378,7 @@ s32 PS4_SYSV_ABI sceCameraStop(s32 handle) { s32 PS4_SYSV_ABI sceCameraStopByHandle(s32 handle) { LOG_DEBUG(Lib_Camera, "called"); - if (handle < 1) { - return ORBIS_CAMERA_ERROR_PARAM; - } - if (!g_library_opened) { - return ORBIS_CAMERA_ERROR_NOT_OPEN; - } - - return ORBIS_OK; + return sceCameraStop(handle); } void RegisterLib(Core::Loader::SymbolsResolver* sym) { diff --git a/src/core/libraries/camera/camera.h b/src/core/libraries/camera/camera.h index f7fdd1184..cac9e4c4b 100644 --- a/src/core/libraries/camera/camera.h +++ b/src/core/libraries/camera/camera.h @@ -1,10 +1,12 @@ -// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include +#include "camera_config_types.h" +#include "camera_error.h" #include "common/types.h" +#include "core/libraries/system/userservice.h" namespace Core::Loader { class SymbolsResolver; @@ -12,6 +14,9 @@ class SymbolsResolver; namespace Libraries::Camera { +extern bool g_library_opened; +extern s32 g_firmware_version; + constexpr s32 ORBIS_CAMERA_MAX_DEVICE_NUM = 2; constexpr s32 ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM = 4; constexpr s32 ORBIS_CAMERA_CALIBRATION_DATA_MESH_NUMBER_OF_TOTAL_VERTICIES = 1276; @@ -29,195 +34,18 @@ struct OrbisCameraOpenParameter { u32 reserved3; }; -enum OrbisCameraConfigType { - ORBIS_CAMERA_CONFIG_TYPE1 = 0x01, - ORBIS_CAMERA_CONFIG_TYPE2 = 0x02, - ORBIS_CAMERA_CONFIG_TYPE3 = 0x03, - ORBIS_CAMERA_CONFIG_TYPE4 = 0x04, - ORBIS_CAMERA_CONFIG_TYPE5 = 0x05, - ORBIS_CAMERA_CONFIG_EXTENTION = 0x10, -}; - -enum OrbisCameraResolution { - ORBIS_CAMERA_RESOLUTION_1280X800 = 0x0, - ORBIS_CAMERA_RESOLUTION_640X400 = 0x1, - ORBIS_CAMERA_RESOLUTION_320X200 = 0x2, - ORBIS_CAMERA_RESOLUTION_160X100 = 0x3, - ORBIS_CAMERA_RESOLUTION_320X192 = 0x4, - ORBIS_CAMERA_RESOLUTION_SPECIFIED_WIDTH_HEIGHT, - ORBIS_CAMERA_RESOLUTION_UNKNOWN = 0xFF, -}; - -enum OrbisCameraFramerate { - ORBIS_CAMERA_FRAMERATE_UNKNOWN = 0, - ORBIS_CAMERA_FRAMERATE_7_5 = 7, - ORBIS_CAMERA_FRAMERATE_15 = 15, - ORBIS_CAMERA_FRAMERATE_30 = 30, - ORBIS_CAMERA_FRAMERATE_60 = 60, - ORBIS_CAMERA_FRAMERATE_120 = 120, - ORBIS_CAMERA_FRAMERATE_240 = 240, -}; - -enum OrbisCameraBaseFormat { - ORBIS_CAMERA_FORMAT_YUV422 = 0x0, - ORBIS_CAMERA_FORMAT_RAW16, - ORBIS_CAMERA_FORMAT_RAW8, - ORBIS_CAMERA_FORMAT_NO_USE = 0x10, - ORBIS_CAMERA_FORMAT_UNKNOWN = 0xFF, -}; - -enum OrbisCameraScaleFormat { - ORBIS_CAMERA_SCALE_FORMAT_YUV422 = 0x0, - ORBIS_CAMERA_SCALE_FORMAT_Y16 = 0x3, - ORBIS_CAMERA_SCALE_FORMAT_Y8, - ORBIS_CAMERA_SCALE_FORMAT_NO_USE = 0x10, - ORBIS_CAMERA_SCALE_FORMAT_UNKNOWN = 0xFF, -}; - enum OrbisCameraCalibrationDataFunctionType { ORBIS_CAMERA_CALIBRATION_DATA_FUNCTION_TYPE_IMAGE_RECTIFICATION = 0, ORBIS_CAMERA_CALIBRATION_DATA_FUNCTION_TYPE_IMAGE_INVERSE_RECTIFICATION = 1, }; -struct OrbisCameraFormat { - OrbisCameraBaseFormat formatLevel0; - OrbisCameraScaleFormat formatLevel1; - OrbisCameraScaleFormat formatLevel2; - OrbisCameraScaleFormat formatLevel3; -}; - -struct OrbisCameraConfigExtention { - OrbisCameraFormat format; - OrbisCameraResolution resolution; - OrbisCameraFramerate framerate; - u32 width; - u32 height; - u32 reserved1; - void* pBaseOption; -}; - struct OrbisCameraConfig { u32 sizeThis; OrbisCameraConfigType configType; OrbisCameraConfigExtention configExtention[ORBIS_CAMERA_MAX_DEVICE_NUM]; }; -constexpr OrbisCameraConfigExtention camera_config_types[5][ORBIS_CAMERA_MAX_DEVICE_NUM]{ - { - // type 1 - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - }, - { - // type 2 - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - }, - { - // type 3 - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - }, - { - // type 4 - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - }, - { - // type 5 - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - { - .format = - { - .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, - .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, - }, - .framerate = ORBIS_CAMERA_FRAMERATE_60, - }, - }}; +extern OrbisCameraConfigExtention output_config0, output_config1; enum OrbisCameraAecAgcTarget { ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF = 0x00, diff --git a/src/core/libraries/camera/camera_audio.cpp b/src/core/libraries/camera/camera_audio.cpp new file mode 100644 index 000000000..8f673219d --- /dev/null +++ b/src/core/libraries/camera/camera_audio.cpp @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/libraries/camera/camera.h" + +namespace Libraries::Camera { + +s32 PS4_SYSV_ABI sceCameraAudioClose() { + LOG_DEBUG(Lib_Camera, "called"); + // Returns ORBIS_OK while internally failing + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraAudioGetData(void* data) { + LOG_DEBUG(Lib_Camera, "called"); + if (data == nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + // Returns ORBIS_OK while internally failing + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraAudioGetData2(void* data) { + LOG_DEBUG(Lib_Camera, "called"); + if (data == nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + // Returns ORBIS_OK while internally failing + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraAudioOpen() { + LOG_DEBUG(Lib_Camera, "called"); + // Returns error fatal as a side effect of not having a camera attached. + return ORBIS_CAMERA_ERROR_FATAL; +} + +s32 PS4_SYSV_ABI sceCameraAudioReset() { + LOG_DEBUG(Lib_Camera, "called"); + // Returns ORBIS_OK while internally failing + return ORBIS_OK; +} + +} // namespace Libraries::Camera \ No newline at end of file diff --git a/src/core/libraries/camera/camera_calibration.cpp b/src/core/libraries/camera/camera_calibration.cpp new file mode 100644 index 000000000..a2194e205 --- /dev/null +++ b/src/core/libraries/camera/camera_calibration.cpp @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/emulator_settings.h" +#include "core/libraries/camera/camera.h" + +namespace Libraries::Camera { + +s32 PS4_SYSV_ABI sceCameraGetCalibData(s32 id, void* calib_data, void* maybe_reserved) { + LOG_WARNING(Lib_Camera, "(DUMMY) called, id: {}", id); + if (calib_data == nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (id != 1 && id != 2) { + return ORBIS_OK; + } + static constexpr u64 dumped_calib_data1[32]{ + 0x000000000b0b0200, 0x00000000bc128639, 0x000000003de79766, 0x00000000be6e2869, + 0x3ca0ce1f3e30521c, 0x4452d55e3d0160b6, 0x3cf7fdaa4453abf1, 0x000000003ce3f40f, + 0x000000003cdbcaa6, 0x000000003d635f4e, 0x00000000be299439, 0xbb98ddc23e1159b4, + 0x44523b6c3c87d83c, 0x3c8d1c46445308a2, 0xbbb83fe03c9bcc40, 0xbab0ed65b8fe93b0, + 0xba677004bb598091, 0x3c0eb61e3b49d173, 0xba1bac9f3c67af0b, 0x00000000b9d0e64d, + 0x0000000000000000, 0x0000000000000000, 0xb97653e400000000, 0x00000000ba95460e, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xbab5330000000000, 0x000001013b07a47f, + }; + static constexpr u64 dumped_calib_data2[32]{ + 0x002d000000ff0009, 0x002d0ff70ffd0f14, 0x002d0efe00010008, 0x002f0ffe0f020008, + 0x002f000800060105, 0x002e00fc0001000a, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + }; + std::memcpy(calib_data, id == 1 ? dumped_calib_data1 : dumped_calib_data2, + sizeof(dumped_calib_data1)); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraGetCalibrationData(const OrbisCameraGetCalibrationDataParameter* param, + OrbisCameraCalibrationData* calibration_data) { + LOG_DEBUG(Lib_Camera, "called"); + if (param == nullptr || calibration_data == nullptr || + param->size != sizeof(OrbisCameraGetCalibrationDataParameter) || param->format_type != 0 || + param->function_type < + OrbisCameraCalibrationDataFunctionType:: + ORBIS_CAMERA_CALIBRATION_DATA_FUNCTION_TYPE_IMAGE_RECTIFICATION || + param->function_type > + OrbisCameraCalibrationDataFunctionType:: + ORBIS_CAMERA_CALIBRATION_DATA_FUNCTION_TYPE_IMAGE_INVERSE_RECTIFICATION) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (EmulatorSettings.GetCameraId() == -1) { + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; + } + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_INIT; + } + return ORBIS_OK; +} + +} // namespace Libraries::Camera \ No newline at end of file diff --git a/src/core/libraries/camera/camera_config.cpp b/src/core/libraries/camera/camera_config.cpp new file mode 100644 index 000000000..7ea1544eb --- /dev/null +++ b/src/core/libraries/camera/camera_config.cpp @@ -0,0 +1,648 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/elf_info.h" +#include "common/logging/log.h" +#include "core/emulator_settings.h" +#include "core/libraries/camera/camera.h" + +namespace Libraries::Camera { + +s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* attribute) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || attribute == nullptr || attribute->sizeThis != sizeof(OrbisCameraAttribute) || + attribute->channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + attribute->channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + auto channel = attribute->channel; + + // Set default attributes + memset(attribute, 0, sizeof(OrbisCameraAttribute)); + attribute->sizeThis = sizeof(OrbisCameraAttribute); + attribute->channel = channel; + attribute->exposureGain.exposure = 83; + attribute->exposureGain.gain = 100; + attribute->whiteBalance.gainRed = 768; + attribute->whiteBalance.gainBlue = 768; + attribute->whiteBalance.gainGreen = 512; + attribute->gamma.value = 4; + attribute->saturation = 64; + attribute->contrast = 32; + attribute->sharpness = 1; + attribute->hue = 1; + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* enable, + OrbisCameraAutoExposureGainTarget* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (option != nullptr && (g_firmware_version < Common::ElfInfo::FW_300 || + option->sizeThis != sizeof(OrbisCameraAutoExposureGainTarget))) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *enable = 0; + if (option != nullptr) { + option->sizeThis = 0; + option->target = OrbisCameraAecAgcTarget::ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF; + } + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* enable, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *enable = 0; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* config) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + // Set default config + config->configType = ORBIS_CAMERA_CONFIG_TYPE1; + + OrbisCameraConfigExtention default_extension; + default_extension.format.formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422; + default_extension.format.formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8; + default_extension.format.formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8; + default_extension.format.formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8; + default_extension.resolution = ORBIS_CAMERA_RESOLUTION_1280X800; + default_extension.framerate = ORBIS_CAMERA_FRAMERATE_60; + default_extension.width = 0; + default_extension.height = 0; + default_extension.reserved1 = 0; + + memcpy(&config->configExtention[0], &default_extension, sizeof(OrbisCameraConfigExtention)); + memcpy(&config->configExtention[1], &default_extension, sizeof(OrbisCameraConfigExtention)); + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* contrast, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || contrast == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *contrast = 32; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel, + u32* enable, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *enable = 0; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel, + OrbisCameraExposureGain* exposure_gain, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || exposure_gain == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + // Return default parameters + exposure_gain->exposureControl = 0; + exposure_gain->exposure = 20; + exposure_gain->gain = 100; + exposure_gain->mode = 0; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* gamma, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || gamma == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + // Return default parameters + memset(gamma, 0, sizeof(OrbisCameraGamma)); + gamma->value = 4; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* hue, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || hue == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *hue = 1; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* enable, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *enable = 0; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount(u32* count) { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + if (count == nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + + *count = 0; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetProductInfo(void* product_info) { + LOG_DEBUG(Lib_Camera, "(STUBBED) called"); + if (product_info == nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_INIT; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraGetRegister() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetRegistryInfo(void* registry_info) { + LOG_DEBUG(Lib_Camera, "(STUBBED) called"); + if (registry_info == nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_INIT; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* saturation, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || saturation == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *saturation = 64; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* sharpness, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || sharpness == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + *sharpness = 1; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel, + OrbisCameraWhiteBalance* white_balance, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel >= OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || white_balance == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + // Set default parameters + white_balance->whiteBalanceControl = 0; + white_balance->gainRed = 768; + white_balance->gainBlue = 768; + white_balance->gainGreen = 512; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* attribute) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || attribute == nullptr || attribute->sizeThis != sizeof(OrbisCameraAttribute) || + attribute->channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + attribute->channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetAttributeInternal() { + // Stubbed on real hardware + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable, + OrbisCameraAutoExposureGainTarget* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (option != nullptr) { + if (g_firmware_version < Common::ElfInfo::FW_300 || + option->sizeThis != sizeof(OrbisCameraAutoExposureGainTarget)) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (option->target % 2 == 1 || option->target < ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF || + option->target > ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_2_0) { + return ORBIS_CAMERA_ERROR_PARAM; + } + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetCalibData() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* config) { + LOG_INFO(Lib_Camera, "called"); + if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { + LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_PARAM"); + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_NOT_OPEN"); + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + if (EmulatorSettings.GetCameraId() == -1) { + LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_NOT_CONNECTED"); + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; + } + + switch (config->configType) { + case ORBIS_CAMERA_CONFIG_TYPE1: + case ORBIS_CAMERA_CONFIG_TYPE2: + case ORBIS_CAMERA_CONFIG_TYPE3: + case ORBIS_CAMERA_CONFIG_TYPE4: + output_config0 = camera_config_types[config->configType - 1][0]; + output_config1 = camera_config_types[config->configType - 1][1]; + break; + case ORBIS_CAMERA_CONFIG_TYPE5: + if (g_firmware_version < Common::ElfInfo::FW_450) { + LOG_ERROR(Lib_Camera, "ORBIS_CAMERA_ERROR_UNKNOWN_CONFIG"); + return ORBIS_CAMERA_ERROR_UNKNOWN_CONFIG; + } + output_config0 = camera_config_types[config->configType - 1][0]; + output_config1 = camera_config_types[config->configType - 1][1]; + break; + case ORBIS_CAMERA_CONFIG_EXTENTION: + output_config0 = config->configExtention[0]; + output_config1 = config->configExtention[1]; + break; + default: + LOG_ERROR(Lib_Camera, "Invalid config type {}", std::to_underlying(config->configType)); + return ORBIS_CAMERA_ERROR_PARAM; + } + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetConfigInternal(s32 handle, OrbisCameraConfig* config) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetDebugStop(u32 debug_stop_enable) { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + if (debug_stop_enable > 1) { + return ORBIS_CAMERA_ERROR_PARAM; + } + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel, + u32 enable, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 1 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal(s32 handle, + OrbisCameraChannel channel, + u32 enable, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 2 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel, + OrbisCameraExposureGain* exposure_gain, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || exposure_gain != nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + if (EmulatorSettings.GetCameraId() == -1) { + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; + } + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetForceActivate() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* gamma, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || gamma != nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 1 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal(s32 handle, OrbisCameraChannel channel, + u32 enable, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || enable > 2 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetProcessFocus() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetRegister() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness, + void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (g_firmware_version >= Common::ElfInfo::FW_350 && sharpness > 10) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +s32 PS4_SYSV_ABI sceCameraSetTrackerMode() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetUacModeInternal() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* video_sync) { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + if (handle < 1 || video_sync == nullptr || + video_sync->sizeThis != sizeof(OrbisCameraVideoSyncParameter) || + video_sync->videoSyncMode > 1 || video_sync->pModeOption != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal(s32 handle, + OrbisCameraVideoSyncParameter* video_sync) { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel, + OrbisCameraWhiteBalance* white_balance, void* option) { + LOG_DEBUG(Lib_Camera, "called"); + if (handle < 1 || channel > OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_BOTH || + channel < OrbisCameraChannel::ORBIS_CAMERA_CHANNEL_0 || white_balance == nullptr || + option != nullptr) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +} // namespace Libraries::Camera \ No newline at end of file diff --git a/src/core/libraries/camera/camera_config_types.h b/src/core/libraries/camera/camera_config_types.h new file mode 100644 index 000000000..6ee935c15 --- /dev/null +++ b/src/core/libraries/camera/camera_config_types.h @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +constexpr s32 ORBIS_CAMERA_MAX_DEVICE_NUM = 2; + +enum OrbisCameraResolution { + ORBIS_CAMERA_RESOLUTION_1280X800 = 0x0, + ORBIS_CAMERA_RESOLUTION_640X400 = 0x1, + ORBIS_CAMERA_RESOLUTION_320X200 = 0x2, + ORBIS_CAMERA_RESOLUTION_160X100 = 0x3, + ORBIS_CAMERA_RESOLUTION_320X192 = 0x4, + ORBIS_CAMERA_RESOLUTION_SPECIFIED_WIDTH_HEIGHT, + ORBIS_CAMERA_RESOLUTION_UNKNOWN = 0xFF, +}; + +enum OrbisCameraFramerate { + ORBIS_CAMERA_FRAMERATE_UNKNOWN = 0, + ORBIS_CAMERA_FRAMERATE_7_5 = 7, + ORBIS_CAMERA_FRAMERATE_15 = 15, + ORBIS_CAMERA_FRAMERATE_30 = 30, + ORBIS_CAMERA_FRAMERATE_60 = 60, + ORBIS_CAMERA_FRAMERATE_120 = 120, + ORBIS_CAMERA_FRAMERATE_240 = 240, +}; + +enum OrbisCameraBaseFormat { + ORBIS_CAMERA_FORMAT_YUV422 = 0x0, + ORBIS_CAMERA_FORMAT_RAW16, + ORBIS_CAMERA_FORMAT_RAW8, + ORBIS_CAMERA_FORMAT_NO_USE = 0x10, + ORBIS_CAMERA_FORMAT_UNKNOWN = 0xFF, +}; + +enum OrbisCameraScaleFormat { + ORBIS_CAMERA_SCALE_FORMAT_YUV422 = 0x0, + ORBIS_CAMERA_SCALE_FORMAT_Y16 = 0x3, + ORBIS_CAMERA_SCALE_FORMAT_Y8, + ORBIS_CAMERA_SCALE_FORMAT_NO_USE = 0x10, + ORBIS_CAMERA_SCALE_FORMAT_UNKNOWN = 0xFF, +}; + +struct OrbisCameraFormat { + OrbisCameraBaseFormat formatLevel0; + OrbisCameraScaleFormat formatLevel1; + OrbisCameraScaleFormat formatLevel2; + OrbisCameraScaleFormat formatLevel3; +}; + +struct OrbisCameraConfigExtention { + OrbisCameraFormat format; + OrbisCameraResolution resolution; + OrbisCameraFramerate framerate; + u32 width; + u32 height; + u32 reserved1; + void* pBaseOption; +}; + +constexpr OrbisCameraConfigExtention camera_config_types[5][ORBIS_CAMERA_MAX_DEVICE_NUM]{ + { + // type 1 + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + }, + { + // type 2 + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + }, + { + // type 3 + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_Y8, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + }, + { + // type 4 + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + }, + { + // type 5 + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_YUV422, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + { + .format = + { + .formatLevel0 = ORBIS_CAMERA_FORMAT_RAW16, + .formatLevel1 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel2 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + .formatLevel3 = ORBIS_CAMERA_SCALE_FORMAT_YUV422, + }, + .framerate = ORBIS_CAMERA_FRAMERATE_60, + }, + }}; + +enum OrbisCameraConfigType { + ORBIS_CAMERA_CONFIG_TYPE1 = 0x01, + ORBIS_CAMERA_CONFIG_TYPE2 = 0x02, + ORBIS_CAMERA_CONFIG_TYPE3 = 0x03, + ORBIS_CAMERA_CONFIG_TYPE4 = 0x04, + ORBIS_CAMERA_CONFIG_TYPE5 = 0x05, + ORBIS_CAMERA_CONFIG_EXTENTION = 0x10, +}; \ No newline at end of file diff --git a/src/core/libraries/camera/camera_device.cpp b/src/core/libraries/camera/camera_device.cpp new file mode 100644 index 000000000..62d1038fb --- /dev/null +++ b/src/core/libraries/camera/camera_device.cpp @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/libraries/camera/camera.h" + +namespace Libraries::Camera { + +s32 PS4_SYSV_ABI sceCameraDeviceOpen() { + // Stubbed on real hardware + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetDeviceConfig(s32 handle, OrbisCameraConfig* config) { + if (handle < 1 || config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + memset(config, 0, sizeof(OrbisCameraConfig)); + config->sizeThis = sizeof(OrbisCameraConfig); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle(OrbisCameraConfig* config) { + if (config == nullptr || config->sizeThis != sizeof(OrbisCameraConfig)) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_OPEN; + } + + memset(config, 0, sizeof(OrbisCameraConfig)); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetDeviceID() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen() { + LOG_ERROR(Lib_Camera, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* device_info) { + LOG_DEBUG(Lib_Camera, "called"); + if (reserved != 0 || device_info == nullptr || + device_info->sizeThis != sizeof(OrbisCameraDeviceInfo) || device_info->infoRevision != 1) { + return ORBIS_CAMERA_ERROR_PARAM; + } + if (!g_library_opened) { + return ORBIS_CAMERA_ERROR_NOT_INIT; + } + + return ORBIS_CAMERA_ERROR_NOT_CONNECTED; +} + +} // namespace Libraries::Camera diff --git a/src/core/libraries/camera/camera_error.h b/src/core/libraries/camera/camera_error.h index acb04dd02..d45ffbc10 100644 --- a/src/core/libraries/camera/camera_error.h +++ b/src/core/libraries/camera/camera_error.h @@ -1,6 +1,8 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/libraries/error_codes.h" + #pragma once constexpr int ORBIS_CAMERA_ERROR_PARAM = 0x802E0000; diff --git a/src/core/libraries/camera/camera_helpers.cpp b/src/core/libraries/camera/camera_helpers.cpp new file mode 100644 index 000000000..5dc8f9426 --- /dev/null +++ b/src/core/libraries/camera/camera_helpers.cpp @@ -0,0 +1,204 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "camera_helpers.h" + +namespace Libraries::Camera { + +static inline u8 ClampU8(int v) { + return static_cast(v < 0 ? 0 : (v > 255 ? 255 : v)); +} + +static inline u16 ClampU16(int v) { + return static_cast(v < 0 ? 0 : (v > 65535 ? 65535 : v)); +} + +static inline u8 RgbaToLuma(const u8* px) { + const u8 b = px[0]; + const u8 g = px[1]; + const u8 r = px[2]; + return ClampU8((77 * r + 150 * g + 29 * b) >> 8); +} + +void ConvertRGBA8888ToRAW16(const u8* src, u16* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 4; + u16* outRow = dst + static_cast(y) * width; + const bool evenRow = (y & 1) == 0; + for (int x = 0; x < width; ++x) { + const u8* px = row + x * 4; + const u16 b = u16(px[1]) << 4; + const u16 g = u16(px[2]) << 4; + const u16 r = u16(px[3]) << 4; + const bool evenCol = (x & 1) == 0; + if (evenRow && evenCol) + outRow[x] = b; + else if (evenRow && !evenCol) + outRow[x] = g; + else if (!evenRow && evenCol) + outRow[x] = g; + else + outRow[x] = r; + } + } +} + +void ConvertRGBA8888ToRAW8(const u8* src, u8* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 4; + u8* outRow = dst + static_cast(y) * width; + const bool evenRow = (y & 1) == 0; + for (int x = 0; x < width; ++x) { + const u8* px = row + x * 4; + const u8 b = px[1]; + const u8 g = px[2]; + const u8 r = px[3]; + const bool evenCol = (x & 1) == 0; + if (evenRow && evenCol) + outRow[x] = b; + else if (evenRow && !evenCol) + outRow[x] = g; + else if (!evenRow && evenCol) + outRow[x] = g; + else + outRow[x] = r; + } + } +} + +void ConvertRGBA8888ToY8(const u8* src, u8* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 4; + u8* outRow = dst + static_cast(y) * width; + for (int x = 0; x < width; ++x) { + outRow[x] = RgbaToLuma(row + x * 4); + } + } +} + +void ConvertRGBA8888ToY16(const u8* src, u16* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 4; + u16* outRow = dst + static_cast(y) * width; + for (int x = 0; x < width; ++x) { + outRow[x] = static_cast(RgbaToLuma(row + x * 4)) << 2; + } + } +} + +void ConvertYUY2ToY8(const u8* src, u8* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 2; + u8* outRow = dst + static_cast(y) * width; + for (int x = 0; x < width; x += 2) { + outRow[x] = row[x * 2 + 0]; // Y0 + outRow[x + 1] = row[x * 2 + 2]; // Y1 + } + } +} + +void ConvertYUY2ToY16(const u8* src, u16* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 2; + u16* outRow = dst + static_cast(y) * width; + for (int x = 0; x < width; x += 2) { + outRow[x] = static_cast(row[x * 2 + 0]) << 2; + outRow[x + 1] = static_cast(row[x * 2 + 2]) << 2; + } + } +} + +static inline void YuvToRgb(u8 y, u8 u, u8 v, u8& r, u8& g, u8& b) { + const int c = static_cast(y) - 16; + const int d = static_cast(u) - 128; + const int e = static_cast(v) - 128; + + r = ClampU8((298 * c + 409 * e + 128) >> 8); + g = ClampU8((298 * c - 100 * d - 208 * e + 128) >> 8); + b = ClampU8((298 * c + 516 * d + 128) >> 8); +} + +void ConvertYUY2ToRAW8(const u8* src, u8* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 2; + u8* outRow = dst + static_cast(y) * width; + const bool evenRow = (y & 1) == 0; + + for (int x = 0; x < width; x += 2) { + const u8 y0 = row[x * 2 + 0]; + const u8 u = row[x * 2 + 1]; + const u8 y1 = row[x * 2 + 2]; + const u8 v = row[x * 2 + 3]; + + u8 r0, g0, b0; + u8 r1, g1, b1; + YuvToRgb(y0, u, v, r0, g0, b0); + YuvToRgb(y1, u, v, r1, g1, b1); + + if (evenRow) { + outRow[x] = b0; + outRow[x + 1] = g1; + } else { + outRow[x] = g0; + outRow[x + 1] = r1; + } + } + } +} + +void ConvertYUY2ToRAW16(const u8* src, u16* dst, int width, int height) { + for (int y = 0; y < height; ++y) { + const u8* row = src + static_cast(y) * width * 2; + u16* outRow = dst + static_cast(y) * width; + const bool evenRow = (y & 1) == 0; + + for (int x = 0; x < width; x += 2) { + const u8 y0 = row[x * 2 + 0]; + const u8 u = row[x * 2 + 1]; + const u8 y1 = row[x * 2 + 2]; + const u8 v = row[x * 2 + 3]; + + u8 r0, g0, b0; + u8 r1, g1, b1; + YuvToRgb(y0, u, v, r0, g0, b0); + YuvToRgb(y1, u, v, r1, g1, b1); + + if (evenRow) { + outRow[x] = static_cast(b0) << 4; + outRow[x + 1] = static_cast(g1) << 4; + } else { + outRow[x] = static_cast(g0) << 4; + outRow[x + 1] = static_cast(r1) << 4; + } + } + } +} + +s32 SizeOfBaseFormat(OrbisCameraBaseFormat f) { + switch (f) { + case ORBIS_CAMERA_FORMAT_YUV422: + return 2; + case ORBIS_CAMERA_FORMAT_RAW16: + return 2; + case ORBIS_CAMERA_FORMAT_RAW8: + return 1; + case ORBIS_CAMERA_FORMAT_NO_USE: + default: + return 0; + } +} + +s32 SizeOfScaleFormat(OrbisCameraScaleFormat f) { + switch (f) { + case ORBIS_CAMERA_SCALE_FORMAT_YUV422: + return 2; + case ORBIS_CAMERA_SCALE_FORMAT_Y16: + return 2; + case ORBIS_CAMERA_SCALE_FORMAT_Y8: + return 1; + case ORBIS_CAMERA_SCALE_FORMAT_NO_USE: + default: + return 0; + } +} +} // namespace Libraries::Camera \ No newline at end of file diff --git a/src/core/libraries/camera/camera_helpers.h b/src/core/libraries/camera/camera_helpers.h new file mode 100644 index 000000000..6ca73aca2 --- /dev/null +++ b/src/core/libraries/camera/camera_helpers.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "camera.h" + +namespace Libraries::Camera { + +void ConvertRGBA8888ToY8(const u8* src, u8* dst, int width, int height); +void ConvertRGBA8888ToY16(const u8* src, u16* dst, int width, int height); +void ConvertRGBA8888ToRAW8(const u8* src, u8* dst, int width, int height); +void ConvertRGBA8888ToRAW16(const u8* src, u16* dst, int width, int height); +void ConvertYUY2ToY8(const u8* src, u8* dst, int width, int height); +void ConvertYUY2ToY16(const u8* src, u16* dst, int width, int height); +void ConvertYUY2ToRAW8(const u8* src, u8* dst, int width, int height); +void ConvertYUY2ToRAW16(const u8* src, u16* dst, int width, int height); + +s32 SizeOfBaseFormat(OrbisCameraBaseFormat f); +s32 SizeOfScaleFormat(OrbisCameraScaleFormat f); + +} // namespace Libraries::Camera \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 552cb7348..61b45b2ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,7 +151,7 @@ int main(int argc, char* argv[]) { // Initialize main log with default config Common::Log::Setup("shadps4.log"); - LOG_INFO(Debug, "Run: {}", fmt::join(std::span(argv, argc), "")); + LOG_INFO(Debug, "Run: {}", fmt::join(std::span(argv, argc), " ")); IPC::Instance().Init();