A high-performance, lightweight cross-platform camera capture library with hardware-accelerated pixel format conversion, providing complete C++ and pure C language interfaces.
- High Performance: Hardware-accelerated pixel format conversion with up to 10x speedup (AVX2, Apple Accelerate, NEON)
- Lightweight: Zero external dependencies - uses only system frameworks
- Cross Platform: Windows (DirectShow), macOS/iOS (AVFoundation), Linux (V4L2)
- Multiple Formats: RGB, BGR, YUV (NV12/I420) with automatic conversion
- Dual Language APIs: ✨ New Complete Pure C Interface - Both modern C++ API and traditional C99 interface for various project integration and language bindings
- Production Ready: Comprehensive test suite with 95%+ accuracy validation
- Virtual Camera Support: Compatible with OBS Virtual Camera and similar tools
- 
Build and install from source (on Windows, use git-bash): git clone https://github.com/wysaid/CameraCapture.git cd CameraCapture ./scripts/build_and_install.sh
- 
Integrate directly using CMake FetchContent: Add the following to your CMakeLists.txt:include(FetchContent) FetchContent_Declare( ccap GIT_REPOSITORY https://github.com/wysaid/CameraCapture.git GIT_TAG main ) FetchContent_MakeAvailable(ccap) target_link_libraries(your_app PRIVATE ccap::ccap) You can then use ccap headers and features directly in your project. 
- 
Install and use via Homebrew on macOS: - 
First, install the binary with Homebrew: brew tap wysaid/ccap brew install ccap 
- 
Then, use it in CMake: find_package(ccap REQUIRED) target_link_libraries(your_app ccap::ccap) 
 
- 
ccap provides both complete C++ and pure C language interfaces to meet different project and development requirements:
- C++ Interface: Modern C++ API with smart pointers, lambda callbacks, and other advanced features
- Pure C Interface: Fully compatible with C99 standard, supporting language bindings and traditional C project integration
#include <ccap.h>
int main() {
    ccap::Provider provider;
    
    // List available cameras
    auto devices = provider.findDeviceNames();
    for (size_t i = 0; i < devices.size(); ++i) {
        printf("[%zu] %s\n", i, devices[i].c_str());
    }
    
    // Open and start camera
    if (provider.open("", true)) {  // Empty string = default camera
        auto frame = provider.grab(3000);  // 3 second timeout
        if (frame) {
            printf("Captured: %dx%d, %s format\n", 
                   frame->width, frame->height,
                   ccap::pixelFormatToString(frame->pixelFormat).data());
        }
    }
    return 0;
}Starting from v1.2.0, ccap uses a global error callback system for simplified error handling across all camera operations:
#include <ccap.h>
#include <iostream>
int main() {
    // Set error callback to receive detailed error information
    ccap::setErrorCallback([](ccap::ErrorCode errorCode, const std::string& description) {
        std::cerr << "Camera Error - Code: " << static_cast<int>(errorCode) 
                  << ", Description: " << description << std::endl;
    });
    
    ccap::Provider provider;
    
    // Camera operations - errors will trigger the global callback
    if (!provider.open("", true)) {
        std::cerr << "Failed to open camera" << std::endl;
    }
    
    return 0;
}Available error codes include:
- ErrorCode::NoDeviceFound- No camera device found
- ErrorCode::InvalidDevice- Invalid device name or index
- ErrorCode::DeviceOpenFailed- Camera open failed
- ErrorCode::DeviceStartFailed- Camera start failed
- ErrorCode::UnsupportedResolution- Unsupported resolution
- ErrorCode::UnsupportedPixelFormat- Unsupported pixel format
- ErrorCode::FrameCaptureTimeout- Frame capture timeout
- ErrorCode::FrameCaptureFailed- Frame capture failed
#include <ccap_c.h>
#include <ccap_utils_c.h>
int main() {
    // Create provider
    CcapProvider* provider = ccap_provider_create();
    if (!provider) return -1;
    
    // Find available devices
    CcapDeviceNamesList deviceList;
    if (ccap_provider_find_device_names_list(provider, &deviceList)) {
        printf("Found %zu camera device(s):\n", deviceList.deviceCount);
        for (size_t i = 0; i < deviceList.deviceCount; i++) {
            printf("  %zu: %s\n", i, deviceList.deviceNames[i]);
        }
    }
    
    // Open default camera
    if (ccap_provider_open(provider, NULL, false)) {
        // Set output format
        ccap_provider_set_property(provider, CCAP_PROPERTY_PIXEL_FORMAT_OUTPUT, 
                                   CCAP_PIXEL_FORMAT_BGR24);
        
        // Start capture
        if (ccap_provider_start(provider)) {
            // Grab a frame
            CcapVideoFrame* frame = ccap_provider_grab(provider, 3000);
            if (frame) {
                CcapVideoFrameInfo frameInfo;
                if (ccap_video_frame_get_info(frame, &frameInfo)) {
                    // Get pixel format string
                    char formatStr[64];
                    ccap_pixel_format_to_string(frameInfo.pixelFormat, formatStr, sizeof(formatStr));
                    
                    printf("Captured: %dx%d, format=%s\n", 
                           frameInfo.width, frameInfo.height, formatStr);
                }
                ccap_video_frame_release(frame);
            }
        }
        
        ccap_provider_stop(provider);
        ccap_provider_close(provider);
    }
    
    ccap_provider_destroy(provider);
    return 0;
}| Platform | Compiler | System Requirements | 
|---|---|---|
| Windows | MSVC 2019+ | DirectShow | 
| macOS | Xcode 11+ | macOS 10.13+ | 
| iOS | Xcode 11+ | iOS 13.0+ | 
| Linux | GCC 7+ / Clang 6+ | V4L2 (Linux 2.6+) | 
Build Requirements: CMake 3.14+, C++17 (C++ interface), C99 (C interface)
- Ubuntu/Debian - All versions with Linux 2.6+ kernel
- CentOS/RHEL/Fedora - All versions with Linux 2.6+ kernel
- SUSE/openSUSE - All versions with Linux 2.6+ kernel
- Arch Linux - All versions
- Alpine Linux - All versions
- Embedded Linux - Any distribution with V4L2 support
| Example | Description | Language | Platform | 
|---|---|---|---|
| 0-print_camera | List available cameras | C++ | Desktop | 
| 0-print_camera_c | List available cameras | C | Desktop | 
| 1-minimal_example | Basic frame capture | C++ | Desktop | 
| 2-capture_grab | Continuous capture | C++ | Desktop | 
| 3-capture_callback | Callback-based capture | C++ | Desktop | 
| 4-example_with_glfw | OpenGL rendering | C++ | Desktop | 
| iOS Demo | iOS application | Objective-C++ | iOS | 
mkdir build && cd build
cmake .. -DCCAP_BUILD_EXAMPLES=ON
cmake --build .
# Run examples
./0-print_camera
./1-minimal_exampleccap provides both complete C++ and pure C interfaces to meet different project requirements.
class Provider {
public:
    // Constructors
    Provider();
    Provider(std::string_view deviceName, std::string_view extraInfo = "");
    Provider(int deviceIndex, std::string_view extraInfo = "");
    
    // Device discovery
    std::vector<std::string> findDeviceNames();
    
    // Camera lifecycle
    bool open(std::string_view deviceName = "", bool autoStart = true);
    bool open(int deviceIndex, bool autoStart = true);
    bool isOpened() const;
    void close();
    
    // Capture control
    bool start();
    void stop();
    bool isStarted() const;
    
    // Frame capture
    std::shared_ptr<VideoFrame> grab(uint32_t timeoutInMs = 0xffffffff);
    void setNewFrameCallback(std::function<bool(const std::shared_ptr<VideoFrame>&)> callback);
    
    // Property configuration
    bool set(PropertyName prop, double value);
    template<class T> bool set(PropertyName prop, T value);
    double get(PropertyName prop);
    
    // Device info and advanced configuration
    std::optional<DeviceInfo> getDeviceInfo() const;
    void setFrameAllocator(std::function<std::shared_ptr<Allocator>()> allocatorFactory);
    void setMaxAvailableFrameSize(uint32_t size);
    void setMaxCacheFrameSize(uint32_t size);
};struct VideoFrame {
    
    // Frame data
    uint8_t* data[3] = {};                  // Raw pixel data planes
    uint32_t stride[3] = {};                // Stride for each plane
    
    // Frame properties
    PixelFormat pixelFormat = PixelFormat::Unknown;  // Pixel format
    uint32_t width = 0;                     // Frame width in pixels
    uint32_t height = 0;                    // Frame height in pixels
    uint32_t sizeInBytes = 0;               // Total frame data size
    uint64_t timestamp = 0;                 // Frame timestamp in nanoseconds
    uint64_t frameIndex = 0;                // Unique incremental frame index
    FrameOrientation orientation = FrameOrientation::Default;  // Frame orientation
    
    // Memory management and platform features
    std::shared_ptr<Allocator> allocator;   // Memory allocator
    void* nativeHandle = nullptr;           // Platform-specific handle
};enum class PropertyName {
    Width, Height, FrameRate,
    PixelFormatInternal,        // Camera's internal format
    PixelFormatOutput,          // Output format (with conversion)
    FrameOrientation
};
enum class PixelFormat : uint32_t {
    Unknown = 0,
    NV12, NV12f,               // YUV 4:2:0 semi-planar
    I420, I420f,               // YUV 4:2:0 planar  
    RGB24, BGR24,              // 24-bit RGB/BGR
    RGBA32, BGRA32             // 32-bit RGBA/BGRA
};namespace ccap {
    // Hardware capabilities
    bool hasAVX2();
    bool hasAppleAccelerate();
    bool hasNEON();
    
    // Backend management
    ConvertBackend getConvertBackend();
    bool setConvertBackend(ConvertBackend backend);
    
    // Format utilities
    std::string_view pixelFormatToString(PixelFormat format);
    
    // File operations
    std::string dumpFrameToFile(VideoFrame* frame, std::string_view filename);
    
    // Logging
    enum class LogLevel { None, Error, Warning, Info, Verbose };
    void setLogLevel(LogLevel level);
}#include <ccap_opencv.h>
auto frame = provider.grab();
cv::Mat mat = ccap::convertRgbFrameToMat(*frame);// Set specific resolution
provider.set(ccap::PropertyName::Width, 1920);
provider.set(ccap::PropertyName::Height, 1080);
// Set camera's internal format (helps clarify behavior and optimize performance)
provider.set(ccap::PropertyName::PixelFormatInternal, 
             static_cast<double>(ccap::PixelFormat::NV12));
// Set camera's output format
provider.set(ccap::PropertyName::PixelFormatOutput, 
             static_cast<double>(ccap::PixelFormat::BGR24));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
./scripts/run_tests.shSee BUILD_AND_INSTALL.md for complete instructions.
git clone https://github.com/wysaid/CameraCapture.git
cd CameraCapture
./scripts/build_and_install.shMIT License. See LICENSE for details.
ccap provides a complete pure C language interface for C projects or scenarios requiring language bindings.
// Create and destroy Provider
CcapProvider* ccap_provider_create(void);
void ccap_provider_destroy(CcapProvider* provider);
// Device discovery
bool ccap_provider_find_device_names_list(CcapProvider* provider, 
                                          CcapDeviceNamesList* deviceList);
// Device management
bool ccap_provider_open(CcapProvider* provider, const char* deviceName, bool autoStart);
bool ccap_provider_open_by_index(CcapProvider* provider, int deviceIndex, bool autoStart);
void ccap_provider_close(CcapProvider* provider);
bool ccap_provider_is_opened(CcapProvider* provider);
// Capture control
bool ccap_provider_start(CcapProvider* provider);
void ccap_provider_stop(CcapProvider* provider);
bool ccap_provider_is_started(CcapProvider* provider);// Synchronous frame capture
CcapVideoFrame* ccap_provider_grab(CcapProvider* provider, uint32_t timeoutMs);
void ccap_video_frame_release(CcapVideoFrame* frame);
// Asynchronous callback
typedef bool (*CcapNewFrameCallback)(const CcapVideoFrame* frame, void* userData);
void ccap_provider_set_new_frame_callback(CcapProvider* provider, 
                                          CcapNewFrameCallback callback, void* userData);
// Frame information
typedef struct {
    uint8_t* data[3];           // Pixel data planes
    uint32_t stride[3];         // Stride for each plane
    uint32_t width;             // Width
    uint32_t height;            // Height
    uint32_t sizeInBytes;       // Total bytes
    uint64_t timestamp;         // Timestamp
    uint64_t frameIndex;        // Frame index
    CcapPixelFormat pixelFormat; // Pixel format
    CcapFrameOrientation orientation; // Orientation
} CcapVideoFrameInfo;
// Device names list
typedef struct {
    char deviceNames[CCAP_MAX_DEVICES][CCAP_MAX_DEVICE_NAME_LENGTH];
    size_t deviceCount;
} CcapDeviceNamesList;
bool ccap_video_frame_get_info(const CcapVideoFrame* frame, CcapVideoFrameInfo* info);// Property setting and getting
bool ccap_provider_set_property(CcapProvider* provider, CcapPropertyName prop, double value);
double ccap_provider_get_property(CcapProvider* provider, CcapPropertyName prop);
// Main properties
typedef enum {
    CCAP_PROPERTY_WIDTH = 0x10001,
    CCAP_PROPERTY_HEIGHT = 0x10002,
    CCAP_PROPERTY_FRAME_RATE = 0x20000,
    CCAP_PROPERTY_PIXEL_FORMAT_OUTPUT = 0x30002,
    CCAP_PROPERTY_FRAME_ORIENTATION = 0x40000
} CcapPropertyName;
// Pixel formats
typedef enum {
    CCAP_PIXEL_FORMAT_UNKNOWN = 0,
    CCAP_PIXEL_FORMAT_NV12 = 1 | (1 << 16),
    CCAP_PIXEL_FORMAT_NV12F = CCAP_PIXEL_FORMAT_NV12 | (1 << 17),
    CCAP_PIXEL_FORMAT_RGB24 = (1 << 3) | (1 << 18),
    CCAP_PIXEL_FORMAT_BGR24 = (1 << 4) | (1 << 18),
    CCAP_PIXEL_FORMAT_RGBA32 = CCAP_PIXEL_FORMAT_RGB24 | (1 << 19),
    CCAP_PIXEL_FORMAT_BGRA32 = CCAP_PIXEL_FORMAT_BGR24 | (1 << 19)
} CcapPixelFormat;Starting from v1.2.0, ccap uses a global error callback system for simplified error handling:
// Error codes
typedef enum {
    CCAP_ERROR_NONE = 0,
    CCAP_ERROR_NO_DEVICE_FOUND = 0x1001,       // No camera device found
    CCAP_ERROR_INVALID_DEVICE = 0x1002,        // Invalid device name or index
    CCAP_ERROR_DEVICE_OPEN_FAILED = 0x1003,    // Camera open failed
    CCAP_ERROR_DEVICE_START_FAILED = 0x1004,   // Camera start failed
    CCAP_ERROR_UNSUPPORTED_RESOLUTION = 0x2001, // Unsupported resolution
    CCAP_ERROR_UNSUPPORTED_PIXEL_FORMAT = 0x2002, // Unsupported pixel format
    CCAP_ERROR_FRAME_CAPTURE_TIMEOUT = 0x3001, // Frame capture timeout
    CCAP_ERROR_FRAME_CAPTURE_FAILED = 0x3002,  // Frame capture failed
    // More error codes...
} CcapErrorCode;
// Error callback function
typedef void (*CcapErrorCallback)(CcapErrorCode errorCode, const char* errorDescription, void* userData);
// Set error callback
bool ccap_set_error_callback(CcapErrorCallback callback, void* userData);
// Get error description
const char* ccap_error_code_to_string(CcapErrorCode errorCode);
// Usage example
void error_callback(CcapErrorCode errorCode, const char* errorDescription, void* userData) {
    printf("Camera Error - Code: %d, Description: %s\n", (int)errorCode, errorDescription);
}
int main() {
    // Set error callback to receive error notifications
    ccap_set_error_callback(error_callback, NULL);
    
    CcapProvider* provider = ccap_provider_create();
    
    if (!ccap_provider_open_by_index(provider, 0, true)) {
        printf("Failed to open camera\n"); // Error callback will also be called
    }
    
    ccap_provider_destroy(provider);
    return 0;
}gcc -std=c99 your_code.c -o your_app \
    -I/path/to/ccap/include \
    -L/path/to/ccap/lib -lccap \
    -framework Foundation -framework AVFoundation \
    -framework CoreMedia -framework CoreVideocl your_code.c /I"path\to\ccap\include" \
   /link "path\to\ccap\lib\ccap.lib" strmiids.lib ole32.lib oleaut32.lib uuid.libgcc -std=c99 your_code.c -o your_app \
    -I/path/to/ccap/include \
    -L/path/to/ccap/lib -lccap \
    -lpthreadFor detailed usage instructions and examples of the C interface, see: C Interface Documentation
Additional C Utilities: For pixel format string conversion and file I/O functions, also include:
- #include <ccap_utils_c.h>- provides- ccap_pixel_format_to_string(),- ccap_dump_frame_to_file()
- #include <ccap_convert_c.h>- provides pixel format conversion functions