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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 50 additions & 11 deletions .github/workflows/release.yml → .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
name: Release
name: Build and Release

on:
push:
branches:
- main
- '**'
tags:
- 'v*'
pull_request:

jobs:
build-linux:
name: Build Linux (.deb)
name: Build Linux
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -31,10 +34,16 @@ jobs:
run: |
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
BUILD_TYPE="Release"
else
BUILD_TYPE="Debug"
fi
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE
make -j$(nproc)

- name: Package with CPack
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
cd build
cpack -G DEB
Expand All @@ -44,32 +53,39 @@ jobs:
with:
name: linux-deb
path: build/*.deb
if-no-files-found: ignore

build-macos:
name: Build macOS (.dmg)
name: Build macOS
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies
run: |
brew install sdl2 sdl2_ttf dylibbundler create-dmg
brew install sdl2 sdl2_ttf pkg-config dylibbundler create-dmg

- name: Configure and Build
run: |
mkdir build
cd build
# We prefer static SDL2 and SDL2_ttf if possible, as per CMakeLists.txt
cmake .. -DCMAKE_BUILD_TYPE=Release
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
BUILD_TYPE="Release"
else
BUILD_TYPE="Debug"
fi
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE
make -j$(sysctl -n hw.ncpu)

- name: Create App Bundle
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
chmod +x bundle_macos.sh
BUILD_DIR="build" ./bundle_macos.sh

- name: Create DMG
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
mkdir -p dist
create-dmg \
Expand All @@ -88,27 +104,48 @@ jobs:
with:
name: macos-dmg
path: dist/*.dmg
if-no-files-found: ignore

build-windows:
name: Build Windows (.zip)
name: Build Windows
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Initialize vcpkg
shell: pwsh
run: |
cd $env:VCPKG_INSTALLATION_ROOT
git fetch --unshallow --tags
git checkout master
git pull

- name: Configure
shell: pwsh
run: |
if ("${{ github.ref }}" -eq "refs/heads/main") {
$build_type = "Release"
} else {
$build_type = "Debug"
}
cmake -S . -B build `
-DCMAKE_BUILD_TYPE=Release `
-DCMAKE_BUILD_TYPE=$build_type `
-DUSE_FFMPEG=OFF `
-DVCPKG_TARGET_TRIPLET=x64-windows `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"

- name: Build
run: cmake --build build --config Release --parallel
run: |
if ("${{ github.ref }}" -eq "refs/heads/main") {
$config = "Release"
} else {
$config = "Debug"
}
cmake --build build --config $config --parallel

- name: Package
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
shell: pwsh
run: |
$dist = "dist/P2ProViewer-Windows"
Expand All @@ -122,10 +159,12 @@ jobs:
with:
name: windows-zip
path: dist/P2ProViewer-windows.zip
if-no-files-found: ignore

release:
name: Release
needs: [build-linux, build-macos, build-windows]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ initial_tests
__pycache__
cmake-build-debug
build
.idea
1 change: 1 addition & 0 deletions .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions .idea/P2Pro-Viewer.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions .idea/git_toolbox_prj.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 48 additions & 37 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,16 @@ find_package(SDL2_ttf CONFIG REQUIRED)
set(SDL2_LIBRARIES SDL2::SDL2 SDL2::SDL2main)
set(SDL2_TTF_LIBRARIES SDL2_ttf::SDL2_ttf)

# Try pkg-config for libusb and ffmpeg
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
if(NOT APPLE AND NOT WIN32)
pkg_check_modules(LIBUSB libusb-1.0)
if(USE_FFMPEG)
pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libswscale libavutil)
# Try pkg-config for libusb and ffmpeg
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
if(NOT APPLE AND NOT WIN32)
pkg_check_modules(LIBUSB libusb-1.0)
if(USE_FFMPEG)
pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libswscale libavutil)
endif()
endif()
endif()
# pkg_check_modules(SDL2_TTF SDL2_ttf) # Commented out to avoid polluting SDL2_TTF variables
endif()

if(WIN32)
# On Windows with vcpkg, libusb-1.0 and ffmpeg are found via find_package or find_library
Expand Down Expand Up @@ -144,18 +143,21 @@ else ()
)
endif ()

if (APPLE)
if(APPLE)
# Prefer static linking for SDL2 and SDL2_ttf on macOS to make it more portable
# We force the search for static libraries for these specific components
set(ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})

# Use pkg-config to find static versions and their dependencies if possible
pkg_check_modules(SDL2_STATIC_PKG QUIET SDL2 STATIC IMPORTED_TARGET)
pkg_check_modules(SDL2_TTF_STATIC_PKG QUIET SDL2_ttf STATIC IMPORTED_TARGET)
# Note: We don't use IMPORTED_TARGET here to avoid issues with missing dependencies in the project environment
pkg_check_modules(SDL2_STATIC_PKG QUIET SDL2 STATIC)
pkg_check_modules(SDL2_TTF_STATIC_PKG QUIET SDL2_ttf STATIC)

if(TARGET PkgConfig::SDL2_TTF_STATIC_PKG)
target_link_libraries(P2ProViewer PkgConfig::SDL2_TTF_STATIC_PKG)
if(SDL2_TTF_STATIC_PKG_FOUND)
target_link_libraries(P2ProViewer ${SDL2_TTF_STATIC_PKG_LIBRARIES})
target_link_directories(P2ProViewer PRIVATE ${SDL2_TTF_STATIC_PKG_LIBRARY_DIRS})
target_include_directories(P2ProViewer PRIVATE ${SDL2_TTF_STATIC_PKG_INCLUDE_DIRS})
elseif(TARGET SDL2_ttf::SDL2_ttf-static)
target_link_libraries(P2ProViewer SDL2_ttf::SDL2_ttf-static)
else()
Expand All @@ -167,9 +169,11 @@ if (APPLE)
endif()
endif()

if(NOT TARGET PkgConfig::SDL2_TTF_STATIC_PKG)
if(TARGET PkgConfig::SDL2_STATIC_PKG)
target_link_libraries(P2ProViewer PkgConfig::SDL2_STATIC_PKG)
if(NOT SDL2_TTF_STATIC_PKG_FOUND)
if(SDL2_STATIC_PKG_FOUND)
target_link_libraries(P2ProViewer ${SDL2_STATIC_PKG_LIBRARIES})
target_link_directories(P2ProViewer PRIVATE ${SDL2_STATIC_PKG_LIBRARY_DIRS})
target_include_directories(P2ProViewer PRIVATE ${SDL2_STATIC_PKG_INCLUDE_DIRS})
elseif(TARGET SDL2::SDL2-static)
target_link_libraries(P2ProViewer SDL2::SDL2-static)
else()
Expand All @@ -191,6 +195,7 @@ if (APPLE)
find_library(AUDIOUNIT_FRAMEWORK AudioUnit)
find_library(FORCEFEEDBACK_FRAMEWORK ForceFeedback)
find_library(GAMECONTROLLER_FRAMEWORK GameController)
find_library(AUDIOTOOLBOX_FRAMEWORK AudioToolbox)
target_link_libraries(P2ProViewer
${METAL_FRAMEWORK}
${QUARTZCORE_FRAMEWORK}
Expand All @@ -200,30 +205,36 @@ if (APPLE)
${AUDIOUNIT_FRAMEWORK}
${FORCEFEEDBACK_FRAMEWORK}
${GAMECONTROLLER_FRAMEWORK}
)

# Link against required frameworks for SDL2 static
find_library(METAL_FRAMEWORK Metal)
find_library(QUARTZCORE_FRAMEWORK QuartzCore)
find_library(COCOA_FRAMEWORK Cocoa)
find_library(CARBON_FRAMEWORK Carbon)
find_library(COREAUDIO_FRAMEWORK CoreAudio)
find_library(AUDIOUNIT_FRAMEWORK AudioUnit)
find_library(FORCEFEEDBACK_FRAMEWORK ForceFeedback)
find_library(GAMECONTROLLER_FRAMEWORK GameController)
target_link_libraries(P2ProViewer
${METAL_FRAMEWORK}
${QUARTZCORE_FRAMEWORK}
${COCOA_FRAMEWORK}
${CARBON_FRAMEWORK}
${COREAUDIO_FRAMEWORK}
${AUDIOUNIT_FRAMEWORK}
${FORCEFEEDBACK_FRAMEWORK}
${GAMECONTROLLER_FRAMEWORK}
${AUDIOTOOLBOX_FRAMEWORK}
"-framework CoreHaptics"
"-lobjc"
)

# Restore original suffixes
set(CMAKE_FIND_LIBRARY_SUFFIXES ${ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})

# Add common library search paths for macOS (Homebrew)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/opt/homebrew/lib -L/usr/local/lib")
include_directories(/opt/homebrew/include /usr/local/include)
# SDL2_ttf headers are sometimes in SDL2/SDL_ttf.h under the include dir
include_directories(/opt/homebrew/include/SDL2 /usr/local/include/SDL2)

# Find and link freetype and harfbuzz if we're linking SDL2_ttf statically
# These are needed because static libraries don't include their dependencies
find_library(FREETYPE_LIB NAMES libfreetype.dylib freetype HINTS /opt/homebrew/lib /usr/local/lib)
find_library(HARFBUZZ_LIB NAMES libharfbuzz.dylib harfbuzz HINTS /opt/homebrew/lib /usr/local/lib)

if(FREETYPE_LIB)
target_link_libraries(P2ProViewer "${FREETYPE_LIB}")
else()
target_link_libraries(P2ProViewer freetype)
endif()

if(HARFBUZZ_LIB)
target_link_libraries(P2ProViewer "${HARFBUZZ_LIB}")
else()
target_link_libraries(P2ProViewer harfbuzz)
endif()
else()
target_link_libraries(P2ProViewer ${SDL2_LIBRARIES} ${SDL2_TTF_LIBRARIES} ${LIBUSB_LIBRARIES} ${FFMPEG_LIBRARIES})
endif()
Expand Down
Binary file added MaterialIcons-Regular.ttf
Binary file not shown.
31 changes: 19 additions & 12 deletions src/AVFoundationVideoSource.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
#include <mutex>
#include <vector>
#include <iostream>
#include <condition_variable>

@interface P2ProCaptureDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate> {
std::vector<uint8_t> latestFrame;
std::mutex frameMutex;
std::condition_variable frameCond;
BOOL hasNewFrame;
}
@property (nonatomic, strong) AVCaptureSession *session;
Expand Down Expand Up @@ -45,25 +47,30 @@ - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleB
// We expect YUYV (kCVPixelFormatType_422YpCbCr8) which is 2 bytes per pixel
size_t expectedBytesPerRow = width * 2;

std::lock_guard<std::mutex> lock(frameMutex);
latestFrame.resize(width * height * 2);

if (bytesPerRow == expectedBytesPerRow) {
memcpy(latestFrame.data(), baseAddress, width * height * 2);
} else {
for (size_t y = 0; y < height; ++y) {
memcpy(latestFrame.data() + y * expectedBytesPerRow, (uint8_t*)baseAddress + y * bytesPerRow, expectedBytesPerRow);
{
std::lock_guard<std::mutex> lock(frameMutex);
latestFrame.resize(width * height * 2);

if (bytesPerRow == expectedBytesPerRow) {
memcpy(latestFrame.data(), baseAddress, width * height * 2);
} else {
for (size_t y = 0; y < height; ++y) {
memcpy(latestFrame.data() + y * expectedBytesPerRow, (uint8_t*)baseAddress + y * bytesPerRow, expectedBytesPerRow);
}
}

hasNewFrame = YES;
}

hasNewFrame = YES;
frameCond.notify_all();

CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
}

- (bool)getLatestFrame:(std::vector<uint8_t>&)frameData {
std::lock_guard<std::mutex> lock(frameMutex);
if (!hasNewFrame) return false;
std::unique_lock<std::mutex> lock(frameMutex);
if (!frameCond.wait_for(lock, std::chrono::milliseconds(500), [self] { return hasNewFrame == YES; })) {
return false;
}
frameData = latestFrame;
hasNewFrame = NO;
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/MacOSAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ bool MacOSAdapter::connect(uint16_t vid, uint16_t pid) {

io_iterator_t iter;
// kIOMasterPortDefault is deprecated but widely used. NULL is also acceptable.
kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
kern_return_t kr = IOServiceGetMatchingServices(kIOMainPortDefault, matchingDict, &iter);
if (kr != KERN_SUCCESS) {
dprintf("MacOSAdapter::connect() - Failed to get matching services.\n");
return false;
Expand Down
Loading
Loading