0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 04:42:18 +02:00

UI: Add fragmented MP4/MOV formats

This commit is contained in:
derrod 2023-01-29 12:48:01 +01:00 committed by Ryan Foster
parent 05b1be4f27
commit 705173a0c3
4 changed files with 112 additions and 80 deletions

View File

@ -931,6 +931,15 @@ Basic.Settings.Stream.Recommended.MaxFPS="Maximum FPS: %1"
# basic mode 'output' settings
Basic.Settings.Output="Output"
Basic.Settings.Output.Format="Recording Format"
Basic.Settings.Output.Format.MKV="Matroska Video (.mkv)"
Basic.Settings.Output.Format.FLV="Flash Video (.flv)"
Basic.Settings.Output.Format.MP4="MPEG-4 (.mp4)"
Basic.Settings.Output.Format.MOV="QuickTime (.mov)"
Basic.Settings.Output.Format.TS="MPEG-TS (.ts)"
Basic.Settings.Output.Format.HLS="HLS (.m3u8 + .ts)"
Basic.Settings.Output.Format.fMP4="Fragmented MP4 (.mp4)"
Basic.Settings.Output.Format.fMOV="Fragmented MOV (.mov)"
Basic.Settings.Output.Format.TT="Fragmented MP4/MOV writes the recording in chunks and does not require the same finalization as traditional MP4/MOV files.\nThis ensures the file remains playable even if writing to disk is interrupted, for example, as a result of a BSOD or power loss.\n\nThis may not be compatible with all players and editors. Use File → Remux Recordings to convert the file into a more compatible format if necessary."
Basic.Settings.Output.Encoder="Encoder"
Basic.Settings.Output.SelectDirectory="Select Recording Directory"
Basic.Settings.Output.SelectFile="Select Recording File"

View File

@ -1888,36 +1888,15 @@
</item>
<item row="3" column="1">
<widget class="QComboBox" name="simpleOutRecFormat">
<item>
<property name="text">
<string notr="true">flv</string>
<property name="toolTip">
<string>Basic.Settings.Output.Format.TT</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">mp4</string>
<property name="editable">
<bool>false</bool>
</property>
</item>
<item>
<property name="text">
<string notr="true">mov</string>
<property name="currentText">
<string/>
</property>
</item>
<item>
<property name="text">
<string notr="true">mkv</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">ts</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">m3u8</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
@ -2652,42 +2631,21 @@
</item>
<item row="2" column="1">
<widget class="QComboBox" name="advOutRecFormat">
<property name="toolTip">
<string>Basic.Settings.Output.Format.TT</string>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string notr="true">flv</string>
<property name="editable">
<bool>false</bool>
</property>
</item>
<item>
<property name="text">
<string notr="true">mp4</string>
<property name="currentText">
<string/>
</property>
</item>
<item>
<property name="text">
<string notr="true">mov</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">mkv</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">ts</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">m3u8</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">

View File

