Skip to content
Open
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
108 changes: 108 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,58 @@
"problemMatcher": "$msCompile"
}
},
{
"label": "Run 6-record_video (Debug)",
"type": "shell",
"command": "bash",
"args": [
"-l",
"-c",
"( if [[ $(pwd) =~ ^/mnt ]]; then ./6-record_video.exe; else ./6-record_video; fi )"
],
"options": {
"cwd": "${workspaceFolder}/build/Debug"
},
"group": "build",
"problemMatcher": "$gcc",
"dependsOn": [
"Build Project (Debug)"
],
"windows": {
"command": ".\\6-record_video.exe",
"args": [],
"options": {
"cwd": "${workspaceFolder}/build/Debug"
},
"problemMatcher": "$msCompile"
}
},
{
"label": "Run 6-record_video (Release)",
"type": "shell",
"command": "bash",
"args": [
"-l",
"-c",
"( if [[ $(pwd) =~ ^/mnt ]]; then ./6-record_video.exe; else ./6-record_video; fi )"
],
"options": {
"cwd": "${workspaceFolder}/build/Release"
},
"group": "build",
"problemMatcher": "$gcc",
"dependsOn": [
"Build Project (Release)"
],
"windows": {
"command": ".\\6-record_video.exe",
"args": [],
"options": {
"cwd": "${workspaceFolder}/build/Release"
},
"problemMatcher": "$msCompile"
}
},
{
"label": "Run ccap CLI --help (Debug)",
"type": "shell",
Expand Down Expand Up @@ -1547,6 +1599,62 @@
},
"problemMatcher": "$msCompile"
}
},
{
"label": "Run ccap CLI --record camera (Debug)",
"type": "shell",
"command": "bash",
"args": [
"-l",
"-c",
"( if [[ $(pwd) =~ ^/mnt ]]; then ./ccap.exe -w 1280 -H 720 --record ./camera_capture.mp4 --timeout 5 --preview; else ./ccap --record ./camera_capture.mp4 -w 1280 -H 720 --timeout 5 --preview; fi )"
],
"options": {
"cwd": "${workspaceFolder}/build/Debug"
},
"group": "build",
"problemMatcher": "$gcc",
"dependsOn": [
"Config: Enable CLI Tool",
"Build Project (Debug)"
],
"dependsOrder": "sequence",
"windows": {
"command": ".\\ccap.exe",
"args": ["--record", ".\\camera_capture.mp4", "-w", "1280", "-H", "720", "--timeout", "5", "--preview"],
"options": {
"cwd": "${workspaceFolder}/build/Debug"
},
"problemMatcher": "$msCompile"
}
},
{
"label": "Run ccap CLI --record camera (Release)",
"type": "shell",
"command": "bash",
"args": [
"-l",
"-c",
"( if [[ $(pwd) =~ ^/mnt ]]; then ./ccap.exe -w 1280 -H 720 --record ./camera_capture.mp4 --timeout 5 --preview; else ./ccap --record ./camera_capture.mp4 -w 1280 -H 720 --timeout 5 --preview; fi )"
],
"options": {
"cwd": "${workspaceFolder}/build/Release"
},
"group": "build",
"problemMatcher": "$gcc",
"dependsOn": [
"Config: Enable CLI Tool",
"Build Project (Release)"
],
"dependsOrder": "sequence",
"windows": {
"command": ".\\ccap.exe",
"args": ["--record", ".\\camera_capture.mp4", "-w", "1280", "-H", "720", "--timeout", "5", "--preview"],
"options": {
"cwd": "${workspaceFolder}/build/Release"
},
"problemMatcher": "$msCompile"
}
}
]
}
11 changes: 11 additions & 0 deletions BUILD_AND_INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ make install
- `CCAP_BUILD_EXAMPLES`: Build example applications (default: ON for root project)
- `CCAP_BUILD_TESTS`: Build unit tests (default: OFF)
- `CCAP_NO_LOG`: Disable logging functionality (default: OFF)
- `CCAP_ENABLE_VIDEO_WRITER`: Enable video writer support (`ccap::VideoWriter`, C writer API, CLI `--record`) on Windows/macOS (default: ON)

### macOS Universal Binary Build

Expand Down Expand Up @@ -205,6 +206,7 @@ build/universal/ # Contains x86_64 + arm64 universal binary
- `CCAP_INSTALL`: Enable install target (default: ON)
- `CCAP_BUILD_EXAMPLES`: Build examples (default: OFF when used as subproject)
- `CCAP_BUILD_TESTS`: Build tests (default: OFF when used as subproject)
- `CCAP_ENABLE_VIDEO_WRITER`: Enable video writing support (Windows/macOS only, default: ON)

### Advanced Usage

