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 foundErrorCode::InvalidDevice
- Invalid device name or indexErrorCode::DeviceOpenFailed
- Camera open failedErrorCode::DeviceStartFailed
- Camera start failedErrorCode::UnsupportedResolution
- Unsupported resolutionErrorCode::UnsupportedPixelFormat
- Unsupported pixel formatErrorCode::FrameCaptureTimeout
- Frame capture timeoutErrorCode::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_example
ccap 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.sh
See BUILD_AND_INSTALL.md for complete instructions.
git clone https://github.com/wysaid/CameraCapture.git
cd CameraCapture
./scripts/build_and_install.sh
MIT 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 CoreVideo
cl your_code.c /I"path\to\ccap\include" \
/link "path\to\ccap\lib\ccap.lib" strmiids.lib ole32.lib oleaut32.lib uuid.lib
gcc -std=c99 your_code.c -o your_app \
-I/path/to/ccap/include \
-L/path/to/ccap/lib -lccap \
-lpthread
For 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>
- providesccap_pixel_format_to_string()
,ccap_dump_frame_to_file()
#include <ccap_convert_c.h>
- provides pixel format conversion functions