plugin-main.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include "decklink.hpp"
  2. #include "decklink-device.hpp"
  3. #include "decklink-device-discovery.hpp"
  4. #include <obs-module.h>
  5. OBS_DECLARE_MODULE()
  6. OBS_MODULE_USE_DEFAULT_LOCALE("decklink", "en-US")
  7. #define DEVICE_HASH "device_hash"
  8. #define DEVICE_NAME "device_name"
  9. #define MODE_ID "mode_id"
  10. #define MODE_NAME "mode_name"
  11. #define CHANNEL_FORMAT "channel_format"
  12. #define PIXEL_FORMAT "pixel_format"
  13. #define BUFFERING "buffering"
  14. #define TEXT_DEVICE obs_module_text("Device")
  15. #define TEXT_MODE obs_module_text("Mode")
  16. #define TEXT_PIXEL_FORMAT obs_module_text("PixelFormat")
  17. #define TEXT_CHANNEL_FORMAT obs_module_text("ChannelFormat")
  18. #define TEXT_CHANNEL_FORMAT_NONE obs_module_text("ChannelFormat.None")
  19. #define TEXT_CHANNEL_FORMAT_2_0CH obs_module_text("ChannelFormat.2_0ch")
  20. #define TEXT_CHANNEL_FORMAT_5_1CH obs_module_text("ChannelFormat.5_1ch")
  21. #define TEXT_CHANNEL_FORMAT_5_1CH_BACK obs_module_text("ChannelFormat.5_1chBack")
  22. #define TEXT_CHANNEL_FORMAT_7_1CH obs_module_text("ChannelFormat.7_1ch")
  23. #define TEXT_BUFFERING obs_module_text("Buffering")
  24. static DeckLinkDeviceDiscovery *deviceEnum = nullptr;
  25. static void decklink_enable_buffering(DeckLink *decklink, bool enabled)
  26. {
  27. obs_source_t *source = decklink->GetSource();
  28. obs_source_set_async_unbuffered(source, !enabled);
  29. }
  30. static void *decklink_create(obs_data_t *settings, obs_source_t *source)
  31. {
  32. DeckLink *decklink = new DeckLink(source, deviceEnum);
  33. decklink_enable_buffering(decklink,
  34. obs_data_get_bool(settings, BUFFERING));
  35. obs_source_update(source, settings);
  36. return decklink;
  37. }
  38. static void decklink_destroy(void *data)
  39. {
  40. DeckLink *decklink = (DeckLink *)data;
  41. delete decklink;
  42. }
  43. static void decklink_update(void *data, obs_data_t *settings)
  44. {
  45. DeckLink *decklink = (DeckLink *)data;
  46. const char *hash = obs_data_get_string(settings, DEVICE_HASH);
  47. long long id = obs_data_get_int(settings, MODE_ID);
  48. BMDPixelFormat pixelFormat = (BMDPixelFormat)obs_data_get_int(settings,
  49. PIXEL_FORMAT);
  50. speaker_layout channelFormat = (speaker_layout)obs_data_get_int(settings,
  51. CHANNEL_FORMAT);
  52. decklink_enable_buffering(decklink,
  53. obs_data_get_bool(settings, BUFFERING));
  54. ComPtr<DeckLinkDevice> device;
  55. device.Set(deviceEnum->FindByHash(hash));
  56. decklink->SetPixelFormat(pixelFormat);
  57. decklink->SetChannelFormat(channelFormat);
  58. decklink->Activate(device, id);
  59. }
  60. static void decklink_get_defaults(obs_data_t *settings)
  61. {
  62. obs_data_set_default_bool(settings, BUFFERING, true);
  63. obs_data_set_default_int(settings, PIXEL_FORMAT, bmdFormat8BitYUV);
  64. obs_data_set_default_int(settings, CHANNEL_FORMAT, SPEAKERS_STEREO);
  65. }
  66. static const char *decklink_get_name(void*)
  67. {
  68. return obs_module_text("BlackmagicDevice");
  69. }
  70. static bool decklink_device_changed(obs_properties_t *props,
  71. obs_property_t *list, obs_data_t *settings)
  72. {
  73. const char *name = obs_data_get_string(settings, DEVICE_NAME);
  74. const char *hash = obs_data_get_string(settings, DEVICE_HASH);
  75. const char *mode = obs_data_get_string(settings, MODE_NAME);
  76. long long modeId = obs_data_get_int(settings, MODE_ID);
  77. size_t itemCount = obs_property_list_item_count(list);
  78. bool itemFound = false;
  79. for (size_t i = 0; i < itemCount; i++) {
  80. const char *curHash = obs_property_list_item_string(list, i);
  81. if (strcmp(hash, curHash) == 0) {
  82. itemFound = true;
  83. break;
  84. }
  85. }
  86. if (!itemFound) {
  87. obs_property_list_insert_string(list, 0, name, hash);
  88. obs_property_list_item_disable(list, 0, true);
  89. }
  90. obs_property_t *modeList = obs_properties_get(props, MODE_ID);
  91. obs_property_t *channelList = obs_properties_get(props, CHANNEL_FORMAT);
  92. obs_property_list_clear(modeList);
  93. obs_property_list_clear(channelList);
  94. obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_NONE,
  95. SPEAKERS_UNKNOWN);
  96. obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_2_0CH,
  97. SPEAKERS_STEREO);
  98. ComPtr<DeckLinkDevice> device;
  99. device.Set(deviceEnum->FindByHash(hash));
  100. if (!device) {
  101. obs_property_list_add_int(modeList, mode, modeId);
  102. obs_property_list_item_disable(modeList, 0, true);
  103. } else {
  104. const std::vector<DeckLinkDeviceMode*> &modes =
  105. device->GetModes();
  106. for (DeckLinkDeviceMode *mode : modes) {
  107. obs_property_list_add_int(modeList,
  108. mode->GetName().c_str(),
  109. mode->GetId());
  110. }
  111. if (device->GetMaxChannel() >= 8) {
  112. obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_5_1CH,
  113. SPEAKERS_5POINT1);
  114. obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_5_1CH_BACK,
  115. SPEAKERS_5POINT1_SURROUND);
  116. obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_7_1CH,
  117. SPEAKERS_7POINT1);
  118. }
  119. }
  120. return true;
  121. }
  122. static void fill_out_devices(obs_property_t *list)
  123. {
  124. deviceEnum->Lock();
  125. const std::vector<DeckLinkDevice*> &devices = deviceEnum->GetDevices();
  126. for (DeckLinkDevice *device : devices) {
  127. obs_property_list_add_string(list,
  128. device->GetDisplayName().c_str(),
  129. device->GetHash().c_str());
  130. }
  131. deviceEnum->Unlock();
  132. }
  133. static obs_properties_t *decklink_get_properties(void *data)
  134. {
  135. obs_properties_t *props = obs_properties_create();
  136. obs_property_t *list = obs_properties_add_list(props, DEVICE_HASH,
  137. TEXT_DEVICE, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
  138. obs_property_set_modified_callback(list, decklink_device_changed);
  139. fill_out_devices(list);
  140. list = obs_properties_add_list(props, MODE_ID, TEXT_MODE,
  141. OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
  142. list = obs_properties_add_list(props, PIXEL_FORMAT,
  143. TEXT_PIXEL_FORMAT, OBS_COMBO_TYPE_LIST,
  144. OBS_COMBO_FORMAT_INT);
  145. obs_property_list_add_int(list, "8-bit YUV", bmdFormat8BitYUV);
  146. obs_property_list_add_int(list, "8-bit BGRA", bmdFormat8BitBGRA);
  147. list = obs_properties_add_list(props, CHANNEL_FORMAT,
  148. TEXT_CHANNEL_FORMAT, OBS_COMBO_TYPE_LIST,
  149. OBS_COMBO_FORMAT_INT);
  150. obs_property_list_add_int(list, TEXT_CHANNEL_FORMAT_NONE,
  151. SPEAKERS_UNKNOWN);
  152. obs_property_list_add_int(list, TEXT_CHANNEL_FORMAT_2_0CH,
  153. SPEAKERS_STEREO);
  154. obs_properties_add_bool(props, BUFFERING, TEXT_BUFFERING);
  155. UNUSED_PARAMETER(data);
  156. return props;
  157. }
  158. bool obs_module_load(void)
  159. {
  160. deviceEnum = new DeckLinkDeviceDiscovery();
  161. if (!deviceEnum->Init())
  162. return true;
  163. struct obs_source_info info = {};
  164. info.id = "decklink-input";
  165. info.type = OBS_SOURCE_TYPE_INPUT;
  166. info.output_flags = OBS_SOURCE_ASYNC_VIDEO | OBS_SOURCE_AUDIO |
  167. OBS_SOURCE_DO_NOT_DUPLICATE;
  168. info.create = decklink_create;
  169. info.destroy = decklink_destroy;
  170. info.get_defaults = decklink_get_defaults;
  171. info.get_name = decklink_get_name;
  172. info.get_properties = decklink_get_properties;
  173. info.update = decklink_update;
  174. obs_register_source(&info);
  175. return true;
  176. }
  177. void obs_module_unload(void)
  178. {
  179. delete deviceEnum;
  180. }