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.

286 lines
6.9 KiB

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