diff --git a/.kdev4/screen-recorder.kdev4 b/.kdev4/screen-recorder.kdev4 index 017eeb6..029b364 100644 --- a/.kdev4/screen-recorder.kdev4 +++ b/.kdev4/screen-recorder.kdev4 @@ -63,6 +63,8 @@ Name=GCC 3=/usr/lib/x86_64-linux-gnu/ 4=/usr/include/sigc++-2.0/ 5=/usr/include/glibmm-2.4/ +6=/usr/include/gdkmm-3.0/ +7=/usr/include/gtk-3.0/ [Launch] Launch Configurations=Launch Configuration 0 diff --git a/Makefile b/Makefile index 9d926dc..ea5e32f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = g++ CFLAGS = -g -Wall -std=c++17 -GCFLAGS = `pkg-config --cflags --libs gtkmm-3.0` -lobs -lv4l2 -OBJFILES = main.o obs-manager.o recording-window.o settings-manager.o settings-window.o +GCFLAGS = `pkg-config --cflags --libs gtkmm-3.0` -lobs -lv4l2 -lglut -lGL +OBJFILES = main.o main-window.o obs-manager.o preview-window.o settings-manager.o settings-window.o TARGET = screenrecorder @@ -11,11 +11,14 @@ $(TARGET): $(OBJFILES) main.o: $(CC) $(CFLAGS) -c main.cpp $(GCFLAGS) +main-window.o: main-window.cpp main-window.hpp + $(CC) $(CFLAGS) -c main-window.cpp $(GCFLAGS) + obs-manager.o: obs-manager.cpp obs-manager.hpp $(CC) $(CFLAGS) -c obs-manager.cpp $(GCFLAGS) -recording-window.o: recording-window.cpp recording-window.hpp - $(CC) $(CFLAGS) -c recording-window.cpp $(GCFLAGS) +preview-window.o: preview-window.cpp preview-window.hpp + $(CC) $(CFLAGS) -c preview-window.cpp $(GCFLAGS) settings-manager.o: settings-manager.cpp settings-manager.hpp $(CC) $(CFLAGS) -c settings-manager.cpp $(GCFLAGS) diff --git a/recording-window.cpp b/main-window.cpp similarity index 53% rename from recording-window.cpp rename to main-window.cpp index dffdb8a..08e849f 100644 --- a/recording-window.cpp +++ b/main-window.cpp @@ -1,36 +1,41 @@ -#include "recording-window.hpp" -#include "obs-manager.hpp" -#include "settings-manager.hpp" #include #include +#include "main-window.hpp" +#include "obs-manager.hpp" +#include "settings-manager.hpp" +#include using namespace std; -RecordingWindow::RecordingWindow(OBSManager *obs) +MainWindow::MainWindow(OBSManager *obs) : mBoxMain(Gtk::Orientation::ORIENTATION_VERTICAL, 2), mButtonStart("Start Recording"), mButtonSettings("Settings"), + mButtonExit("Exit"), mLabelVersion("Version: "), - mSettingsWindow(obs) + mSettingsWindow(obs), + mPreviewWindow(obs) { set_title("New Recording"); set_default_size(1048, 720); set_border_width(10); + + mOBS = obs; + mButtonStart.signal_clicked().connect( - sigc::mem_fun(*this, &RecordingWindow::onStartClicked)); + sigc::mem_fun(*this, &MainWindow::onStartClicked)); mButtonSettings.signal_clicked().connect( - sigc::mem_fun(*this, &RecordingWindow::onSettingsClicked)); + sigc::mem_fun(*this, &MainWindow::onSettingsClicked)); + mButtonExit.signal_clicked().connect( + sigc::mem_fun(*this, &MainWindow::onExitClicked)); mBoxMain.add(mButtonStart); mBoxMain.add(mButtonSettings); + mBoxMain.add(mButtonExit); mBoxMain.add(mLabelVersion); - mButtonStart.show(); - mButtonSettings.show(); - mLabelVersion.show(); - add(mBoxMain); - mBoxMain.show(); + mBoxMain.show_all(); string version; version.append("OBS Version: "); @@ -38,23 +43,31 @@ RecordingWindow::RecordingWindow(OBSManager *obs) mLabelVersion.set_text(version); auto settings = new SettingsManager(); - obs->LoadSettings(settings); + mOBS->LoadSettings(settings); + mOBS->Initialize(); } -RecordingWindow::~RecordingWindow() +MainWindow::~MainWindow() { + mOBS->Cleanup(); } -void RecordingWindow::onStartClicked() +void MainWindow::onStartClicked() { - cout << "Clicked" << endl; + mPreviewWindow.show(); } -void RecordingWindow::onSettingsClicked() +void MainWindow::onSettingsClicked() { mSettingsWindow.set_transient_for(*this); mSettingsWindow.show(); } +void MainWindow::onExitClicked() +{ + mOBS->Cleanup(); + Gtk::Main::quit(); +} + diff --git a/main-window.hpp b/main-window.hpp new file mode 100644 index 0000000..dad3a41 --- /dev/null +++ b/main-window.hpp @@ -0,0 +1,28 @@ +#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" + +class MainWindow : public Gtk::Window +{ +public: + MainWindow(OBSManager *obs); + virtual ~MainWindow(); +private: + OBSManager *mOBS; + void onStartClicked(); + void onSettingsClicked(); + void onExitClicked(); + Gtk::Box mBoxMain; + Gtk::Button mButtonStart; + Gtk::Button mButtonSettings; + Gtk::Button mButtonExit; + Gtk::Label mLabelVersion; + SettingsWindow mSettingsWindow; + PreviewWindow mPreviewWindow; +}; + +#endif diff --git a/main.cpp b/main.cpp index 13d6f39..a03291a 100644 --- a/main.cpp +++ b/main.cpp @@ -1,13 +1,18 @@ -#include "recording-window.hpp" +#include "main-window.hpp" #include "obs-manager.hpp" #include +#include int main(int argc, char *argv[]) { auto app = Gtk::Application::create(argc, argv, "xyz.dwayne.screenrecorder"); auto obs = new OBSManager(); - RecordingWindow win(obs); + // This just initializes OpenGL. + // The program won't run if OpenGL hasn't been initialized. + glutInit(&argc, argv); + + MainWindow win(obs); return app->run(win); } diff --git a/obs-manager.cpp b/obs-manager.cpp index 3b9a9fe..9032404 100644 --- a/obs-manager.cpp +++ b/obs-manager.cpp @@ -1,15 +1,23 @@ -#include "obs-manager.hpp" -#include "settings-manager.hpp" #include +#include #include +#include +#include #include #include +#include "obs-manager.hpp" +#include "settings-manager.hpp" using namespace Glib; +static void obs_render(void *param, uint32_t cx, uint32_t cy) +{ + obs_render_main_texture(); +} + OBSManager::OBSManager() { - plugins = { + mPlugins = { "obs-ffmpeg.so", "linux-v4l2.so", "linux-capture.so", @@ -35,16 +43,119 @@ void OBSManager::Initialize() if (!obs_startup("en-US", NULL, NULL)) throw std::runtime_error("Failed to initialize OBS"); - struct gs_init_data info = { - .cx = 1280, - .cy = 720, - .format = GS_BGRA, - .zsformat = GS_ZS_NONE, - }; + loadPlugins(); + printInputTypes(); + + obs_video_info v = {}; + v.graphics_module = "libobs-opengl.so.0"; + v.fps_num = 30000; + v.fps_den = 1001; + v.base_width = PreviewWidth; + v.base_height = PreviewHeight; + v.output_width = PreviewWidth; + v.output_height = PreviewHeight; + v.output_format = VIDEO_FORMAT_NV12; + v.adapter = 0; + v.gpu_conversion = true; + v.colorspace = VIDEO_CS_601; + v.range = VIDEO_RANGE_PARTIAL; + v.scale_type = OBS_SCALE_BICUBIC; + + obs_audio_info a = {}; + a.samples_per_sec = 44100; + a.speakers = SPEAKERS_STEREO; + + obs_reset_video(&v); + obs_reset_audio(&a); + + isInitialized = true; +} + +void OBSManager::SetPreviewWindow(XID wid, Display *wdisplay) +{ + auto settings = new SettingsManager(); + + gs_init_data init = {}; + init.cx = PreviewWidth; + init.cy = PreviewHeight; + init.format = GS_BGRA; + init.zsformat = GS_ZS_NONE; + init.window.id = wid; + init.window.display = (void*)wdisplay; - display = obs_display_create(&info, 0); + display = obs_display_create(&init, 0); if (display == nullptr) throw std::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"); + + if (settings->GetBool("desktopenabled")) + { + auto source = CreateScreenSource(); + obs_scene_add(scene, source); + } + + if (settings->GetBool("videoenabled")) + { + auto source = CreateWebcamSource(); + obs_scene_add(scene, source); + } + + if (settings->GetBool("audioenabled")) + { + auto source = CreateAudioSource(); + obs_scene_add(scene, source); + } + + obs_set_output_source(0, obs_scene_get_source(scene)); +} + +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"); + + return source; +} + +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"); + + return source; +} + +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"); + + return source; +} + +void OBSManager::Cleanup() +{ + if (!isInitialized) + return; + + if (display != nullptr) + obs_display_destroy(display); + + obs_shutdown(); } void OBSManager::LoadSettings(SettingsManager *settings) @@ -60,6 +171,8 @@ void OBSManager::LoadSettings(SettingsManager *settings) outputDir = std::filesystem::current_path(); OutputDir = outputDir; + + mWebcamDeviceID = settings->Get("webcamdeviceid"); } void OBSManager::loadPlugin(ustring name) @@ -80,10 +193,21 @@ void OBSManager::loadPlugin(ustring name) void OBSManager::loadPlugins() { - for (ustring plugin : plugins) + for (ustring plugin : mPlugins) { loadPlugin(plugin); } + + obs_post_load_modules(); +} + +void OBSManager::printInputTypes() +{ + const char *inputType; + for (int i = 0; obs_enum_input_types(i, &inputType); ++i) + { + std::cout << "input type: " << inputType << std::endl; + } } diff --git a/obs-manager.hpp b/obs-manager.hpp index 2c0c69a..02856f2 100644 --- a/obs-manager.hpp +++ b/obs-manager.hpp @@ -1,10 +1,13 @@ #ifndef SCREEN_RECORDER_OBS_MANAGER_HPP #define SCREEN_RECORDER_OBS_MANAGER_HPP -#include "settings-manager.hpp" #include +#include #include +#include +#include #include +#include "settings-manager.hpp" using namespace Glib; @@ -15,17 +18,25 @@ public: virtual ~OBSManager(); ustring GetVersion(); void Initialize(); + void SetPreviewWindow(XID wid, Display *wdisplay); + 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(); // Plugins - std::list plugins; + std::list mPlugins; void loadPlugin(ustring name); void loadPlugins(); }; diff --git a/preview-window.cpp b/preview-window.cpp new file mode 100644 index 0000000..f7a9958 --- /dev/null +++ b/preview-window.cpp @@ -0,0 +1,25 @@ +#include "preview-window.hpp" +#include "obs-manager.hpp" + +PreviewWindow::PreviewWindow(OBSManager *obs) +{ + set_title("Preview"); + set_default_size(obs->PreviewWidth, obs->PreviewHeight); + + mOBS = obs; +} + +PreviewWindow::~PreviewWindow() +{ +} + +void PreviewWindow::on_realize() +{ + Gtk::Widget::on_realize(); + + mOBS->Initialize(); + mOBS->SetPreviewWindow( + GDK_WINDOW_XID(get_window()->gobj()), + GDK_WINDOW_XDISPLAY(get_window()->gobj()) + ); +} diff --git a/preview-window.hpp b/preview-window.hpp new file mode 100644 index 0000000..56b3532 --- /dev/null +++ b/preview-window.hpp @@ -0,0 +1,17 @@ +#ifndef SCREEN_RECORDER_PREVIEW_WINDOW_HPP +#define SCREEN_RECORDER_PREVIEW_WINDOW_HPP + +#include +#include "obs-manager.hpp" + +class PreviewWindow : public Gtk::Window +{ +public: + PreviewWindow(OBSManager *obs); + virtual ~PreviewWindow(); +private: + void on_realize(); + OBSManager *mOBS; +}; + +#endif diff --git a/recording-window.hpp b/recording-window.hpp deleted file mode 100644 index ebf6d05..0000000 --- a/recording-window.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef SCREEN_RECORDER_RECORDING_WINDOW_HPP -#define SCREEN_RECORDER_RECORDING_WINDOW_HPP - -#include -#include "obs-manager.hpp" -#include "settings-window.hpp" - -class RecordingWindow : public Gtk::Window -{ -public: - RecordingWindow(OBSManager *obs); - virtual ~RecordingWindow(); -private: - void onStartClicked(); - void onSettingsClicked(); - Gtk::Box mBoxMain; - Gtk::Button mButtonStart; - Gtk::Button mButtonSettings; - Gtk::Label mLabelVersion; - SettingsWindow mSettingsWindow; -}; - -#endif diff --git a/screenrecorder b/screenrecorder new file mode 100755 index 0000000..2860abd Binary files /dev/null and b/screenrecorder differ diff --git a/settings-manager.cpp b/settings-manager.cpp index 652ec56..0487227 100644 --- a/settings-manager.cpp +++ b/settings-manager.cpp @@ -16,7 +16,6 @@ SettingsManager::~SettingsManager() void SettingsManager::Update(string key, string value) { - cout << "Update: key: " << key << "; value: " << value << endl; for (auto entry : settings) { if (entry->key == key) @@ -99,7 +98,6 @@ void SettingsManager::saveAll() for (auto entry : settings) { - cout << "Saving: key: " << entry->key << "; value: " << entry->value << endl; fout << entry->key << "=" << entry->value << endl; } } diff --git a/settings-window.cpp b/settings-window.cpp index f71353d..12d13bd 100644 --- a/settings-window.cpp +++ b/settings-window.cpp @@ -6,6 +6,7 @@ #include #include #include + using namespace std; SettingsWindow::SettingsWindow(OBSManager* obs)