19 #define WIN32_LEAN_AND_MEAN
26 #include <libavdevice/avdevice.h>
36 std::string WideToUtf8(
const wchar_t* value)
38 if (!value || !*value) {
41 const int length = WideCharToMultiByte(CP_UTF8, 0, value, -1,
nullptr, 0,
nullptr,
nullptr);
45 std::string converted(
static_cast<size_t>(length - 1),
'\0');
46 WideCharToMultiByte(CP_UTF8, 0, value, -1, &converted[0], length,
nullptr,
nullptr);
50 bool ContainsDeviceName(
const AudioDeviceList& devices,
const std::string& name)
52 for (
const auto& device : devices) {
53 if (device.second == name) {
63 const HRESULT init_result = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
64 const bool should_uninitialize = SUCCEEDED(init_result);
65 if (FAILED(init_result) && init_result != RPC_E_CHANGED_MODE) {
69 ICreateDevEnum* device_enumerator =
nullptr;
70 HRESULT result = CoCreateInstance(
71 CLSID_SystemDeviceEnum,
75 reinterpret_cast<void**
>(&device_enumerator)
77 if (SUCCEEDED(result) && device_enumerator) {
78 IEnumMoniker* moniker_enumerator =
nullptr;
79 result = device_enumerator->CreateClassEnumerator(
80 CLSID_VideoInputDeviceCategory,
84 if (result == S_OK && moniker_enumerator) {
85 IMoniker* moniker =
nullptr;
86 while (moniker_enumerator->Next(1, &moniker,
nullptr) == S_OK) {
87 IPropertyBag* property_bag =
nullptr;
88 result = moniker->BindToStorage(
92 reinterpret_cast<void**
>(&property_bag)
94 if (SUCCEEDED(result) && property_bag) {
95 VARIANT friendly_name;
96 VariantInit(&friendly_name);
97 result = property_bag->Read(L
"FriendlyName", &friendly_name,
nullptr);
98 if (SUCCEEDED(result) && friendly_name.vt == VT_BSTR) {
99 const std::string name = WideToUtf8(friendly_name.bstrVal);
100 if (!name.empty() && !ContainsDeviceName(devices, name)) {
101 devices.emplace_back(name, name);
104 VariantClear(&friendly_name);
105 property_bag->Release();
110 moniker_enumerator->Release();
112 device_enumerator->Release();
114 if (should_uninitialize) {
123 : settings(new_settings)
140 #if defined(__linux__)
142 #elif defined(_WIN32)
144 #elif defined(__APPLE__)
154 #if defined(__linux__)
156 #elif defined(_WIN32)
158 #elif defined(__APPLE__)
172 const char* input_format_name =
nullptr;
173 #if defined(__linux__)
175 input_format_name =
"v4l2";
177 #elif defined(_WIN32)
179 return GetWindowsDirectShowVideoDevices();
181 #elif defined(__APPLE__)
183 input_format_name =
"avfoundation";
186 if (!input_format_name) {
190 avdevice_register_all();
191 AVInputFormat* input_format =
const_cast<AVInputFormat*
>(av_find_input_format(input_format_name));
196 AVDeviceInfoList* device_list =
nullptr;
197 const int result = avdevice_list_input_sources(input_format,
nullptr,
nullptr, &device_list);
198 if (result >= 0 && device_list) {
199 for (
int index = 0; index < device_list->nb_devices; ++index) {
200 const AVDeviceInfo* device = device_list->devices[index];
201 if (!device || !device->device_name) {
204 const std::string name = device->device_name;
205 const std::string label = device->device_description
206 ? device->device_description
207 : device->device_name;
208 #if defined(__APPLE__)
213 devices.emplace_back(label, name);
216 avdevice_free_list_devices(&device_list);
220 void CameraCaptureReader::ValidateSettings()
const
223 throw InvalidOptions(
"Camera capture backend is not supported on this OS.");
228 throw InvalidOptions(
"Camera capture backend is not implemented in this build.");
230 if (settings.
device.empty()) {
234 throw InvalidOptions(
"Camera capture requires a positive width and height.");
237 throw InvalidOptions(
"Camera capture requires a positive frame rate.");
247 converted.
fps = settings.
fps;
252 converted.
options[
"input_format_name"] =
"dshow";
255 converted.
display = settings.
device.find(
':') == std::string::npos
256 ? settings.
device +
":none"
258 converted.
options[
"input_format_name"] =
"avfoundation";
261 converted.
options[
"input_format_name"] =
"v4l2";
266 void CameraCaptureReader::RebuildReader()
268 reader = std::make_unique<ScreenCaptureReader>(ToDeviceSettings());
294 return reader->GetFrame(number);
305 root[
"type"] =
"CameraCaptureReader";
306 root[
"backend"] = settings.
backend;
307 root[
"device"] = settings.
device;
308 root[
"width"] = settings.
width;
309 root[
"height"] = settings.
height;
310 root[
"fps"][
"num"] = settings.
fps.
num;
311 root[
"fps"][
"den"] = settings.
fps.
den;
312 root[
"options"] = Json::Value(Json::objectValue);
313 for (
const auto& option : settings.
options) {
314 root[
"options"][option.first] = option.second;
323 }
catch (
const std::exception&) {
324 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
330 if (!root[
"backend"].isNull())
332 if (!root[
"device"].isNull())
333 settings.
device = root[
"device"].asString();
334 if (!root[
"width"].isNull())
335 settings.
width = root[
"width"].asInt();
336 if (!root[
"height"].isNull())
337 settings.
height = root[
"height"].asInt();
338 if (!root[
"fps"].isNull() && root[
"fps"].isObject()) {
339 if (!root[
"fps"][
"num"].isNull())
340 settings.
fps.
num = root[
"fps"][
"num"].asInt();
341 if (!root[
"fps"][
"den"].isNull())
342 settings.
fps.
den = root[
"fps"][
"den"].asInt();
344 if (!root[
"options"].isNull() && root[
"options"].isObject()) {
346 for (
const auto& key : root[
"options"].getMemberNames()) {
347 settings.
options[key] = root[
"options"][key].asString();