Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HW/SimpleAudioDec.h
Core/HW/AsyncIOManager.cpp
Core/HW/AsyncIOManager.h
Core/HW/Camera.cpp
Core/HW/Camera.h
Core/HW/MediaEngine.cpp
Core/HW/MediaEngine.h
Core/HW/MpegDemux.cpp
Expand Down
4 changes: 2 additions & 2 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,8 +707,8 @@ static ConfigSetting graphicsSettings[] = {
#ifdef _WIN32
ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false),
#endif
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
ConfigSetting("WinCameraDevice", &g_Config.sWinCameraDevice, "", true, false),
#if (defined(_WIN32) && !PPSSPP_PLATFORM(UWP)) || PPSSPP_PLATFORM(LINUX)
ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", true, false),
#endif
ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false),
ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, 1, true, true),
Expand Down
2 changes: 1 addition & 1 deletion Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ struct Config {
// If not set, will use the "best" device.
std::string sVulkanDevice;
std::string sD3D11Device; // Windows only
std::string sWinCameraDevice; // Windows only
std::string sCameraDevice;

bool bSoftwareRendering;
bool bHardwareTransform; // only used in the GLES backend
Expand Down
2 changes: 2 additions & 0 deletions Core/Core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@
<ClCompile Include="HLE\sceUsbAcc.cpp" />
<ClCompile Include="HLE\sceUsbCam.cpp" />
<ClCompile Include="HLE\sceUsbMic.cpp" />
<ClCompile Include="HW\Camera.cpp" />
<ClCompile Include="MIPS\IR\IRAsm.cpp" />
<ClCompile Include="MIPS\IR\IRCompALU.cpp" />
<ClCompile Include="MIPS\IR\IRCompBranch.cpp" />
Expand Down Expand Up @@ -903,6 +904,7 @@
<ClInclude Include="HLE\sceUsbAcc.h" />
<ClInclude Include="HLE\sceUsbCam.h" />
<ClInclude Include="HLE\sceUsbMic.h" />
<ClInclude Include="HW\Camera.h" />
<ClInclude Include="MIPS\IR\IRFrontend.h" />
<ClInclude Include="MIPS\IR\IRInst.h" />
<ClInclude Include="MIPS\IR\IRInterpreter.h" />
Expand Down
6 changes: 6 additions & 0 deletions Core/Core.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,9 @@
<ClCompile Include="HLE\sceUsbMic.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
<ClCompile Include="HW\Camera.cpp">
<Filter>HW</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
Expand Down Expand Up @@ -1373,6 +1376,9 @@
<ClInclude Include="HLE\sceUsbMic.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="HW\Camera.h">
<Filter>HW</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
Expand Down
14 changes: 12 additions & 2 deletions Core/HLE/sceUsb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ static int sceUsbDeactivate(u32 pid) {
return 0;
}

static int sceUsbWaitState(int state, int waitMode, u32 timeoutAddr) {
ERROR_LOG(HLE, "UNIMPL sceUsbWaitStat(%i, %i, %08x)", state, waitMode, timeoutAddr);
return sceUsbGetState();
}

static int sceUsbWaitStateCB(int state, int waitMode, u32 timeoutAddr) {
ERROR_LOG(HLE, "UNIMPL sceUsbWaitStateCB(%i, %i, %08x)", state, waitMode, timeoutAddr);
return 0;
}

const HLEFunction sceUsb[] =
{
{0XAE5DE6AF, &WrapI_CUU<sceUsbStart>, "sceUsbStart", 'i', "sxx"},
Expand All @@ -108,8 +118,8 @@ const HLEFunction sceUsb[] =
{0X112CC951, nullptr, "sceUsbGetDrvState", '?', "" },
{0X586DB82C, &WrapI_U<sceUsbActivate>, "sceUsbActivate", 'i', "x" },
{0XC572A9C8, &WrapI_U<sceUsbDeactivate>, "sceUsbDeactivate", 'i', "x" },
{0X5BE0E002, nullptr, "sceUsbWaitState", '?', "" },
{0X616F2B61, nullptr, "sceUsbWaitStateCB", '?', "" },
{0X5BE0E002, &WrapI_IIU<sceUsbWaitState>, "sceUsbWaitState", '?', "xxx"},
{0X616F2B61, &WrapI_IIU<sceUsbWaitStateCB>, "sceUsbWaitStateCB", '?', "xxx"},
{0X1C360735, nullptr, "sceUsbWaitCancel", '?', "" },
};

Expand Down
214 changes: 155 additions & 59 deletions Core/HLE/sceUsbCam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,95 @@
#include <mutex>

#include "base/NativeApp.h"
#include "ppsspp_config.h"
#include "Common/ChunkFile.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceUsbCam.h"
#include "Core/HW/Camera.h"
#include "Core/MemMapHelpers.h"

#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "Windows/CaptureDevice.h"
#undef min
#endif


PspUsbCamSetupMicParam micParam;
PspUsbCamSetupVideoParam videoParam;
Camera::Config *config;

unsigned int videoBufferLength = 0;
unsigned int nextVideoFrame = 0;
uint8_t *videoBuffer;
std::mutex videoBufferMutex;
bool isShutDown = false;

enum {
VIDEO_BUFFER_SIZE = 40 * 1000,
};

void __UsbCamInit() {
videoBuffer = new uint8_t[VIDEO_BUFFER_SIZE];
isShutDown = false;
config = new Camera::Config;
config->mode = Camera::Mode::Unused;
config->type = Camera::ConfigType::CfNone;
videoBuffer = new uint8_t[VIDEO_BUFFER_SIZE];
}

void __UsbCamShutdown() {
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::SHUTDOWN, nullptr });
}
#endif
isShutDown = true;
void __UsbCamDoState(PointerWrap &p) {
auto s = p.Section("sceUsbCam", 0, 1);
if (!s) {
return;
}

p.Do(*config);
if (config->mode == Camera::Mode::Video) { // stillImage? TBD
Camera::startCapture();
}
}

