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();
std::vector< std::pair< std::string, std::string > > AudioDeviceList
Header file for live camera capture readers.
Header file for all Exception classes.
void Open() override
Open the reader (and start consuming resources, such as images or video files)
Json::Value JsonValue() const override
Generate Json::Value for this object.
void Close() override
Close the reader (and any resources it was consuming)
static bool IsBackendSupported(CameraCaptureBackend backend)
static AudioDeviceList GetDeviceNames(CameraCaptureBackend backend=CAMERA_CAPTURE_AUTO)
CameraCaptureReader(const CameraCaptureSettings &settings)
std::string Json() const override
Generate JSON string of this object.
openshot::CaptureReaderStats GetStats() const
std::shared_ptr< openshot::Frame > GetFrame(int64_t number) override
~CameraCaptureReader() override
static CameraCaptureBackend DefaultBackend()
void SetJson(const std::string value) override
Load JSON string into this object.
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
int num
Numerator for the fraction.
int den
Denominator for the fraction.
Exception for invalid JSON.
Exception when invalid encoding options are used.
openshot::ReaderInfo info
Information about the current media file.
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
This namespace is the default namespace for all code in the openshot library.
@ SCREEN_CAPTURE_MAC_AVFOUNDATION
@ SCREEN_CAPTURE_WINDOWS_GDI
@ CAMERA_CAPTURE_WINDOWS_DSHOW
@ CAMERA_CAPTURE_MAC_AVFOUNDATION
std::vector< std::pair< std::string, std::string > > AudioDeviceList
const Json::Value stringToJson(const std::string value)
std::map< std::string, std::string > options
CameraCaptureBackend backend
std::map< std::string, std::string > metadata
An optional map/dictionary of metadata for this reader.
std::map< std::string, std::string > options
ScreenCaptureBackend backend