@ -1149,9 +1149,15 @@ bool SimpleOutput::ConfigureRecording(bool updateReplayBuffer)
int rbSize =
config_get_int(main->Config(), "SimpleOutput", "RecRBSize");
bool is_fragmented = strcmp(format, "fmp4") == 0 ||
strcmp(format, "fmov") == 0;
string f;
string strPath;
if (is_fragmented)
++format;
OBSDataAutoRelease settings = obs_data_create();
if (updateReplayBuffer) {
f = GetFormatString(filenameFormat, rbPrefix, rbSuffix);
@ -1175,7 +1181,23 @@ bool SimpleOutput::ConfigureRecording(bool updateReplayBuffer)
strPath.c_str());
}
// Use fragmented MOV/MP4 if user has not already specified custom movflags
if (is_fragmented && (!mux || strstr(mux, "movflags") == NULL)) {
string mux_frag =
"movflags=frag_keyframe+empty_moov+delay_moov";
if (mux) {
mux_frag += " ";
mux_frag += mux;
}
obs_data_set_string(settings, "muxer_settings",
mux_frag.c_str());
} else {
if (is_fragmented)
blog(LOG_WARNING,
"User enabled fragmented recording, "
"but custom muxer settings contained movflags.");
obs_data_set_string(settings, "muxer_settings", mux);
}
if (updateReplayBuffer)
obs_output_update(replayBuffer, settings);
@ -1592,6 +1614,9 @@ inline void AdvancedOutput::SetupRecording()
const char *recFormat =
config_get_string(main->Config(), "AdvOut", "RecFormat");
bool is_fragmented = strcmp(recFormat, "fmp4") == 0 ||
strcmp(recFormat, "fmov") == 0;
bool flv = strcmp(recFormat, "flv") == 0;
if (flv)
@ -1647,8 +1672,25 @@ inline void AdvancedOutput::SetupRecording()
aacTrack[tracks - 1], idx);
}
obs_data_set_string(settings, "path", path);
// Use fragmented MOV/MP4 if user has not already specified custom movflags
if (is_fragmented && (!mux || strstr(mux, "movflags") == NULL)) {
string mux_fmp4 =
"movflags=frag_keyframe+empty_moov+delay_moov";
if (mux) {
mux_fmp4 += " ";
mux_fmp4 += mux;
}
obs_data_set_string(settings, "muxer_settings",
mux_fmp4.c_str());
} else {
if (is_fragmented)
blog(LOG_WARNING,
"User enabled fragmented recording, "
"but custom muxer settings contained movflags.");
obs_data_set_string(settings, "muxer_settings", mux);
}
obs_data_set_string(settings, "path", path);
obs_output_update(fileOutput, settings);
if (replayBuffer)
obs_output_update(replayBuffer, settings);
@ -2039,6 +2081,11 @@ bool AdvancedOutput::StartRecording()
splitFile = config_get_bool(main->Config(), "AdvOut",
"RecSplitFile");
// Strip leading "f" in case fragmented format was selected
if (strcmp(recFormat, "fmp4") == 0 ||
strcmp(recFormat, "fmov") == 0)
++recFormat;
string strPath = GetRecordingFilename(path, recFormat, noSpace,
overwriteIfExists,
filenameFormat,

View File

@ -1031,6 +1031,7 @@ void OBSBasicSettings::LoadColorFormats()
void OBSBasicSettings::LoadFormats()
{
#define FORMAT_STR(str) QTStr("Basic.Settings.Output.Format." str)
ui->advOutFFFormat->blockSignals(true);
formats.reset(ff_format_supported());
@ -1059,6 +1060,25 @@ void OBSBasicSettings::LoadFormats()
ui->advOutFFFormat->insertItem(0, AV_FORMAT_DEFAULT_STR);
ui->advOutFFFormat->blockSignals(false);
ui->simpleOutRecFormat->addItem(FORMAT_STR("FLV"), "flv");
ui->simpleOutRecFormat->addItem(FORMAT_STR("MKV"), "mkv");
ui->simpleOutRecFormat->addItem(FORMAT_STR("MP4"), "mp4");
ui->simpleOutRecFormat->addItem(FORMAT_STR("MOV"), "mov");
ui->simpleOutRecFormat->addItem(FORMAT_STR("fMP4"), "fmp4");
ui->simpleOutRecFormat->addItem(FORMAT_STR("fMOV"), "fmov");
ui->simpleOutRecFormat->addItem(FORMAT_STR("TS"), "ts");
ui->advOutRecFormat->addItem(FORMAT_STR("FLV"), "flv");
ui->advOutRecFormat->addItem(FORMAT_STR("MKV"), "mkv");
ui->advOutRecFormat->addItem(FORMAT_STR("MP4"), "mp4");
ui->advOutRecFormat->addItem(FORMAT_STR("MOV"), "mov");
ui->advOutRecFormat->addItem(FORMAT_STR("fMP4"), "fmp4");
ui->advOutRecFormat->addItem(FORMAT_STR("fMOV"), "fmov");
ui->advOutRecFormat->addItem(FORMAT_STR("TS"), "ts");
ui->advOutRecFormat->addItem(FORMAT_STR("HLS"), "m3u8");
#undef FORMAT_STR
}
static void AddCodec(QComboBox *combo, const ff_codec_desc *codec_desc)
@ -1844,7 +1864,7 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
ui->simpleNoSpace->setChecked(noSpace);
ui->simpleOutputVBitrate->setValue(videoBitrate);
int idx = ui->simpleOutRecFormat->findText(format);
int idx = ui->simpleOutRecFormat->findData(format);
ui->simpleOutRecFormat->setCurrentIndex(idx);
const char *speakers =
@ -2022,7 +2042,7 @@ void OBSBasicSettings::LoadAdvOutputRecordingSettings()
ui->advOutRecRescale->setCurrentText(rescaleRes);
ui->advOutMuxCustom->setText(muxCustom);
int idx = ui->advOutRecFormat->findText(format);
int idx = ui->advOutRecFormat->findData(format);
ui->advOutRecFormat->setCurrentIndex(idx);
ui->advOutRecTrack1->setChecked(tracks & (1 << 0));
@ -3621,7 +3641,7 @@ void OBSBasicSettings::SaveOutputSettings()
SaveCombo(ui->simpleOutputABitrate, "SimpleOutput", "ABitrate");
SaveEdit(ui->simpleOutputPath, "SimpleOutput", "FilePath");
SaveCheckBox(ui->simpleNoSpace, "SimpleOutput", "FileNameWithoutSpace");
SaveCombo(ui->simpleOutRecFormat, "SimpleOutput", "RecFormat");
SaveComboData(ui->simpleOutRecFormat, "SimpleOutput", "RecFormat");
SaveCheckBox(ui->simpleOutAdvanced, "SimpleOutput", "UseAdvanced");
SaveComboData(ui->simpleOutPreset, "SimpleOutput", presetType);
SaveEdit(ui->simpleOutCustom, "SimpleOutput", "x264Settings");
@ -3648,7 +3668,7 @@ void OBSBasicSettings::SaveOutputSettings()
SaveEdit(ui->advOutRecPath, "AdvOut", "RecFilePath");
SaveCheckBox(ui->advOutNoSpace, "AdvOut", "RecFileNameWithoutSpace");
SaveCombo(ui->advOutRecFormat, "AdvOut", "RecFormat");
SaveComboData(ui->advOutRecFormat, "AdvOut", "RecFormat");
SaveComboData(ui->advOutRecEncoder, "AdvOut", "RecEncoder");
SaveCheckBox(ui->advOutRecUseRescale, "AdvOut", "RecRescale");
SaveCombo(ui->advOutRecRescale, "AdvOut", "RecRescaleRes");
@ -4709,7 +4729,9 @@ void OBSBasicSettings::AdvOutRecCheckWarnings()
warningMsg += QTStr("OutputWarnings.CannotPause");
}
if (ui->advOutRecFormat->currentText().compare("flv") == 0) {
QString recFormat = ui->advOutRecFormat->currentData().toString();
if (recFormat == "flv") {
ui->advRecTrackWidget->setCurrentWidget(ui->flvTracks);
} else {
ui->advRecTrackWidget->setCurrentWidget(ui->recTracks);
@ -4718,20 +4740,18 @@ void OBSBasicSettings::AdvOutRecCheckWarnings()
errorMsg = QTStr("OutputWarnings.NoTracksSelected");
}
QString recFormat = ui->advOutRecFormat->currentText();
QString recEncoder = ui->advOutRecEncoder->currentText();
if (recEncoder.contains("ProRes")) {
if (recFormat.compare("mkv") == 0) {
if (recFormat == "mkv") {
ui->autoRemux->setText(
QTStr("Basic.Settings.Advanced.AutoRemux")
.arg("mov"));
} else if (recFormat.compare("mov") == 0) {
if (!warningMsg.isEmpty()) {
} else if (recFormat == "mov") {
if (!warningMsg.isEmpty())
warningMsg += "\n\n";
}
warningMsg += QTStr("OutputWarnings.MP4Recording");
ui->autoRemux->setText(
QTStr("Basic.Settings.Advanced.AutoRemux")
.arg("mov") +
@ -4746,11 +4766,9 @@ void OBSBasicSettings::AdvOutRecCheckWarnings()
.arg(recFormat);
}
} else {
if (recFormat.compare("mp4") == 0 ||
recFormat.compare("mov") == 0) {
if (!warningMsg.isEmpty()) {
if (recFormat == "mp4" || recFormat == "mov") {
if (!warningMsg.isEmpty())
warningMsg += "\n\n";
}
warningMsg += QTStr("OutputWarnings.MP4Recording");
ui->autoRemux->setText(
@ -5317,9 +5335,9 @@ void OBSBasicSettings::SimpleRecordingEncoderChanged()
warning += SIMPLE_OUTPUT_WARNING("CannotPause");
}
if (qual != "Lossless" &&
(ui->simpleOutRecFormat->currentText().compare("mp4") == 0 ||
ui->simpleOutRecFormat->currentText().compare("mov") == 0)) {
QString format = ui->simpleOutRecFormat->currentData().toString();
if (qual != "Lossless" && (format == "mp4" || format == "mov")) {
if (!warning.isEmpty())
warning += "\n\n";
warning += QTStr("OutputWarnings.MP4Recording");