Mux backup video after each vchunk

TODO: Remove .bak video after muxing final video
This commit is contained in:
N00MKRAD
2021-06-05 11:30:55 +02:00
parent 2ea198a24c
commit 67c79d07d1
6 changed files with 50 additions and 26 deletions

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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}" : "";

View File

@@ -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);
}
}