mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-19 20:32:15 +02:00
UI: Add fragmented MP4/MOV formats
This commit is contained in:
parent
05b1be4f27
commit
705173a0c3
@ -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"
|
||||
|
@ -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>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">mp4</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>
|
||||
<property name="toolTip">
|
||||
<string>Basic.Settings.Output.Format.TT</string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string/>
|
||||
</property>
|
||||
</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>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">mp4</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>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
obs_data_set_string(settings, "muxer_settings", mux);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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_data_set_string(settings, "muxer_settings", mux);
|
||||
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,
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user