diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index b9325190d31380..9a164738f627f6 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -967,6 +967,7 @@ 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.hMP4="Hybrid MP4 (.mp4) [experimental]" Basic.Settings.Output.Format.fMOV="Fragmented MOV (.mov)" Basic.Settings.Output.Format.TT.fragmented_mov="Fragmented MOV writes the recording in chunks and does not require the same finalization as traditional 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.Format.TT.fragmented_mp4="Fragmented MP4 writes the recording in chunks and does not require the same finalization as traditional MP4 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." diff --git a/UI/ffmpeg-utils.cpp b/UI/ffmpeg-utils.cpp index c3cd54eb3f8e33..ce684d05abfa24 100644 --- a/UI/ffmpeg-utils.cpp +++ b/UI/ffmpeg-utils.cpp @@ -185,6 +185,19 @@ static const unordered_map> codec_compat = { "pcm_f32le", #endif }}, + // Not part of FFmpeg, see obs-outputs module + {"hybrid_mp4", + { + "h264", + "hevc", + "av1", + "aac", + "flac", + "alac", + "pcm_s16le", + "pcm_s24le", + "pcm_f32le", + }}, {"mov", { "h264", diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 781838e5e17179..fd957856c0e295 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -1783,6 +1783,8 @@ string GetFormatExt(const char *container) string ext = container; if (ext == "fragmented_mp4") ext = "mp4"; + if (ext == "hybrid_mp4") + ext = "mp4"; else if (ext == "fragmented_mov") ext = "mov"; else if (ext == "hls") diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp index f87e16dcd29ba6..4f26dc27f24c22 100644 --- a/UI/window-basic-main-outputs.cpp +++ b/UI/window-basic-main-outputs.cpp @@ -1568,6 +1568,8 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) config_get_string(main->Config(), "AdvOut", "RecEncoder"); const char *recAudioEncoder = config_get_string(main->Config(), "AdvOut", "RecAudioEncoder"); + const char *recFormat = + config_get_string(main->Config(), "AdvOut", "RecFormat2"); #ifdef __APPLE__ translate_macvth264_encoder(streamEncoder); translate_macvth264_encoder(recordEncoder); @@ -1623,8 +1625,11 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) OBSReplayBufferSaved, this); } + bool native_muxer = strcmp(recFormat, "hybrid_mp4") == 0; + fileOutput = obs_output_create( - "ffmpeg_muxer", "adv_file_output", nullptr, nullptr); + native_muxer ? "mp4_output" : "ffmpeg_muxer", + "adv_file_output", nullptr, nullptr); if (!fileOutput) throw "Failed to create recording output " "(advanced output)"; diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 6d1b4ae943f27b..38c21b509cf89d 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -1162,6 +1162,7 @@ void OBSBasicSettings::LoadFormats() ui->advOutRecFormat->addItem(FORMAT_STR("MOV"), "mov"); ui->advOutRecFormat->addItem(FORMAT_STR("fMP4"), "fragmented_mp4"); ui->advOutRecFormat->addItem(FORMAT_STR("fMOV"), "fragmented_mov"); + ui->advOutRecFormat->addItem(FORMAT_STR("hMP4"), "hybrid_mp4"); ui->advOutRecFormat->addItem(FORMAT_STR("TS"), "mpegts"); ui->advOutRecFormat->addItem(FORMAT_STR("HLS"), "hls");