mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Buildfixes, dependency shuffling to make things more logical
This commit is contained in:
1 parent
dd8c282a26
commit
afe4d5beaf
16 files changed
+558
-506
No files matched your search
+104
-89
@@ -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
@@ -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
@@ -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)
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Common/Log.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/HW/Camera.h"
|
||||
#include "Core/HLE/sceUsbCam.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'; }
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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; }
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
Reference in new issue
Block a user