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
341 lines
8.2 KiB
#include "obs-manager.hpp"
|
|
#include "settings-manager.hpp"
|
|
|
|
#include <ctime>
|
|
#include <list>
|
|
#include <filesystem>
|
|
#include <stdexcept>
|
|
|
|
using namespace std;
|
|
|
|
//
|
|
// Static Functions
|
|
//
|
|
static void OBSRender(void *param, uint32_t cx, uint32_t cy)
|
|
{
|
|
obs_render_main_texture();
|
|
}
|
|
|
|
static void OBSStartRecording(void *data, calldata_t *params)
|
|
{
|
|
OBSManager *o = static_cast<OBSManager*>(data);
|
|
o->sigStartRecording.emit();
|
|
}
|
|
|
|
static void OBSStopRecording(void *data, calldata_t *params)
|
|
{
|
|
OBSManager *o = static_cast<OBSManager*>(data);
|
|
o->sigStopRecording.emit();
|
|
}
|
|
|
|
//
|
|
// OBSManager
|
|
//
|
|
OBSManager::OBSManager()
|
|
{
|
|
mPlugins = {
|
|
"obs-ffmpeg.so",
|
|
"obs-outputs.so",
|
|
"obs-x264.so",
|
|
"linux-alsa.so",
|
|
"linux-pulseaudio.so",
|
|
"linux-v4l2.so",
|
|
"linux-capture.so",
|
|
};
|
|
}
|
|
|
|
OBSManager::~OBSManager()
|
|
{
|
|
Cleanup();
|
|
}
|
|
|
|
string OBSManager::GetVersion()
|
|
{
|
|
return string(obs_get_version_string());
|
|
}
|
|
|
|
void OBSManager::LoadSettings(SettingsManager *settings)
|
|
{
|
|
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);
|
|
mAudioDeviceID = settings->Get(SETTINGS_KEY_AUDIO_DEVICE_ID);
|
|
mScreenEnabled = settings->GetBool(SETTINGS_KEY_SCREEN_ENABLED);
|
|
mWebcamEnabled = settings->GetBool(SETTINGS_KEY_WEBCAM_ENABLED);
|
|
mAudioEnabled = settings->GetBool(SETTINGS_KEY_AUDIO_ENABLED);
|
|
}
|
|
|
|
void OBSManager::Initialize(Gdk::Rectangle rect)
|
|
{
|
|
if (isInitialized)
|
|
return;
|
|
|
|
mScreenWidth = rect.get_width();
|
|
mScreenHeight = rect.get_height();
|
|
|
|
auto settings = new SettingsManager();
|
|
LoadSettings(settings);
|
|
|
|
if (!obs_startup("en-US", NULL, NULL))
|
|
throw runtime_error("Failed to initialize OBS");
|
|
|
|
loadPlugins();
|
|
|
|
obs_video_info v = {};
|
|
v.graphics_module = "libobs-opengl.so.0";
|
|
v.fps_num = 30000;
|
|
v.fps_den = 1001;
|
|
v.base_width = mScreenWidth;
|
|
v.base_height = mScreenHeight;
|
|
v.output_width = mScreenWidth;
|
|
v.output_height = mScreenHeight;
|
|
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;
|
|
//printTypes();
|
|
}
|
|
|
|
void OBSManager::StartPreview(XID wid, Display *wdisplay)
|
|
{
|
|
gs_init_data init = {};
|
|
init.cx = mScreenWidth;
|
|
init.cy = mScreenHeight;
|
|
init.format = GS_BGRA;
|
|
init.zsformat = GS_ZS_NONE;
|
|
init.window.id = wid;
|
|
init.window.display = (void*)wdisplay;
|
|
|
|
mDisplay = obs_display_create(&init, 0);
|
|
if (mDisplay == nullptr)
|
|
throw runtime_error("Failed to create display");
|
|
|
|
//obs_display_resize(mDisplay, PreviewWidth, PreviewHeight);
|
|
obs_display_add_draw_callback(mDisplay, OBSRender, nullptr);
|
|
|
|
auto sources = new list<OBSSource>();
|
|
|
|
OBSScene scene = obs_scene_create("Main");
|
|
if (scene == NULL)
|
|
throw runtime_error("Couldn't create scene\n");
|
|
|
|
if (mScreenEnabled)
|
|
{
|
|
auto source = CreateScreenSource();
|
|
obs_scene_add(scene, source);
|
|
sources->push_back(source);
|
|
}
|
|
|
|
if (mWebcamEnabled)
|
|
{
|
|
vec2 scale;
|
|
vec2_set(&scale, 0.5f, 0.5f);
|
|
|
|
auto source = CreateWebcamSource();
|
|
auto item = obs_scene_add(scene, source);
|
|
obs_sceneitem_set_scale(item, &scale);
|
|
sources->push_back(source);
|
|
}
|
|
|
|
if (mAudioEnabled)
|
|
{
|
|
auto source = CreateAudioSource();
|
|
obs_scene_add(scene, source);
|
|
sources->push_back(source);
|
|
}
|
|
|
|
obs_set_output_source(0, obs_scene_get_source(scene));
|
|
obs_scene_release(scene);
|
|
|
|
for (auto source : *sources)
|
|
{
|
|
obs_source_release(source);
|
|
}
|
|
|
|
sigStartPreview.emit();
|
|
}
|
|
|
|
void OBSManager::StopPreview()
|
|
{
|
|
if (mDisplay != nullptr)
|
|
obs_display_destroy(mDisplay);
|
|
|
|
sigStopPreview.emit();
|
|
}
|
|
|
|
void OBSManager::StartRecording()
|
|
{
|
|
if (isRecording)
|
|
return;
|
|
|
|
auto s = new SettingsManager();
|
|
|
|
OBSEncoder venc = obs_video_encoder_create("obs_x264", "x264_enc", nullptr, nullptr);
|
|
OBSEncoder aenc = obs_audio_encoder_create("ffmpeg_aac", "aac_enc", nullptr, 0, nullptr);
|
|
|
|
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());
|
|
obs_data_set_string(settings, "path", fileName.c_str());
|
|
|
|
mOutput = obs_output_create("ffmpeg_muxer", "output", nullptr, nullptr);
|
|
obs_output_set_video_encoder(mOutput, venc);
|
|
obs_output_set_audio_encoder(mOutput, aenc, 0);
|
|
obs_output_update(mOutput, settings);
|
|
obs_output_set_media(mOutput, obs_get_video(), obs_get_audio());
|
|
|
|
obs_encoder_set_video(venc, obs_get_video());
|
|
obs_encoder_set_audio(aenc, obs_get_audio());
|
|
|
|
obs_data_release(settings);
|
|
if (!obs_output_start(mOutput))
|
|
throw runtime_error("Failed to start recording");
|
|
|
|
obsStartRecording.Connect(obs_output_get_signal_handler(mOutput), "start", OBSStartRecording, this);
|
|
obsStopRecording.Connect(obs_output_get_signal_handler(mOutput), "stop", OBSStopRecording, this);
|
|
|
|
obs_encoder_release(venc);
|
|
obs_encoder_release(aenc);
|
|
obs_output_release(mOutput);
|
|
|
|
isRecording = true;
|
|
}
|
|
|
|
void OBSManager::StopRecording()
|
|
{
|
|
if (isRecording && mOutput != nullptr)
|
|
obs_output_stop(mOutput);
|
|
|
|
isRecording = false;
|
|
}
|
|
|
|
bool OBSManager::IsRecording()
|
|
{
|
|
return isRecording;
|
|
}
|
|
|
|
void OBSManager::Cleanup()
|
|
{
|
|
if (isInitialized)
|
|
{
|
|
StopRecording();
|
|
StopPreview();
|
|
|
|
if (obs_initialized())
|
|
obs_shutdown();
|
|
|
|
isInitialized = false;
|
|
}
|
|
|
|
sigCleanup.emit();
|
|
}
|
|
|
|
//
|
|
// Sources
|
|
//
|
|
OBSSource OBSManager::CreateScreenSource()
|
|
{
|
|
obs_data_t *settings = obs_data_create();
|
|
OBSSource source = obs_source_create("xshm_input", "Screen Source", settings, NULL);
|
|
if (source == NULL)
|
|
throw runtime_error("Couldn't create screen source");
|
|
|
|
obs_data_release(settings);
|
|
return source;
|
|
}
|
|
|
|
OBSSource OBSManager::CreateWebcamSource()
|
|
{
|
|
obs_data_t *settings = obs_data_create();
|
|
obs_data_set_string(settings, "device_id", mWebcamDeviceID.c_str());
|
|
|
|
OBSSource source = obs_source_create("v4l2_input", "Webcam Source", settings, NULL);
|
|
if (source == NULL)
|
|
throw runtime_error("Couldn't create webcam source");
|
|
|
|
obs_data_release(settings);
|
|
return source;
|
|
}
|
|
|
|
OBSSource OBSManager::CreateAudioSource()
|
|
{
|
|
obs_data_t *settings = obs_data_create();
|
|
obs_data_set_string(settings, "device_id", mAudioDeviceID.c_str());
|
|
|
|
OBSSource source = obs_source_create("pulse_input_capture", "Audio Source", settings, NULL);
|
|
if (source == NULL)
|
|
throw runtime_error("Couldn't create audio source");
|
|
|
|
obs_data_release(settings);
|
|
return source;
|
|
}
|
|
|
|
//
|
|
// Private (Helpers)
|
|
//
|
|
void OBSManager::loadPlugin(string name)
|
|
{
|
|
obs_module_t *module;
|
|
|
|
string path;
|
|
path.append(mPluginDir);
|
|
path.append(name);
|
|
|
|
int res = obs_open_module(&module, path.c_str(), nullptr);
|
|
if (res != MODULE_SUCCESS)
|
|
throw runtime_error("Failed to open plugin");
|
|
|
|
obs_init_module(module);
|
|
}
|
|
|
|
|
|
void OBSManager::loadPlugins()
|
|
{
|
|
for (string plugin : mPlugins)
|
|
{
|
|
loadPlugin(plugin);
|
|
}
|
|
|
|
obs_post_load_modules();
|
|
}
|
|
|
|
void OBSManager::printTypes()
|
|
{
|
|
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)
|
|
{
|
|
cout << "encoder type: " << t << endl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|