void __UsbCamShutdown() {
Camera::stopCapture();
delete[] videoBuffer;
videoBuffer = nullptr;
delete[] config;
config = nullptr;
}

// TODO: Technically, we should store the videoBuffer into the savestate, if this
// module has been initialized.

static int getCameraResolution(Camera::ConfigType type, int *width, int *height) {
if (type == Camera::ConfigType::CfStill || type == Camera::ConfigType::CfVideo) {
switch(config->stillParam.resolution) {
case 0: *width = 160; *height = 120; return 0;
case 1: *width = 176; *height = 144; return 0;
case 2: *width = 320; *height = 240; return 0;
case 3: *width = 352; *height = 288; return 0;
case 4: *width = 640; *height = 480; return 0;
case 5: *width =1024; *height = 768; return 0;
case 6: *width =1280; *height = 960; return 0;
case 7: *width = 480; *height = 272; return 0;
case 8: *width = 360; *height = 272; return 0;
}
} else if (type == Camera::ConfigType::CfStillEx || type == Camera::ConfigType::CfVideoEx) {
switch(config->stillExParam.resolution) {
case 0: *width = 160; *height = 120; return 0;
case 1: *width = 176; *height = 144; return 0;
case 2: *width = 320; *height = 240; return 0;
case 3: *width = 352; *height = 288; return 0;
case 4: *width = 360; *height = 272; return 0;
case 5: *width = 480; *height = 272; return 0;
case 6: *width = 640; *height = 480; return 0;
case 7: *width =1024; *height = 768; return 0;
case 8: *width =1280; *height = 960; return 0;
}
}
*width = 0; *height = 0; return 1;
}


