{"id":28794235,"url":"https://github.com/wysaid/cameracapture","last_synced_at":"2026-05-24T21:06:51.468Z","repository":{"id":293731390,"uuid":"970773035","full_name":"wysaid/CameraCapture","owner":"wysaid","description":"ccap `(C)amera(CAP)ture` is a simple and easy-to-use C++ camera capture library designed to provide you with simple and efficient camera data access. It currently supports Windows and macOS .","archived":false,"fork":false,"pushed_at":"2025-06-13T19:22:53.000Z","size":1128,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-13T19:27:27.304Z","etag":null,"topics":["camera","capture","ccap","ios","ios-camera","mac","obs","video-capture","virtual-camera","windows"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wysaid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-22T14:11:33.000Z","updated_at":"2025-06-13T19:22:57.000Z","dependencies_parsed_at":"2025-05-16T21:29:50.288Z","dependency_job_id":"c9bac93a-3527-4dfa-9e5d-5284a3cd0165","html_url":"https://github.com/wysaid/CameraCapture","commit_stats":null,"previous_names":["wysaid/cameracapture"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/wysaid/CameraCapture","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wysaid%2FCameraCapture","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wysaid%2FCameraCapture/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wysaid%2FCameraCapture/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wysaid%2FCameraCapture/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wysaid","download_url":"https://codeload.github.com/wysaid/CameraCapture/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wysaid%2FCameraCapture/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260471632,"owners_count":23014255,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["camera","capture","ccap","ios","ios-camera","mac","obs","video-capture","virtual-camera","windows"],"created_at":"2025-06-18T02:05:21.615Z","updated_at":"2026-05-24T21:06:51.455Z","avatar_url":"https://github.com/wysaid.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ccap (CameraCapture)\n\n[![Contributors](https://img.shields.io/github/contributors/wysaid/CameraCapture?style=flat-square)](https://github.com/wysaid/CameraCapture/graphs/contributors)\n[![Pull Requests Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/wysaid/CameraCapture/pulls)\n[![Windows Build](https://github.com/wysaid/CameraCapture/actions/workflows/windows-build.yml/badge.svg)](https://github.com/wysaid/CameraCapture/actions/workflows/windows-build.yml)\n[![macOS Build](https://github.com/wysaid/CameraCapture/actions/workflows/macos-build.yml/badge.svg)](https://github.com/wysaid/CameraCapture/actions/workflows/macos-build.yml)\n[![Linux Build](https://github.com/wysaid/CameraCapture/actions/workflows/linux-build.yml/badge.svg)](https://github.com/wysaid/CameraCapture/actions/workflows/linux-build.yml)\n[![Rust CI](https://github.com/wysaid/CameraCapture/actions/workflows/rust.yml/badge.svg)](https://github.com/wysaid/CameraCapture/actions/workflows/rust.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![C++17](https://img.shields.io/badge/C++-17-blue.svg)](https://isocpp.org/)\n[![C99](https://img.shields.io/badge/C-99-blue.svg)](https://en.wikipedia.org/wiki/C99)\n[![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20iOS%20%7C%20Linux-brightgreen)](https://github.com/wysaid/CameraCapture)\n\n[English](./README.md) | [中文](./README.zh-CN.md)\n\nA high-performance, lightweight cross-platform camera capture library with hardware-accelerated pixel format conversion, supporting both camera capture and video file playback (Windows/macOS). On Windows, ccap now fully supports both DirectShow and Media Foundation, with DirectShow remaining the default for strong virtual-camera compatibility. Provides complete C++ and pure C interfaces, plus Rust bindings.\n\n\u003e 🌐 **Official Website:** [ccap.work](https://ccap.work)\n\n## Table of Contents\n\n- [Features](#features)\n- [Quick Start](#quick-start)\n- [System Requirements](#system-requirements)\n- [Examples](#examples)\n- [API Reference](#api-reference)\n- [Testing](#testing)\n- [Build and Install](#build-and-install)\n- [Contributors](#contributors)\n- [License](#license)\n\n## Features\n\n- **High Performance**: Hardware-accelerated pixel format conversion with up to 10x speedup (AVX2, Apple Accelerate, NEON)\n- **Lightweight**: No third-party dependencies - uses only system frameworks\n- **Cross Platform**: Windows (dual backends: DirectShow by default, Media Foundation fully supported), macOS/iOS (AVFoundation), Linux (V4L2)\n- **Windows Dual Backends**: DirectShow stays the default on Windows for compatibility with OBS Virtual Camera and other virtual devices, while Media Foundation is also fully supported through `auto`, environment overrides, and explicit backend selection\n- **Multiple Formats**: RGB, BGR, YUV (NV12/I420) with automatic conversion\n- **Dual Language APIs**: ✨ **Complete Pure C Interface** - Both modern C++ API and traditional C99 interface for various project integration and language bindings\n- **Video File Playback**: 🎬 Play video files (MP4, AVI, MOV, etc.) using the same API as camera capture - supports Windows and macOS\n- **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`)\n- **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))\n- **Production Ready**: Comprehensive test suite with 95%+ accuracy validation\n- **Virtual Camera Support**: Compatible with OBS Virtual Camera and similar tools through the default DirectShow path on Windows\n\n## Quick Start\n\n### Agent Skill\n\nThis repository also includes a standalone agent skill for `ccap`, which can be used as a standard skill entry for installation, device inspection, capture, and video inspection workflows.\n\n- Skill folder: [skills/ccap](./skills/ccap)\n- Skill definition: [skills/ccap/SKILL.md](./skills/ccap/SKILL.md)\n\nUse this skill when you want an agent to work through the practical `ccap` flows instead of reading the source tree first, for example:\n\n- install `ccap` on the current machine\n- list available camera devices\n- inspect device capabilities\n- capture frames or preview video with the CLI\n- inspect video metadata with structured output when available\n\nThe skill guides agents to choose among an existing installation, Homebrew on macOS, source builds, and release-binary fallback, then prefer the `ccap` CLI with `--json` where supported.\n\n### Installation\n\n1. Build and install from source (on Windows, use git-bash):\n\n    ```bash\n    git clone https://github.com/wysaid/CameraCapture.git\n    cd CameraCapture\n    ./scripts/build_and_install.sh\n    ```\n\n2. Integrate directly using CMake FetchContent:\n\n    Add the following to your `CMakeLists.txt`:\n\n    ```cmake\n    include(FetchContent)\n    FetchContent_Declare(\n        ccap\n        GIT_REPOSITORY https://github.com/wysaid/CameraCapture.git\n        GIT_TAG        main\n    )\n    FetchContent_MakeAvailable(ccap)\n\n    target_link_libraries(your_app PRIVATE ccap::ccap)\n    ```\n\n    You can then use ccap headers and features directly in your project.\n\n3. Install and use via Homebrew on macOS:\n\n    - First, install the binary with Homebrew:\n\n        ```bash\n        brew tap wysaid/ccap\n        brew install ccap\n        ```\n\n    - Then, use it in CMake:\n\n        ```cmake\n        find_package(ccap REQUIRED)\n        target_link_libraries(your_app ccap::ccap)\n        ```\n\n### Basic Usage\n\nccap provides both complete **C++** and **pure C language** interfaces to meet different project and development requirements:\n\n- **C++ Interface**: Modern C++ API with smart pointers, lambda callbacks, and other advanced features\n- **Pure C Interface**: Fully compatible with C99 standard, supporting language bindings and traditional C project integration\n\n#### C++ Interface\n\n```cpp\n#include \u003cccap.h\u003e\n\nint main() {\n    ccap::Provider provider;\n    \n    // List available cameras\n    auto devices = provider.findDeviceNames();\n    for (size_t i = 0; i \u003c devices.size(); ++i) {\n        printf(\"[%zu] %s\\n\", i, devices[i].c_str());\n    }\n    \n    // Open and start camera\n    if (provider.open(\"\", true)) {  // Empty string = default camera\n        auto frame = provider.grab(3000);  // 3 second timeout\n        if (frame) {\n            printf(\"Captured: %dx%d, %s format\\n\", \n                   frame-\u003ewidth, frame-\u003eheight,\n                   ccap::pixelFormatToString(frame-\u003epixelFormat).data());\n        }\n    }\n    return 0;\n}\n```\n\n##### Error Handling in C++\n\nStarting from v1.2.0, ccap uses a global error callback system for simplified error handling across all camera operations:\n\n```cpp\n#include \u003cccap.h\u003e\n#include \u003ciostream\u003e\n\nint main() {\n    // Set error callback to receive detailed error information\n    ccap::setErrorCallback([](ccap::ErrorCode errorCode, const std::string\u0026 description) {\n        std::cerr \u003c\u003c \"Camera Error - Code: \" \u003c\u003c static_cast\u003cint\u003e(errorCode) \n                  \u003c\u003c \", Description: \" \u003c\u003c description \u003c\u003c std::endl;\n    });\n    \n    ccap::Provider provider;\n    \n    // Camera operations - errors will trigger the global callback\n    if (!provider.open(\"\", true)) {\n        std::cerr \u003c\u003c \"Failed to open camera\" \u003c\u003c std::endl;\n    }\n    \n    return 0;\n}\n```\n\nAvailable error codes include:\n\n- `ErrorCode::NoDeviceFound` - No camera device found\n- `ErrorCode::InvalidDevice` - Invalid device name or index  \n- `ErrorCode::DeviceOpenFailed` - Camera open failed\n- `ErrorCode::DeviceStartFailed` - Camera start failed\n- `ErrorCode::UnsupportedResolution` - Unsupported resolution\n- `ErrorCode::UnsupportedPixelFormat` - Unsupported pixel format\n- `ErrorCode::FrameCaptureTimeout` - Frame capture timeout\n- `ErrorCode::FrameCaptureFailed` - Frame capture failed\n\n#### Pure C Interface\n\n```c\n#include \u003cccap_c.h\u003e\n#include \u003cccap_utils_c.h\u003e\n\nint main() {\n    // Create provider\n    CcapProvider* provider = ccap_provider_create();\n    if (!provider) return -1;\n    \n    // Find available devices\n    CcapDeviceNamesList deviceList;\n    if (ccap_provider_find_device_names_list(provider, \u0026deviceList)) {\n        printf(\"Found %zu camera device(s):\\n\", deviceList.deviceCount);\n        for (size_t i = 0; i \u003c deviceList.deviceCount; i++) {\n            printf(\"  %zu: %s\\n\", i, deviceList.deviceNames[i]);\n        }\n    }\n    \n    // Open default camera\n    if (ccap_provider_open(provider, NULL, false)) {\n        // Set output format\n        ccap_provider_set_property(provider, CCAP_PROPERTY_PIXEL_FORMAT_OUTPUT, \n                                   CCAP_PIXEL_FORMAT_BGR24);\n        \n        // Start capture\n        if (ccap_provider_start(provider)) {\n            // Grab a frame\n            CcapVideoFrame* frame = ccap_provider_grab(provider, 3000);\n            if (frame) {\n                CcapVideoFrameInfo frameInfo;\n                if (ccap_video_frame_get_info(frame, \u0026frameInfo)) {\n                    // Get pixel format string\n                    char formatStr[64];\n                    ccap_pixel_format_to_string(frameInfo.pixelFormat, formatStr, sizeof(formatStr));\n                    \n                    printf(\"Captured: %dx%d, format=%s\\n\", \n                           frameInfo.width, frameInfo.height, formatStr);\n                }\n                ccap_video_frame_release(frame);\n            }\n        }\n        \n        ccap_provider_stop(provider);\n        ccap_provider_close(provider);\n    }\n    \n    ccap_provider_destroy(provider);\n    return 0;\n}\n```\n\n### Windows Backend Selection\n\nOn Windows, camera capture now uses DirectShow by default. This keeps OBS Virtual Camera and other virtual cameras working reliably after upgrades, while Media Foundation remains available when you explicitly request it. In `auto` mode, camera enumeration merges results from both Windows backends and `Provider::open()` routes the selected device to a compatible backend automatically: DirectShow-only devices stay on DirectShow, Media Foundation-only devices go straight to Media Foundation, and devices visible in both backends prefer DirectShow with Media Foundation as the secondary fallback.\n\nFor 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.\n\nFor 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`).\n\n- Pass `extraInfo` as `\"auto\"`, `\"msmf\"`, `\"dshow\"`, or `\"backend=\u003cvalue\u003e\"` in the C++/C constructors that accept it.\n- Set the environment variable `CCAP_WINDOWS_BACKEND=auto|msmf|dshow` to affect the whole process, including the CLI and Rust bindings.\n\n```powershell\n# PowerShell: opt into Media Foundation for the current process\n$env:CCAP_WINDOWS_BACKEND = \"msmf\"\n.\\ccap --list-devices\n```\n\n```cpp\n// Force Media Foundation explicitly on Windows\nccap::Provider msmfProvider(\"\", \"msmf\");\n\n// Force DirectShow explicitly on Windows\nccap::Provider dshowProvider(\"\", \"dshow\");\n```\n\n### Rust Bindings\n\nRust bindings are available as a crate on crates.io:\n\n- Crate: [ccap-rs on crates.io](https://crates.io/crates/ccap-rs)\n- Docs: [docs.rs/ccap-rs](https://docs.rs/ccap-rs)\n- Source: `bindings/rust/`\n\nQuick install:\n\n```bash\ncargo add ccap-rs\n```\n\nOr, if you want the crate name in code to be `ccap`:\n\n```toml\n[dependencies]\nccap = { package = \"ccap-rs\", version = \"\u003clatest\u003e\" }\n```\n\n## CLI Tool\n\nccap includes a powerful command-line tool for quick camera operations and video processing without writing code:\n\n```bash\n# Build with CLI tool enabled\nmkdir build \u0026\u0026 cd build\ncmake .. -DCCAP_BUILD_CLI=ON\ncmake --build .\n\n# List available cameras\n./ccap --list-devices\n\n# Capture 5 images from default camera\n./ccap -c 5 -o ./captures\n\n# Real-time preview (requires GLFW)\n./ccap --preview\n\n# Play video file and extract frames\n./ccap -i video.mp4 -c 30 -o ./frames\n\n# Video preview with playback controls\n./ccap -i video.mp4 --preview --speed 1.0\n\n# Record camera stream to MP4 (Windows/macOS)\n./ccap -d 0 --record ./camera_capture.mp4 --timeout 5\n```\n\n**Key Features:**\n\n- 📷 List and select camera devices\n- 🎯 Capture single or multiple images\n- 👁️ Real-time preview window (with GLFW)\n- 🎬 Video file playback and frame extraction\n- 🎥 Record camera stream to MP4/MOV (`--record`)\n- ⚙️ Configure resolution, format, and frame rate\n- 💾 Save images in various formats (JPEG, PNG, BMP, etc.)\n- ⏱️ Duration-based or count-based capture modes\n- 🔁 Video looping and playback speed control\n\n\nFor complete CLI documentation, see [CLI Tool Guide](./docs/content/cli.md).\n\n## System Requirements\n\n| Platform | Compiler | System Requirements |\n| -------- | -------- | ------------------- |\n| **Windows** | MSVC 2019+ (including 2026) / MinGW-w64 | DirectShow (default) + Media Foundation support |\n| **macOS** | Xcode 11+ | macOS 10.13+ |\n| **iOS** | Xcode 11+ | iOS 13.0+ |\n| **Linux** | GCC 7+ / Clang 6+ | V4L2 (Linux 2.6+) |\n\n**Build Requirements**: CMake 3.14+ (3.31+ recommended for MSVC 2026), C++17 (C++ interface), C99 (C interface)\n\n### Supported Linux Distributions\n\n- [x] **Ubuntu/Debian** - All versions with Linux 2.6+ kernel  \n- [x] **CentOS/RHEL/Fedora** - All versions with Linux 2.6+ kernel  \n- [x] **SUSE/openSUSE** - All versions with Linux 2.6+ kernel  \n- [x] **Arch Linux** - All versions  \n- [x] **Alpine Linux** - All versions  \n- [x] **Embedded Linux** - Any distribution with V4L2 support  \n\n## Examples\n\n| Example | Description | Language | Platform |\n| ------- | ----------- | -------- | -------- |\n| [0-print_camera](./examples/desktop/0-print_camera.cpp) / [0-print_camera_c](./examples/desktop/0-print_camera_c.c) | List available cameras | C++ / C | Desktop |\n| [1-minimal_example](./examples/desktop/1-minimal_example.cpp) / [1-minimal_example_c](./examples/desktop/1-minimal_example_c.c) | Basic frame capture | C++ / C | Desktop |\n| [2-capture_grab](./examples/desktop/2-capture_grab.cpp) / [2-capture_grab_c](./examples/desktop/2-capture_grab_c.c) | Continuous capture | C++ / C | Desktop |\n| [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 |\n| [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 |\n| [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 |\n| [6-record_video](./examples/desktop/6-record_video.cpp) | Video recording with `VideoWriter` | C++ | Windows/macOS |\n| [iOS Demo](./examples/) | iOS application | Objective-C++ | iOS |\n\n### Build and Run Examples\n\n```bash\nmkdir build \u0026\u0026 cd build\ncmake .. -DCCAP_BUILD_EXAMPLES=ON\ncmake --build .\n\n# Run examples\n./0-print_camera\n./1-minimal_example\n\n# Run the pure C variants (if you built C examples)\n./0-print_camera_c\n./1-minimal_example_c\n```\n\n\u003e Note: Each desktop example is available in both C++ (.cpp) and pure C (.c) variants. Use the filenames with a trailing `_c` (e.g. `1-minimal_example_c.c`) for the C versions.\n\n## API Reference\n\nccap provides both complete C++ and pure C interfaces to meet different project requirements.\n\n### Core Classes\n\n#### ccap::Provider\n\n```cpp\nclass Provider {\npublic:\n    // Constructors\n    Provider();\n    Provider(std::string_view deviceName, std::string_view extraInfo = \"\");\n    Provider(int deviceIndex, std::string_view extraInfo = \"\");\n    \n    // Device discovery\n    std::vector\u003cstd::string\u003e findDeviceNames();\n    \n    // Camera lifecycle\n    bool open(std::string_view deviceName = \"\", bool autoStart = true);\n    bool open(int deviceIndex, bool autoStart = true);\n    bool isOpened() const;\n    void close();\n    \n    // Capture control\n    bool start();\n    void stop();\n    bool isStarted() const;\n    \n    // Frame capture\n    std::shared_ptr\u003cVideoFrame\u003e grab(uint32_t timeoutInMs = 0xffffffff);\n    void setNewFrameCallback(std::function\u003cbool(const std::shared_ptr\u003cVideoFrame\u003e\u0026)\u003e callback);\n    \n    // Property configuration\n    bool set(PropertyName prop, double value);\n    template\u003cclass T\u003e bool set(PropertyName prop, T value);\n    double get(PropertyName prop);\n    \n    // Device info and advanced configuration\n    std::optional\u003cDeviceInfo\u003e getDeviceInfo() const;\n    bool isFileMode() const;  // Check if playing video file vs camera\n    void setFrameAllocator(std::function\u003cstd::shared_ptr\u003cAllocator\u003e()\u003e allocatorFactory);\n    void setMaxAvailableFrameSize(uint32_t size);\n    void setMaxCacheFrameSize(uint32_t size);\n};\n```\n\n#### ccap::VideoFrame\n\n```cpp\nstruct VideoFrame {\n    \n    // Frame data\n    uint8_t* data[3] = {};                  // Raw pixel data planes\n    uint32_t stride[3] = {};                // Stride for each plane\n    \n    // Frame properties\n    PixelFormat pixelFormat = PixelFormat::Unknown;  // Pixel format\n    uint32_t width = 0;                     // Frame width in pixels\n    uint32_t height = 0;                    // Frame height in pixels\n    uint32_t sizeInBytes = 0;               // Total frame data size\n    uint64_t timestamp = 0;                 // Frame timestamp in nanoseconds\n    uint64_t frameIndex = 0;                // Unique incremental frame index\n    FrameOrientation orientation = FrameOrientation::Default;  // Frame orientation\n    \n    // Memory management and platform features\n    std::shared_ptr\u003cAllocator\u003e allocator;   // Memory allocator\n    void* nativeHandle = nullptr;           // Platform-specific handle\n};\n```\n\n#### Configuration\n\n```cpp\nenum class PropertyName {\n    Width, Height, FrameRate,\n    PixelFormatInternal,        // Camera's internal format\n    PixelFormatOutput,          // Output format (with conversion)\n    FrameOrientation,\n    \n    // Video file playback properties (file mode only)\n    Duration,                   // Video duration in seconds (read-only)\n    CurrentTime,                // Current playback time in seconds\n    FrameCount,                 // Total frame count (read-only)\n    PlaybackSpeed               // Playback speed multiplier (1.0 = normal speed)\n};\n\nenum class PixelFormat : uint32_t {\n    Unknown = 0,\n    NV12, NV12f,               // YUV 4:2:0 semi-planar\n    I420, I420f,               // YUV 4:2:0 planar  \n    RGB24, BGR24,              // 24-bit RGB/BGR\n    RGBA32, BGRA32             // 32-bit RGBA/BGRA\n};\n```\n\n### Video Writing (Windows/macOS)\n\nVideo writing is available on Windows and macOS when `CCAP_ENABLE_VIDEO_WRITER=ON`.\n\n```cpp\n#include \u003cccap.h\u003e\n#include \u003cccap_writer.h\u003e\n\nccap::Provider provider;\nccap::VideoWriter writer;\n\nif (provider.open(\"\", true)) {\n    ccap::WriterConfig cfg;\n    cfg.width = 1280;\n    cfg.height = 720;\n    cfg.frameRate = 30.0;\n    cfg.codec = ccap::VideoCodec::H264;\n    cfg.container = ccap::VideoFormat::MP4;\n\n    if (writer.open(\"camera_record.mp4\", cfg)) {\n        while (auto frame = provider.grab(3000)) {\n            // timestampNs == 0 means auto timestamp generation from frameRate.\n            writer.writeFrame(*frame, 0);\n        }\n        writer.close();\n    }\n}\n```\n\nNotes:\n\n- Writer input supports `NV12`, `I420`, `BGR24`, and `BGRA32`.\n- `VideoFrame::orientation` is honored by the writer path (including `BottomToTop` frames common on Windows RGB capture).\n- `CCAP_ENABLE_VIDEO_WRITER` is independent from `CCAP_ENABLE_FILE_PLAYBACK`.\n\n### Utility Functions\n\n```cpp\nnamespace ccap {\n    // Hardware capabilities\n    bool hasAVX2();\n    bool hasAppleAccelerate();\n    bool hasNEON();\n    \n    // Backend management\n    ConvertBackend getConvertBackend();\n    bool setConvertBackend(ConvertBackend backend);\n    \n    // Format utilities\n    std::string_view pixelFormatToString(PixelFormat format);\n    \n    // File operations\n    std::string dumpFrameToFile(VideoFrame* frame, std::string_view filename);\n    \n    // Logging\n    enum class LogLevel { None, Error, Warning, Info, Verbose };\n    void setLogLevel(LogLevel level);\n}\n```\n\n### Video File Playback\n\nccap supports playing video files using the same API as camera capture (Windows and macOS only):\n\n```cpp\n#include \u003cccap.h\u003e\n\nccap::Provider provider;\n\n// Open video file - same API as camera\nif (provider.open(\"/path/to/video.mp4\", true)) {\n    // Check if in file mode\n    if (provider.isFileMode()) {\n        // Get video properties\n        double duration = provider.get(ccap::PropertyName::Duration);\n        double frameCount = provider.get(ccap::PropertyName::FrameCount);\n        double frameRate = provider.get(ccap::PropertyName::FrameRate);\n        \n        // Set playback speed (1.0 = normal speed)\n        provider.set(ccap::PropertyName::PlaybackSpeed, 1.0);\n        \n        // Seek to specific time\n        provider.set(ccap::PropertyName::CurrentTime, 10.0);  // Seek to 10 seconds\n    }\n    \n    // Grab frames - same API as camera\n    while (auto frame = provider.grab(3000)) {\n        // Process frame...\n    }\n}\n```\n\n**Supported video formats**: MP4, AVI, MOV, MKV, and other formats supported by the platform's media framework.\n\n**Note**: Video playback is currently not supported on Linux. This feature is available on Windows and macOS only.\n\n### OpenCV Integration\n\n```cpp\n#include \u003cccap_opencv.h\u003e\n\nauto frame = provider.grab();\ncv::Mat mat = ccap::convertRgbFrameToMat(*frame);\n```\n\n### Fine-tuned Configuration\n\n```cpp\n// Set specific resolution\nprovider.set(ccap::PropertyName::Width, 1920);\nprovider.set(ccap::PropertyName::Height, 1080);\n\n// Set camera's internal format (helps clarify behavior and optimize performance)\nprovider.set(ccap::PropertyName::PixelFormatInternal, \n             static_cast\u003cdouble\u003e(ccap::PixelFormat::NV12));\n\n// Set camera's output format\nprovider.set(ccap::PropertyName::PixelFormatOutput, \n             static_cast\u003cdouble\u003e(ccap::PixelFormat::BGR24));\n```\n\n### C Language Interface\n\nccap provides a complete pure C language interface for C projects or scenarios requiring language bindings.\n\n#### Core API\n\n##### Provider Lifecycle\n\n```c\n// Create and destroy Provider\nCcapProvider* ccap_provider_create(void);\nvoid ccap_provider_destroy(CcapProvider* provider);\n\n// Device discovery\nbool ccap_provider_find_device_names_list(CcapProvider* provider, \n                                          CcapDeviceNamesList* deviceList);\n\n// Device management\nbool ccap_provider_open(CcapProvider* provider, const char* deviceName, bool autoStart);\nbool ccap_provider_open_by_index(CcapProvider* provider, int deviceIndex, bool autoStart);\nvoid ccap_provider_close(CcapProvider* provider);\nbool ccap_provider_is_opened(CcapProvider* provider);\n\n// Capture control\nbool ccap_provider_start(CcapProvider* provider);\nvoid ccap_provider_stop(CcapProvider* provider);\nbool ccap_provider_is_started(CcapProvider* provider);\n```\n\n##### Video Writer API (C)\n\n```c\nCcapVideoWriter* ccap_video_writer_create(void);\nvoid ccap_video_writer_destroy(CcapVideoWriter* writer);\nbool ccap_video_writer_open(CcapVideoWriter* writer, const char* filePath, const CcapWriterConfig* config);\nbool ccap_video_writer_write_frame(CcapVideoWriter* writer, const CcapVideoFrameInfo* frameInfo, uint64_t timestampNs);\nvoid ccap_video_writer_close(CcapVideoWriter* writer);\nbool ccap_video_writer_is_opened(const CcapVideoWriter* writer);\nCcapVideoCodec ccap_video_writer_actual_codec(const CcapVideoWriter* writer);\n```\n\n`timestampNs == 0` is treated as an auto-timestamp sentinel (derived from configured frame rate), not a literal timeline timestamp.\n\n##### Frame Capture and Processing\n\n```c\n// Synchronous frame capture\nCcapVideoFrame* ccap_provider_grab(CcapProvider* provider, uint32_t timeoutMs);\nvoid ccap_video_frame_release(CcapVideoFrame* frame);\n\n// Asynchronous callback\ntypedef bool (*CcapNewFrameCallback)(const CcapVideoFrame* frame, void* userData);\nvoid ccap_provider_set_new_frame_callback(CcapProvider* provider, \n                                          CcapNewFrameCallback callback, void* userData);\n\n// Frame information\ntypedef struct {\n    uint8_t* data[3];           // Pixel data planes\n    uint32_t stride[3];         // Stride for each plane\n    uint32_t width;             // Width\n    uint32_t height;            // Height\n    uint32_t sizeInBytes;       // Total bytes\n    uint64_t timestamp;         // Timestamp\n    uint64_t frameIndex;        // Frame index\n    CcapPixelFormat pixelFormat; // Pixel format\n    CcapFrameOrientation orientation; // Orientation\n} CcapVideoFrameInfo;\n\n// Device names list\ntypedef struct {\n    char deviceNames[CCAP_MAX_DEVICES][CCAP_MAX_DEVICE_NAME_LENGTH];\n    size_t deviceCount;\n} CcapDeviceNamesList;\n\nbool ccap_video_frame_get_info(const CcapVideoFrame* frame, CcapVideoFrameInfo* info);\n```\n\n##### Property Configuration\n\n```c\n// Property setting and getting\nbool ccap_provider_set_property(CcapProvider* provider, CcapPropertyName prop, double value);\ndouble ccap_provider_get_property(CcapProvider* provider, CcapPropertyName prop);\n\n// Main properties\ntypedef enum {\n    CCAP_PROPERTY_WIDTH = 0x10001,\n    CCAP_PROPERTY_HEIGHT = 0x10002,\n    CCAP_PROPERTY_FRAME_RATE = 0x20000,\n    CCAP_PROPERTY_PIXEL_FORMAT_OUTPUT = 0x30002,\n    CCAP_PROPERTY_FRAME_ORIENTATION = 0x40000\n} CcapPropertyName;\n\n// Pixel formats\ntypedef enum {\n    CCAP_PIXEL_FORMAT_UNKNOWN = 0,\n    CCAP_PIXEL_FORMAT_NV12 = 1 | (1 \u003c\u003c 16),\n    CCAP_PIXEL_FORMAT_NV12F = CCAP_PIXEL_FORMAT_NV12 | (1 \u003c\u003c 17),\n    CCAP_PIXEL_FORMAT_RGB24 = (1 \u003c\u003c 3) | (1 \u003c\u003c 18),\n    CCAP_PIXEL_FORMAT_BGR24 = (1 \u003c\u003c 4) | (1 \u003c\u003c 18),\n    CCAP_PIXEL_FORMAT_RGBA32 = CCAP_PIXEL_FORMAT_RGB24 | (1 \u003c\u003c 19),\n    CCAP_PIXEL_FORMAT_BGRA32 = CCAP_PIXEL_FORMAT_BGR24 | (1 \u003c\u003c 19)\n} CcapPixelFormat;\n```\n\n##### Error Handling\n\nStarting from v1.2.0, ccap uses a global error callback system for simplified error handling:\n\n```c\n// Error codes\ntypedef enum {\n    CCAP_ERROR_NONE = 0,\n    CCAP_ERROR_NO_DEVICE_FOUND = 0x1001,       // No camera device found\n    CCAP_ERROR_INVALID_DEVICE = 0x1002,        // Invalid device name or index\n    CCAP_ERROR_DEVICE_OPEN_FAILED = 0x1003,    // Camera open failed\n    CCAP_ERROR_DEVICE_START_FAILED = 0x1004,   // Camera start failed\n    CCAP_ERROR_UNSUPPORTED_RESOLUTION = 0x2001, // Unsupported resolution\n    CCAP_ERROR_UNSUPPORTED_PIXEL_FORMAT = 0x2002, // Unsupported pixel format\n    CCAP_ERROR_FRAME_CAPTURE_TIMEOUT = 0x3001, // Frame capture timeout\n    CCAP_ERROR_FRAME_CAPTURE_FAILED = 0x3002,  // Frame capture failed\n    // More error codes...\n} CcapErrorCode;\n\n// Error callback function\ntypedef void (*CcapErrorCallback)(CcapErrorCode errorCode, const char* errorDescription, void* userData);\n\n// Set error callback\nbool ccap_set_error_callback(CcapErrorCallback callback, void* userData);\n\n// Get error description\nconst char* ccap_error_code_to_string(CcapErrorCode errorCode);\n\n// Usage example\nvoid error_callback(CcapErrorCode errorCode, const char* errorDescription, void* userData) {\n    printf(\"Camera Error - Code: %d, Description: %s\\n\", (int)errorCode, errorDescription);\n}\n\nint main() {\n    // Set error callback to receive error notifications\n    ccap_set_error_callback(error_callback, NULL);\n    \n    CcapProvider* provider = ccap_provider_create();\n    \n    if (!ccap_provider_open_by_index(provider, 0, true)) {\n        printf(\"Failed to open camera\\n\"); // Error callback will also be called\n    }\n    \n    ccap_provider_destroy(provider);\n    return 0;\n}\n```\n\n#### Compilation and Linking\n\n##### macOS\n\n```bash\ngcc -std=c99 your_code.c -o your_app \\\n    -I/path/to/ccap/include \\\n    -L/path/to/ccap/lib -lccap \\\n    -framework Foundation -framework AVFoundation \\\n    -framework CoreMedia -framework CoreVideo\n```\n\n##### Windows (MSVC)\n\n```cmd\ncl your_code.c /I\"path\\to\\ccap\\include\" \\\n   /link \"path\\to\\ccap\\lib\\ccap.lib\" ole32.lib oleaut32.lib uuid.lib\n```\n\n##### Linux\n\n```bash\ngcc -std=c99 your_code.c -o your_app \\\n    -I/path/to/ccap/include \\\n    -L/path/to/ccap/lib -lccap \\\n    -lpthread\n```\n\n#### Complete Documentation\n\nFor detailed usage instructions and examples of the C interface, see: [C Interface Documentation](./docs/content/c-interface.md)\n\n**Additional C Utilities**: For pixel format string conversion and file I/O functions, also include:\n\n- `#include \u003cccap_utils_c.h\u003e` - provides `ccap_pixel_format_to_string()`, `ccap_dump_frame_to_file()`\n- `#include \u003cccap_convert_c.h\u003e` - provides pixel format conversion functions\n\n## Testing\n\nComprehensive test suite with 50+ test cases covering all functionality:\n\n- Multi-backend testing (CPU, AVX2, Apple Accelerate, NEON)\n- Performance benchmarks and accuracy validation  \n- 95%+ precision for pixel format conversions\n- Video writer regression tests (`ccap_video_writer_test`) covering C++ and C APIs, codec fallback, MOV container, `BottomToTop` orientation, and transcode duration checks\n\n```bash\n./scripts/run_tests.sh\n```\n\n## Build and Install\n\nSee [BUILD_AND_INSTALL.md](./BUILD_AND_INSTALL.md) for complete instructions.\n\n```bash\ngit clone https://github.com/wysaid/CameraCapture.git\ncd CameraCapture\n./scripts/build_and_install.sh\n```\n\n## Contributors\n\nThis project is built with help from the open-source community. Contributions of code, documentation, tests, bug reports, and reviews are all welcome.\n\n[![Contributors](https://contrib.rocks/image?repo=wysaid/CameraCapture)](https://github.com/wysaid/CameraCapture/graphs/contributors)\n\n## License\n\nMIT License. See [LICENSE](./LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwysaid%2Fcameracapture","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwysaid%2Fcameracapture","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwysaid%2Fcameracapture/lists"}