|
@@ -0,0 +1,174 @@
|
|
|
+#include "decklink.hpp"
|
|
|
+#include "decklink-device.hpp"
|
|
|
+#include "decklink-device-discovery.hpp"
|
|
|
+
|
|
|
+#include <obs-module.h>
|
|
|
+
|
|
|
+OBS_DECLARE_MODULE()
|
|
|
+OBS_MODULE_USE_DEFAULT_LOCALE("decklink", "en-US")
|
|
|
+
|
|
|
+static DeckLinkDeviceDiscovery *deviceEnum = nullptr;
|
|
|
+
|
|
|
+static void decklink_enable_buffering(DeckLink *decklink, bool enabled)
|
|
|
+{
|
|
|
+ obs_source_t *source = decklink->GetSource();
|
|
|
+ uint32_t flags = obs_source_get_flags(source);
|
|
|
+ if (enabled)
|
|
|
+ flags &= ~OBS_SOURCE_FLAG_UNBUFFERED;
|
|
|
+ else
|
|
|
+ flags |= OBS_SOURCE_FLAG_UNBUFFERED;
|
|
|
+ obs_source_set_flags(source, flags);
|
|
|
+}
|
|
|
+
|
|
|
+static void *decklink_create(obs_data_t *settings, obs_source_t *source)
|
|
|
+{
|
|
|
+ DeckLink *decklink = new DeckLink(source, deviceEnum);
|
|
|
+
|
|
|
+ decklink_enable_buffering(decklink,
|
|
|
+ obs_data_get_bool(settings, "buffering"));
|
|
|
+
|
|
|
+ obs_source_update(source, settings);
|
|
|
+ return decklink;
|
|
|
+}
|
|
|
+
|
|
|
+static void decklink_destroy(void *data)
|
|
|
+{
|
|
|
+ DeckLink *decklink = (DeckLink *)data;
|
|
|
+ delete decklink;
|
|
|
+}
|
|
|
+
|
|
|
+static void decklink_update(void *data, obs_data_t *settings)
|
|
|
+{
|
|
|
+ DeckLink *decklink = (DeckLink *)data;
|
|
|
+ const char *hash = obs_data_get_string(settings, "device_hash");
|
|
|
+ long long id = obs_data_get_int(settings, "mode_id");
|
|
|
+
|
|
|
+ decklink_enable_buffering(decklink,
|
|
|
+ obs_data_get_bool(settings, "buffering"));
|
|
|
+
|
|
|
+ ComPtr<DeckLinkDevice> device;
|
|
|
+ device.Set(deviceEnum->FindByHash(hash));
|
|
|
+
|
|
|
+ decklink->Activate(device, id);
|
|
|
+}
|
|
|
+
|
|
|
+static void decklink_get_defaults(obs_data_t *settings)
|
|
|
+{
|
|
|
+ obs_data_set_default_bool(settings, "buffering", true);
|
|
|
+}
|
|
|
+
|
|
|
+static const char *decklink_get_name()
|
|
|
+{
|
|
|
+ return obs_module_text("BlackmagicDevice");
|
|
|
+}
|
|
|
+
|
|
|
+static bool decklink_device_changed(obs_properties_t *props,
|
|
|
+ obs_property_t *list, obs_data_t *settings)
|
|
|
+{
|
|
|
+ const char *name = obs_data_get_string(settings, "device_name");
|
|
|
+ const char *hash = obs_data_get_string(settings, "device_hash");
|
|
|
+ const char *mode = obs_data_get_string(settings, "mode_name");
|
|
|
+ long long modeId = obs_data_get_int(settings, "mode_id");
|
|
|
+
|
|
|
+ size_t itemCount = obs_property_list_item_count(list);
|
|
|
+ bool itemFound = false;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < itemCount; i++) {
|
|
|
+ const char *curHash = obs_property_list_item_string(list, i);
|
|
|
+ if (strcmp(hash, curHash) == 0) {
|
|
|
+ itemFound = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!itemFound) {
|
|
|
+ obs_property_list_insert_string(list, 0, name, hash);
|
|
|
+ obs_property_list_item_disable(list, 0, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ list = obs_properties_get(props, "mode_id");
|
|
|
+
|
|
|
+ obs_property_list_clear(list);
|
|
|
+
|
|
|
+ ComPtr<DeckLinkDevice> device;
|
|
|
+ device.Set(deviceEnum->FindByHash(hash));
|
|
|
+
|
|
|
+ if (!device) {
|
|
|
+ obs_property_list_add_int(list, mode, modeId);
|
|
|
+ obs_property_list_item_disable(list, 0, true);
|
|
|
+ } else {
|
|
|
+ const std::vector<DeckLinkDeviceMode*> &modes =
|
|
|
+ device->GetModes();
|
|
|
+
|
|
|
+ for (DeckLinkDeviceMode *mode : modes) {
|
|
|
+ obs_property_list_add_int(list,
|
|
|
+ mode->GetName().c_str(),
|
|
|
+ mode->GetId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static void fill_out_devices(obs_property_t *list)
|
|
|
+{
|
|
|
+ deviceEnum->Lock();
|
|
|
+
|
|
|
+ const std::vector<DeckLinkDevice*> &devices = deviceEnum->GetDevices();
|
|
|
+ for (DeckLinkDevice *device : devices) {
|
|
|
+ obs_property_list_add_string(list,
|
|
|
+ device->GetDisplayName().c_str(),
|
|
|
+ device->GetHash().c_str());
|
|
|
+ }
|
|
|
+
|
|
|
+ deviceEnum->Unlock();
|
|
|
+}
|
|
|
+
|
|
|
+static obs_properties_t *decklink_get_properties(void *data)
|
|
|
+{
|
|
|
+ obs_properties_t *props = obs_properties_create();
|
|
|
+
|
|
|
+ obs_property_t *list = obs_properties_add_list(props, "device_hash",
|
|
|
+ obs_module_text("Device"), OBS_COMBO_TYPE_LIST,
|
|
|
+ OBS_COMBO_FORMAT_STRING);
|
|
|
+ obs_property_set_modified_callback(list, decklink_device_changed);
|
|
|
+
|
|
|
+ fill_out_devices(list);
|
|
|
+
|
|
|
+ list = obs_properties_add_list(props, "mode_id",
|
|
|
+ obs_module_text("Mode"), OBS_COMBO_TYPE_LIST,
|
|
|
+ OBS_COMBO_FORMAT_INT);
|
|
|
+
|
|
|
+ obs_properties_add_bool(props, "buffering",
|
|
|
+ obs_module_text("Buffering"));
|
|
|
+
|
|
|
+ UNUSED_PARAMETER(data);
|
|
|
+ return props;
|
|
|
+}
|
|
|
+
|
|
|
+bool obs_module_load(void)
|
|
|
+{
|
|
|
+ deviceEnum = new DeckLinkDeviceDiscovery();
|
|
|
+ if (!deviceEnum->Init())
|
|
|
+ return true;
|
|
|
+
|
|
|
+ struct obs_source_info info = {};
|
|
|
+ info.id = "decklink-input";
|
|
|
+ info.type = OBS_SOURCE_TYPE_INPUT;
|
|
|
+ info.output_flags = OBS_SOURCE_ASYNC_VIDEO | OBS_SOURCE_AUDIO;
|
|
|
+ info.create = decklink_create;
|
|
|
+ info.destroy = decklink_destroy;
|
|
|
+ info.get_defaults = decklink_get_defaults;
|
|
|
+ info.get_name = decklink_get_name;
|
|
|
+ info.get_properties = decklink_get_properties;
|
|
|
+ info.update = decklink_update;
|
|
|
+
|
|
|
+ obs_register_source(&info);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void obs_module_unload(void)
|
|
|
+{
|
|
|
+ delete deviceEnum;
|
|
|
+}
|