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:
jp9000 2014-05-20 23:27:27 -07:00
parent 52ddee9755
commit 00086f0890
7 changed files with 132 additions and 18 deletions

View file

@ -34,6 +34,10 @@ Output.ConnectFail.InvalidStream="Could not access the specified channel or stre
Output.ConnectFail.Error="An unexpected error occurred when trying to connect to the server. More information in the log file."
Output.ConnectFail.Disconnected="Disconnected from server."
# output recording messages
Output.BadPath.Title="Bad File Path"
Output.BadPath.Text="The configured file output path is invalid. Please check your settings to confirm that a valid file path has been set."
# log upload dialog text and messages
LogReturnDialog="Log Upload Successful"
LogReturnDialog.CopyURL="Copy URL"
@ -106,7 +110,7 @@ Basic.Settings.Output="Output"
Basic.Settings.Output.Mode="Output Mode"
Basic.Settings.Output.Mode.Simple="Simple (Stream and/or record)"
Basic.Settings.Output.Mode.Advanced="Advanced (Custom output type)"
Basic.Settings.Output.Simple.SavePath="Recording Path"
Basic.Settings.Output.Simple.SavePath="FLV Recording Path"
Basic.Settings.Output.Simple.VideoBitrate="Video Bitrate"
Basic.Settings.output.Simple.AudioBitrate="Audio Bitrate"

View file

@ -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>

View file

@ -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>

View file

@ -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"));
}
}
}

View file

@ -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();

View file

@ -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;

View file

@ -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);