static int sceUsbCamSetupMic(u32 paramAddr, u32 workareaAddr, int wasize) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupMic");
if (Memory::IsValidRange(paramAddr, sizeof(micParam))) {
Memory::ReadStruct(paramAddr, &micParam);
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupMicParam))) {
Memory::ReadStruct(paramAddr, &config->micParam);
}
return 0;
}
Expand All @@ -89,59 +129,37 @@ static int sceUsbCamReadMicBlocking(u32 bufAddr, u32 size) {
Memory::Write_U8(i & 0xFF, bufAddr + i);
}
}
hleEatMicro(1000000 / micParam.frequency * (size / 2));
hleEatMicro(1000000 / config->micParam.frequency * (size / 2));
return size;
}

static int sceUsbCamSetupVideo(u32 paramAddr, u32 workareaAddr, int wasize) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo");
if (Memory::IsValidRange(paramAddr, sizeof(videoParam))) {
Memory::ReadStruct(paramAddr, &videoParam);
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupVideoParam))) {
Memory::ReadStruct(paramAddr, &config->videoParam);
}

INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - size: %d", videoParam.size);
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - resolution: %d", videoParam.resolution);
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - framesize: %d", videoParam.framesize);

std::lock_guard<std::mutex> lock(videoBufferMutex);
videoBufferLength = sizeof(sceUsbCamDummyImage);
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
memcpy(videoBuffer, sceUsbCamDummyImage, sizeof(sceUsbCamDummyImage));
config->type = Camera::ConfigType::CfVideo;
return 0;
}

static int sceUsbCamStartVideo() {
INFO_LOG(HLE, "UNIMPL sceUsbCamStartVideo");
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
if (winCamera->isShutDown()) {
delete winCamera;
winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO);
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr });
}

winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::START, nullptr });
static int sceUsbCamSetupVideoEx(u32 paramAddr, u32 workareaAddr, int wasize) {
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupVideoExParam))) {
Memory::ReadStruct(paramAddr, &config->videoExParam);
}

#else
System_SendMessage("camera_command", "startVideo");
#endif
config->type = Camera::ConfigType::CfVideoEx;
return 0;
}

static int sceUsbCamStopVideo() {
INFO_LOG(HLE, "UNIMPL sceUsbCamStopVideo");
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera)
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::STOP, nullptr });
#else
System_SendMessage("camera_command", "stopVideo");
#endif
static int sceUsbCamStartVideo() {
std::lock_guard<std::mutex> lock(videoBufferMutex);
videoBufferLength = sizeof(sceUsbCamDummyImage);
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
memcpy(videoBuffer, sceUsbCamDummyImage, sizeof(sceUsbCamDummyImage));
Camera::startCapture();
return 0;
}

static int sceUsbCamAutoImageReverseSW(int rev) {
INFO_LOG(HLE, "UNIMPL sceUsbCamAutoImageReverseSW");
static int sceUsbCamStopVideo() {
Camera::stopCapture();
return 0;
}

Expand Down Expand Up @@ -169,6 +187,29 @@ static int sceUsbCamPollReadVideoFrameEnd() {
return nextVideoFrame;
}

static int sceUsbCamSetupStill(u32 paramAddr) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupStill");
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupStillParam))) {
Memory::ReadStruct(paramAddr, &config->stillParam);
}
config->type = Camera::ConfigType::CfStill;
return 0;
}

static int sceUsbCamSetupStillEx(u32 paramAddr) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupStillEx");
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupStillExParam))) {
Memory::ReadStruct(paramAddr, &config->stillExParam);
}
config->type = Camera::ConfigType::CfStillEx;
return 0;
}

static int sceUsbCamAutoImageReverseSW(int rev) {
INFO_LOG(HLE, "UNIMPL sceUsbCamAutoImageReverseSW");
return 0;
}

