mirror of
https://github.com/n00mkrad/flowframes.git
synced 2025-12-16 16:37:48 +01:00
128 lines
5.5 KiB
C#
128 lines
5.5 KiB
C#
using Flowframes;
|
|
using Flowframes.FFmpeg;
|
|
using Flowframes.IO;
|
|
using Flowframes.Magick;
|
|
using Flowframes.Main;
|
|
using Flowframes.OS;
|
|
using Flowframes.UI;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using i = Flowframes.Interpolate;
|
|
|
|
namespace Flowframes.Main
|
|
{
|
|
class CreateVideo
|
|
{
|
|
public static async Task FramesToVideo(string path, string outPath, i.OutMode mode)
|
|
{
|
|
if (!mode.ToString().ToLower().Contains("vid")) // Skip output mode is not a video (e.g. image sequence)
|
|
return;
|
|
if (IOUtils.GetAmountOfFiles(path, false, $"*.{InterpolateUtils.lastExt}") <= 1)
|
|
{
|
|
i.Cancel("Output folder does not contain frames - An error must have occured during interpolation!");
|
|
return;
|
|
}
|
|
await Task.Delay(10);
|
|
if(Config.GetInt("timingMode") == 1)
|
|
await FrameDedup.Reduplicate(path);
|
|
Program.mainForm.SetStatus("Creating output video from frames...");
|
|
try
|
|
{
|
|
int maxFps = Config.GetInt("maxFps");
|
|
if (maxFps == 0) maxFps = 500;
|
|
|
|
if (mode == i.OutMode.VidMp4 && i.currentOutFps > maxFps)
|
|
{
|
|
bool createSecondVid = (Config.GetInt("maxFpsMode") == 1);
|
|
await Encode(mode, path, outPath, i.currentOutFps, maxFps, createSecondVid);
|
|
}
|
|
else
|
|
{
|
|
await Encode(mode, path, outPath, i.currentOutFps);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Log("FramesToVideo Error: " + e.Message, false);
|
|
MessageBox.Show("An error occured while trying to convert the interpolated frames to a video.\nCheck the log for details.");
|
|
}
|
|
}
|
|
|
|
static async Task Encode(i.OutMode mode, string framesPath, string outPath, float fps, float changeFps = -1, bool keepOriginalFpsVid = true)
|
|
{
|
|
if (mode == i.OutMode.VidGif)
|
|
{
|
|
if (new DirectoryInfo(framesPath).GetFiles()[0].Extension != ".png")
|
|
{
|
|
Logger.Log("Converting output frames to PNG to encode with Gifski...");
|
|
await Coverter.Convert(framesPath, ImageMagick.MagickFormat.Png00, 20, "png", false);
|
|
}
|
|
await GifskiCommands.CreateGifFromFrames(i.currentOutFps.RoundToInt(), Config.GetInt("gifskiQ"), framesPath, outPath);
|
|
}
|
|
|
|
if (mode == i.OutMode.VidMp4)
|
|
{
|
|
string ext = InterpolateUtils.lastExt;
|
|
int looptimes = GetLoopTimes(framesPath);
|
|
|
|
if (looptimes > 0) Logger.Log($"Looping {looptimes} times to reach target length");
|
|
|
|
bool h265 = Config.GetInt("mp4Enc") == 1;
|
|
int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf");
|
|
|
|
await FFmpegCommands.FramesToMp4(framesPath, outPath, h265, crf, fps, "", false, looptimes, ext);
|
|
await MergeAudio(i.lastInputPath, outPath);
|
|
|
|
if (changeFps > 0)
|
|
{
|
|
string newOutPath = IOUtils.FilenameSuffix(outPath, $"-{changeFps.ToString("0")}fps");
|
|
Program.mainForm.SetStatus("Creating video with desired frame rate...");
|
|
await FFmpegCommands.ConvertFramerate(outPath, newOutPath, h265, crf, changeFps, !keepOriginalFpsVid);
|
|
await MergeAudio(i.lastInputPath, newOutPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static int GetLoopTimes(string framesOutPath)
|
|
{
|
|
int minLength = Config.GetInt("minOutVidLength");
|
|
int minFrameCount = (minLength * i.currentOutFps).RoundToInt();
|
|
int outFrames = new DirectoryInfo(framesOutPath).GetFiles($"*.{InterpolateUtils.lastExt}", SearchOption.TopDirectoryOnly).Length;
|
|
if (outFrames / i.currentOutFps < minLength)
|
|
return (int)Math.Ceiling((double)minFrameCount / (double)outFrames);
|
|
return -1;
|
|
}
|
|
|
|
public static async Task MergeAudio(string sourceVideo, string outVideo, int looptimes = -1)
|
|
{
|
|
if (!Config.GetBool("enableAudio")) return;
|
|
try
|
|
{
|
|
Logger.Log("Adding input audio to output video...");
|
|
string audioFileBasePath = Path.Combine(i.currentTempDir, "audio");
|
|
if(IOUtils.IsPathDirectory(sourceVideo) && !File.Exists(IOUtils.GetAudioFile(audioFileBasePath))) // Try loading out of same folder as input if input is a folder
|
|
audioFileBasePath = Path.Combine(i.currentTempDir.GetParentDir(), "audio");
|
|
if (!File.Exists(IOUtils.GetAudioFile(audioFileBasePath)))
|
|
await FFmpegCommands.ExtractAudio(sourceVideo, audioFileBasePath); // Extract from sourceVideo to audioFile unless it already exists
|
|
if (!File.Exists(IOUtils.GetAudioFile(audioFileBasePath)))
|
|
{
|
|
Logger.Log("No compatible audio stream found.");
|
|
return;
|
|
}
|
|
await FFmpegCommands.MergeAudio(outVideo, IOUtils.GetAudioFile(audioFileBasePath)); // Merge from audioFile into outVideo
|
|
}
|
|
catch
|
|
{
|
|
Logger.Log("Failed to copy audio!");
|
|
}
|
|
}
|
|
}
|
|
}
|