You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
8.2 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. #include "obs-manager.hpp"
  2. #include "settings-manager.hpp"
  3. #include <ctime>
  4. #include <list>
  5. #include <filesystem>
  6. #include <stdexcept>
  7. using namespace std;
  8. //
  9. // Static Functions
  10. //
  11. static void OBSRender(void *param, uint32_t cx, uint32_t cy)
  12. {
  13. obs_render_main_texture();
  14. }
  15. static void OBSStartRecording(void *data, calldata_t *params)
  16. {
  17. OBSManager *o = static_cast<OBSManager*>(data);
  18. o->sigStartRecording.emit();
  19. }
  20. static void OBSStopRecording(void *data, calldata_t *params)
  21. {
  22. OBSManager *o = static_cast<OBSManager*>(data);
  23. o->sigStopRecording.emit();
  24. }
  25. //
  26. // OBSManager
  27. //
  28. OBSManager::OBSManager()
  29. {
  30. mPlugins = {
  31. "obs-ffmpeg.so",
  32. "obs-outputs.so",
  33. "obs-x264.so",
  34. "linux-alsa.so",
  35. "linux-pulseaudio.so",
  36. "linux-v4l2.so",
  37. "linux-capture.so",
  38. };
  39. }
  40. OBSManager::~OBSManager()
  41. {
  42. Cleanup();
  43. }
  44. string OBSManager::GetVersion()
  45. {
  46. return string(obs_get_version_string());
  47. }
  48. void OBSManager::LoadSettings(SettingsManager *settings)
  49. {
  50. mPluginDir = settings->GetWithDefault(SETTINGS_KEY_PLUGIN_DIR, SETTINGS_DEFAULT_PLUGIN_DIR);
  51. mOutputDir = settings->GetWithDefault(SETTINGS_KEY_OUTPUT_DIR, std::filesystem::current_path());
  52. mWebcamDeviceID = settings->Get(SETTINGS_KEY_VIDEO_DEVICE_ID);
  53. mAudioDeviceID = settings->Get(SETTINGS_KEY_AUDIO_DEVICE_ID);
  54. mScreenEnabled = settings->GetBool(SETTINGS_KEY_SCREEN_ENABLED);
  55. mWebcamEnabled = settings->GetBool(SETTINGS_KEY_WEBCAM_ENABLED);
  56. mAudioEnabled = settings->GetBool(SETTINGS_KEY_AUDIO_ENABLED);
  57. }
  58. void OBSManager::Initialize(Gdk::Rectangle rect)
  59. {
  60. if (isInitialized)
  61. return;
  62. mScreenWidth = rect.get_width();
  63. mScreenHeight = rect.get_height();
  64. auto settings = new SettingsManager();
  65. LoadSettings(settings);
  66. if (!obs_startup("en-US", NULL, NULL))
  67. throw runtime_error("Failed to initialize OBS");
  68. loadPlugins();
  69. obs_video_info v = {};
  70. v.graphics_module = "libobs-opengl.so.0";
  71. v.fps_num = 30000;
  72. v.fps_den = 1001;
  73. v.base_width = mScreenWidth;
  74. v.base_height = mScreenHeight;
  75. v.output_width = mScreenWidth;
  76. v.output_height = mScreenHeight;
  77. v.output_format = VIDEO_FORMAT_NV12;
  78. v.adapter = 0;
  79. v.gpu_conversion = true;
  80. v.colorspace = VIDEO_CS_601;
  81. v.range = VIDEO_RANGE_PARTIAL;
  82. v.scale_type = OBS_SCALE_BICUBIC;
  83. obs_audio_info a = {};
  84. a.samples_per_sec = 44100;
  85. a.speakers = SPEAKERS_STEREO;
  86. obs_reset_video(&v);
  87. obs_reset_audio(&a);
  88. isInitialized = true;
  89. //printTypes();
  90. }
  91. void OBSManager::StartPreview(XID wid, Display *wdisplay)
  92. {
  93. gs_init_data init = {};
  94. init.cx = mScreenWidth;
  95. init.cy = mScreenHeight;
  96. init.format = GS_BGRA;
  97. init.zsformat = GS_ZS_NONE;
  98. init.window.id = wid;
  99. init.window.display = (void*)wdisplay;
  100. mDisplay = obs_display_create(&init, 0);
  101. if (mDisplay == nullptr)
  102. throw runtime_error("Failed to create display");
  103. //obs_display_resize(mDisplay, PreviewWidth, PreviewHeight);
  104. obs_display_add_draw_callback(mDisplay, OBSRender, nullptr);
  105. auto sources = new list<OBSSource>();
  106. OBSScene scene = obs_scene_create("Main");
  107. if (scene == NULL)
  108. throw runtime_error("Couldn't create scene\n");
  109. if (mScreenEnabled)
  110. {
  111. auto source = CreateScreenSource();
  112. obs_scene_add(scene, source);
  113. sources->push_back(source);
  114. }
  115. if (mWebcamEnabled)
  116. {
  117. vec2 scale;
  118. vec2_set(&scale, 0.5f, 0.5f);
  119. auto source = CreateWebcamSource();
  120. auto item = obs_scene_add(scene, source);
  121. obs_sceneitem_set_scale(item, &scale);
  122. sources->push_back(source);
  123. }
  124. if (mAudioEnabled)
  125. {
  126. auto source = CreateAudioSource();
  127. obs_scene_add(scene, source);
  128. sources->push_back(source);
  129. }
  130. obs_set_output_source(0, obs_scene_get_source(scene));
  131. obs_scene_release(scene);
  132. for (auto source : *sources)
  133. {
  134. obs_source_release(source);
  135. }
  136. sigStartPreview.emit();
  137. }
  138. void OBSManager::StopPreview()
  139. {
  140. if (mDisplay != nullptr)
  141. obs_display_destroy(mDisplay);
  142. sigStopPreview.emit();
  143. }
  144. void OBSManager::StartRecording()
  145. {
  146. if (isRecording)
  147. return;
  148. auto s = new SettingsManager();
  149. OBSEncoder venc = obs_video_encoder_create("obs_x264", "x264_enc", nullptr, nullptr);
  150. OBSEncoder aenc = obs_audio_encoder_create("ffmpeg_aac", "aac_enc", nullptr, 0, nullptr);
  151. string path = s->GetWithDefault(SETTINGS_KEY_OUTPUT_DIR, filesystem::current_path());
  152. if (path.back() != '/')
  153. path += "/";
  154. string fileName = path + "recording_" + to_string(time(0)) + ".mp4";
  155. obs_data_t *settings = obs_data_create();
  156. obs_data_set_string(settings, "directory", path.c_str());
  157. obs_data_set_string(settings, "url", fileName.c_str());
  158. obs_data_set_string(settings, "path", fileName.c_str());
  159. mOutput = obs_output_create("ffmpeg_muxer", "output", nullptr, nullptr);
  160. obs_output_set_video_encoder(mOutput, venc);
  161. obs_output_set_audio_encoder(mOutput, aenc, 0);
  162. obs_output_update(mOutput, settings);
  163. obs_output_set_media(mOutput, obs_get_video(), obs_get_audio());
  164. obs_encoder_set_video(venc, obs_get_video());
  165. obs_encoder_set_audio(aenc, obs_get_audio());
  166. obs_data_release(settings);
  167. if (!obs_output_start(mOutput))
  168. throw runtime_error("Failed to start recording");
  169. obsStartRecording.Connect(obs_output_get_signal_handler(mOutput), "start", OBSStartRecording, this);
  170. obsStopRecording.Connect(obs_output_get_signal_handler(mOutput), "stop", OBSStopRecording, this);
  171. obs_encoder_release(venc);
  172. obs_encoder_release(aenc);
  173. obs_output_release(mOutput);
  174. isRecording = true;
  175. }
  176. void OBSManager::StopRecording()
  177. {
  178. if (isRecording && mOutput != nullptr)
  179. obs_output_stop(mOutput);
  180. isRecording = false;
  181. }
  182. bool OBSManager::IsRecording()
  183. {
  184. return isRecording;
  185. }
  186. void OBSManager::Cleanup()
  187. {
  188. if (isInitialized)
  189. {
  190. StopRecording();
  191. StopPreview();
  192. if (obs_initialized())
  193. obs_shutdown();
  194. isInitialized = false;
  195. }
  196. sigCleanup.emit();
  197. }
  198. //
  199. // Sources
  200. //
  201. OBSSource OBSManager::CreateScreenSource()
  202. {
  203. obs_data_t *settings = obs_data_create();
  204. OBSSource source = obs_source_create("xshm_input", "Screen Source", settings, NULL);
  205. if (source == NULL)
  206. throw runtime_error("Couldn't create screen source");
  207. obs_data_release(settings);
  208. return source;
  209. }
  210. OBSSource OBSManager::CreateWebcamSource()
  211. {
  212. obs_data_t *settings = obs_data_create();
  213. obs_data_set_string(settings, "device_id", mWebcamDeviceID.c_str());
  214. OBSSource source = obs_source_create("v4l2_input", "Webcam Source", settings, NULL);
  215. if (source == NULL)
  216. throw runtime_error("Couldn't create webcam source");
  217. obs_data_release(settings);
  218. return source;
  219. }
  220. OBSSource OBSManager::CreateAudioSource()
  221. {
  222. obs_data_t *settings = obs_data_create();
  223. obs_data_set_string(settings, "device_id", mAudioDeviceID.c_str());
  224. OBSSource source = obs_source_create("pulse_input_capture", "Audio Source", settings, NULL);
  225. if (source == NULL)
  226. throw runtime_error("Couldn't create audio source");
  227. obs_data_release(settings);
  228. return source;
  229. }
  230. //
  231. // Private (Helpers)
  232. //
  233. void OBSManager::loadPlugin(string name)
  234. {
  235. obs_module_t *module;
  236. string path;
  237. path.append(mPluginDir);
  238. path.append(name);
  239. int res = obs_open_module(&module, path.c_str(), nullptr);
  240. if (res != MODULE_SUCCESS)
  241. throw runtime_error("Failed to open plugin");
  242. obs_init_module(module);
  243. }
  244. void OBSManager::loadPlugins()
  245. {
  246. for (string plugin : mPlugins)
  247. {
  248. loadPlugin(plugin);
  249. }
  250. obs_post_load_modules();
  251. }
  252. void OBSManager::printTypes()
  253. {
  254. const char *t;
  255. for (int i = 0; obs_enum_input_types(i, &t); ++i)
  256. {
  257. cout << "input type: " << t << endl;
  258. }
  259. for (int i = 0; obs_enum_output_types(i, &t); ++i)
  260. {
  261. cout << "output type: " << t << endl;
  262. }
  263. for (int i = 0; obs_enum_encoder_types(i, &t); ++i)
  264. {
  265. cout << "encoder type: " << t << endl;
  266. }
  267. }