Expand Down Expand Up @@ -250,6 +252,15 @@ git clean -fdx install/

**Note**: Video file playback is currently supported on Windows and macOS only. Linux video playback support may be added in a future release.

### Video Writer Support Matrix

- ✅ Windows: supported (`CCAP_ENABLE_VIDEO_WRITER=ON`)
- ✅ macOS: supported (`CCAP_ENABLE_VIDEO_WRITER=ON`)
- ❌ Linux: not supported
- ❌ iOS: not supported

`CCAP_ENABLE_VIDEO_WRITER` is independent from `CCAP_ENABLE_FILE_PLAYBACK`.

## Version Information

Current version: 1.7.2
Expand Down
27 changes: 27 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,31 @@ if (NOT CCAP_ENABLE_FILE_PLAYBACK)
message(STATUS "ccap: Video file playback support disabled")
endif ()

# Video writer sources (Windows and macOS only)
option(CCAP_ENABLE_VIDEO_WRITER "Enable video file writing support (Windows/macOS)" ON)
if (CCAP_ENABLE_VIDEO_WRITER AND (APPLE OR WIN32))
# Exclude writer sources from main glob to avoid double-compilation
list(FILTER LIB_SOURCE EXCLUDE REGEX ".*ccap_writer_apple.*")
list(FILTER LIB_SOURCE EXCLUDE REGEX ".*ccap_writer_windows.*")
list(FILTER LIB_SOURCE EXCLUDE REGEX ".*ccap_writer_c\..*$")
list(FILTER LIB_SOURCE EXCLUDE REGEX ".*ccap_writer\..*$")
list(APPEND LIB_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/src/ccap_writer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/ccap_writer_c.cpp
)
if (APPLE)
list(APPEND LIB_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/ccap_writer_apple.mm)
elseif (WIN32)
list(APPEND LIB_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/ccap_writer_windows.cpp)
endif ()
message(STATUS "ccap: Video file writing support enabled")
else ()
message(STATUS "ccap: Video file writing support disabled (unsupported platform or disabled)")
endif ()

if (APPLE)
file(GLOB LIB_SOURCE_MAC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.mm)
list(FILTER LIB_SOURCE_MAC EXCLUDE REGEX ".*ccap_writer_apple.*")
message(STATUS "ccap: Using Objective-C++ for macOS: ${LIB_SOURCE_MAC}")
list(APPEND LIB_SOURCE ${LIB_SOURCE_MAC})
endif ()
Expand Down Expand Up @@ -207,6 +230,10 @@ else ()
message(STATUS "ccap: Video file playback support disabled")
endif ()

if (CCAP_ENABLE_VIDEO_WRITER AND (APPLE OR WIN32))
target_compile_definitions(ccap PUBLIC CCAP_ENABLE_VIDEO_WRITER=1)
endif ()

# Configure shared library export definitions
if (CCAP_BUILD_SHARED)
target_compile_definitions(ccap PUBLIC CCAP_SHARED=1)
Expand Down
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ A high-performance, lightweight cross-platform camera capture library with hardw
- **Multiple Formats**: RGB, BGR, YUV (NV12/I420) with automatic conversion
- **Dual Language APIs**: ✨ **Complete Pure C Interface** - Both modern C++ API and traditional C99 interface for various project integration and language bindings
- **Video File Playback**: 🎬 Play video files (MP4, AVI, MOV, etc.) using the same API as camera capture - supports Windows and macOS
- **Video Writing / Recording**: 🎥 Write MP4/MOV files from camera frames via `ccap::VideoWriter`, `ccap_video_writer_*`, or CLI `--record` (Windows/macOS, `CCAP_ENABLE_VIDEO_WRITER=ON`)
- **CLI Tool**: Ready-to-use command-line tool for quick camera operations and video processing - list devices, capture images, real-time preview, video playback ([Documentation](./docs/content/cli.md))
- **Production Ready**: Comprehensive test suite with 95%+ accuracy validation
- **Virtual Camera Support**: Compatible with OBS Virtual Camera and similar tools through the default DirectShow path on Windows
Expand Down Expand Up @@ -235,6 +236,8 @@ On Windows, camera capture now uses DirectShow by default. This keeps OBS Virtua

For most Windows applications, staying in `auto` mode is recommended. ccap normalizes the public capture API, frame orientation handling, and output pixel-format conversion across both backends so callers usually do not need backend-specific code.

For video writing, backend selection is a separate axis: on Windows, `VideoWriter` uses Media Foundation's writer stack regardless of camera capture backend (`auto` / `dshow` / `msmf`).

- Pass `extraInfo` as `"auto"`, `"msmf"`, `"dshow"`, or `"backend=<value>"` in the C++/C constructors that accept it.
- Set the environment variable `CCAP_WINDOWS_BACKEND=auto|msmf|dshow` to affect the whole process, including the CLI and Rust bindings.

