diff --git a/config.cfg b/config.cfg index faf4905..bd93c10 100644 --- a/config.cfg +++ b/config.cfg @@ -1,6 +1,6 @@ -outputdir=/home/parallels/Projects/Progrium/screen-recorder -pluginsdir=/usr/lib/x86_64-linux-gnu/obs-plugins/ -desktopenabled=true -videoenabled=true -videodevice=/dev/video3 -audioenabled=false +plugin_dir=/usr/lib/x86_64-linux-gnu/obs-plugins/ +output_dir=/home/parallels/Projects/Progrium/screen-recorder +screen_enabled=true +webcam_enabled=true +video_device_id=/dev/video2 +audio_enabled=true diff --git a/main-window.cpp b/main-window.cpp index 08e849f..4ec51c8 100644 --- a/main-window.cpp +++ b/main-window.cpp @@ -1,8 +1,8 @@ -#include -#include #include "main-window.hpp" #include "obs-manager.hpp" -#include "settings-manager.hpp" + +#include +#include #include using namespace std; @@ -42,8 +42,6 @@ MainWindow::MainWindow(OBSManager *obs) version.append(obs->GetVersion()); mLabelVersion.set_text(version); - auto settings = new SettingsManager(); - mOBS->LoadSettings(settings); mOBS->Initialize(); } diff --git a/main-window.hpp b/main-window.hpp index dad3a41..6df5941 100644 --- a/main-window.hpp +++ b/main-window.hpp @@ -1,11 +1,12 @@ #ifndef SCREEN_RECORDER_MAIN_WINDOW_HPP #define SCREEN_RECORDER_MAIN_WINDOW_HPP -#include #include "obs-manager.hpp" #include "settings-window.hpp" #include "preview-window.hpp" +#include + class MainWindow : public Gtk::Window { public: diff --git a/main.cpp b/main.cpp index a03291a..f6b6211 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,6 @@ #include "main-window.hpp" #include "obs-manager.hpp" + #include #include diff --git a/obs-manager.cpp b/obs-manager.cpp index 9032404..d0dd3e2 100644 --- a/obs-manager.cpp +++ b/obs-manager.cpp @@ -1,13 +1,17 @@ +#include "obs-manager.hpp" +#include "settings-manager.hpp" + #include #include #include #include #include +#include +#include #include #include -#include "obs-manager.hpp" -#include "settings-manager.hpp" +using namespace std; using namespace Glib; static void obs_render(void *param, uint32_t cx, uint32_t cy) @@ -19,6 +23,8 @@ OBSManager::OBSManager() { mPlugins = { "obs-ffmpeg.so", + "obs-outputs.so", + "obs-x264.so", "linux-v4l2.so", "linux-capture.so", }; @@ -26,8 +32,7 @@ OBSManager::OBSManager() OBSManager::~OBSManager() { - if (display != nullptr) - obs_display_destroy(display); + Cleanup(); } ustring OBSManager::GetVersion() @@ -40,11 +45,15 @@ void OBSManager::Initialize() if (isInitialized) return; + sources = list(); + auto settings = new SettingsManager(); + LoadSettings(settings); + if (!obs_startup("en-US", NULL, NULL)) - throw std::runtime_error("Failed to initialize OBS"); + throw runtime_error("Failed to initialize OBS"); loadPlugins(); - printInputTypes(); + printTypes(); obs_video_info v = {}; v.graphics_module = "libobs-opengl.so.0"; @@ -85,42 +94,94 @@ void OBSManager::SetPreviewWindow(XID wid, Display *wdisplay) display = obs_display_create(&init, 0); if (display == nullptr) - throw std::runtime_error("Failed to create display"); + throw runtime_error("Failed to create display"); obs_display_add_draw_callback(display, obs_render, nullptr); obs_scene_t *scene = obs_scene_create("scene1"); if (scene == NULL) - throw std::runtime_error("Couldn't create scene\n"); + throw runtime_error("Couldn't create scene\n"); - if (settings->GetBool("desktopenabled")) + if (settings->GetBool(SETTINGS_KEY_SCREEN_ENABLED)) { auto source = CreateScreenSource(); obs_scene_add(scene, source); + sources.push_back(source); } - if (settings->GetBool("videoenabled")) + if (settings->GetBool(SETTINGS_KEY_WEBCAM_ENABLED)) { + vec2 scale; + vec2_set(&scale, 0.5f, 0.5f); + auto source = CreateWebcamSource(); - obs_scene_add(scene, source); + auto item = obs_scene_add(scene, source); + obs_sceneitem_set_scale(item, &scale); + sources.push_back(source); } - if (settings->GetBool("audioenabled")) + if (settings->GetBool(SETTINGS_KEY_AUDIO_ENABLED)) { auto source = CreateAudioSource(); obs_scene_add(scene, source); + sources.push_back(source); } obs_set_output_source(0, obs_scene_get_source(scene)); } +void OBSManager::StartRecording() +{ + if (isRecording) + return; + + auto s = new SettingsManager(); + + obs_encoder_t *venc = obs_video_encoder_create("obs_x264", "x264", nullptr, nullptr); + obs_encoder_t *aenc = obs_audio_encoder_create("ffmpeg_aac", "aac", nullptr, 0, nullptr); + + obs_encoder_set_video(venc, obs_get_video()); + obs_encoder_set_audio(aenc, obs_get_audio()); + + string path = s->GetWithDefault(SETTINGS_KEY_OUTPUT_DIR, filesystem::current_path()); + if (path.back() != '/') + path += "/"; + + string fileName = path + "recording_" + to_string(time(0)) + ".mp4"; + + obs_data_t *settings = obs_data_create(); + obs_data_set_string(settings, "directory", path.c_str()); + obs_data_set_string(settings, "url", fileName.c_str()); + + output = obs_output_create("ffmpeg_output", "ffmpeg_output", nullptr, nullptr); + obs_output_set_video_encoder(output, venc); + obs_output_set_audio_encoder(output, aenc, 0); + obs_output_update(output, settings); + obs_output_set_media(output, obs_get_video(), obs_get_audio()); + + obs_data_release(settings); + if (!obs_output_start(output)) + throw runtime_error("Failed to start recording"); + + isRecording = true; +} + +void OBSManager::StopRecording() +{ + if (isRecording && output != nullptr) + obs_output_stop(output); + + isRecording = false; +} + obs_source_t *OBSManager::CreateScreenSource() { obs_data_t *settings = obs_data_create(); obs_source_t *source = obs_source_create("xshm_input", "Screen Source", settings, NULL); if (source == NULL) - throw std::runtime_error("Couldn't create screen source"); - + throw runtime_error("Couldn't create screen source"); + + obs_data_release(settings); return source; } @@ -128,12 +189,12 @@ obs_source_t *OBSManager::CreateWebcamSource() { obs_data_t *settings = obs_data_create(); obs_data_set_string(settings, "device_id", mWebcamDeviceID.c_str()); - //obs_data_set_string(settings, "format", "NV12"); obs_source_t *source = obs_source_create("v4l2_input", "Webcam Source", settings, NULL); if (source == NULL) - throw std::runtime_error("Couldn't create webcam source"); - + throw runtime_error("Couldn't create webcam source"); + + obs_data_release(settings); return source; } @@ -142,8 +203,9 @@ obs_source_t *OBSManager::CreateAudioSource() obs_data_t *settings = obs_data_create(); obs_source_t *source = obs_source_create("audio_line", "Audio Source", settings, NULL); if (source == NULL) - throw std::runtime_error("Couldn't create screen source"); - + throw runtime_error("Couldn't create screen source"); + + obs_data_release(settings); return source; } @@ -152,27 +214,25 @@ void OBSManager::Cleanup() if (!isInitialized) return; + StopRecording(); + + for (auto source : sources) + { + obs_source_remove(source); + } + if (display != nullptr) obs_display_destroy(display); obs_shutdown(); + isInitialized = false; } void OBSManager::LoadSettings(SettingsManager *settings) { - string pluginsDir = settings->Get("pluginsdir"); - if (pluginsDir == "") - pluginsDir = "/usr/lib/x86_64-linux-gnu/obs-plugins/"; - - PluginsDir = pluginsDir; - - string outputDir = settings->Get("outputdir"); - if (outputDir == "") - outputDir = std::filesystem::current_path(); - - OutputDir = outputDir; - - mWebcamDeviceID = settings->Get("webcamdeviceid"); + mPluginDir = settings->GetWithDefault(SETTINGS_KEY_PLUGIN_DIR, SETTINGS_DEFAULT_PLUGIN_DIR); + mOutputDir = settings->GetWithDefault(SETTINGS_KEY_OUTPUT_DIR, std::filesystem::current_path()); + mWebcamDeviceID = settings->Get(SETTINGS_KEY_VIDEO_DEVICE_ID); } void OBSManager::loadPlugin(ustring name) @@ -180,12 +240,12 @@ void OBSManager::loadPlugin(ustring name) obs_module_t *module; ustring path; - path.append(PluginsDir); + path.append(mPluginDir); path.append(name); int res = obs_open_module(&module, path.c_str(), nullptr); if (res != MODULE_SUCCESS) - throw std::runtime_error("Failed to open plugin"); + throw runtime_error("Failed to open plugin"); obs_init_module(module); } @@ -201,12 +261,22 @@ void OBSManager::loadPlugins() obs_post_load_modules(); } -void OBSManager::printInputTypes() +void OBSManager::printTypes() { - const char *inputType; - for (int i = 0; obs_enum_input_types(i, &inputType); ++i) + const char *t; + for (int i = 0; obs_enum_input_types(i, &t); ++i) + { + cout << "input type: " << t << endl; + } + + for (int i = 0; obs_enum_output_types(i, &t); ++i) + { + cout << "output type: " << t << endl; + } + + for (int i = 0; obs_enum_encoder_types(i, &t); ++i) { - std::cout << "input type: " << inputType << std::endl; + cout << "encoder type: " << t << endl; } } diff --git a/obs-manager.hpp b/obs-manager.hpp index 02856f2..75581a1 100644 --- a/obs-manager.hpp +++ b/obs-manager.hpp @@ -10,6 +10,7 @@ #include "settings-manager.hpp" using namespace Glib; +using namespace std; class OBSManager { @@ -19,24 +20,29 @@ public: ustring GetVersion(); void Initialize(); void SetPreviewWindow(XID wid, Display *wdisplay); + void StartRecording(); + void StopRecording(); obs_source_t *CreateScreenSource(); obs_source_t *CreateWebcamSource(); obs_source_t *CreateAudioSource(); void Cleanup(); void LoadSettings(SettingsManager *settings); - std::string PluginsDir; - std::string OutputDir; int PreviewWidth = 1280; int PreviewHeight = 720; private: bool isInitialized = false; - obs_display_t *display = nullptr; - std::string mWebcamDeviceID; - void printInputTypes(); + bool isRecording = false; + obs_display_t *display; + obs_output_t *output; + list sources; + ustring mPluginDir; + ustring mOutputDir; + ustring mWebcamDeviceID; + void printTypes(); // Plugins - std::list mPlugins; + list mPlugins; void loadPlugin(ustring name); void loadPlugins(); }; diff --git a/preview-window.cpp b/preview-window.cpp index f7a9958..29cbc75 100644 --- a/preview-window.cpp +++ b/preview-window.cpp @@ -11,6 +11,7 @@ PreviewWindow::PreviewWindow(OBSManager *obs) PreviewWindow::~PreviewWindow() { + std::cout << "PreviewWindow::~PreviewWindow" << std::endl; } void PreviewWindow::on_realize() @@ -23,3 +24,15 @@ void PreviewWindow::on_realize() GDK_WINDOW_XDISPLAY(get_window()->gobj()) ); } + +void PreviewWindow::on_show() +{ + Gtk::Widget::on_show(); + mOBS->StartRecording(); +} + +void PreviewWindow::on_hide() +{ + Gtk::Widget::on_hide(); + mOBS->StopRecording(); +} diff --git a/preview-window.hpp b/preview-window.hpp index 56b3532..7b6b598 100644 --- a/preview-window.hpp +++ b/preview-window.hpp @@ -1,8 +1,8 @@ #ifndef SCREEN_RECORDER_PREVIEW_WINDOW_HPP #define SCREEN_RECORDER_PREVIEW_WINDOW_HPP -#include #include "obs-manager.hpp" +#include class PreviewWindow : public Gtk::Window { @@ -11,6 +11,8 @@ public: virtual ~PreviewWindow(); private: void on_realize(); + void on_show(); + void on_hide(); OBSManager *mOBS; }; diff --git a/screenrecorder b/screenrecorder deleted file mode 100755 index 2860abd..0000000 Binary files a/screenrecorder and /dev/null differ diff --git a/settings-manager.cpp b/settings-manager.cpp index 0487227..5845780 100644 --- a/settings-manager.cpp +++ b/settings-manager.cpp @@ -1,5 +1,4 @@ #include "settings-manager.hpp" -#include #include using namespace std; @@ -63,6 +62,15 @@ string SettingsManager::Get(string key) return ""; } +string SettingsManager::GetWithDefault(string key, string defaultValue) +{ + auto value = Get(key); + if (value == "") + return defaultValue; + + return value; +} + bool SettingsManager::GetBool(string key) { if (Get(key) == "true") @@ -71,6 +79,19 @@ bool SettingsManager::GetBool(string key) return false; } +bool SettingsManager::GetBoolWithDefault(string key, bool defaultValue) +{ + auto value = Get(key); + + if (value == "true") + return true; + + if (value == "false") + return false; + + return defaultValue; +} + void SettingsManager::readAll() { settings.clear(); diff --git a/settings-manager.hpp b/settings-manager.hpp index 2db1a34..b34a2a8 100644 --- a/settings-manager.hpp +++ b/settings-manager.hpp @@ -1,6 +1,15 @@ #ifndef SCREEN_RECORDER_SETTINGS_MANAGER_HPP #define SCREEN_RECORDER_SETTINGS_MANAGER_HPP +#define SETTINGS_KEY_PLUGIN_DIR "plugin_dir" +#define SETTINGS_KEY_OUTPUT_DIR "output_dir" +#define SETTINGS_KEY_SCREEN_ENABLED "screen_enabled" +#define SETTINGS_KEY_WEBCAM_ENABLED "webcam_enabled" +#define SETTINGS_KEY_VIDEO_DEVICE_ID "video_device_id" +#define SETTINGS_KEY_AUDIO_ENABLED "audio_enabled" + +#define SETTINGS_DEFAULT_PLUGIN_DIR "/usr/lib/x86_64-linux-gnu/obs-plugins/" + #include #include @@ -23,7 +32,9 @@ public: void Save(string key, string value); void SaveAll(); string Get(string key); + string GetWithDefault(string key, string defaultValue); bool GetBool(string key); + bool GetBoolWithDefault(string key, bool defaultValue); private: list settings; void readAll(); diff --git a/settings-window.cpp b/settings-window.cpp index 12d13bd..a69e06c 100644 --- a/settings-window.cpp +++ b/settings-window.cpp @@ -1,7 +1,9 @@ #include "settings-window.hpp" #include "settings-manager.hpp" + #include #include +#include #include #include #include @@ -30,7 +32,6 @@ SettingsWindow::SettingsWindow(OBSManager* obs) set_type_hint(Gdk::WindowTypeHint::WINDOW_TYPE_HINT_DIALOG); settings = new SettingsManager(); - obs->LoadSettings(settings); populateVideoDevices(); @@ -45,14 +46,14 @@ SettingsWindow::SettingsWindow(OBSManager* obs) mBoxSettings.set_border_width(10); mEntryPluginDir.set_hexpand(true); - mEntryPluginDir.set_text(obs->PluginsDir.c_str()); + mEntryPluginDir.set_text(settings->GetWithDefault(SETTINGS_KEY_PLUGIN_DIR, SETTINGS_DEFAULT_PLUGIN_DIR)); mBoxPluginDir.set_border_width(10); mBoxPluginDir.add(mLabelPluginDir); mBoxPluginDir.add(mEntryPluginDir); mEntryOutputDir.set_hexpand(true); - mEntryOutputDir.set_text(obs->OutputDir.c_str()); + mEntryOutputDir.set_text(settings->GetWithDefault(SETTINGS_KEY_OUTPUT_DIR, std::filesystem::current_path())); mBoxOutputDir.set_border_width(10); mBoxOutputDir.add(mLabelOutputDir); @@ -61,14 +62,14 @@ SettingsWindow::SettingsWindow(OBSManager* obs) mFrameDesktop.set_label("Desktop"); mFrameDesktop.set_border_width(10); mCheckButtonDesktop.set_border_width(10); - mCheckButtonDesktop.set_active(settings->GetBool("desktopenabled")); + mCheckButtonDesktop.set_active(settings->GetBoolWithDefault(SETTINGS_KEY_SCREEN_ENABLED, true)); mFrameDesktop.add(mCheckButtonDesktop); mComboBoxVideoDevice.set_border_width(10); mFrameWebcam.set_label("Webcam"); mFrameWebcam.set_border_width(10); mBoxWebcam.set_border_width(10); - mCheckButtonWebcam.set_active(settings->GetBool("videoenabled")); + mCheckButtonWebcam.set_active(settings->GetBoolWithDefault(SETTINGS_KEY_WEBCAM_ENABLED, true)); mBoxWebcam.add(mCheckButtonWebcam); mBoxWebcam.add(mComboBoxVideoDevice); mFrameWebcam.add(mBoxWebcam); @@ -76,7 +77,7 @@ SettingsWindow::SettingsWindow(OBSManager* obs) mFrameAudio.set_label("Microphone"); mFrameAudio.set_border_width(10); mCheckButtonAudio.set_border_width(10); - mCheckButtonAudio.set_active(settings->GetBool("audioenabled")); + mCheckButtonAudio.set_active(settings->GetBoolWithDefault(SETTINGS_KEY_AUDIO_ENABLED, true)); mFrameAudio.add(mCheckButtonAudio); mBoxSettings.add(mBoxPluginDir); @@ -121,20 +122,20 @@ void SettingsWindow::onClosePressed() void SettingsWindow::onSavePressed() { - settings->Update("pluginsdir", mEntryPluginDir.get_text()); - settings->Update("outputdir", mEntryOutputDir.get_text()); - settings->UpdateBool("desktopenabled", mCheckButtonDesktop.get_active()); - settings->UpdateBool("videoenabled", mCheckButtonWebcam.get_active()); - settings->Update("videodevice", mComboBoxVideoDevice.get_active_id()); - settings->UpdateBool("audioenabled", mCheckButtonAudio.get_active()); + settings->Update(SETTINGS_KEY_PLUGIN_DIR, mEntryPluginDir.get_text()); + settings->Update(SETTINGS_KEY_OUTPUT_DIR, mEntryOutputDir.get_text()); + settings->UpdateBool(SETTINGS_KEY_SCREEN_ENABLED, mCheckButtonDesktop.get_active()); + settings->UpdateBool(SETTINGS_KEY_WEBCAM_ENABLED, mCheckButtonWebcam.get_active()); + settings->Update(SETTINGS_KEY_VIDEO_DEVICE_ID, mComboBoxVideoDevice.get_active_id()); + settings->UpdateBool(SETTINGS_KEY_AUDIO_ENABLED, mCheckButtonAudio.get_active()); settings->SaveAll(); + close(); } void SettingsWindow::populateVideoDevices() { - auto settings = new SettingsManager(); - struct v4l2_capability cap; - struct dirent *dp; + v4l2_capability cap; + dirent *dp; auto dirp = opendir("/sys/class/video4linux"); if (!dirp) @@ -169,7 +170,7 @@ void SettingsWindow::populateVideoDevices() n += " (" + device + ")"; mComboBoxVideoDevice.append(device, n); - if (settings->Get("videodevice") == device) + if (settings->Get(SETTINGS_KEY_VIDEO_DEVICE_ID) == device) mComboBoxVideoDevice.set_active_id(device); v4l2_close(fd); diff --git a/settings-window.hpp b/settings-window.hpp index 7533222..241dfd5 100644 --- a/settings-window.hpp +++ b/settings-window.hpp @@ -1,9 +1,9 @@ #ifndef SCREEN_RECORDER_SETTINGS_WINDOW_HPP #define SCREEN_RECORDER_SETTINGS_WINDOW_HPP -#include #include "obs-manager.hpp" #include "settings-manager.hpp" +#include class SettingsWindow : public Gtk::Window {