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
20 changes: 19 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
mkdir -p build
cd build
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
..
Expand All @@ -49,3 +49,21 @@ jobs:
cd build
file uvc2gl
./uvc2gl --version

- name: Prepare artifacts
if: github.ref == 'refs/heads/dev'
run: |
cd build
mkdir -p artifacts
cp uvc2gl artifacts/
cp -r shaders artifacts/
cd artifacts
tar -czf uvc2gl-dev-linux-x86_64.tar.gz uvc2gl shaders

- name: Upload dev build artifact
if: github.ref == 'refs/heads/dev'
uses: actions/upload-artifact@v4
with:
name: uvc2gl-dev-linux-x86_64
path: build/artifacts/uvc2gl-dev-linux-x86_64.tar.gz
retention-days: 30
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:

**Full Changelog**: https://github.com/${{ github.repository }}/compare/v${{ steps.version.outputs.version }}...HEAD
draft: false
prerelease: ${{ contains(github.ref, '-alpha') || contains(github.ref, '-beta') || contains(github.ref, '-rc') || contains(github.ref, '-dev') }}
prerelease: ${{ contains(github.ref, '-') && !contains(github.ref, 'v0.0.0-') }}

- name: Upload Release Asset
uses: actions/upload-release-asset@v1
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ CMakeUserPresets.json
build/
plan.md

# Generated files
src/core/Version.h

.vscode/
.cache/

Expand Down
30 changes: 27 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
cmake_minimum_required(VERSION 3.12)
project(uvc2gl VERSION 1.0.0 LANGUAGES C CXX)

# Version is managed in src/core/Version.h
# Update VERSION_PRERELEASE in Version.h for dev/alpha/beta builds
# Read version from VERSION file
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VERSION_STRING)
string(STRIP "${VERSION_STRING}" VERSION_STRING)
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-(.+))?" VERSION_MATCH "${VERSION_STRING}")
set(VERSION_MAJOR "${CMAKE_MATCH_1}")
set(VERSION_MINOR "${CMAKE_MATCH_2}")
set(VERSION_PATCH "${CMAKE_MATCH_3}")
set(VERSION_PRERELEASE "${CMAKE_MATCH_5}")

project(uvc2gl VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH} LANGUAGES C CXX)

# Configure Version.h with values from VERSION file
configure_file(
"${CMAKE_SOURCE_DIR}/src/core/Version.h.in"
"${CMAKE_SOURCE_DIR}/src/core/Version.h"
@ONLY
)

# C++ Standard
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Optimization flags
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -DNDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O3 -march=native")