const HLEFunction sceUsbCam[] =
{
{ 0X03ED7A82, &WrapI_UUI<sceUsbCamSetupMic>, "sceUsbCamSetupMic", 'i', "xxi" },
Expand All @@ -183,7 +224,7 @@ const HLEFunction sceUsbCam[] =
{ 0X08AEE98A, nullptr, "sceUsbCamSetMicGain", '?', "" },

{ 0X17F7B2FB, &WrapI_UUI<sceUsbCamSetupVideo>, "sceUsbCamSetupVideo", 'i', "xxi" },
{ 0XCFE9E999, nullptr, "sceUsbCamSetupVideoEx", '?', "" },
{ 0XCFE9E999, &WrapI_UUI<sceUsbCamSetupVideoEx>, "sceUsbCamSetupVideoEx", 'i', "xxi" },
{ 0X574A8C3F, &WrapI_V<sceUsbCamStartVideo>, "sceUsbCamStartVideo", 'i', "" },
{ 0X6CF32CB9, &WrapI_V<sceUsbCamStopVideo>, "sceUsbCamStopVideo", 'i', "" },
{ 0X7DAC0C71, &WrapI_UU<sceUsbCamReadVideoFrameBlocking>, "sceUsbCamReadVideoFrameBlocking", 'i', "xx" },
Expand All @@ -192,8 +233,8 @@ const HLEFunction sceUsbCam[] =
{ 0X41E73E95, &WrapI_V<sceUsbCamPollReadVideoFrameEnd>, "sceUsbCamPollReadVideoFrameEnd", 'i', "" },
{ 0XDF9D0C92, nullptr, "sceUsbCamGetReadVideoFrameSize", '?', "" },

{ 0X3F0CF289, nullptr, "sceUsbCamSetupStill", '?', "" },
{ 0X0A41A298, nullptr, "sceUsbCamSetupStillEx", '?', "" },
{ 0X3F0CF289, &WrapI_U<sceUsbCamSetupStill>, "sceUsbCamSetupStill", 'i', "x" },
{ 0X0A41A298, &WrapI_U<sceUsbCamSetupStillEx>, "sceUsbCamSetupStillEx", 'i', "x" },
{ 0X61BE5CAC, nullptr, "sceUsbCamStillInputBlocking", '?', "" },
{ 0XFB0A6C5D, nullptr, "sceUsbCamStillInput", '?', "" },
{ 0X7563AFA1, nullptr, "sceUsbCamStillWaitInputEnd", '?', "" },
Expand Down Expand Up @@ -233,10 +274,65 @@ void Register_sceUsbCam()
RegisterModule("sceUsbCam", ARRAY_SIZE(sceUsbCam), sceUsbCam);
}

std::vector<std::string> Camera::getDeviceList() {
#if PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
return __v4l_getDeviceList();
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
return winCamera->getDeviceList();
}
#endif
return std::vector<std::string>();
}

int Camera::startCapture() {
int width, height;
getCameraResolution(config->type, &width, &height);
INFO_LOG(HLE, "%s resolution: %dx%d", __FUNCTION__, width, height);

config->mode = Camera::Mode::Video;
#if PPSSPP_PLATFORM(ANDROID)
System_SendMessage("camera_command", "startVideo");
#elif PPSSPP_PLATFORM(LINUX)
__v4l_startCapture(width, height);
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
if (winCamera->isShutDown()) {
delete winCamera;
winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO);
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr });
}
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::START, nullptr });
}
#else
ERROR_LOG(HLE, "%s not implemented", __FUNCTION__);
#endif
return 0;
}

int Camera::stopCapture() {
INFO_LOG(HLE, "%s", __FUNCTION__);
#if PPSSPP_PLATFORM(ANDROID)
System_SendMessage("camera_command", "stopVideo");
#elif PPSSPP_PLATFORM(LINUX)
__v4l_stopCapture();
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::STOP, nullptr });
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::SHUTDOWN, nullptr });
}
#else
ERROR_LOG(HLE, "%s not implemented", __FUNCTION__);
#endif
config->mode = Camera::Mode::Unused;
return 0;
}

void Camera::pushCameraImage(long long length, unsigned char* image) {
std::lock_guard<std::mutex> lock(videoBufferMutex);
if (isShutDown)
if (!videoBuffer) {
return;
}
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
if (length > VIDEO_BUFFER_SIZE) {
videoBufferLength = 0;
Expand Down
Loading