Buildfixes, dependency shuffling to make things more logical

This commit is contained in:
Henrik Rydgård committed 2026-07-24 14:43:34 +02:00
1 parent dd8c282a26
commit afe4d5beaf
16 files changed
+558 -506

No files matched your search

+104 -89
View File
@@ -561,66 +561,6 @@ endmacro()
add_subdirectory(ext)
set(CommonJIT
Core/MIPS/JitCommon/JitCommon.cpp
Core/MIPS/JitCommon/JitCommon.h
Core/MIPS/JitCommon/JitBlockCache.cpp
Core/MIPS/JitCommon/JitBlockCache.h
Core/MIPS/JitCommon/JitState.cpp
Core/MIPS/JitCommon/JitState.h
)
set(CommonX86
Common/ABI.cpp
Common/ABI.h
Common/CPUDetect.cpp
Common/CPUDetect.h
Common/Thunk.cpp
Common/Thunk.h
Common/x64Analyzer.cpp
Common/x64Analyzer.h
Common/x64Emitter.cpp
Common/x64Emitter.h
)
source_group(x86 FILES ${CommonX86})
set(CommonARM
Common/ArmCPUDetect.cpp
Common/ArmEmitter.h
Common/ArmEmitter.cpp
)
source_group(ARM FILES ${CommonARM})
set(CommonARM64
Common/Arm64Emitter.h
Common/Arm64Emitter.cpp
Common/ArmEmitter.h
Common/ArmEmitter.cpp
Core/Util/DisArm64.h
Core/Util/DisArm64.cpp
)
source_group(ARM64 FILES ${CommonARM64})
set(CommonRISCV64
${CommonJIT}
Common/RiscVCPUDetect.cpp
Common/RiscVEmitter.cpp
Common/RiscVEmitter.h
Core/MIPS/fake/FakeJit.cpp
Core/MIPS/fake/FakeJit.h
)
source_group(RISCV64 FILES ${CommonRISCV64})
set(CommonLOONGARCH64
${CommonJIT}
Common/LoongArchCPUDetect.cpp
Common/LoongArch64Emitter.cpp
Common/LoongArch64Emitter.h
Core/MIPS/fake/FakeJit.cpp
Core/MIPS/fake/FakeJit.h
)
source_group(LOONGARCH64 FILES ${CommonLOONGARCH64})
if(WIN32)
set(CommonD3D
Common/GPU/D3D11/thin3d_d3d11.cpp
@@ -651,11 +591,29 @@ include_directories(ext/OpenXR-SDK/include)
include_directories(ext)
add_library(Common STATIC
${CommonX86}
${CommonARM}
${CommonARM64}
${CommonRISCV64}
${CommonLOONGARCH64}
Common/ABI.cpp
Common/ABI.h
Common/CPUDetect.cpp
Common/CPUDetect.h
Common/Thunk.cpp
Common/Thunk.h
Common/x64Analyzer.cpp
Common/x64Analyzer.h
Common/x64Emitter.cpp
Common/x64Emitter.h
Common/ArmCPUDetect.cpp
Common/ArmEmitter.h
Common/ArmEmitter.cpp
Common/Arm64Emitter.h
Common/Arm64Emitter.cpp
Common/ArmEmitter.h
Common/ArmEmitter.cpp
Common/RiscVCPUDetect.cpp
Common/RiscVEmitter.cpp
Common/RiscVEmitter.h
Common/LoongArchCPUDetect.cpp
Common/LoongArch64Emitter.cpp
Common/LoongArch64Emitter.h
${CommonD3D}
${CommonVR}
Common/Serialize/Serializer.cpp
@@ -857,8 +815,6 @@ add_library(Common STATIC
Common/Render/Text/draw_text.h
Common/Render/Text/draw_text_android.cpp
Common/Render/Text/draw_text_android.h
Common/Render/Text/draw_text_sdl.cpp
Common/Render/Text/draw_text_sdl.h
Common/Render/Text/draw_text_win.cpp
Common/Render/Text/draw_text_win.h
Common/Render/Text/draw_text_uwp.cpp
@@ -1455,9 +1411,12 @@ elseif(IOS AND NOT LIBRETRO)
# TODO: Enable arc globally?
set_source_files_properties(ios/AppDelegate.mm
ios/SceneDelegate.mm
ios/ViewControllerCommon.mm
ios/ViewController.mm
ios/ViewControllerMetal.mm
ios/iOSCoreAudio.mm
ios/IAPManager.mm
ios/PPSSPPUIApplication.mm
ios/iCade/iCadeReaderView.m
ios/main.mm
@@ -1561,9 +1520,10 @@ else()
UI/PSPNSApplicationDelegate.mm
UI/PSPNSApplicationDelegate.h)
set_source_files_properties(Core/Util/DarwinFileSystemServices.mm
set_source_files_properties(
Core/Util/DarwinFileSystemServices.mm
UI/PSPNSApplicationDelegate.mm
SDL/CocoaMetalLayer.mm
SDL/SDLCocoaMetalLayer.mm
SDL/CocoaBarItems.mm
SDL/PPSSPPAboutViewController.m
SDL/MacCameraHelper.mm
@@ -1572,11 +1532,17 @@ else()
PROPERTIES COMPILE_FLAGS -fobjc-arc)
list(APPEND targetExtraLibs ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} "-framework AVFoundation" "-framework CoreMedia" "-framework CoreVideo")
list(APPEND targetExtraLibs ${SDL_LIB_TARGET})
elseif(USING_EGL)
list(APPEND targetExtraLibs pthread ${SDL_LIB_TARGET})
else()
list(APPEND targetExtra
Common/Render/Text/draw_text_sdl.cpp
Common/Render/Text/draw_text_sdl.h
)
list(APPEND targetExtraLibs ${SDL_LIB_TARGET})
endif()
if(USING_EGL AND NOT APPLE)
list(APPEND targetExtraLibs pthread)
endif()
endif()
if(WIN32)
@@ -1722,11 +1688,6 @@ if (IOS AND NOT LIBRETRO)
list(APPEND targetExtra ${NativeAppSource})
endif()
if(LIBRETRO)
target_include_directories(core PRIVATE libretro/libretro-common/include)
target_include_directories(${TargetBin} PRIVATE libretro/libretro-common/include)
endif()
if(LINUX AND NOT ANDROID)
set(RT_LIB rt)
endif()
@@ -2522,6 +2483,16 @@ add_library(core STATIC
Core/MIPS/MIPSAsm.h
Core/MIPS/MIPSTracer.cpp
Core/MIPS/MIPSTracer.h
Core/MIPS/JitCommon/JitCommon.cpp
Core/MIPS/JitCommon/JitCommon.h
Core/MIPS/JitCommon/JitBlockCache.cpp
Core/MIPS/JitCommon/JitBlockCache.h
Core/MIPS/JitCommon/JitState.cpp
Core/MIPS/JitCommon/JitState.h
Core/Util/DisArm64.h
Core/Util/DisArm64.cpp
Core/MIPS/fake/FakeJit.cpp
Core/MIPS/fake/FakeJit.h
Core/MemFault.cpp
Core/MemFault.h
Core/MemMap.cpp
@@ -2897,8 +2868,6 @@ set(WindowsFiles
Windows/stdafx.h
)
list(APPEND LinkCommon ${CMAKE_THREAD_LIBS_INIT})
if(WIN32)
#setup_target_project(${TargetBin} Windows)
list(APPEND NativeAppSource ${WindowsFiles})
@@ -2954,6 +2923,19 @@ if(HEADLESS)
headless/SDLHeadlessHost.cpp
headless/SDLHeadlessHost.h
)
if(APPLE)
list(APPEND HeadlessSource
Common/Render/Text/draw_text_cocoa.mm
Common/Render/Text/draw_text_cocoa.h
)
set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc)
elseif(SDL_TTF_LIB_TARGET AND NOT WIN32)
list(APPEND HeadlessSource
Common/Render/Text/draw_text_sdl.cpp
Common/Render/Text/draw_text_sdl.h
)
endif()
if(WIN32)
list(APPEND HeadlessSource
headless/WindowsHeadlessHost.cpp
@@ -2971,7 +2953,16 @@ if(HEADLESS)
)
endif()
add_executable(PPSSPPHeadless ${HeadlessSource})
target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} ${LinkCommon} Common core)
target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} core)
if(SDL_LIB_TARGET)
target_link_libraries(PPSSPPHeadless ${SDL_LIB_TARGET})
endif()
if(SDL_TTF_LIB_TARGET)
target_link_libraries(PPSSPPHeadless ${SDL_TTF_LIB_TARGET})
endif()
if(FONTCONFIG_LIB_TARGET)
target_link_libraries(PPSSPPHeadless ${FONTCONFIG_LIB_TARGET})
endif()
if(WIN32)
target_link_libraries(PPSSPPHeadless d2d1 dwrite d3d11)
endif()
@@ -2996,13 +2987,35 @@ if(UNITTEST)
Core/MIPS/ARM/ArmRegCache.cpp
Core/MIPS/ARM/ArmRegCacheFPU.cpp
)
if(APPLE)
target_sources(PPSSPPUnitTest PRIVATE
Common/Render/Text/draw_text_cocoa.mm
Common/Render/Text/draw_text_cocoa.h
)
set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc)
elseif(SDL_TTF_LIB_TARGET AND NOT WIN32)
target_sources(PPSSPPUnitTest PRIVATE
Common/Render/Text/draw_text_sdl.cpp
Common/Render/Text/draw_text_sdl.h
)
endif()
if(WIN32)
target_sources(PPSSPPUnitTest PRIVATE
Windows/CaptureDevice.cpp
Windows/CaptureDevice.h
)
endif()
target_link_libraries(PPSSPPUnitTest ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} ${LinkCommon} Common core)
target_link_libraries(PPSSPPUnitTest ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} Common core)
if(SDL_LIB_TARGET)
target_link_libraries(PPSSPPUnitTest ${SDL_LIB_TARGET})
endif()
if(SDL_TTF_LIB_TARGET)
target_link_libraries(PPSSPPUnitTest ${SDL_TTF_LIB_TARGET})
endif()
if(FONTCONFIG_LIB_TARGET)
target_link_libraries(PPSSPPUnitTest ${FONTCONFIG_LIB_TARGET})
endif()
if(WIN32)
target_link_libraries(PPSSPPUnitTest d2d1 dwrite d3d11)
endif()
@@ -3037,7 +3050,7 @@ if(ATLAS_TOOL)
ext/native/tools/atlastool.cpp
)
add_executable(AtlasTool ${AtlasToolSource})
target_link_libraries(AtlasTool ${LinkCommon} freetype)
target_link_libraries(AtlasTool ${CMAKE_THREAD_LIBS_INIT} freetype)
setup_target_project(AtlasTool atlastool)
endif()
@@ -3116,18 +3129,20 @@ if(TargetBin)
target_link_options(${TargetBin} PRIVATE "-Wl,-z,max-page-size=16384")
endif()
if(TARGET ppsspp_ui)
target_link_libraries(${TargetBin} ${LinkCommon} ${targetExtraLibs} ppsspp_ui)
target_link_libraries(${TargetBin} ${CMAKE_THREAD_LIBS_INIT} ${targetExtraLibs} ppsspp_ui)
else()
target_link_libraries(${TargetBin} ${LinkCommon} ${targetExtraLibs} core)
target_link_libraries(${TargetBin} ${CMAKE_THREAD_LIBS_INIT} ${targetExtraLibs} core)
endif()
endif()
if(ANDROID)
target_link_libraries(${TargetBin} log EGL OpenSLES)
elseif(WIN32)
target_link_libraries(${TargetBin} ws2_32 winmm)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "^(DragonFly|FreeBSD|NetBSD)$")
target_link_libraries(${TargetBin} execinfo)
if(TargetBin)
if(ANDROID)
target_link_libraries(${TargetBin} log EGL OpenSLES)
elseif(WIN32)
target_link_libraries(${TargetBin} ws2_32 winmm)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "^(DragonFly|FreeBSD|NetBSD)$")
target_link_libraries(${TargetBin} execinfo)
endif()
endif()
# installs
+2 -12
View File
@@ -332,14 +332,9 @@ std::vector<std::string> Camera::getDeviceList() {
if (winCamera) {
return winCamera->getDeviceList();
}
#elif PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
#else
return System_GetCameraDeviceList();
#elif defined(USING_QT_UI) // Qt:macOS / Qt:Linux
return System_GetCameraDeviceList();
#elif PPSSPP_PLATFORM(LINUX) // SDL:Linux
return __v4l_getDeviceList();
#endif
return std::vector<std::string>();
}
int Camera::startCapture() {
@@ -361,9 +356,6 @@ int Camera::startCapture() {
char command[40] = {0};
snprintf(command, sizeof(command), "startVideo_%dx%d", width, height);
System_CameraCommand(command);
#elif PPSSPP_PLATFORM(LINUX)
__v4l_startCapture(width, height);
#else
ERROR_LOG(Log::HLE, "%s not implemented", __FUNCTION__);
#endif
return 0;
@@ -375,10 +367,8 @@ int Camera::stopCapture() {
if (winCamera) {
winCamera->sendMessage({ CAPTUREDEVICE_COMMAND::STOP, nullptr });
}
#elif PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || defined(USING_QT_UI)
#elif PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || defined(USING_QT_UI)
System_CameraCommand("stopVideo");
#elif PPSSPP_PLATFORM(LINUX)
__v4l_stopCapture();
#else
ERROR_LOG(Log::HLE, "%s not implemented", __FUNCTION__);
#endif
+2 -312
View File
@@ -18,45 +18,7 @@
#include "Camera.h"
#include "Core/Config.h"
#ifdef USE_FFMPEG
void convert_frame(int inw, int inh, unsigned char *inData, AVPixelFormat inFormat,
int outw, int outh, unsigned char **outData, int *outLen) {
struct SwsContext *sws_context = sws_getContext(
inw, inh, inFormat,
outw, outh, AV_PIX_FMT_RGB24,
SWS_BICUBIC, NULL, NULL, NULL);
// resize
uint8_t *src[4] = {0};
uint8_t *dst[4] = {0};
int srcStride[4], dstStride[4];
unsigned char *rgbData = (unsigned char*)malloc(outw * outh * 4);
av_image_fill_linesizes(srcStride, inFormat, inw);
av_image_fill_linesizes(dstStride, AV_PIX_FMT_RGB24, outw);
av_image_fill_pointers(src, inFormat, inh, inData, srcStride);
av_image_fill_pointers(dst, AV_PIX_FMT_RGB24, outh, rgbData, dstStride);
sws_scale(sws_context,
src, srcStride, 0, inh,
dst, dstStride);
// compress jpeg
*outLen = outw * outh * 2;
*outData = (unsigned char*)malloc(*outLen);
jpge::params params;
params.m_quality = 60;
params.m_subsampling = jpge::H2V2;
params.m_two_pass_flag = false;
jpge::compress_image_to_jpeg_file_in_memory(
*outData, *outLen, outw, outh, 3, rgbData, params);
free(rgbData);
}
#endif //USE_FFMPEG
#include "ext/jpge/jpge.h"
void __cameraDummyImage(int width, int height, unsigned char** outData, int* outLen) {
#ifdef USE_FFMPEG
@@ -65,6 +27,7 @@ void __cameraDummyImage(int width, int height, unsigned char** outData, int* out
*outData = nullptr;
return;
}
// Generate a solid RED surface for camera detection (e.g., Invizimals)
// RGB: (255, 0, 0) = Red
for (int y = 0; y < height; y++) {
@@ -87,276 +50,3 @@ void __cameraDummyImage(int width, int height, unsigned char** outData, int* out
free(rgbData);
#endif //USE_FFMPEG
}
#if PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
std::vector<std::string> __v4l_getDeviceList() {
std::vector<std::string> deviceList;
#ifdef USE_FFMPEG
for (int i = 0; i < 64; i++) {
char path[256];
snprintf(path, sizeof(path), "/dev/video%d", i);
if (access(path, F_OK) < 0) {
break;
}
int fd = -1;
if((fd = open(path, O_RDONLY)) < 0) {
ERROR_LOG(Log::HLE, "Cannot open '%s'; errno=%d(%s)", path, errno, strerror(errno));
continue;
}
struct v4l2_capability video_cap;
if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) < 0) {
ERROR_LOG(Log::HLE, "VIDIOC_QUERYCAP");
goto cont;
} else {
char device[256];
snprintf(device, sizeof(device), "%d:%s", i, video_cap.card);
deviceList.push_back(device);
}
cont:
close(fd);
fd = -1;
}
#endif //USE_FFMPEG
return deviceList;
}
void *v4l_loop(void *data) {
#ifdef USE_FFMPEG
SetCurrentThreadName("v4l_loop");
while (v4l_fd >= 0) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_DQBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_DQBUF; errno=%d(%s)", errno, strerror(errno));
switch (errno) {
case EAGAIN:
continue;
default:
return nullptr;
}
}
unsigned char *jpegData = nullptr;
int jpegLen = 0;
if (v4l_format == V4L2_PIX_FMT_YUYV) {
convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)v4l_buffers[buf.index].start, AV_PIX_FMT_YUYV422,
v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen);
} else if (v4l_format == V4L2_PIX_FMT_JPEG
|| v4l_format == V4L2_PIX_FMT_MJPEG) {
// decompress jpeg
int width, height, req_comps;
unsigned char *rgbData = jpgd::decompress_jpeg_image_from_memory(
(unsigned char*)v4l_buffers[buf.index].start, buf.bytesused, &width, &height, &req_comps, 3);
convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)rgbData, AV_PIX_FMT_RGB24,
v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen);
free(rgbData);
}
if (jpegData) {
Camera::pushCameraImage(jpegLen, jpegData);
free(jpegData);
jpegData = nullptr;
}
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QBUF");
return nullptr;
}
}
#endif //USE_FFMPEG
return nullptr;
}
int __v4l_startCapture(int ideal_width, int ideal_height) {
#ifdef USE_FFMPEG
if (v4l_fd >= 0) {
__v4l_stopCapture();
}
v4l_ideal_width = ideal_width;
v4l_ideal_height = ideal_height;
int dev_index = 0;
char dev_name[64];
sscanf(g_Config.sCameraDevice.c_str(), "%d:", &dev_index);
snprintf(dev_name, sizeof(dev_name), "/dev/video%d", dev_index);
if ((v4l_fd = open(dev_name, O_RDWR)) == -1) {
ERROR_LOG(Log::HLE, "Cannot open '%s'; errno=%d(%s)", dev_name, errno, strerror(errno));
return -1;
}
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
if (ioctl(v4l_fd, VIDIOC_QUERYCAP, &cap) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QUERYCAP");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
ERROR_LOG(Log::HLE, "V4L2_CAP_VIDEO_CAPTURE");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
ERROR_LOG(Log::HLE, "V4L2_CAP_STREAMING");
return -1;
}
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = 0;
// select a pixel format
struct v4l2_fmtdesc desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(v4l_fd, VIDIOC_ENUM_FMT, &desc) == 0) {
desc.index++;
INFO_LOG(Log::HLE, "V4L2: pixel format supported: %s", desc.description);
if (fmt.fmt.pix.pixelformat != 0) {
continue;
} else if (desc.pixelformat == V4L2_PIX_FMT_YUYV
|| desc.pixelformat == V4L2_PIX_FMT_JPEG
|| desc.pixelformat == V4L2_PIX_FMT_MJPEG) {
INFO_LOG(Log::HLE, "V4L2: %s selected", desc.description);
fmt.fmt.pix.pixelformat = desc.pixelformat;
v4l_format = desc.pixelformat;
}
}
if (fmt.fmt.pix.pixelformat == 0) {
ERROR_LOG(Log::HLE, "V4L2: No supported format found");
return -1;
}
// select a frame size
fmt.fmt.pix.width = 0;
fmt.fmt.pix.height = 0;
struct v4l2_frmsizeenum frmsize;
memset(&frmsize, 0, sizeof(frmsize));
frmsize.pixel_format = fmt.fmt.pix.pixelformat;
while (ioctl(v4l_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) {
frmsize.index++;
if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
INFO_LOG(Log::HLE, "V4L2: frame size supported: %dx%d", frmsize.discrete.width, frmsize.discrete.height);
bool matchesIdeal = frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height;
bool zeroPix = fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0;
bool pixLarger = frmsize.discrete.width < fmt.fmt.pix.width && frmsize.discrete.height < fmt.fmt.pix.height;
if (matchesIdeal && (zeroPix || pixLarger)) {
fmt.fmt.pix.width = frmsize.discrete.width;
fmt.fmt.pix.height = frmsize.discrete.height;
}
}
}
if (fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0) {
fmt.fmt.pix.width = ideal_width;
fmt.fmt.pix.height = ideal_height;
}
INFO_LOG(Log::HLE, "V4L2: asking for %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
if (ioctl(v4l_fd, VIDIOC_S_FMT, &fmt) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_S_FMT");
return -1;
}
v4l_hw_width = fmt.fmt.pix.width;
v4l_hw_height = fmt.fmt.pix.height;
INFO_LOG(Log::HLE, "V4L2: will receive %dx%d", v4l_hw_width, v4l_hw_height);
v4l_height_fixed_aspect = v4l_hw_width * ideal_height / ideal_width;
INFO_LOG(Log::HLE, "V4L2: will use %dx%d", v4l_hw_width, v4l_height_fixed_aspect);
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_REQBUFS, &req) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_REQBUFS");
return -1;
}
v4l_buffer_count = req.count;
INFO_LOG(Log::HLE, "V4L2: buffer count: %d", v4l_buffer_count);
v4l_buffers = (v4l_buf_t*) calloc(v4l_buffer_count, sizeof(v4l_buf_t));
for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = buf_id;
if (ioctl(v4l_fd, VIDIOC_QUERYBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QUERYBUF");
return -1;
}
v4l_buffers[buf_id].length = buf.length;
v4l_buffers[buf_id].start = mmap(NULL,
buf.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
v4l_fd, buf.m.offset);
if (v4l_buffers[buf_id].start == MAP_FAILED) {
ERROR_LOG(Log::HLE, "MAP_FAILED");
return -1;
}
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = buf_id;
if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QBUF");
return -1;
}
}
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(v4l_fd, VIDIOC_STREAMON, &type) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_STREAMON");
return -1;
}
pthread_create(&v4l_thread, NULL, v4l_loop, NULL);
#endif //USE_FFMPEG
return 0;
}
int __v4l_stopCapture() {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (v4l_fd < 0) {
goto exit;
}
if (ioctl(v4l_fd, VIDIOC_STREAMOFF, &type) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_STREAMOFF");
goto exit;
}
for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) {
if (munmap(v4l_buffers[buf_id].start, v4l_buffers[buf_id].length) == -1) {
ERROR_LOG(Log::HLE, "munmap");
goto exit;
}
}
if (close(v4l_fd) == -1) {
ERROR_LOG(Log::HLE, "close");
goto exit;
}
v4l_fd = -1;
//pthread_join(v4l_thread, NULL);
exit:
v4l_fd = -1;
return 0;
}
#endif // PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
-64
View File
@@ -17,69 +17,5 @@
#pragma once
#include "ppsspp_config.h"
#include "Core/HLE/sceUsbCam.h"
#include "ext/jpge/jpgd.h"
#include "ext/jpge/jpge.h"
extern "C" {
#ifdef USE_FFMPEG
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#endif //USE_FFMPEG
}
void __cameraDummyImage(int width, int height, unsigned char** outData, int* outLen);
#if defined(USING_QT_UI)
#include <QAbstractVideoSurface>
#include <QCameraInfo>
class MyViewfinder : public QAbstractVideoSurface {
Q_OBJECT
public:
QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
bool present(const QVideoFrame &frame);
};
static int qtc_ideal_width;
static int qtc_ideal_height;
static QCamera *qt_camera;
static QAbstractVideoSurface *qt_viewfinder;
int __qt_startCapture(int width, int height);
int __qt_stopCapture();
#elif PPSSPP_PLATFORM(MAC)
std::vector<std::string> __mac_getDeviceList();
int __mac_startCapture(int width, int height);
int __mac_stopCapture();
#elif PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "Common/Thread/ThreadUtil.h"
typedef struct {
void *start;
int length;
} v4l_buf_t;
static int v4l_fd = -1;
static uint32_t v4l_format;
static int v4l_hw_width;
static int v4l_hw_height;
static int v4l_height_fixed_aspect;
static int v4l_ideal_width;
static int v4l_ideal_height;
static pthread_t v4l_thread;
static int v4l_buffer_count;
static v4l_buf_t *v4l_buffers;
std::vector<std::string> __v4l_getDeviceList();
int __v4l_startCapture(int width, int height);
int __v4l_stopCapture();
#endif
+31 -7
View File
@@ -6,9 +6,9 @@
// Currently supports: Android, Linux, Windows, Mac OSX
#include "ppsspp_config.h"
#include <QApplication>
#include <QClipboard>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QDir>
#include <QFile>
@@ -17,6 +17,8 @@
#include <QScreen>
#include <QThread>
#include <QUrl>
#include <QAbstractVideoSurface>
#include <QCameraInfo>
#include "ext/glslang/glslang/Public/ShaderLang.h"
@@ -209,6 +211,21 @@ std::string System_GetProperty(SystemProperty prop) {
}
}
class MyViewfinder : public QAbstractVideoSurface {
Q_OBJECT
public:
QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
bool present(const QVideoFrame &frame);
};
static int qtc_ideal_width;
static int qtc_ideal_height;
static QCamera *qt_camera;
static QAbstractVideoSurface *qt_viewfinder;
int __qt_startCapture(int width, int height);
int __qt_stopCapture();
std::vector<std::string> __qt_getDeviceList() {
std::vector<std::string> deviceList;
const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
@@ -268,8 +285,10 @@ int __qt_startCapture(int width, int height) {
return -1;
}
char selectedCamera[80];
sscanf(g_Config.sCameraDevice.c_str(), "%80s ", &selectedCamera[0]);
char selectedCamera[81]{};
if (sscanf(g_Config.sCameraDevice.c_str(), "%80s ", &selectedCamera[0]) != 1) {
selectedCamera[0] = '\0';
}
const QList<QCameraInfo> availableCameras = QCameraInfo::availableCameras();
if (availableCameras.size() < 1) {
@@ -809,7 +828,13 @@ bool MainUI::event(QEvent *e) {
NativeTouch(input);
break;
case QEvent::Wheel:
NativeKey(KeyInput(DEVICE_ID_MOUSE, ((QWheelEvent*)e)->delta()<0 ? NKCODE_EXT_MOUSEWHEEL_DOWN : NKCODE_EXT_MOUSEWHEEL_UP, KeyInputFlags::DOWN));
{
const QPoint wheelDelta = ((QWheelEvent *)e)->angleDelta();
const int delta = wheelDelta.y() != 0 ? wheelDelta.y() : wheelDelta.x();
if (delta != 0) {
NativeKey(KeyInput(DEVICE_ID_MOUSE, delta < 0 ? NKCODE_EXT_MOUSEWHEEL_DOWN : NKCODE_EXT_MOUSEWHEEL_UP, KeyInputFlags::DOWN));
}
}
break;
case QEvent::KeyPress:
{
@@ -994,9 +1019,6 @@ int main(int argc, char *argv[])
PROFILE_INIT();
glslang::InitializeProcess();
#if defined(Q_OS_LINUX)
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
#endif
// Qt would otherwise default to a 3.0 compatibility profile
// except on Nvidia, where Nvidia gives us the highest supported anyway
@@ -1050,3 +1072,5 @@ int main(int argc, char *argv[])
glslang::FinalizeProcess();
return ret;
}
#include "QtMain.moc"
+12 -3
View File
@@ -3,10 +3,10 @@
#include <QApplication>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QScreen>
#include "mainwindow.h"
@@ -395,11 +395,20 @@ void MainWindow::SetFullScreen(bool fullscreen) {
if (GetUIState() == UISTATE_INGAME && QApplication::overrideCursor())
QApplication::restoreOverrideCursor();
QDesktopWidget *desktop = QApplication::desktop();
int screenNum = QProcessEnvironment::systemEnvironment().value("SDL_VIDEO_FULLSCREEN_HEAD", "0").toInt();
// Move window to the center of selected screen
QRect rect = desktop->screenGeometry(screenNum);
QRect rect;
const QList<QScreen *> screens = QGuiApplication::screens();
if (!screens.empty()) {
if (screenNum < 0)
screenNum = 0;
if (screenNum >= screens.size())
screenNum = screens.size() - 1;
rect = screens[screenNum]->geometry();
} else {
rect = QRect(QPoint(0, 0), size());
}
move((rect.width() - frameGeometry().width()) / 4, (rect.height() - frameGeometry().height()) / 4);
}
}
+1
View File
@@ -13,6 +13,7 @@
#include "Common/Log.h"
#include "Core/Config.h"
#include "Core/HW/Camera.h"
#include "Core/HLE/sceUsbCam.h"
namespace {
+6 -5
View File
@@ -11,17 +11,18 @@
void *makeWindowMetalCompatible(void *window) {
// https://github.com/KhronosGroup/MoltenVK/issues/78#issuecomment-371118536
#if PPSSPP_PLATFORM(MAC)
NSView *view = ((NSWindow *)window).contentView;
NSWindow *nsWindow = (__bridge NSWindow *)window;
NSView *view = nsWindow.contentView;
assert([view isKindOfClass:[NSView class]]);
if (![view.layer isKindOfClass:[CAMetalLayer class]])
{
[view setLayer:[CAMetalLayer layer]];
[[view layer] setContentsScale:[window backingScaleFactor]];
[[view layer] setContentsScale:[nsWindow backingScaleFactor]];
}
return view.layer;
return (__bridge void *)view.layer;
#else
UIView *view = (UIView *)window;
UIView *view = (__bridge UIView *)window;
assert([view isKindOfClass:[UIView class]]);
CAMetalLayer *metalLayer = [CAMetalLayer new];
@@ -33,6 +34,6 @@ void *makeWindowMetalCompatible(void *window) {
metalLayer.drawableSize = viewSize;
metalLayer.pixelFormat = (MTLPixelFormat)80;//BGRA8Unorm==80
[view.layer addSublayer:metalLayer];
return metalLayer;
return (__bridge void *)metalLayer;
#endif
}
+382 -6
View File
@@ -112,7 +112,374 @@ struct WindowState {
};
static WindowState g_windowState;
int getDisplayNumber(void) {
#if PPSSPP_PLATFORM(MAC)
// These are from MacCameraHelper.mm.
std::vector<std::string> __mac_getDeviceList();
int __mac_startCapture(int width, int height);
int __mac_stopCapture();
#endif
#if PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
#include "Core/HLE/sceUsbCam.h"
#include "ext/jpge/jpgd.h"
#include "ext/jpge/jpge.h"
extern "C" {
#ifdef USE_FFMPEG
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#endif //USE_FFMPEG
}
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "Common/Thread/ThreadUtil.h"
typedef struct {
void *start;
int length;
} v4l_buf_t;
static int v4l_fd = -1;
static uint32_t v4l_format;
static int v4l_hw_width;
static int v4l_hw_height;
static int v4l_height_fixed_aspect;
static int v4l_ideal_width;
static int v4l_ideal_height;
static pthread_t v4l_thread;
static int v4l_buffer_count;
static v4l_buf_t *v4l_buffers;
std::vector<std::string> __v4l_getDeviceList();
int __v4l_startCapture(int width, int height);
int __v4l_stopCapture();
#ifdef USE_FFMPEG
void convert_frame(int inw, int inh, unsigned char *inData, AVPixelFormat inFormat,
int outw, int outh, unsigned char **outData, int *outLen) {
struct SwsContext *sws_context = sws_getContext(
inw, inh, inFormat,
outw, outh, AV_PIX_FMT_RGB24,
SWS_BICUBIC, NULL, NULL, NULL);
// resize
uint8_t *src[4] = {0};
uint8_t *dst[4] = {0};
int srcStride[4], dstStride[4];
unsigned char *rgbData = (unsigned char*)malloc(outw * outh * 4);
av_image_fill_linesizes(srcStride, inFormat, inw);
av_image_fill_linesizes(dstStride, AV_PIX_FMT_RGB24, outw);
av_image_fill_pointers(src, inFormat, inh, inData, srcStride);
av_image_fill_pointers(dst, AV_PIX_FMT_RGB24, outh, rgbData, dstStride);
sws_scale(sws_context,
src, srcStride, 0, inh,
dst, dstStride);
// compress jpeg
*outLen = outw * outh * 2;
*outData = (unsigned char*)malloc(*outLen);
jpge::params params;
params.m_quality = 60;
params.m_subsampling = jpge::H2V2;
params.m_two_pass_flag = false;
jpge::compress_image_to_jpeg_file_in_memory(
*outData, *outLen, outw, outh, 3, rgbData, params);
free(rgbData);
}
#endif //USE_FFMPEG
#endif
#if PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
std::vector<std::string> __v4l_getDeviceList() {
std::vector<std::string> deviceList;
#ifdef USE_FFMPEG
for (int i = 0; i < 64; i++) {
char path[256];
snprintf(path, sizeof(path), "/dev/video%d", i);
if (access(path, F_OK) < 0) {
break;
}
int fd = -1;
if((fd = open(path, O_RDONLY)) < 0) {
ERROR_LOG(Log::HLE, "Cannot open '%s'; errno=%d(%s)", path, errno, strerror(errno));
continue;
}
struct v4l2_capability video_cap;
if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) < 0) {
ERROR_LOG(Log::HLE, "VIDIOC_QUERYCAP");
goto cont;
} else {
char device[256];
snprintf(device, sizeof(device), "%d:%s", i, video_cap.card);
deviceList.push_back(device);
}
cont:
close(fd);
fd = -1;
}
#endif //USE_FFMPEG
return deviceList;
}
void *v4l_loop(void *data) {
#ifdef USE_FFMPEG
SetCurrentThreadName("v4l_loop");
while (v4l_fd >= 0) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_DQBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_DQBUF; errno=%d(%s)", errno, strerror(errno));
switch (errno) {
case EAGAIN:
continue;
default:
return nullptr;
}
}
unsigned char *jpegData = nullptr;
int jpegLen = 0;
if (v4l_format == V4L2_PIX_FMT_YUYV) {
convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)v4l_buffers[buf.index].start, AV_PIX_FMT_YUYV422,
v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen);
} else if (v4l_format == V4L2_PIX_FMT_JPEG
|| v4l_format == V4L2_PIX_FMT_MJPEG) {
// decompress jpeg
int width, height, req_comps;
unsigned char *rgbData = jpgd::decompress_jpeg_image_from_memory(
(unsigned char*)v4l_buffers[buf.index].start, buf.bytesused, &width, &height, &req_comps, 3);
convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)rgbData, AV_PIX_FMT_RGB24,
v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen);
free(rgbData);
}
if (jpegData) {
Camera::pushCameraImage(jpegLen, jpegData);
free(jpegData);
jpegData = nullptr;
}
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QBUF");
return nullptr;
}
}
#endif //USE_FFMPEG
return nullptr;
}
int __v4l_startCapture(int ideal_width, int ideal_height) {
#ifdef USE_FFMPEG
if (v4l_fd >= 0) {
__v4l_stopCapture();
}
v4l_ideal_width = ideal_width;
v4l_ideal_height = ideal_height;
int dev_index = 0;
char dev_name[64];
sscanf(g_Config.sCameraDevice.c_str(), "%d:", &dev_index);
snprintf(dev_name, sizeof(dev_name), "/dev/video%d", dev_index);
if ((v4l_fd = open(dev_name, O_RDWR)) == -1) {
ERROR_LOG(Log::HLE, "Cannot open '%s'; errno=%d(%s)", dev_name, errno, strerror(errno));
return -1;
}
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
if (ioctl(v4l_fd, VIDIOC_QUERYCAP, &cap) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QUERYCAP");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
ERROR_LOG(Log::HLE, "V4L2_CAP_VIDEO_CAPTURE");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
ERROR_LOG(Log::HLE, "V4L2_CAP_STREAMING");
return -1;
}
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = 0;
// select a pixel format
struct v4l2_fmtdesc desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(v4l_fd, VIDIOC_ENUM_FMT, &desc) == 0) {
desc.index++;
INFO_LOG(Log::HLE, "V4L2: pixel format supported: %s", desc.description);
if (fmt.fmt.pix.pixelformat != 0) {
continue;
} else if (desc.pixelformat == V4L2_PIX_FMT_YUYV
|| desc.pixelformat == V4L2_PIX_FMT_JPEG
|| desc.pixelformat == V4L2_PIX_FMT_MJPEG) {
INFO_LOG(Log::HLE, "V4L2: %s selected", desc.description);
fmt.fmt.pix.pixelformat = desc.pixelformat;
v4l_format = desc.pixelformat;
}
}
if (fmt.fmt.pix.pixelformat == 0) {
ERROR_LOG(Log::HLE, "V4L2: No supported format found");
return -1;
}
// select a frame size
fmt.fmt.pix.width = 0;
fmt.fmt.pix.height = 0;
struct v4l2_frmsizeenum frmsize;
memset(&frmsize, 0, sizeof(frmsize));
frmsize.pixel_format = fmt.fmt.pix.pixelformat;
while (ioctl(v4l_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) {
frmsize.index++;
if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
INFO_LOG(Log::HLE, "V4L2: frame size supported: %dx%d", frmsize.discrete.width, frmsize.discrete.height);
bool matchesIdeal = frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height;
bool zeroPix = fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0;
bool pixLarger = frmsize.discrete.width < fmt.fmt.pix.width && frmsize.discrete.height < fmt.fmt.pix.height;
if (matchesIdeal && (zeroPix || pixLarger)) {
fmt.fmt.pix.width = frmsize.discrete.width;
fmt.fmt.pix.height = frmsize.discrete.height;
}
}
}
if (fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0) {
fmt.fmt.pix.width = ideal_width;
fmt.fmt.pix.height = ideal_height;
}
INFO_LOG(Log::HLE, "V4L2: asking for %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
if (ioctl(v4l_fd, VIDIOC_S_FMT, &fmt) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_S_FMT");
return -1;
}
v4l_hw_width = fmt.fmt.pix.width;
v4l_hw_height = fmt.fmt.pix.height;
INFO_LOG(Log::HLE, "V4L2: will receive %dx%d", v4l_hw_width, v4l_hw_height);
v4l_height_fixed_aspect = v4l_hw_width * ideal_height / ideal_width;
INFO_LOG(Log::HLE, "V4L2: will use %dx%d", v4l_hw_width, v4l_height_fixed_aspect);
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_REQBUFS, &req) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_REQBUFS");
return -1;
}
v4l_buffer_count = req.count;
INFO_LOG(Log::HLE, "V4L2: buffer count: %d", v4l_buffer_count);
v4l_buffers = (v4l_buf_t*) calloc(v4l_buffer_count, sizeof(v4l_buf_t));
for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = buf_id;
if (ioctl(v4l_fd, VIDIOC_QUERYBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QUERYBUF");
return -1;
}
v4l_buffers[buf_id].length = buf.length;
v4l_buffers[buf_id].start = mmap(NULL,
buf.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
v4l_fd, buf.m.offset);
if (v4l_buffers[buf_id].start == MAP_FAILED) {
ERROR_LOG(Log::HLE, "MAP_FAILED");
return -1;
}
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = buf_id;
if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_QBUF");
return -1;
}
}
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(v4l_fd, VIDIOC_STREAMON, &type) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_STREAMON");
return -1;
}
pthread_create(&v4l_thread, NULL, v4l_loop, NULL);
#endif //USE_FFMPEG
return 0;
}
int __v4l_stopCapture() {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (v4l_fd < 0) {
goto exit;
}
if (ioctl(v4l_fd, VIDIOC_STREAMOFF, &type) == -1) {
ERROR_LOG(Log::HLE, "VIDIOC_STREAMOFF");
goto exit;
}
for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) {
if (munmap(v4l_buffers[buf_id].start, v4l_buffers[buf_id].length) == -1) {
ERROR_LOG(Log::HLE, "munmap");
goto exit;
}
}
if (close(v4l_fd) == -1) {
ERROR_LOG(Log::HLE, "close");
goto exit;
}
v4l_fd = -1;
//pthread_join(v4l_thread, NULL);
exit:
v4l_fd = -1;
return 0;
}
#endif // PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
static int getDisplayNumber(void) {
int displayNumber = 0;
char * displayNumberStr;
@@ -126,7 +493,7 @@ int getDisplayNumber(void) {
return displayNumber;
}
void sdl_mixaudio_callback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount) {
static void sdl_mixaudio_callback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount) {
(void)total_amount;
if (additional_amount <= 0) {
return;
@@ -505,18 +872,27 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
return true;
}
case SystemRequestType::CAMERA_COMMAND:
#if PPSSPP_PLATFORM(MAC)
{
if (!strncmp(param1.c_str(), "startVideo", 10)) {
int width = 0, height = 0;
sscanf(param1.c_str(), "startVideo_%dx%d", &width, &height);
#if PPSSPP_PLATFORM(MAC)
__mac_startCapture(width, height);
#elif PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
__v4l_startCapture(width, height);
#endif
} else if (!strcmp(param1.c_str(), "stopVideo")) {
#if PPSSPP_PLATFORM(MAC)
__mac_stopCapture();
#elif PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
__v4l_stopCapture();
#endif
} else {
ERROR_LOG(Log::System, "Unknown camera command: %s", param1.c_str());
return false;
}
return true;
#else
return false;
#endif
}
case SystemRequestType::NOTIFY_UI_EVENT:
{
switch ((UIEventNotification)param3) {
+1 -1
View File
@@ -338,7 +338,7 @@ void RemoteISOScreen::CreateConnectTab(UI::ViewGroup *tab) {
PermissionStatus status = System_GetPermissionStatus(SYSTEM_PERMISSION_LOCAL_NETWORK);
if (status != PERMISSION_STATUS_GRANTED) {
// Proceed with local network functionality
tab->Add(new Choice(ri->T("Ask for network permission")))->OnClick.Add([this](UI::EventParams &e) {
tab->Add(new Choice(ri->T("Ask for network permission")))->OnClick.Add([](UI::EventParams &e) {
System_AskForPermission(SYSTEM_PERMISSION_LOCAL_NETWORK);
});
return;
+5
View File
@@ -677,6 +677,11 @@ void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
}
}
// Stub
std::vector<std::string> System_GetCameraDeviceList() {
return std::vector<std::string>();
}
void System_Vibrate(int length_ms) {
#if _M_ARM
if (length_ms == -1 || length_ms == -3)
+1
View File
@@ -106,6 +106,7 @@ void System_Notify(SystemNotification notification) {}
void System_PostUIMessage(UIMessage message, std::string_view param) {}
void System_RunOnMainThread(std::function<void()>) {}
std::vector<std::string> System_GetCameraDeviceList() { return std::vector<std::string>(); }
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; }
+4
View File
@@ -6,6 +6,8 @@
#include "../ppsspp_config.h"
#if PPSSPP_PLATFORM(IOS_APP_STORE)
// Only one operation can be in progress at once.
@implementation IAPManager {
#ifdef USE_IAP
@@ -229,3 +231,5 @@ static bool SafeStringEqual(NSString *a, NSString *b) {
#endif
@end
#endif
+4 -1
View File
@@ -42,4 +42,7 @@ if(NOT MSVC)
target_link_libraries(ppsspp_libretro "-Wl,-Bsymbolic")
endif()
endif()
target_link_libraries(ppsspp_libretro ${LinkCommon})
target_link_libraries(ppsspp_libretro core ${CMAKE_THREAD_LIBS_INIT})
if(ANDROID)
target_link_libraries(ppsspp_libretro log)
endif()
+2 -6
View File
@@ -2025,15 +2025,11 @@ void System_AudioPushSamples(const int32_t *audio, int numSamples, float volume)
void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; }
void System_AudioClear() {}
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
std::vector<std::string> System_GetCameraDeviceList() { return std::vector<std::string>(); }
bool System_AudioRecordingIsAvailable() { return false; }
bool System_AudioRecordingState() { return false; }
#else
// Stub for now.
std::vector<std::string> System_GetCameraDeviceList() {
return std::vector<std::string>();
}
#endif
// Stub for now.
std::vector<std::string> System_GetCameraDeviceList() { return std::vector<std::string>(); }
// TODO: To avoid having to define these here, these should probably be turned into system "requests".
bool NativeSaveSecret(std::string_view nameOfSecret, std::string_view data) { return false; }
+1
View File
@@ -127,6 +127,7 @@ void System_AudioClear() {}
void System_AudioPushSamples(const s32 *audio, int numSamples, float volume) {}
bool System_SendDebugOutput(std::string_view data) { return false; }
void System_SendDebugScreenshot(const uint8_t *data, int width, int height) {}
std::vector<std::string> System_GetCameraDeviceList() { return std::vector<std::string>(); }
// Temporary hacks around annoying linking errors. Copied from Headless.
void NativeFrame(GraphicsContext *graphicsContext) {}