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();