# SDL2
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
Expand Down Expand Up @@ -52,6 +74,7 @@ set(SOURCES
src/graphics/Shader.cpp
src/video/VideoCapture.cpp
src/video/MjpgDecoder.cpp
src/video/YuyvDecoder.cpp
src/video/V4L2Capabilities.cpp
src/audio/AudioCapture.cpp
src/audio/AudioPlayback.cpp
Expand All @@ -64,6 +87,7 @@ add_executable(${PROJECT_NAME} ${SOURCES})
add_executable(Probe src/video/v4l2Probe.cpp)
add_executable(StreamMjpg src/video/v4l2StreamMjpg.cpp)
add_executable(MjpgDecodeTest src/video/MjpgDecodeTest.cpp)
add_executable(YuyvDecodeTest src/video/YuyvDecodeTest.cpp src/video/YuyvDecoder.cpp)
add_executable(AudioProbe src/audio/AudioProbe.cpp)

# Copy shader files to build directory
Expand Down
43 changes: 36 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@ A Linux application that captures video and audio from USB capture cards (UVC/V4
## Features

- **Multi-Device Support**: Switch between multiple video and audio capture devices at runtime
- **V4L2 Video Capture**: Direct MJPEG capture from USB capture devices
- **Dual Format Support**: MJPEG and YUYV video format support with runtime switching
- **V4L2 Video Capture**: Direct capture from USB capture devices with V4L2
- **ALSA Audio Capture**: Real-time audio capture with SDL2 playback
- **Hardware Decoding**: FFmpeg-based MJPEG to RGB decoding
- **Optimized Decoding**:
- FFmpeg-based MJPEG hardware decoding
- Custom YUYV decoder with ITU-R BT.601 color space conversion
- Achieves 60fps at 1080p on modern CPUs with compiler auto-vectorization
- **OpenGL Rendering**: Modern OpenGL 4.6 with custom shaders
- **Live Format Switching**: Right-click context menu to change resolution/framerate/devices
- **Live Format Switching**: Right-click context menu to change resolution/framerate/format/devices
- **Audio Volume Control**: Adjustable volume with real-time slider
- **Configuration Persistence**: Saves device preferences, resolution, and volume settings
- **Configuration Persistence**: Saves device preferences, resolution, framerate, format, and volume settings
- **Fullscreen Support**: Press F11 or F to toggle fullscreen mode
- **Auto-detected Formats**: Queries available formats from each capture device
- **Dynamic Aspect Ratio**: Automatically maintains correct aspect ratio for any resolution
- **Multithreaded**: Separate capture/decode threads for smooth performance
- **Dear ImGui UI**: Lightweight immediate-mode collapsible menu overlay
- **Semantic Versioning**: Auto-generated version info from VERSION file

## Building

Expand All @@ -32,10 +37,12 @@ sudo apt install libsdl2-dev libglew-dev cmake ninja-build clang libavcodec-dev
### Compile
```bash
mkdir -p build && cd build
cmake -G Ninja ..
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..
ninja
```

**Note**: Release mode is recommended for optimal performance (includes `-O3 -march=native` flags for 60fps YUYV decoding).

### Run
```bash
cd build
Expand All @@ -57,6 +64,7 @@ GameCapture/
│ ├── Probe # V4L2 device info utility
│ ├── StreamMjpg # MJPEG stream capture test
│ ├── MjpgDecodeTest # FFmpeg decoder test
│ ├── YuyvDecodeTest # YUYV decoder test
│ └── shaders/ # Copied shader files
├── external/
│ └── imgui/ # Dear ImGui library
Expand All @@ -76,11 +84,14 @@ GameCapture/
├── video/ # Video capture & decode
│ ├── VideoCapture.h/cpp
│ ├── MjpgDecoder.h/cpp
│ ├── YuyvDecoder.h/cpp
│ ├── Frame.h
│ ├── RingBuffer.h
│ ├── V4L2Capabilities.h/cpp
│ ├── v4l2Probe.cpp
│ └── v4l2StreamMjpg.cpp
│ ├── v4l2StreamMjpg.cpp
│ ├── MjpgDecodeTest.cpp
│ └── YuyvDecodeTest.cpp
└── assets/
└── shaders/
├── Quad.vert
Expand All @@ -93,12 +104,30 @@ The application automatically saves your preferences to `uvc2gl.conf`:
- Last used video device
- Last used audio device
- Resolution and framerate
- Video format (MJPEG or YUYV)
- Audio volume level

Settings are restored on next startup. If devices are unavailable, defaults to first available device.

## Performance

- **MJPEG**: Hardware-accelerated decoding via FFmpeg (low CPU usage)
- **YUYV**: Optimized CPU-based conversion with ITU-R BT.601 color space
- 60fps at 1920x1080 on modern CPUs with AVX2 support
- Compiled with `-O3 -march=native` for auto-vectorization
- Higher CPU usage than MJPEG but no hardware encoding required

## Utilities

- **Probe**: Query V4L2 device capabilities
- **StreamMjpg**: Capture raw MJPEG frames to disk
- **MjpgDecodeTest**: Test FFmpeg MJPEG decoding
- **MjpgDecodeTest**: Test FFmpeg MJPEG decoding
- **YuyvDecodeTest**: Test YUYV decoder with known patterns

## Releases

- **Stable releases** (e.g., `v1.1.0`): Tested and ready for production use
- **Experimental releases** (e.g., `v1.2.0-yuyv.1`): Pre-release builds for testing new features
- **Dev builds**: Automatic builds from `dev` branch available as GitHub Actions artifacts

Download the latest release from the [Releases page](../../releases).
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.0
1.2.0-dev
32 changes: 26 additions & 6 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ src/
│ ├── VideoCapture.cpp
│ ├── MjpgDecoder.h
│ ├── MjpgDecoder.cpp
│ ├── YuyvDecoder.h
│ ├── YuyvDecoder.cpp
│ ├── V4L2Capabilities.h
│ ├── V4L2Capabilities.cpp
│ ├── Frame.h
│ ├── RingBuffer.h
│ ├── v4l2Probe.cpp
│ └── v4l2StreamMjpg.cpp
│ ├── v4l2StreamMjpg.cpp
│ ├── MjpgDecodeTest.cpp
│ └── YuyvDecodeTest.cpp
├── assets/ # Shader files and resources
│ └── shaders/
│ ├── Quad.vert
Expand Down Expand Up @@ -66,7 +70,7 @@ src/
- **Purpose**: Configuration file management
- **Responsibilities**:
- Saves/loads device preferences (video/audio)
- Persists resolution, framerate, and volume settings
- Persists resolution, framerate, format, and volume settings
- Simple key=value format (uvc2gl.conf)
- Validates settings on load and falls back to defaults

Expand Down Expand Up @@ -143,7 +147,8 @@ src/
- Opens and configures V4L2 device
- Manages memory-mapped buffers
- Runs capture loop in separate thread
- Decodes MJPEG frames to RGB
- Supports both MJPEG and YUYV formats
- Decodes frames to RGB using appropriate decoder
- Pushes decoded frames to ring buffer
- Handles device errors and cleanup
- Exception-safe destruction and stopping
Expand All @@ -157,6 +162,15 @@ src/
- Manages codec context and frame buffers
- Validates MJPEG data integrity

#### YuyvDecoder (`YuyvDecoder.h/cpp`)
- **Purpose**: CPU-based YUYV to RGB conversion
- **Responsibilities**:
- Decodes YUYV 4:2:2 format to RGB
- Implements ITU-R BT.601 color space conversion
- Processes 2 pixels at a time (Y0 U Y1 V)
- Optimized with pointer arithmetic and value reuse
- Achieves 60fps at 1080p with compiler auto-vectorization (-O3 -march=native)

#### V4L2Capabilities (`V4L2Capabilities.h/cpp`)
- **Purpose**: Query devices and available video formats
- **Responsibilities**:
Expand All @@ -181,6 +195,8 @@ src/
#### Utilities
- **v4l2Probe.cpp**: Standalone tool to query V4L2 device info
- **v4l2StreamMjpg.cpp**: Test utility to capture MJPEG frames to disk
- **MjpgDecodeTest.cpp**: Test FFmpeg MJPEG decoder
- **YuyvDecodeTest.cpp**: Test YUYV decoder with known patterns (validates color conversion)

## Design Principles

Expand All @@ -203,8 +219,8 @@ src/

### Data Flow
```
V4L2 Device → MJPEG Buffers → FFmpeg Decoder → RGB Frame → Ring Buffer → GPU Texture → OpenGL Quad
(video capture thread) (main thread)
V4L2 Device → Format Buffers → Decoder (MJPEG/YUYV) → RGB Frame → Ring Buffer → GPU Texture → OpenGL Quad
(video capture thread) (main thread)

ALSA Device → PCM Samples → Double Buffer → Main Thread → SDL Ring Buffer → Audio Playback
(audio capture thread) (main thread) (SDL audio thread)
Expand All @@ -218,9 +234,13 @@ ALSA Device → PCM Samples → Double Buffer → Main Thread → SDL Ring Buffe

## Recent Improvements

- **YUYV Format Support**: CPU-based YUYV decoder with 60fps performance at 1080p
- **Dual Format Support**: Runtime switching between MJPEG and YUYV formats
- **Compiler Optimizations**: Release builds with -O3 -march=native for auto-vectorization
- **Semantic Versioning**: Auto-generated version from VERSION file via CMake
- **Audio Support**: Full ALSA capture with SDL2 playback
- **Volume Control**: Real-time adjustable volume with ImGui slider
- **Configuration Persistence**: Auto-saves device preferences and settings
- **Configuration Persistence**: Auto-saves device preferences, format, and settings
- **Device Validation**: Checks if devices are actually working before use
- **Fullscreen Mode**: F11/F/ESC support with proper window management
- **Collapsible UI**: Organized Video/Audio sections in context menu
Expand Down
Loading