UI: Add FLV file output (sharing encoders)
Implement the 'file path' in output settings, and implement the 'start recording' button, though for the time being I'm just going to make it use a directory rather than allow custom file names. This file output will actually share the video and audio encoder with the stream. I don't really know what to do about MP4 -- I don't really like the idea of saving directly in the program, if you do and the program crashes, that MP4 file is lost. I'm contemplating making some sort of mp4 output process stub. So no MP4 file output for the time being. If you need MP4, just remux it with FFmpeg: ffmpeg -i flv_file.flv -acodec copy -vcodec copy mp4_file.mp4
This commit is contained in:
@@ -401,7 +401,7 @@
|
||||
<item>
|
||||
<widget class="QPushButton" name="recordButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Basic.Main.StartRecording</string>
|
||||
|
@@ -383,14 +383,14 @@
|
||||
<item>
|
||||
<widget class="QLineEdit" name="simpleOutputPath">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="simpleOutputBrowse">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
|
@@ -54,14 +54,16 @@ Q_DECLARE_METATYPE(OBSSceneItem);
|
||||
Q_DECLARE_METATYPE(order_movement);
|
||||
|
||||
OBSBasic::OBSBasic(QWidget *parent)
|
||||
: OBSMainWindow (parent),
|
||||
: OBSMainWindow (parent),
|
||||
properties (nullptr),
|
||||
fileOutput (nullptr),
|
||||
streamOutput (nullptr),
|
||||
service (nullptr),
|
||||
aac (nullptr),
|
||||
x264 (nullptr),
|
||||
sceneChanging (false),
|
||||
resizeTimer (0),
|
||||
activeRefs (0),
|
||||
ui (new Ui::OBSBasic)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
@@ -243,6 +245,14 @@ static void OBSStopStreaming(void *data, calldata_t params)
|
||||
"StreamingStop", Q_ARG(int, code));
|
||||
}
|
||||
|
||||
static void OBSStopRecording(void *data, calldata_t params)
|
||||
{
|
||||
UNUSED_PARAMETER(params);
|
||||
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
|
||||
"RecordingStop");
|
||||
}
|
||||
|
||||
#define SERVICE_PATH "obs-studio/basic/service.json"
|
||||
|
||||
void OBSBasic::SaveService()
|
||||
@@ -297,6 +307,10 @@ bool OBSBasic::LoadService()
|
||||
|
||||
bool OBSBasic::InitOutputs()
|
||||
{
|
||||
fileOutput = obs_output_create("flv_output", "default", nullptr);
|
||||
if (!fileOutput)
|
||||
return false;
|
||||
|
||||
streamOutput = obs_output_create("rtmp_output", "default", nullptr);
|
||||
if (!streamOutput)
|
||||
return false;
|
||||
@@ -306,6 +320,9 @@ bool OBSBasic::InitOutputs()
|
||||
signal_handler_connect(obs_output_signalhandler(streamOutput),
|
||||
"stop", OBSStopStreaming, this);
|
||||
|
||||
signal_handler_connect(obs_output_signalhandler(fileOutput),
|
||||
"stop", OBSStopRecording, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -357,7 +374,8 @@ bool OBSBasic::InitBasicConfigDefaults()
|
||||
uint32_t cy = monitors[0].cy;
|
||||
|
||||
/* TODO: temporary */
|
||||
config_set_default_string(basicConfig, "SimpleOutput", "path", "");
|
||||
config_set_default_string(basicConfig, "SimpleOutput", "FilePath",
|
||||
GetDefaultVideoSavePath().c_str());
|
||||
config_set_default_uint (basicConfig, "SimpleOutput", "VBitrate",
|
||||
2500);
|
||||
config_set_default_uint (basicConfig, "SimpleOutput", "ABitrate", 128);
|
||||
@@ -1355,6 +1373,8 @@ void OBSBasic::StreamingStop(int code)
|
||||
errorMessage = Str("Output.ConnectFail.Disconnected");
|
||||
}
|
||||
|
||||
activeRefs--;
|
||||
|
||||
ui->streamButton->setText(QTStr("Basic.Main.StartStreaming"));
|
||||
ui->streamButton->setEnabled(true);
|
||||
|
||||
@@ -1364,12 +1384,15 @@ void OBSBasic::StreamingStop(int code)
|
||||
QT_UTF8(errorMessage));
|
||||
}
|
||||
|
||||
void OBSBasic::on_streamButton_clicked()
|
||||
void OBSBasic::RecordingStop()
|
||||
{
|
||||
if (obs_output_active(streamOutput)) {
|
||||
obs_output_stop(streamOutput);
|
||||
activeRefs--;
|
||||
ui->recordButton->setText(QTStr("Basic.Main.StartRecording"));
|
||||
}
|
||||
|
||||
} else {
|
||||
void OBSBasic::SetupEncoders()
|
||||
{
|
||||
if (activeRefs == 0) {
|
||||
obs_data_t x264Settings = obs_data_create();
|
||||
obs_data_t aacSettings = obs_data_create();
|
||||
|
||||
@@ -1378,11 +1401,6 @@ void OBSBasic::on_streamButton_clicked()
|
||||
int audioBitrate = config_get_uint(basicConfig, "SimpleOutput",
|
||||
"ABitrate");
|
||||
|
||||
ui->streamButton->setEnabled(false);
|
||||
ui->streamButton->setText(QTStr("Basic.Main.Connecting"));
|
||||
|
||||
SaveService();
|
||||
|
||||
obs_data_setint(x264Settings, "bitrate", videoBitrate);
|
||||
obs_data_setbool(x264Settings, "cbr", true);
|
||||
|
||||
@@ -1396,10 +1414,79 @@ void OBSBasic::on_streamButton_clicked()
|
||||
|
||||
obs_encoder_set_video(x264, obs_video());
|
||||
obs_encoder_set_audio(aac, obs_audio());
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasic::on_streamButton_clicked()
|
||||
{
|
||||
if (obs_output_active(streamOutput)) {
|
||||
obs_output_stop(streamOutput);
|
||||
} else {
|
||||
|
||||
SaveService();
|
||||
SetupEncoders();
|
||||
|
||||
obs_output_set_video_encoder(streamOutput, x264);
|
||||
obs_output_set_audio_encoder(streamOutput, aac);
|
||||
obs_output_set_service(streamOutput, service);
|
||||
obs_output_start(streamOutput);
|
||||
|
||||
if (obs_output_start(streamOutput)) {
|
||||
activeRefs++;
|
||||
|
||||
ui->streamButton->setEnabled(false);
|
||||
ui->streamButton->setText(
|
||||
QTStr("Basic.Main.Connecting"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasic::on_recordButton_clicked()
|
||||
{
|
||||
if (obs_output_active(fileOutput)) {
|
||||
obs_output_stop(fileOutput);
|
||||
} else {
|
||||
|
||||
const char *path = config_get_string(basicConfig,
|
||||
"SimpleOutput", "FilePath");
|
||||
|
||||
os_dir_t dir = path ? os_opendir(path) : nullptr;
|
||||
|
||||
if (!dir) {
|
||||
QMessageBox::information(this,
|
||||
QTStr("Output.BadPath.Title"),
|
||||
QTStr("Output.BadPath.Text"));
|
||||
return;
|
||||
}
|
||||
|
||||
os_closedir(dir);
|
||||
|
||||
string strPath;
|
||||
strPath += path;
|
||||
|
||||
char lastChar = strPath.back();
|
||||
if (lastChar != '/' && lastChar != '\\')
|
||||
strPath += "/";
|
||||
|
||||
strPath += GenerateTimeDateFilename("flv");
|
||||
|
||||
SetupEncoders();
|
||||
|
||||
obs_output_set_video_encoder(fileOutput, x264);
|
||||
obs_output_set_audio_encoder(fileOutput, aac);
|
||||
|
||||
obs_data_t settings = obs_data_create();
|
||||
obs_data_setstring(settings, "path", strPath.c_str());
|
||||
|
||||
obs_output_update(fileOutput, settings);
|
||||
|
||||
obs_data_release(settings);
|
||||
|
||||
if (obs_output_start(fileOutput)) {
|
||||
activeRefs++;
|
||||
|
||||
ui->recordButton->setText(
|
||||
QTStr("Basic.Main.StopRecording"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -58,6 +58,7 @@ private:
|
||||
QNetworkReply *logUploadReply;
|
||||
QByteArray logUploadReturnData;
|
||||
|
||||
obs_output_t fileOutput;
|
||||
obs_output_t streamOutput;
|
||||
obs_service_t service;
|
||||
obs_encoder_t aac;
|
||||
@@ -71,6 +72,10 @@ private:
|
||||
|
||||
ConfigFile basicConfig;
|
||||
|
||||
int activeRefs;
|
||||
|
||||
void SetupEncoders();
|
||||
|
||||
void CreateDefaultScene();
|
||||
|
||||
void ClearVolumeControls();
|
||||
@@ -112,6 +117,8 @@ public slots:
|
||||
void StreamingStart();
|
||||
void StreamingStop(int errorcode);
|
||||
|
||||
void RecordingStop();
|
||||
|
||||
private slots:
|
||||
void AddSceneItem(OBSSceneItem item);
|
||||
void RemoveSceneItem(OBSSceneItem item);
|
||||
@@ -190,6 +197,7 @@ private slots:
|
||||
void on_actionUploadCurrentLog_triggered();
|
||||
void on_actionUploadLastLog_triggered();
|
||||
void on_streamButton_clicked();
|
||||
void on_recordButton_clicked();
|
||||
void on_settingsButton_clicked();
|
||||
|
||||
void logUploadRead();
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "obs-app.hpp"
|
||||
#include "platform.hpp"
|
||||
@@ -372,7 +373,7 @@ void OBSBasicSettings::LoadVideoSettings()
|
||||
void OBSBasicSettings::LoadSimpleOutputSettings()
|
||||
{
|
||||
const char *path = config_get_string(main->Config(), "SimpleOutput",
|
||||
"path");
|
||||
"FilePath");
|
||||
int videoBitrate = config_get_uint(main->Config(), "SimpleOutput",
|
||||
"VBitrate");
|
||||
int audioBitrate = config_get_uint(main->Config(), "SimpleOutput",
|
||||
@@ -557,7 +558,7 @@ void OBSBasicSettings::SaveOutputSettings()
|
||||
videoBitrate);
|
||||
config_set_string(main->Config(), "SimpleOutput", "ABitrate",
|
||||
QT_TO_UTF8(audioBitrate));
|
||||
config_set_string(main->Config(), "SimpleOutput", "path",
|
||||
config_set_string(main->Config(), "SimpleOutput", "FilePath",
|
||||
QT_TO_UTF8(path));
|
||||
}
|
||||
|
||||
@@ -693,6 +694,19 @@ void OBSBasicSettings::on_streamType_currentIndexChanged(int idx)
|
||||
LoadServiceInfo();
|
||||
}
|
||||
|
||||
void OBSBasicSettings::on_simpleOutputBrowse_clicked()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this,
|
||||
QTStr("OpenDirectory"),
|
||||
ui->simpleOutputPath->text(),
|
||||
QFileDialog::ShowDirsOnly |
|
||||
QFileDialog::DontResolveSymlinks);
|
||||
if (dir.isEmpty())
|
||||
return;
|
||||
|
||||
ui->simpleOutputPath->setText(dir);
|
||||
}
|
||||
|
||||
static inline bool StreamExists(const char *name)
|
||||
{
|
||||
return obs_get_service_by_name(name) != nullptr;
|
||||
|
@@ -108,6 +108,7 @@ private slots:
|
||||
void on_buttonBox_clicked(QAbstractButton *button);
|
||||
|
||||
void on_streamType_currentIndexChanged(int idx);
|
||||
void on_simpleOutputBrowse_clicked();
|
||||
|
||||
void on_baseResolution_editTextChanged(const QString &text);
|
||||
|
||||
|
Reference in New Issue
Block a user