UI: Add VOD track support in advanced output
Adds a VOD track option (specific to Twitch) that allows a user to specify which audio track to use for their Twitch VODs, which uses a separate encoder to encode the track. This allows users the ability to choose what audio goes on their VOD, separately from the live stream.master
parent
5b8f89d86e
commit
6b81c106d8
|
@ -769,6 +769,7 @@ Basic.Settings.Output.Adv.Audio.Track3="Track 3"
|
|||
Basic.Settings.Output.Adv.Audio.Track4="Track 4"
|
||||
Basic.Settings.Output.Adv.Audio.Track5="Track 5"
|
||||
Basic.Settings.Output.Adv.Audio.Track6="Track 6"
|
||||
Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Track"
|
||||
|
||||
# basic mode 'output' settings - advanced section - recording subsection
|
||||
Basic.Settings.Output.Adv.Recording="Recording"
|
||||
|
|
|
@ -1907,7 +1907,7 @@
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_7">
|
||||
<layout class="QFormLayout" name="advOutTopLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
|
|
|
@ -1054,6 +1054,7 @@ bool SimpleOutput::ReplayBufferActive() const
|
|||
|
||||
struct AdvancedOutput : BasicOutputHandler {
|
||||
OBSEncoder streamAudioEnc;
|
||||
OBSEncoder streamArchiveEnc;
|
||||
OBSEncoder aacTrack[MAX_AUDIO_MIXES];
|
||||
OBSEncoder h264Streaming;
|
||||
OBSEncoder h264Recording;
|
||||
|
@ -1229,6 +1230,14 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||
throw "Failed to create streaming audio encoder "
|
||||
"(advanced output)";
|
||||
|
||||
id = "";
|
||||
int vodTrack =
|
||||
config_get_int(main->Config(), "AdvOut", "VodTrackIndex") - 1;
|
||||
if (!CreateAACEncoder(streamArchiveEnc, id, GetAudioBitrate(vodTrack),
|
||||
"avc_aac_archive", vodTrack))
|
||||
throw "Failed to create archive audio encoder "
|
||||
"(advanced output)";
|
||||
|
||||
startRecording.Connect(obs_output_get_signal_handler(fileOutput),
|
||||
"start", OBSStartRecording, this);
|
||||
stopRecording.Connect(obs_output_get_signal_handler(fileOutput), "stop",
|
||||
|
@ -1280,6 +1289,18 @@ void AdvancedOutput::Update()
|
|||
UpdateAudioSettings();
|
||||
}
|
||||
|
||||
static inline bool ServiceSupportsVodTrack(const char *service)
|
||||
{
|
||||
static const char *vodTrackServices[] = {"Twitch"};
|
||||
|
||||
for (const char *vodTrackService : vodTrackServices) {
|
||||
if (astrcmpi(vodTrackService, service) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void AdvancedOutput::SetupStreaming()
|
||||
{
|
||||
bool rescale = config_get_bool(main->Config(), "AdvOut", "Rescale");
|
||||
|
@ -1461,6 +1482,8 @@ inline void AdvancedOutput::UpdateAudioSettings()
|
|||
"ApplyServiceSettings");
|
||||
int streamTrackIndex =
|
||||
config_get_int(main->Config(), "AdvOut", "TrackIndex");
|
||||
int vodTrackIndex =
|
||||
config_get_int(main->Config(), "AdvOut", "VodTrackIndex");
|
||||
obs_data_t *settings[MAX_AUDIO_MIXES];
|
||||
|
||||
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||
|
@ -1481,18 +1504,23 @@ inline void AdvancedOutput::UpdateAudioSettings()
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||
int track = (int)(i + 1);
|
||||
|
||||
obs_encoder_update(aacTrack[i], settings[i]);
|
||||
|
||||
if ((int)(i + 1) == streamTrackIndex) {
|
||||
if (track == streamTrackIndex || track == vodTrackIndex) {
|
||||
if (applyServiceSettings) {
|
||||
obs_service_apply_encoder_settings(
|
||||
main->GetService(), nullptr,
|
||||
settings[i]);
|
||||
}
|
||||
|
||||
obs_encoder_update(streamAudioEnc, settings[i]);
|
||||
}
|
||||
|
||||
if (track == streamTrackIndex)
|
||||
obs_encoder_update(streamAudioEnc, settings[i]);
|
||||
if (track == vodTrackIndex)
|
||||
obs_encoder_update(streamArchiveEnc, settings[i]);
|
||||
|
||||
obs_data_release(settings[i]);
|
||||
}
|
||||
}
|
||||
|
@ -1505,6 +1533,7 @@ void AdvancedOutput::SetupOutputs()
|
|||
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
|
||||
obs_encoder_set_audio(aacTrack[i], obs_get_audio());
|
||||
obs_encoder_set_audio(streamAudioEnc, obs_get_audio());
|
||||
obs_encoder_set_audio(streamArchiveEnc, obs_get_audio());
|
||||
|
||||
SetupStreaming();
|
||||
|
||||
|
@ -1527,7 +1556,11 @@ int AdvancedOutput::GetAudioBitrate(size_t i) const
|
|||
bool AdvancedOutput::SetupStreaming(obs_service_t *service)
|
||||
{
|
||||
int streamTrack =
|
||||
config_get_int(main->Config(), "AdvOut", "TrackIndex") - 1;
|
||||
config_get_int(main->Config(), "AdvOut", "TrackIndex");
|
||||
bool vodTrackEnabled =
|
||||
config_get_bool(main->Config(), "AdvOut", "VodTrackEnabled");
|
||||
int vodTrackIndex =
|
||||
config_get_int(main->Config(), "AdvOut", "VodTrackIndex");
|
||||
|
||||
if (!useStreamEncoder ||
|
||||
(!ffmpegOutput && !obs_output_active(fileOutput))) {
|
||||
|
@ -1609,7 +1642,7 @@ bool AdvancedOutput::SetupStreaming(obs_service_t *service)
|
|||
|
||||
streamAudioEnc = obs_audio_encoder_create(
|
||||
id, "alt_audio_enc", nullptr,
|
||||
streamTrack, nullptr);
|
||||
streamTrack - 1, nullptr);
|
||||
|
||||
if (!streamAudioEnc)
|
||||
return false;
|
||||
|
@ -1626,6 +1659,23 @@ bool AdvancedOutput::SetupStreaming(obs_service_t *service)
|
|||
|
||||
obs_output_set_video_encoder(streamOutput, h264Streaming);
|
||||
obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0);
|
||||
|
||||
const char *id = obs_service_get_id(service);
|
||||
if (strcmp(id, "rtmp_custom") == 0) {
|
||||
vodTrackEnabled = false;
|
||||
} else {
|
||||
obs_data_t *settings = obs_service_get_settings(service);
|
||||
const char *service = obs_data_get_string(settings, "service");
|
||||
if (!ServiceSupportsVodTrack(service))
|
||||
vodTrackEnabled = false;
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
if (vodTrackEnabled && streamTrack != vodTrackIndex)
|
||||
obs_output_set_audio_encoder(streamOutput, streamArchiveEnc, 1);
|
||||
else
|
||||
obs_output_set_audio_encoder(streamOutput, nullptr, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1301,6 +1301,7 @@ bool OBSBasic::InitBasicConfigDefaults()
|
|||
true);
|
||||
config_set_default_bool(basicConfig, "AdvOut", "UseRescale", false);
|
||||
config_set_default_uint(basicConfig, "AdvOut", "TrackIndex", 1);
|
||||
config_set_default_uint(basicConfig, "AdvOut", "VodTrackIndex", 2);
|
||||
config_set_default_string(basicConfig, "AdvOut", "Encoder", "obs_x264");
|
||||
|
||||
config_set_default_string(basicConfig, "AdvOut", "RecType", "Standard");
|
||||
|
|
|
@ -71,6 +71,8 @@ void OBSBasicSettings::InitStreamPage()
|
|||
SLOT(UpdateServerList()));
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(UpdateKeyLink()));
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(UpdateVodTrackSetting()));
|
||||
connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
|
||||
SLOT(UpdateKeyLink()));
|
||||
connect(ui->customServer, SIGNAL(editingFinished(const QString &)),
|
||||
|
@ -141,6 +143,7 @@ void OBSBasicSettings::LoadStream1Settings()
|
|||
|
||||
UpdateKeyLink();
|
||||
UpdateMoreInfoLink();
|
||||
UpdateVodTrackSetting();
|
||||
|
||||
bool streamActive = obs_frontend_streaming_active();
|
||||
ui->streamPage->setEnabled(!streamActive);
|
||||
|
@ -594,3 +597,56 @@ void OBSBasicSettings::on_useAuth_toggled()
|
|||
ui->authPwLabel->setVisible(use_auth);
|
||||
ui->authPwWidget->setVisible(use_auth);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::UpdateVodTrackSetting()
|
||||
{
|
||||
bool enableVodTrack = ui->service->currentText() == "Twitch";
|
||||
bool wasEnabled = !!vodTrackCheckbox;
|
||||
|
||||
if (enableVodTrack == wasEnabled)
|
||||
return;
|
||||
|
||||
if (!enableVodTrack) {
|
||||
delete vodTrackCheckbox;
|
||||
delete vodTrackContainer;
|
||||
return;
|
||||
}
|
||||
|
||||
vodTrackCheckbox = new QCheckBox(
|
||||
QTStr("Basic.Settings.Output.Adv.TwitchVodTrack"));
|
||||
vodTrackCheckbox->setLayoutDirection(Qt::RightToLeft);
|
||||
|
||||
vodTrackContainer = new QWidget();
|
||||
QHBoxLayout *vodTrackLayout = new QHBoxLayout();
|
||||
for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||
vodTrack[i] = new QRadioButton(QString::number(i + 1));
|
||||
vodTrackLayout->addWidget(vodTrack[i]);
|
||||
|
||||
HookWidget(vodTrack[i], SIGNAL(clicked(bool)),
|
||||
SLOT(OutputsChanged()));
|
||||
}
|
||||
|
||||
HookWidget(vodTrackCheckbox, SIGNAL(clicked(bool)),
|
||||
SLOT(OutputsChanged()));
|
||||
|
||||
vodTrackLayout->addStretch();
|
||||
vodTrackLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
vodTrackContainer->setLayout(vodTrackLayout);
|
||||
|
||||
ui->advOutTopLayout->insertRow(2, vodTrackCheckbox, vodTrackContainer);
|
||||
|
||||
bool vodTrackEnabled =
|
||||
config_get_bool(main->Config(), "AdvOut", "VodTrackEnabled");
|
||||
vodTrackCheckbox->setChecked(vodTrackEnabled);
|
||||
vodTrackContainer->setEnabled(vodTrackEnabled);
|
||||
|
||||
connect(vodTrackCheckbox, SIGNAL(clicked(bool)), vodTrackContainer,
|
||||
SLOT(setEnabled(bool)));
|
||||
|
||||
int trackIndex =
|
||||
config_get_int(main->Config(), "AdvOut", "VodTrackIndex");
|
||||
for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||
vodTrack[i]->setChecked((i + 1) == trackIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3386,6 +3386,13 @@ void OBSBasicSettings::SaveOutputSettings()
|
|||
SaveEdit(ui->advOutTrack5Name, "AdvOut", "Track5Name");
|
||||
SaveEdit(ui->advOutTrack6Name, "AdvOut", "Track6Name");
|
||||
|
||||
if (vodTrackCheckbox) {
|
||||
SaveCheckBox(vodTrackCheckbox, "AdvOut", "VodTrackEnabled");
|
||||
SaveTrackIndex(main->Config(), "AdvOut", "VodTrackIndex",
|
||||
vodTrack[0], vodTrack[1], vodTrack[2],
|
||||
vodTrack[3], vodTrack[4], vodTrack[5]);
|
||||
}
|
||||
|
||||
SaveCheckBox(ui->advReplayBuf, "AdvOut", "RecRB");
|
||||
SaveSpinBox(ui->advRBSecMax, "AdvOut", "RecRBTime");
|
||||
SaveSpinBox(ui->advRBMegsMax, "AdvOut", "RecRBSize");
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
class OBSBasic;
|
||||
class QAbstractButton;
|
||||
class QRadioButton;
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class QLabel;
|
||||
|
@ -156,6 +157,10 @@ private:
|
|||
uint32_t outputCX = 0;
|
||||
uint32_t outputCY = 0;
|
||||
|
||||
QPointer<QCheckBox> vodTrackCheckbox;
|
||||
QPointer<QWidget> vodTrackContainer;
|
||||
QPointer<QRadioButton> vodTrack[MAX_AUDIO_MIXES];
|
||||
|
||||
void SaveCombo(QComboBox *widget, const char *section,
|
||||
const char *value);
|
||||
void SaveComboData(QComboBox *widget, const char *section,
|
||||
|
@ -239,6 +244,7 @@ private:
|
|||
private slots:
|
||||
void UpdateServerList();
|
||||
void UpdateKeyLink();
|
||||
void UpdateVodTrackSetting();
|
||||
void UpdateMoreInfoLink();
|
||||
void on_show_clicked();
|
||||
void on_authPwShow_clicked();
|
||||
|
|
Loading…
Reference in New Issue