Merge pull request #21963 from hrydgard/camera-request

Camera: Use the abstraction on more platforms, refactor CMakeLists.txt
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-07-24 15:13:09 +02:00
commit dcb512d2eb
20 files changed
+804 -709

No files matched your search

+195 -171
View File
@@ -268,14 +268,6 @@ if(ANDROID)
set(USING_GLES2 ON)
endif()
if(ANDROID AND NOT LIBRETRO)
set(CoreLibName ppsspp_jni)
set(CoreLinkType SHARED)
else()
set(CoreLibName Core)
set(CoreLinkType STATIC)
endif()
if(NOT ANDROID AND NOT WIN32 AND (NOT APPLE OR IOS))
set(HTTPS_NOT_AVAILABLE ON)
endif()
@@ -569,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
@@ -659,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
@@ -865,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
@@ -956,6 +904,10 @@ add_library(Common STATIC
Common/SysError.cpp
Common/TimeUtil.cpp
Common/TimeUtil.h
ext/jpge/jpgd.cpp
ext/jpge/jpgd.h
ext/jpge/jpge.cpp
ext/jpge/jpge.h
)
if(LIBRETRO)
@@ -1279,7 +1231,6 @@ else()
)
endif()
target_compile_definitions(libzip PRIVATE HAVE_STDBOOL_H)
target_link_libraries(libzip)
include_directories(ext/libzip)
set(LIBZIP_LIBRARY libzip)
endif()
@@ -1300,7 +1251,6 @@ add_library(7zip STATIC
ext/lzma-sdk/Lzma2Dec.c
ext/lzma-sdk/LzmaDec.c
)
target_link_libraries(7zip)
include_directories(ext/lzma-sdk)
set(LIB7ZIP_LIBRARY 7zip)
@@ -1386,20 +1336,22 @@ add_library(pugixml STATIC
)
set(nativeExtra)
set(nativeExtraLibs)
set(targetExtra)
set(targetExtraLibs)
set(UISource)
if(OPENXR AND NOT ARMV7_DEVICE)
list(APPEND nativeExtraLibs openxr_loader)
list(APPEND targetExtraLibs openxr_loader)
endif()
if(IOS OR MACOSX)
list(APPEND nativeExtra
list(APPEND targetExtra
Common/Render/Text/draw_text_cocoa.mm
Common/Render/Text/draw_text_cocoa.h)
endif()
if(ANDROID)
list(APPEND NativeAppSource
list(APPEND AndroidJniSource
android/jni/app-android.cpp
android/jni/AndroidJavaGLContext.cpp
android/jni/AndroidJavaGLContext.h
@@ -1413,7 +1365,7 @@ if(ANDROID)
)
# No target
elseif(IOS AND NOT LIBRETRO)
list(APPEND nativeExtra
list(APPEND targetExtra
ios/main.mm
ios/AppDelegate.mm
ios/AppDelegate.h
@@ -1445,23 +1397,26 @@ elseif(IOS AND NOT LIBRETRO)
Common/Battery/AppleBatteryClient.m
)
list(APPEND nativeExtraLibs "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework CoreMotion -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreText -framework CoreVideo -framework CoreMedia -framework CoreServices -framework Metal -framework IOSurface -framework Photos" )
list(APPEND targetExtraLibs "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework CoreMotion -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreText -framework CoreVideo -framework CoreMedia -framework CoreServices -framework Metal -framework IOSurface -framework Photos" )
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
list(APPEND nativeExtraLibs "-weak_framework GameController")
list(APPEND targetExtraLibs "-weak_framework GameController")
endif()
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/PhotosUI.framework")
list(APPEND nativeExtraLibs "-weak_framework PhotosUI")
list(APPEND targetExtraLibs "-weak_framework PhotosUI")
endif()
if(NOT ICONV_LIBRARY)
list(APPEND nativeExtraLibs iconv)
list(APPEND targetExtraLibs iconv)
endif()
# 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
@@ -1476,10 +1431,13 @@ elseif(IOS AND NOT LIBRETRO)
set(TargetBin PPSSPP)
elseif(IOS AND LIBRETRO)
list(APPEND nativeExtraLibs "-framework GLKit")
list(APPEND targetExtraLibs "-framework GLKit")
elseif(USING_QT_UI)
set(CMAKE_AUTOMOC ON)
find_package(Qt5 COMPONENTS OpenGL Gui Core Multimedia)
if(NOT Qt5_FOUND)
message(FATAL_ERROR "Qt5 not found for USING_QT_UI=ON. On macOS with Homebrew, install qt@5 and set CMAKE_PREFIX_PATH to /opt/homebrew/opt/qt@5 (or use ./b.sh --qtbrew).")
endif()
list(APPEND NativeAppSource
Qt/QtMain.cpp
Qt/QtMain.h
@@ -1496,21 +1454,25 @@ elseif(USING_QT_UI)
set_source_files_properties(Common/Battery/AppleBatteryClient.m
Common/Render/Text/draw_text_cocoa.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc)
list(APPEND nativeExtraLibs ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY})
list(APPEND targetExtraLibs ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY})
endif()
include_directories(Qt)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
list(APPEND nativeExtraLibs Qt5::OpenGL Qt5::Gui Qt5::Core Qt5::Multimedia)
list(APPEND targetExtraLibs Qt5::OpenGL Qt5::Gui Qt5::Core Qt5::Multimedia)
set(TargetBin PPSSPPQt)
list(APPEND targetExtra
Common/Render/Text/draw_text_qt.cpp
Common/Render/Text/draw_text_qt.h
)
# Enable SDL joystick if SDL is found
if(SDL_LIB_TARGET)
add_compile_definitions(SDL)
list(APPEND nativeExtra
list(APPEND targetExtra
SDL/SDLJoystick.h
SDL/SDLJoystick.cpp
)
list(APPEND nativeExtraLibs ${SDL_LIB_TARGET})
list(APPEND targetExtraLibs ${SDL_LIB_TARGET})
endif()
elseif(WIN32)
@@ -1528,25 +1490,25 @@ else()
endif()
# Require SDL
add_compile_definitions(SDL)
list(APPEND nativeExtra
list(APPEND targetExtra
SDL/SDLJoystick.h
SDL/SDLJoystick.cpp
SDL/SDLMain.cpp
SDL/SDLGLGraphicsContext.cpp
)
if(NOT USE_LIBNX)
list(APPEND nativeExtra
list(APPEND targetExtra
SDL/SDLVulkanGraphicsContext.cpp
)
endif()
if(SDL_TTF_LIB_TARGET)
list(APPEND nativeExtraLibs ${SDL_TTF_LIB_TARGET})
list(APPEND targetExtraLibs ${SDL_TTF_LIB_TARGET})
endif()
if(FONTCONFIG_LIB_TARGET)
list(APPEND nativeExtraLibs ${FONTCONFIG_LIB_TARGET})
list(APPEND targetExtraLibs ${FONTCONFIG_LIB_TARGET})
endif()
if(APPLE)
list(APPEND nativeExtra
list(APPEND targetExtra
SDL/SDLCocoaMetalLayer.h
SDL/SDLCocoaMetalLayer.mm
SDL/CocoaBarItems.mm
@@ -1558,21 +1520,28 @@ 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
Common/Battery/AppleBatteryClient.m
Common/Render/Text/draw_text_cocoa.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc)
list(APPEND nativeExtraLibs ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} "-framework AVFoundation" "-framework CoreMedia" "-framework CoreVideo")
list(APPEND nativeExtraLibs ${SDL_LIB_TARGET})
elseif(USING_EGL)
list(APPEND nativeExtraLibs pthread ${SDL_LIB_TARGET})
list(APPEND targetExtraLibs ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} "-framework AVFoundation" "-framework CoreMedia" "-framework CoreVideo")
list(APPEND targetExtraLibs ${SDL_LIB_TARGET})
else()
list(APPEND nativeExtraLibs ${SDL_LIB_TARGET})
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()
@@ -1581,13 +1550,13 @@ if(WIN32)
endif()
if(NOT LIBRETRO)
list(APPEND NativeAppSource
list(APPEND UISource
UI/AudioCommon.h
UI/AudioCommon.cpp
)
endif()
list(APPEND NativeAppSource
list(APPEND UISource
UI/ImDebugger/ImDebugger.cpp
UI/ImDebugger/ImDebugger.h
UI/ImDebugger/ImGe.cpp
@@ -1698,6 +1667,11 @@ list(APPEND NativeAppSource
UI/RetroAchievementScreens.h
)
if(NOT LIBRETRO)
add_library(ppsspp_ui STATIC ${UISource})
target_link_libraries(ppsspp_ui Common core)
endif()
if(ANDROID)
if(ARM)
list(APPEND NativeAppSource android/jni/ArmEmitterTest.cpp)
@@ -1706,26 +1680,12 @@ if(ANDROID)
endif()
if (NOT LIBRETRO)
list(APPEND nativeExtra ${NativeAppSource})
list(APPEND targetExtra ${NativeAppSource})
endif()
endif()
if (IOS AND NOT LIBRETRO)
list(APPEND nativeExtra ${NativeAppSource})
endif()
add_library(native STATIC
${nativeExtra}
Common/Render/Text/draw_text_qt.cpp
Common/Render/Text/draw_text_qt.h
ext/jpge/jpgd.cpp
ext/jpge/jpgd.h
ext/jpge/jpge.cpp
ext/jpge/jpge.h
)
if(LIBRETRO)
target_include_directories(native PRIVATE libretro/libretro-common/include)
list(APPEND targetExtra ${NativeAppSource})
endif()
if(LINUX AND NOT ANDROID)
@@ -1737,20 +1697,6 @@ if(ANDROID OR (LINUX AND ARM_DEVICE) OR (LINUX AND RISCV64) OR (LINUX AND LOONGA
set(ATOMIC_LIB atomic)
endif()
target_link_libraries(native ${LIBZIP_LIBRARY} ${LIB7ZIP_LIBRARY} ${PNG_LIBRARIES} ${BASISU_LIBRARIES} ${ZLIB_LIBRARY} pugixml vma gason udis86 ${RT_LIB} ${nativeExtraLibs} ${ATOMIC_LIB} Common)
if(TARGET Ext::GLEW)
target_link_libraries(native Ext::GLEW)
endif()
if(ANDROID)
target_link_libraries(native log EGL OpenSLES)
elseif(WIN32)
target_link_libraries(native ws2_32 winmm)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "^(DragonFly|FreeBSD|NetBSD)$")
target_link_libraries(native execinfo)
endif()
add_library(kirk STATIC
ext/libkirk/AES.c
ext/libkirk/AES.h
@@ -1788,6 +1734,8 @@ add_library(xxhash STATIC
)
target_include_directories(xxhash PRIVATE ext/xxhash)
target_link_libraries(Common ${LIBZIP_LIBRARY} ${LIB7ZIP_LIBRARY} ${PNG_LIBRARIES} ${BASISU_LIBRARIES} ${ZLIB_LIBRARY} pugixml vma gason udis86 ${RT_LIB} ${ATOMIC_LIB})
set(CoreExtra)
set(CoreExtraLibs)
@@ -2146,11 +2094,8 @@ if(NOT LIBRETRO)
)
endif()
# 'ppsspp_jni' on ANDROID, 'Core' everywhere else
# SHARED on ANDROID, STATIC everywhere else
add_library(${CoreLibName} ${CoreLinkType}
add_library(core STATIC
${CoreExtra}
${CommonJIT}
${CmdLine}
Core/Config.cpp
Core/Config.h
@@ -2538,6 +2483,16 @@ add_library(${CoreLibName} ${CoreLinkType}
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
@@ -2596,7 +2551,7 @@ if((MACOSX OR IOS) AND NOT LIBRETRO)
endif()
if(LIBRETRO)
target_include_directories(${CoreLibName} PRIVATE libretro/libretro-common/include)
target_include_directories(core PRIVATE libretro/libretro-common/include)
endif()
if(ANDROID)
@@ -2629,8 +2584,8 @@ endif()
if(USE_SYSTEM_ZSTD)
find_package(ZSTD REQUIRED)
target_include_directories(${CoreLibName} PRIVATE ${ZSTD_INCLUDE_DIR})
target_link_libraries(${CoreLibName} ${ZSTD_LIBRARY})
target_include_directories(core PRIVATE ${ZSTD_INCLUDE_DIR})
list(APPEND CoreExtraLibs ${ZSTD_LIBRARY})
else()
add_subdirectory(ext/zstd-build)
list(APPEND CoreExtraLibs libzstd_static)
@@ -2646,28 +2601,28 @@ else()
include_directories(ext/libchdr/include)
endif()
target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos minimp3 at3_standalone lua ${GlslangLibs}
target_link_libraries(core Common chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos minimp3 at3_standalone lua ${GlslangLibs}
${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS})
# Winsock
if(WIN32)
target_link_libraries(${CoreLibName} ws2_32)
target_link_libraries(core ws2_32)
endif()
if(NOT HTTPS_NOT_AVAILABLE)
target_link_libraries(${CoreLibName} naett)
target_link_libraries(core naett)
endif()
target_compile_features(${CoreLibName} PUBLIC cxx_std_17)
target_compile_features(core PUBLIC cxx_std_17)
if(FFmpeg_FOUND)
target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1)
target_compile_definitions(core PRIVATE USE_FFMPEG=1)
if (HAVE_LIBAVCODEC_CONST_AVCODEC)
target_compile_definitions(${CoreLibName} PRIVATE HAVE_LIBAVCODEC_CONST_AVCODEC=1)
target_compile_definitions(core PRIVATE HAVE_LIBAVCODEC_CONST_AVCODEC=1)
endif()
set_target_properties(${CoreLibName} PROPERTIES NO_SYSTEM_FROM_IMPORTED true)
target_include_directories(${CoreLibName} BEFORE PUBLIC ${FFmpeg_INCLUDE_avcodec} ${FFmpeg_INCLUDE_avformat})
target_link_libraries(${CoreLibName}
set_target_properties(core PROPERTIES NO_SYSTEM_FROM_IMPORTED true)
target_include_directories(core BEFORE PUBLIC ${FFmpeg_INCLUDE_avcodec} ${FFmpeg_INCLUDE_avformat})
target_link_libraries(core
FFmpeg::avcodec
FFmpeg::avformat
FFmpeg::avutil
@@ -2676,9 +2631,9 @@ if(FFmpeg_FOUND)
${ZLIB_LIBRARY}
)
elseif(BUILD_BUNDLED_FFMPEG)
target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1)
set_target_properties(${CoreLibName} PROPERTIES NO_SYSTEM_FROM_IMPORTED true)
target_link_libraries(${CoreLibName}
target_compile_definitions(core PRIVATE USE_FFMPEG=1)
set_target_properties(core PROPERTIES NO_SYSTEM_FROM_IMPORTED true)
target_link_libraries(core
avcodec
avformat
avutil
@@ -2691,15 +2646,15 @@ endif()
# Discord integration
if(USE_DISCORD AND NOT IOS AND NOT LIBRETRO)
add_compile_definitions(USE_DISCORD=1)
target_link_libraries(${CoreLibName} discord-rpc)
target_link_libraries(core discord-rpc)
endif()
# miniUPnPc integration (MiniUPnPc supposed to works on any POSIX system, not sure if some of these are redundant/not needed tho)
if(USE_MINIUPNPC)
if(USE_SYSTEM_MINIUPNPC)
find_package(MINIUPNPC REQUIRED)
target_include_directories(${CoreLibName} PRIVATE ${MINIUPNP_INCLUDE_DIR})
target_link_libraries(${CoreLibName} ${MINIUPNP_LIBRARY})
target_include_directories(core PRIVATE ${MINIUPNP_INCLUDE_DIR})
target_link_libraries(core ${MINIUPNP_LIBRARY})
add_compile_definitions(WITH_UPNP USE_SYSTEM_MINIUPNPC)
else()
set (MINIUPNPC_VERSION 2.2) # used by miniupnpcstrings.h.cmake
@@ -2764,7 +2719,7 @@ if(USE_MINIUPNPC)
endif()
if (UPNPC_BUILD_STATIC)
add_library(miniupnpc STATIC ${MINIUPNPC_SOURCES})
target_link_libraries(${CoreLibName} miniupnpc ${LDLIBS})
target_link_libraries(core miniupnpc ${LDLIBS})
set(UPNPC_LIBRARY miniupnpc)
if (MSVC)
# Suppress noise warnings
@@ -2777,7 +2732,7 @@ if(USE_MINIUPNPC)
endif()
endif()
setup_target_project(${CoreLibName} Core)
setup_target_project(core Core)
# Generate git-version at build time.
add_custom_target(GitVersion DEPENDS something_that_never_exists)
@@ -2796,7 +2751,22 @@ add_custom_command(OUTPUT something_that_never_exists
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/git-version.cpp
PROPERTIES GENERATED TRUE
SKIP_AUTOMOC ON)
add_dependencies(${CoreLibName} GitVersion)
add_dependencies(core GitVersion)
if(ANDROID AND NOT LIBRETRO)
add_library(ppsspp_jni SHARED ${AndroidJniSource})
target_link_libraries(ppsspp_jni core)
if(TARGET ppsspp_ui)
target_link_libraries(ppsspp_jni ppsspp_ui)
endif()
if(TARGET native)
target_link_libraries(ppsspp_jni native)
endif()
if(ARM64)
# Support 16kb page size on Android
target_link_options(ppsspp_jni PRIVATE "-Wl,-z,max-page-size=16384")
endif()
endif()
set(WindowsFiles
Windows/WindowsAudio.cpp
@@ -2898,13 +2868,6 @@ set(WindowsFiles
Windows/stdafx.h
)
if(ANDROID AND ARM64)
# Support 16kb page size on Android
target_link_options(${CoreLibName} PRIVATE "-Wl,-z,max-page-size=16384")
endif()
list(APPEND LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT})
if(WIN32)
#setup_target_project(${TargetBin} Windows)
list(APPEND NativeAppSource ${WindowsFiles})
@@ -2960,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
@@ -2977,7 +2953,16 @@ if(HEADLESS)
)
endif()
add_executable(PPSSPPHeadless ${HeadlessSource})
target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY} ${LinkCommon})
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()
@@ -3002,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)
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()
@@ -3043,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()
@@ -3115,10 +3122,27 @@ if(TargetBin)
else()
add_executable(${TargetBin} ${NativeAppSource})
endif()
if(targetExtra)
target_sources(${TargetBin} PRIVATE ${targetExtra})
endif()
if(ANDROID AND ARM64)
target_link_options(${TargetBin} PRIVATE "-Wl,-z,max-page-size=16384")
endif()
target_link_libraries(${TargetBin} ${LinkCommon} Common)
if(TARGET ppsspp_ui)
target_link_libraries(${TargetBin} ${CMAKE_THREAD_LIBS_INIT} ${targetExtraLibs} ppsspp_ui)
else()
target_link_libraries(${TargetBin} ${CMAKE_THREAD_LIBS_INIT} ${targetExtraLibs} core)
endif()
endif()
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
+3 -19
View File
@@ -332,16 +332,9 @@ std::vector<std::string> Camera::getDeviceList() {
if (winCamera) {
return winCamera->getDeviceList();
}
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
#else
return System_GetCameraDeviceList();
#elif PPSSPP_PLATFORM(MAC)
return __mac_getDeviceList();
#elif defined(USING_QT_UI) // Qt:macOS / Qt:Linux
return __qt_getDeviceList();
#elif PPSSPP_PLATFORM(LINUX) // SDL:Linux
return __v4l_getDeviceList();
#endif
return std::vector<std::string>();
}
int Camera::startCapture() {
@@ -359,15 +352,10 @@ int Camera::startCapture() {
void* resolution = static_cast<void*>(new std::vector<int>({ width, height }));
winCamera->sendMessage({ CAPTUREDEVICE_COMMAND::START, resolution });
}
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || defined(USING_QT_UI)
#elif PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || defined(USING_QT_UI)
char command[40] = {0};
snprintf(command, sizeof(command), "startVideo_%dx%d", width, height);
System_CameraCommand(command);
#elif PPSSPP_PLATFORM(MAC)
__mac_startCapture(width, height);
#elif PPSSPP_PLATFORM(LINUX)
__v4l_startCapture(width, height);
#else
ERROR_LOG(Log::HLE, "%s not implemented", __FUNCTION__);
#endif
return 0;
@@ -379,12 +367,8 @@ int Camera::stopCapture() {
if (winCamera) {
winCamera->sendMessage({ CAPTUREDEVICE_COMMAND::STOP, nullptr });
}
#elif 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(MAC)
__mac_stopCapture();
#elif PPSSPP_PLATFORM(LINUX)
__v4l_stopCapture();
#else
ERROR_LOG(Log::HLE, "%s not implemented", __FUNCTION__);
#endif
+2 -425
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,389 +50,3 @@ void __cameraDummyImage(int width, int height, unsigned char** outData, int* out
free(rgbData);
#endif //USE_FFMPEG
}
#if defined(USING_QT_UI)
std::vector<std::string> __qt_getDeviceList() {
std::vector<std::string> deviceList;
const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
for (const QCameraInfo &cameraInfo : cameras) {
deviceList.push_back(cameraInfo.deviceName().toStdString()
+ " (" + cameraInfo.description().toStdString() + ")");
}
return deviceList;
}
QList<QVideoFrame::PixelFormat> MyViewfinder::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const {
Q_UNUSED(handleType);
// Return the formats you will support
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_YUYV
;
}
bool MyViewfinder::present(const QVideoFrame &frame) {
#ifdef USE_FFMPEG
if (frame.isValid()) {
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
unsigned char *jpegData = nullptr;
int jpegLen = 0;
QVideoFrame::PixelFormat frameFormat = cloneFrame.pixelFormat();
if (frameFormat == QVideoFrame::Format_RGB24) {
convert_frame(cloneFrame.size().width(), cloneFrame.size().height(),
(unsigned char*)cloneFrame.bits(), AV_PIX_FMT_RGB24,
qtc_ideal_width, qtc_ideal_height, &jpegData, &jpegLen);
} else if (frameFormat == QVideoFrame::Format_YUYV) {
convert_frame(cloneFrame.size().width(), cloneFrame.size().height(),
(unsigned char*)cloneFrame.bits(), AV_PIX_FMT_YUYV422,
qtc_ideal_width, qtc_ideal_height, &jpegData, &jpegLen);
}
if (jpegData) {
Camera::pushCameraImage(jpegLen, jpegData);
free(jpegData);
jpegData = nullptr;
}
cloneFrame.unmap();
return true;
}
#endif //USE_FFMPEG
return false;
}
int __qt_startCapture(int width, int height) {
if (qt_camera != nullptr) {
ERROR_LOG(Log::HLE, "camera already started");
return -1;
}
char selectedCamera[80];
sscanf(g_Config.sCameraDevice.c_str(), "%80s ", &selectedCamera[0]);
const QList<QCameraInfo> availableCameras = QCameraInfo::availableCameras();
if (availableCameras.size() < 1) {
delete qt_camera;
qt_camera = nullptr;
ERROR_LOG(Log::HLE, "no camera found");
return -1;
}
for (const QCameraInfo &cameraInfo : availableCameras) {
if (cameraInfo.deviceName() == selectedCamera) {
qt_camera = new QCamera(cameraInfo);
}
}
if (qt_camera == nullptr) {
qt_camera = new QCamera();
if (qt_camera == nullptr) {
ERROR_LOG(Log::HLE, "cannot open camera");
return -1;
}
}
qtc_ideal_width = width;
qtc_ideal_height = height;
qt_viewfinder = new MyViewfinder;
QCameraViewfinderSettings viewfinderSettings = qt_camera->viewfinderSettings();
viewfinderSettings.setResolution(640, 480);
viewfinderSettings.setMinimumFrameRate(15.0);
viewfinderSettings.setMaximumFrameRate(15.0);
qt_camera->setViewfinderSettings(viewfinderSettings);
qt_camera->setViewfinder(qt_viewfinder);
qt_camera->start();
return 0;
}
int __qt_stopCapture() {
if (qt_camera != nullptr) {
qt_camera->stop();
qt_camera->unload();
delete qt_camera;
delete qt_viewfinder;
qt_camera = nullptr;
}
return 0;
}
//endif defined(USING_QT_UI)
#elif 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)
-66
View File
@@ -17,71 +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;
std::vector<std::string> __qt_getDeviceList();
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
+1 -3
View File
@@ -115,9 +115,7 @@ static inline FShaderBit operator +(FShaderBit bit, int i) {
}
struct ShaderID {
ShaderID() {
clear();
}
ShaderID() : d(0) {}
void clear() {
d = 0;
}
+1
View File
@@ -350,6 +350,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
}
VulkanPipelineKey key{};
memset(&key, 0, sizeof(key));
key.raster = rasterKey;
key.useHWTransform = useHwTransform;
+143 -5
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,137 @@ 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();
for (const QCameraInfo &cameraInfo : cameras) {
deviceList.push_back(cameraInfo.deviceName().toStdString()
+ " (" + cameraInfo.description().toStdString() + ")");
}
return deviceList;
}
QList<QVideoFrame::PixelFormat> MyViewfinder::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const {
Q_UNUSED(handleType);
// Return the formats you will support
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_YUYV
;
}
bool MyViewfinder::present(const QVideoFrame &frame) {
#ifdef USE_FFMPEG
if (frame.isValid()) {
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
unsigned char *jpegData = nullptr;
int jpegLen = 0;
QVideoFrame::PixelFormat frameFormat = cloneFrame.pixelFormat();
if (frameFormat == QVideoFrame::Format_RGB24) {
convert_frame(cloneFrame.size().width(), cloneFrame.size().height(),
(unsigned char*)cloneFrame.bits(), AV_PIX_FMT_RGB24,
qtc_ideal_width, qtc_ideal_height, &jpegData, &jpegLen);
} else if (frameFormat == QVideoFrame::Format_YUYV) {
convert_frame(cloneFrame.size().width(), cloneFrame.size().height(),
(unsigned char*)cloneFrame.bits(), AV_PIX_FMT_YUYV422,
qtc_ideal_width, qtc_ideal_height, &jpegData, &jpegLen);
}
if (jpegData) {
Camera::pushCameraImage(jpegLen, jpegData);
free(jpegData);
jpegData = nullptr;
}
cloneFrame.unmap();
return true;
}
#endif //USE_FFMPEG
return false;
}
int __qt_startCapture(int width, int height) {
if (qt_camera != nullptr) {
ERROR_LOG(Log::HLE, "camera already started");
return -1;
}
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) {
delete qt_camera;
qt_camera = nullptr;
ERROR_LOG(Log::HLE, "no camera found");
return -1;
}
for (const QCameraInfo &cameraInfo : availableCameras) {
if (cameraInfo.deviceName() == selectedCamera) {
qt_camera = new QCamera(cameraInfo);
}
}
if (qt_camera == nullptr) {
qt_camera = new QCamera();
if (qt_camera == nullptr) {
ERROR_LOG(Log::HLE, "cannot open camera");
return -1;
}
}
qtc_ideal_width = width;
qtc_ideal_height = height;
qt_viewfinder = new MyViewfinder;
QCameraViewfinderSettings viewfinderSettings = qt_camera->viewfinderSettings();
viewfinderSettings.setResolution(640, 480);
viewfinderSettings.setMinimumFrameRate(15.0);
viewfinderSettings.setMaximumFrameRate(15.0);
qt_camera->setViewfinderSettings(viewfinderSettings);
qt_camera->setViewfinder(qt_viewfinder);
qt_camera->start();
return 0;
}
int __qt_stopCapture() {
if (qt_camera != nullptr) {
qt_camera->stop();
qt_camera->unload();
delete qt_camera;
delete qt_viewfinder;
qt_camera = nullptr;
}
return 0;
}
std::vector<std::string> System_GetCameraDeviceList() {
return __qt_getDeviceList();
}
std::vector<std::string> System_GetPropertyStringVec(SystemProperty prop) {
std::vector<std::string> result;
switch (prop) {
@@ -695,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:
{
@@ -880,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
@@ -936,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
}
+400 -2
View File
@@ -56,6 +56,7 @@ SDLJoystick *joystick = NULL;
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/StringUtils.h"
#include "Core/HW/Camera.h"
#include "Core/System.h"
#include "Core/Core.h"
#include "Core/Config.h"
@@ -111,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;
@@ -125,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;
@@ -503,6 +871,28 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
#endif /* PPSSPP_PLATFORM(WINDOWS) */
return true;
}
case SystemRequestType::CAMERA_COMMAND:
{
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;
}
case SystemRequestType::NOTIFY_UI_EVENT:
{
switch ((UIEventNotification)param3) {
@@ -532,6 +922,14 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
std::vector<std::string> System_GetCameraDeviceList() {
#if PPSSPP_PLATFORM(MAC)
return __mac_getDeviceList();
#elif PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
return __v4l_getDeviceList();
#endif
}
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
switch (urlType) {
case LaunchUrlType::BROWSER_URL:
+1 -1
View File
@@ -134,7 +134,7 @@ public:
void update() override;
InputMode PassInputToMapper() const {
InputMode PassInputToMapper() const override {
return InputMode::Other | InputMode::Keyboard | InputMode::Mouse;
}
+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)
+21 -1
View File
@@ -8,10 +8,27 @@ do
--qt) echo "Qt enabled"
QT=1
CMAKE_ARGS="-DUSING_QT_UI=ON ${CMAKE_ARGS}"
if [[ "$OSTYPE" == "darwin"* ]]; then
if command -v brew >/dev/null 2>&1; then
if brew --prefix qt@5 >/dev/null 2>&1; then
QT_PREFIX="$(brew --prefix qt@5)"
CMAKE_ARGS="-DCMAKE_PREFIX_PATH=${QT_PREFIX} ${CMAKE_ARGS}"
echo "Using Homebrew Qt5 from ${QT_PREFIX}"
fi
fi
fi
;;
--qtbrew) echo "Qt enabled (homebrew)"
QT=1
CMAKE_ARGS="-DUSING_QT_UI=ON -DCMAKE_PREFIX_PATH=$(brew --prefix qt5) ${CMAKE_ARGS}"
if brew --prefix qt@5 >/dev/null 2>&1; then
QT_PREFIX="$(brew --prefix qt@5)"
elif brew --prefix qt5 >/dev/null 2>&1; then
QT_PREFIX="$(brew --prefix qt5)"
else
echo "Could not find Homebrew Qt5 (qt@5). Install it with: brew install qt@5"
exit 1
fi
CMAKE_ARGS="-DUSING_QT_UI=ON -DCMAKE_PREFIX_PATH=${QT_PREFIX} ${CMAKE_ARGS}"
;;
--ios) CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/ios.cmake ${CMAKE_ARGS}"
TARGET_OS=iOS
@@ -56,6 +73,9 @@ do
--debug)
CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Debug ${CMAKE_ARGS}"
;;
--build)
# Compatibility flag: build is the default action of this script.
;;
--reldebug)
CMAKE_ARGS="-DCMAKE_BUILD_TYPE=RelWithDebInfo ${CMAKE_ARGS}"
;;
+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
@@ -2024,16 +2024,12 @@ 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; }
#elif PPSSPP_PLATFORM(MAC)
std::vector<std::string> __mac_getDeviceList() { return std::vector<std::string>(); }
int __mac_startCapture(int width, int height) { return 0; }
int __mac_stopCapture() { return 0; }
#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) {}