diff --git a/Code/IO/IOUtils.cs b/Code/IO/IOUtils.cs index 2463d03..4f74693 100644 --- a/Code/IO/IOUtils.cs +++ b/Code/IO/IOUtils.cs @@ -21,7 +21,7 @@ namespace Flowframes.IO { class IOUtils { - public static Image GetImage(string path) + public static Image GetImage(string path, bool allowMagickFallback = true, bool log = true) { try { @@ -34,12 +34,17 @@ namespace Flowframes.IO { MagickImage img = new MagickImage(path); Bitmap bitmap = img.ToBitmap(); - Logger.Log($"GetImage: Native image reading for '{Path.GetFileName(path)}' failed - Using Magick.NET fallback instead.", true); + + if(log) + Logger.Log($"GetImage: Native image reading for '{Path.GetFileName(path)}' failed - Using Magick.NET fallback instead.", true); + return bitmap; } catch (Exception e) { - Logger.Log($"GetImage failed: {e.Message}", true); + if (log) + Logger.Log($"GetImage failed: {e.Message}", true); + return null; } } diff --git a/Code/Main/AutoEncode.cs b/Code/Main/AutoEncode.cs index c883b56..726fb0e 100644 --- a/Code/Main/AutoEncode.cs +++ b/Code/Main/AutoEncode.cs @@ -128,6 +128,7 @@ namespace Flowframes.Main lastEncodedFrameNum = (frameLinesToEncode.Last() + 1); videoIndex++; + await CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outPath, true); busy = false; } catch (Exception e) diff --git a/Code/Main/CreateVideo.cs b/Code/Main/CreateVideo.cs index afcd456..e1dc099 100644 --- a/Code/Main/CreateVideo.cs +++ b/Code/Main/CreateVideo.cs @@ -11,6 +11,7 @@ using System.Diagnostics; using Flowframes.Data; using Flowframes.Media; using Microsoft.VisualBasic.Logging; +using Flowframes.MiscUtils; namespace Flowframes.Main { @@ -160,7 +161,7 @@ namespace Flowframes.Main } } - public static async Task ChunksToVideos(string tempFolder, string chunksFolder, string baseOutPath) + public static async Task ChunksToVideos(string tempFolder, string chunksFolder, string baseOutPath, bool isBackup = false) { if (IOUtils.GetAmountOfFiles(chunksFolder, true, "*" + FFmpegUtils.GetExt(I.current.outMode)) < 1) { @@ -168,8 +169,11 @@ namespace Flowframes.Main return; } - await Task.Delay(10); - Program.mainForm.SetStatus("Merging video chunks..."); + NmkdStopwatch sw = new NmkdStopwatch(); + + if(!isBackup) + Program.mainForm.SetStatus("Merging video chunks..."); + try { DirectoryInfo chunksDir = new DirectoryInfo(chunksFolder); @@ -186,21 +190,33 @@ namespace Flowframes.Main Logger.Log($"CreateVideo: Running MergeChunks() for frames file '{Path.GetFileName(tempConcatFile)}'", true); bool fpsLimit = dir.Name.Contains(Paths.fpsLimitSuffix); string outPath = Path.Combine(baseOutPath, await IOUtils.GetCurrentExportFilename(fpsLimit, true)); - await MergeChunks(tempConcatFile, outPath); + await MergeChunks(tempConcatFile, outPath, isBackup); } } catch (Exception e) { - Logger.Log("ChunksToVideo Error: " + e.Message, false); - MessageBox.Show("An error occured while trying to merge the video chunks.\nCheck the log for details."); + Logger.Log("ChunksToVideo Error: " + e.Message, isBackup); + + if (!isBackup) + MessageBox.Show("An error occured while trying to merge the video chunks.\nCheck the log for details."); } + + Logger.Log($"Merged video chunks in {sw.GetElapsedStr()}", true); } - static async Task MergeChunks(string vfrFile, string outPath) + static async Task MergeChunks(string framesFile, string outPath, bool isIncomplete = false) { - await FfmpegCommands.ConcatVideos(vfrFile, outPath, -1); - await MuxOutputVideo(I.current.inPath, outPath); - await Loop(outPath, await GetLoopTimes()); + if (isIncomplete) + { + outPath = IOUtils.FilenameSuffix(outPath, ".bak"); + await IOUtils.TryDeleteIfExistsAsync(outPath); + } + + await FfmpegCommands.ConcatVideos(framesFile, outPath, -1, !isIncomplete); + await MuxOutputVideo(I.current.inPath, outPath, isIncomplete, !isIncomplete); + + if(!isIncomplete) + await Loop(outPath, await GetLoopTimes()); } public static async Task EncodeChunk(string outPath, I.OutMode mode, int firstFrameNum, int framesAmount) @@ -251,7 +267,7 @@ namespace Flowframes.Main return times; } - public static async Task MuxOutputVideo(string inputPath, string outVideo) + public static async Task MuxOutputVideo(string inputPath, string outVideo, bool shortest = false, bool showLog = true) { if (!File.Exists(outVideo)) { @@ -262,7 +278,8 @@ namespace Flowframes.Main if (!Config.GetBool(Config.Key.keepAudio) && !Config.GetBool(Config.Key.keepAudio)) return; - Program.mainForm.SetStatus("Muxing audio/subtitles into video..."); + if(showLog) + Program.mainForm.SetStatus("Muxing audio/subtitles into video..."); if (I.current.inputIsFrames) { @@ -272,11 +289,11 @@ namespace Flowframes.Main try { - await FfmpegAudioAndMetadata.MergeStreamsFromInput(inputPath, outVideo, I.current.tempFolder); + await FfmpegAudioAndMetadata.MergeStreamsFromInput(inputPath, outVideo, I.current.tempFolder, shortest); } catch (Exception e) { - Logger.Log("Failed to merge audio/subtitles with output video!"); + Logger.Log("Failed to merge audio/subtitles with output video!", !showLog); Logger.Log("MergeAudio() Exception: " + e.Message, true); } } diff --git a/Code/Media/FfmpegAudioAndMetadata.cs b/Code/Media/FfmpegAudioAndMetadata.cs index 5c03cec..7a27fdb 100644 --- a/Code/Media/FfmpegAudioAndMetadata.cs +++ b/Code/Media/FfmpegAudioAndMetadata.cs @@ -11,7 +11,8 @@ namespace Flowframes.Media partial class FfmpegAudioAndMetadata : FfmpegCommands { #region Mux From Input - public static async Task MergeStreamsFromInput (string inputVideo, string interpVideo, string tempFolder) + + public static async Task MergeStreamsFromInput (string inputVideo, string interpVideo, string tempFolder, bool shortest) { if (!File.Exists(inputVideo) && !I.current.inputIsFrames) { @@ -48,6 +49,7 @@ namespace Flowframes.Media bool isMkv = I.current.outMode == I.OutMode.VidMkv; string mkvFix = isMkv ? "-max_interleave_delta 0" : ""; // https://reddit.com/r/ffmpeg/comments/efddfs/starting_new_cluster_due_to_timestamp/ string metaArg = (isMkv && meta) ? "-map 1:t?" : ""; // https://reddit.com/r/ffmpeg/comments/fw4jnh/how_to_make_ffmpeg_keep_attached_images_in_mkv_as/ + string shortestArg = shortest ? "-shortest" : ""; if (QuickSettingsTab.trimEnabled) { @@ -57,14 +59,14 @@ namespace Flowframes.Media string args1 = $"{trim[0]} -i {inputVideo.Wrap()} {trim[1]} -map 0 -map -0:v -map -0:d -c copy {audioArgs} {subArgs} {otherStreamsName}"; // Extract trimmed await RunFfmpeg(args1, tempFolder, LogMode.Hidden); - string args2 = $"-i {inName} -i {otherStreamsName} -map 0:v:0 -map 1:a:? -map 1:s:? {metaArg} -c copy {audioArgs} {subArgs} {mkvFix} {outName}"; // Merge interp + trimmed original + string args2 = $"-i {inName} -i {otherStreamsName} -map 0:v:0 -map 1:a:? -map 1:s:? {metaArg} -c copy {audioArgs} {subArgs} {mkvFix} {shortestArg} {outName}"; // Merge interp + trimmed original await RunFfmpeg(args2, tempFolder, LogMode.Hidden); IOUtils.TryDeleteIfExists(Path.Combine(tempFolder, otherStreamsName)); } else // If trimming is disabled we can pull the streams directly from the input file { - string args = $"-i {inName} -i {inputVideo.Wrap()} -map 0:v:0 -map 1:a:? -map 1:s:? {metaArg} -c copy {audioArgs} {subArgs} {mkvFix} {outName}"; + string args = $"-i {inName} -i {inputVideo.Wrap()} -map 0:v:0 -map 1:a:? -map 1:s:? {metaArg} -c copy {audioArgs} {subArgs} {mkvFix} {shortestArg} {outName}"; await RunFfmpeg(args, tempFolder, LogMode.Hidden); } diff --git a/Code/Media/FfmpegCommands.cs b/Code/Media/FfmpegCommands.cs index 89008fb..c4bf79d 100644 --- a/Code/Media/FfmpegCommands.cs +++ b/Code/Media/FfmpegCommands.cs @@ -34,10 +34,12 @@ namespace Flowframes return $"pad=width=ceil(iw/{padPixels})*{padPixels}:height=ceil(ih/{padPixels})*{padPixels}:color=black@0"; } - public static async Task ConcatVideos(string concatFile, string outPath, int looptimes = -1) + public static async Task ConcatVideos(string concatFile, string outPath, int looptimes = -1, bool showLog = true) { Logger.Log($"ConcatVideos('{Path.GetFileName(concatFile)}', '{outPath}', {looptimes})", true, false, "ffmpeg"); - Logger.Log($"Merging videos...", false, Logger.GetLastLine().Contains("frame")); + + if(showLog) + Logger.Log($"Merging videos...", false, Logger.GetLastLine().Contains("frame")); IOUtils.RenameExistingFile(outPath); string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : ""; diff --git a/Code/UI/InterpolationProgress.cs b/Code/UI/InterpolationProgress.cs index be33aaf..1538fe8 100644 --- a/Code/UI/InterpolationProgress.cs +++ b/Code/UI/InterpolationProgress.cs @@ -1,7 +1,5 @@ using Flowframes.IO; using Flowframes.MiscUtils; -using Flowframes.OS; -using Flowframes.UI; using System; using System.Diagnostics; using System.Drawing; @@ -13,7 +11,6 @@ using System.Windows.Forms; using Flowframes.Forms; using Flowframes.Main; using I = Flowframes.Interpolate; -using Padding = Flowframes.Data.Padding; namespace Flowframes.UI { @@ -125,7 +122,7 @@ namespace Flowframes.UI { if (bigPreviewForm == null && !preview.Visible /* ||Program.mainForm.WindowState != FormWindowState.Minimized */ /* || !Program.mainForm.IsInFocus()*/) return; // Skip if the preview is not visible or the form is not in focus if (timeSinceLastPreviewUpdate.IsRunning && timeSinceLastPreviewUpdate.ElapsedMilliseconds < previewUpdateRateMs) return; - Image img = IOUtils.GetImage(latestFramePath); + Image img = IOUtils.GetImage(latestFramePath, false, false); SetPreviewImg(img); } }