Expand Down Expand Up @@ -297,6 +300,9 @@ cmake --build .

# Video preview with playback controls
./ccap -i video.mp4 --preview --speed 1.0

# Record camera stream to MP4 (Windows/macOS)
./ccap -d 0 --record ./camera_capture.mp4 --timeout 5
```

**Key Features:**
Expand All @@ -305,6 +311,7 @@ cmake --build .
- 🎯 Capture single or multiple images
- 👁️ Real-time preview window (with GLFW)
- 🎬 Video file playback and frame extraction
- 🎥 Record camera stream to MP4/MOV (`--record`)
- ⚙️ Configure resolution, format, and frame rate
- 💾 Save images in various formats (JPEG, PNG, BMP, etc.)
- ⏱️ Duration-based or count-based capture modes
Expand Down Expand Up @@ -343,6 +350,7 @@ For complete CLI documentation, see [CLI Tool Guide](./docs/content/cli.md).
| [3-capture_callback](./examples/desktop/3-capture_callback.cpp) / [3-capture_callback_c](./examples/desktop/3-capture_callback_c.c) | Callback-based capture | C++ / C | Desktop |
| [4-example_with_glfw](./examples/desktop/4-example_with_glfw.cpp) / [4-example_with_glfw_c](./examples/desktop/4-example_with_glfw_c.c) | OpenGL rendering | C++ / C | Desktop |
| [5-play_video](./examples/desktop/5-play_video.cpp) / [5-play_video_c](./examples/desktop/5-play_video_c.c) | Video file playback | C++ / C | Windows/macOS |
| [6-record_video](./examples/desktop/6-record_video.cpp) | Video recording with `VideoWriter` | C++ | Windows/macOS |
| [iOS Demo](./examples/) | iOS application | Objective-C++ | iOS |

### Build and Run Examples
Expand Down Expand Up @@ -460,6 +468,41 @@ enum class PixelFormat : uint32_t {
};
```

### Video Writing (Windows/macOS)

Video writing is available on Windows and macOS when `CCAP_ENABLE_VIDEO_WRITER=ON`.

```cpp
#include <ccap.h>
#include <ccap_writer.h>

ccap::Provider provider;
ccap::VideoWriter writer;

if (provider.open("", true)) {
ccap::WriterConfig cfg;
cfg.width = 1280;
cfg.height = 720;
cfg.frameRate = 30.0;
cfg.codec = ccap::VideoCodec::H264;
cfg.container = ccap::VideoFormat::MP4;

if (writer.open("camera_record.mp4", cfg)) {
while (auto frame = provider.grab(3000)) {
// timestampNs == 0 means auto timestamp generation from frameRate.
writer.writeFrame(*frame, 0);
}
writer.close();
}
}
```

Notes:

- Writer input supports `NV12`, `I420`, `BGR24`, and `BGRA32`.
- `VideoFrame::orientation` is honored by the writer path (including `BottomToTop` frames common on Windows RGB capture).
- `CCAP_ENABLE_VIDEO_WRITER` is independent from `CCAP_ENABLE_FILE_PLAYBACK`.

### Utility Functions

```cpp
Expand Down Expand Up @@ -575,6 +618,20 @@ void ccap_provider_stop(CcapProvider* provider);
bool ccap_provider_is_started(CcapProvider* provider);
```

##### Video Writer API (C)

```c
CcapVideoWriter* ccap_video_writer_create(void);
void ccap_video_writer_destroy(CcapVideoWriter* writer);
bool ccap_video_writer_open(CcapVideoWriter* writer, const char* filePath, const CcapWriterConfig* config);
bool ccap_video_writer_write_frame(CcapVideoWriter* writer, const CcapVideoFrameInfo* frameInfo, uint64_t timestampNs);
void ccap_video_writer_close(CcapVideoWriter* writer);
bool ccap_video_writer_is_opened(const CcapVideoWriter* writer);
CcapVideoCodec ccap_video_writer_actual_codec(const CcapVideoWriter* writer);
```

`timestampNs == 0` is treated as an auto-timestamp sentinel (derived from configured frame rate), not a literal timeline timestamp.

##### Frame Capture and Processing

```c
Expand Down Expand Up @@ -729,6 +786,7 @@ Comprehensive test suite with 50+ test cases covering all functionality:
- Multi-backend testing (CPU, AVX2, Apple Accelerate, NEON)
- Performance benchmarks and accuracy validation
- 95%+ precision for pixel format conversions
- Video writer regression tests (`ccap_video_writer_test`) covering C++ and C APIs, codec fallback, MOV container, `BottomToTop` orientation, and transcode duration checks

```bash
./scripts/run_tests.sh
Expand Down
Loading
Loading