1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/**
* @file ccap_core.h
* @author wysaid (this@wysaid.org)
* @brief Header file for CameraCapture class.
* @date 2025-04
*
* @note For C language, use ccap_c.h instead of this header.
*
*/
#ifndef __cplusplus
#error "ccap_core.h is for C++ only. For C language, please use ccap_c.h instead."
#endif
#pragma once
#ifndef CCAP_H_
#define CCAP_H_
#include "ccap_def.h"
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
// ccap is short for (C)amera(CAP)ture
namespace ccap {
/// A default allocator
class CCAP_EXPORT DefaultAllocator : public Allocator {
public:
~DefaultAllocator() override;
void resize(size_t size) override;
uint8_t* data() override;
size_t size() override;
private:
uint8_t* m_data = nullptr;
size_t m_size = 0;
};
enum {
/// @brief The default maximum number of frames that can be cached.
DEFAULT_MAX_CACHE_FRAME_SIZE = 15,
/// @brief The default maximum number of frames that can be available.
DEFAULT_MAX_AVAILABLE_FRAME_SIZE = 3
};
class ProviderImp;
/**
* @brief Camera capture provider. This class is used to open a camera device and capture frames from it.
* The actual implementation is platform-dependent.
* @note This class is not thread-safe. It is recommended to use it in a single thread.
* If you need to use it in multiple threads, consider using a mutex or other synchronization methods.
*/
class CCAP_EXPORT Provider final {
public:
/// @brief Default constructor. The camera device is not opened yet.
/// You can use the `open` method to open a camera device later.
Provider();
/**
* @brief Construct a new Provider object, and open the camera device.
* @param deviceName The name of the device to open. @see #open
* @param extraInfo Optional backend hint.
* On Windows, accepted values include `auto`, `msmf`, `dshow`, and `backend=<value>`.
* `auto` enumerates both Windows backends and routes each device to a compatible backend automatically.
* Other platforms ignore this parameter.
*/
explicit Provider(std::string_view deviceName, std::string_view extraInfo = "");
/**
* @brief Construct a new Provider object, and open the camera device.
* @param deviceIndex The index of the device to open. @see #open
* @param extraInfo Optional backend hint.
* On Windows, accepted values include `auto`, `msmf`, `dshow`, and `backend=<value>`.
* `auto` enumerates both Windows backends and routes each device to a compatible backend automatically.
* Other platforms ignore this parameter.
*/
explicit Provider(int deviceIndex, std::string_view extraInfo = "");
/**
* @brief Retrieves the names of all available capture devices. Will perform a scan.
* @return std::vector<std::string> A list of device names, usable with the `open` method.
* @note The first device in the list is not necessarily the default device.
* To use the default device, pass an empty string to the `open` method.
* This method attempts to place real cameras at the beginning of the list and virtual cameras at the end.
*/
std::vector<std::string> findDeviceNames();
/**
* @brief Opens a capture device.
*
* @param deviceName The name of the device to open. The format is platform-dependent. Pass an empty string to use the default device.
* @param autoStart Whether to start capturing frames automatically after opening the device. Default is true.
* @return true if the device was successfully opened, false otherwise.
* @note The device name can be obtained using the `findDeviceNames` method.
*/
bool open(std::string_view deviceName = "", bool autoStart = true);
/**
* @brief Opens a camera by index.
* @param deviceIndex Camera index from findDeviceNames(). A negative value indicates using the default device,
* and a value exceeding the number of devices indicates using the last device.
* @param autoStart Whether to start capturing frames automatically after opening the device. Default is true.
* @return true if successful, false otherwise.
*/
bool open(int deviceIndex, bool autoStart = true);
/**
* @return true if the capture device is currently open, false otherwise.
*/
bool isOpened() const;
/**
* @brief Check if the provider is in file playback mode.
* @return true if opened with a video file path, false otherwise.
*/
bool isFileMode() const;
/**
* @brief Get device info, including current device name, supported resolutions, supported pixel formats, etc.
* @return DeviceInfo. Should be called after `open` succeeds. If the device is not opened, returns std::nullopt.
*/
std::optional<DeviceInfo> getDeviceInfo() const;
/**
* @brief Closes the capture device. After calling this, the object should no longer be used.
* @note This function is automatically called when the object is destroyed.
* You can also call it manually to release resources.
*/
void close();
/**
* @brief Starts capturing frames.
* @return true if capturing started successfully, false otherwise.
*/
bool start();
/**
* @brief Stop frame capturing. You can call `start` to resume capturing later.
*/
void stop();
/**
* @brief Determines whether the camera is currently in a started state. Even if not manually stopped,
* the camera may stop due to reasons such as the device going offline (e.g., USB camera being unplugged).
* @return true if the capture device is open and actively capturing frames, false otherwise.
*/
bool isStarted() const;
/**
* @brief Sets a property of the camera.
* @param prop The property to set. See #Property.
* @param value The value to assign to the property. The value type is double, but the actual type depends on the property.
* Not all properties can be set.
* @return true if the property was successfully set, false otherwise.
* @note Some properties may require the camera to be restarted to take effect.
*/
bool set(PropertyName prop, double value);
template <class T>
bool set(PropertyName prop, T value) {
return set(prop, static_cast<double>(value));
}
/**
* @brief Get a property of the camera.
* @param prop See #Property
* @return The value of the property.
* The value type is double, but the actual type depends on the property.
* Not all properties support being get.
*/
double get(PropertyName prop);
/**
* @brief Grab a new frame. Can be called from any thread, but avoid concurrent calls.
* This method will block the current thread until a new frame is available.
* @param timeoutInMs The maximum wait time (milliseconds). 0 means return immediately. The default is 0xffffffff (wait indefinitely).
* @return a valid `shared_ptr<Frame>` if a new frame is available, nullptr otherwise.
* @note The returned frame is a shared pointer, and the caller can hold and use it later in any thread.
* You don't need to deep copy this `std::shared_ptr<Frame>` object, even if you want to use it in
* different threads or at different times. Just save the smart pointer.
* The frame will be automatically reused when the last reference is released.
*/
std::shared_ptr<VideoFrame> grab(uint32_t timeoutInMs = 0xffffffff);
/**
* @brief Registers a callback to receive new frames.
* @param callback The function to be invoked when a new frame is available.
* The callback returns true to indicate that the frame has been processed and does not need to be retained.
* In this case, the next call to grab() will not return this frame.
* The callback returns false to indicate that the frame should be retained.
* In this case, the next call to grab() may return this frame.
* @note The callback is executed in a background thread.
* The provided frame is a shared pointer, allowing the caller to retain and use it in any thread.
* You don't need to deep copy this `std::shared_ptr<Frame>` object, even if you want to use it in
* different threads or at different times. Just save the smart pointer.
* The frame will be automatically reused when the last reference is released.
*/
void setNewFrameCallback(std::function<bool(const std::shared_ptr<VideoFrame>&)> callback);
/**
* @brief Sets the frame allocator factory. After calling this method, the default Allocator implementation will be overridden.
* @refitem #Frame::allocator
* @param allocatorFactory A factory function that returns a shared pointer to an Allocator instance.
* @note Please call this method before `start()`. Otherwise, errors may occur.
*/
void setFrameAllocator(std::function<std::shared_ptr<Allocator>()> allocatorFactory);
/**
* @brief Sets the maximum number of available frames in the cache. If this limit is exceeded, the oldest frames will be discarded.
* @param size The new maximum number of available frames in the cache.
* It is recommended to set this to at least 1 to avoid performance degradation.
* The default value is DEFAULT_MAX_AVAILABLE_FRAME_SIZE (3).
*/
void setMaxAvailableFrameSize(uint32_t size);
/**
* @brief Sets the maximum number of frames in the internal cache. This affects performance.
* Setting it too high will consume excessive memory, while setting it too low may cause frequent memory allocations, reducing performance.
* @param size The new maximum number of frames in the cache.
* It is recommended to set this to at least 3 to avoid performance degradation.
* The default value is DEFAULT_MAX_CACHE_FRAME_SIZE (15).
*/
void setMaxCacheFrameSize(uint32_t size);
// ↓ This part is not relevant to the user ↓
Provider(Provider&&) noexcept;
Provider& operator=(Provider&&) noexcept;
~Provider();
private:
void applyCachedState(ProviderImp* imp) const;
bool tryOpenWithImplementation(ProviderImp* imp, std::string_view deviceName, bool autoStart) const;
private:
ProviderImp* m_imp = nullptr;
};
/**
* @brief Sets the error callback function to handle errors from all camera operations.
* @param callback The callback function to be invoked when an error occurs.
* The callback receives an error code and English description of the error.
* Pass nullptr to remove the error callback.
* @note The callback is executed in the same thread where the error occurs.
* Keep the callback implementation lightweight to avoid blocking camera operations.
* This callback will be used by all Provider instances.
*/
CCAP_EXPORT void setErrorCallback(ErrorCallback callback);
/**
* @brief Gets the current error callback function.
* @return The current error callback, or nullptr if none is set.
*/
CCAP_EXPORT ErrorCallback getErrorCallback();
} // namespace ccap
#endif // CCAP_H_