diff --git a/README.md b/README.md index 7bdb300..57d2baf 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ - Resolution (supports output higher than your display resolution) - Frame rate (FPS) - Camera settings (Camera2, ReeCamera, None or Default) + - Encoding (h.264, HEVC, AV1) - Output files saved to: ``` Beat Saber/Renders/Finished @@ -37,4 +38,3 @@ From there, you can: *(The mod will not run unless using `-fpfc` or the first person flying controller)* - Ensure that the replay files being played are not broken or your replay playback mod is broken, this mod does not handle the replays themselves -- Audio is currently **NOT** recorded from the game, and is instead muxed in from the beatmaps ogg/egg file diff --git a/RenderMod/Render/EncoderHelpers.cs b/RenderMod/Render/EncoderHelpers.cs index 64abb9a..d7f259e 100644 --- a/RenderMod/Render/EncoderHelpers.cs +++ b/RenderMod/Render/EncoderHelpers.cs @@ -1,6 +1,8 @@ +using System; using IPA.Utilities; using System.Diagnostics; using System.IO; +using Debug = UnityEngine.Debug; namespace RenderMod.Render { @@ -23,7 +25,7 @@ public static string SelectBestEncoder() if (IsEncoderUsable("hevc_qsv", encodersOutput)) return "hevc_qsv"; - + return "libx265"; } @@ -48,7 +50,7 @@ public static string SelectBestEncoder() if (IsEncoderUsable("h264_qsv", encodersOutput)) return "h264_qsv"; - + return "libx264"; } @@ -77,12 +79,14 @@ private static string GetEncodersOutput() return string.Empty; } } - + private static bool IsEncoderUsable(string encoder, string encodersOutput) { if (!encodersOutput.Contains(encoder)) + { + Debug.LogError($"{encoder} is unavailable!"); return false; - + } return TestEncoder(encoder); } @@ -95,7 +99,7 @@ public static bool TestEncoder(string encoder) proc.StartInfo.Arguments = $"-hide_banner -loglevel error " + $"-f lavfi -i testsrc=size=1280x720:rate=30 " + - $"-c:v {encoder} -t 1 -f null -"; + $"-vf format=yuv420p -c:v {encoder} -t 1 -f null -"; proc.StartInfo.RedirectStandardError = true; proc.StartInfo.UseShellExecute = false; @@ -130,7 +134,11 @@ public static (string encoder, string args) BuildEncoderArgs(string encoder) switch (ReplayRenderSettings.Preset) { case QualityPreset.Low: - if (encoder.Contains("nvenc")) + if (encoder.Contains("av1_nvenc")) + { + presetArgs = $"-preset fast -rc vbr {bitrateArg}"; + } + else if (encoder.Contains("nvenc")) { presetArgs = $"-preset fast -rc vbr_hq -cq 28 {bitrateArg}"; } @@ -153,7 +161,11 @@ public static (string encoder, string args) BuildEncoderArgs(string encoder) break; case QualityPreset.Medium: - if (encoder.Contains("nvenc")) + if (encoder.Contains("av1_nvenc")) + { + presetArgs = $"-preset medium -rc vbr {bitrateArg}"; + } + else if (encoder.Contains("nvenc")) { presetArgs = $"-preset medium -rc vbr_hq -cq 23 {bitrateArg}"; } @@ -176,7 +188,11 @@ public static (string encoder, string args) BuildEncoderArgs(string encoder) break; case QualityPreset.High: - if (encoder.Contains("nvenc")) + if (encoder.Contains("av1_nvenc")) + { + presetArgs = $"-preset slow -rc vbr -tune hq {bitrateArg}"; + } + else if (encoder.Contains("nvenc")) { presetArgs = $"-preset slow -rc vbr_hq -cq 18 {bitrateArg}"; } diff --git a/RenderMod/Render/RenderManager.cs b/RenderMod/Render/RenderManager.cs index 26a5f47..01f16df 100644 --- a/RenderMod/Render/RenderManager.cs +++ b/RenderMod/Render/RenderManager.cs @@ -47,12 +47,12 @@ public static void StartAudioCapture() currentState = RenderState.Audio; if (beatleaderRender) { - _log.Notice("Starting video render for BeatLeader replay"); + _log.Notice("Starting audio render for BeatLeader replay"); BeatLeaderWarningPatch.TargetMethod()?.Invoke(BeatLeaderWarningPatch.instance, null); } else { - _log.Notice("Starting video render for ScoreSaber replay"); + _log.Notice("Starting audio render for ScoreSaber replay"); ScoreSaberWarningPatch.TargetMethod()?.Invoke(ScoreSaberWarningPatch.instance, null); } } @@ -105,14 +105,19 @@ public static void StopRender() try { + _log.Notice($"Muxing raw video stream to mp4..."); FFmpegPipe.RemuxRawStreamToMp4(latestVideoFile, tempVideoMp4, ReplayRenderSettings.FPS); _log.Notice($"Raw video stream remuxed to MP4: {tempVideoMp4}"); - + + _log.Notice($"Muxing audio and video into a final mp4 file..."); FFmpegPipe.AddAudioToMp4(tempVideoMp4, latestAudioFile, finalMp4, ReplayRenderSettings.AudioBitrateKbps); _log.Notice($"Final muxed MP4 created: {finalMp4}"); Process.Start("explorer.exe", $"/select,\"{finalMp4}\""); DingPlayer.shouldPlayDing = true; + //deleting temp files + File.Delete(latestVideoFile); + File.Delete(latestAudioFile); } catch (Exception ex) { @@ -151,11 +156,22 @@ internal static void SceneChange(Scene scene1, Scene scene2) case RenderState.None: break; case RenderState.Video: + if (scene2.name.ToLower() != "gamecore") { _log.Notice("Exiting gameplay scene, starting audio capture in 2 seconds"); // leaving gameplay (render end) - Task.Delay(2000).ContinueWith(t => StartAudioCapture()); + var codec = ReplayRenderSettings.VideoCodec; + if (codec == "av1") //have to delay audio capture a bit more when using av1, ffmpeg takes longer to finish doing its av1 shit + { + _log.Notice("AV1 detected, waiting 15 seconds instead of 2..."); + Task.Delay(15000).ContinueWith(t => StartAudioCapture()); //ideally wait for ffmpeg exit and then delay by 2 seconds, fml + } + else + { + Task.Delay(2000).ContinueWith(t => StartAudioCapture()); + } + } break; case RenderState.Audio: @@ -177,4 +193,4 @@ internal static void SceneChange(Scene scene1, Scene scene2) } } } -} +} \ No newline at end of file