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.

299 lines
7.3 KiB

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