2021-08-23 16:50:18 +02:00
using Flowframes.IO ;
using System ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
using System.Threading.Tasks ;
using Flowframes.Ui ;
using Flowframes.Main ;
using Flowframes.Data ;
using Flowframes.MiscUtils ;
2022-04-07 14:20:28 +02:00
using System.Collections.Generic ;
using ImageMagick ;
using Paths = Flowframes . IO . Paths ;
2022-05-31 22:17:22 +02:00
using Flowframes.Media ;
using System.Drawing ;
2022-07-25 10:37:44 +02:00
using Flowframes.Utilities ;
2024-08-12 10:47:19 +02:00
using static NmkdUtils . StringExtensions ;
2021-08-23 16:50:18 +02:00
namespace Flowframes.Os
{
class AiProcess
{
public static bool hasShownError ;
public static string lastLogName ;
public static Process lastAiProcess ;
public static Stopwatch processTime = new Stopwatch ( ) ;
public static Stopwatch processTimeMulti = new Stopwatch ( ) ;
public static int lastStartupTimeMs = 1000 ;
static string lastInPath ;
2022-04-22 09:23:31 +02:00
public static void Kill ( )
2021-08-23 16:50:18 +02:00
{
if ( lastAiProcess = = null ) return ;
try
{
AiProcessSuspend . SetRunning ( false ) ;
OsUtils . KillProcessTree ( lastAiProcess . Id ) ;
}
catch ( Exception e )
{
Logger . Log ( $"Failed to kill currentAiProcess process tree: {e.Message}" , true ) ;
}
}
2022-04-22 09:23:31 +02:00
static void AiStarted ( Process proc , int startupTimeMs , string inPath = "" )
2021-08-23 16:50:18 +02:00
{
lastStartupTimeMs = startupTimeMs ;
processTime . Restart ( ) ;
lastAiProcess = proc ;
AiProcessSuspend . SetRunning ( true ) ;
2022-07-20 18:10:31 +02:00
lastInPath = string . IsNullOrWhiteSpace ( inPath ) ? Interpolate . currentSettings . framesFolder : inPath ;
2021-08-23 16:50:18 +02:00
hasShownError = false ;
}
2022-06-09 00:30:58 +02:00
static void AiStartedRt ( Process proc , string inPath = "" )
{
lastAiProcess = proc ;
AiProcessSuspend . SetRunning ( true ) ;
2022-07-20 18:10:31 +02:00
lastInPath = string . IsNullOrWhiteSpace ( inPath ) ? Interpolate . currentSettings . framesFolder : inPath ;
2022-06-09 00:30:58 +02:00
hasShownError = false ;
}
2021-08-23 16:50:18 +02:00
static void SetProgressCheck ( string interpPath , float factor )
{
int frames = IoUtils . GetAmountOfFiles ( lastInPath , false ) ;
int target = ( ( frames * factor ) - ( factor - 1 ) ) . RoundToInt ( ) ;
InterpolationProgress . progressPaused = false ;
InterpolationProgress . currentFactor = factor ;
if ( InterpolationProgress . progCheckRunning )
InterpolationProgress . targetFrames = target ;
else
InterpolationProgress . GetProgressByFrameAmount ( interpPath , target ) ;
}
2022-05-31 22:17:22 +02:00
static void SetProgressCheck ( int sourceFrames , float factor , string logFile )
{
int target = ( ( sourceFrames * factor ) - ( factor - 1 ) ) . RoundToInt ( ) ;
InterpolationProgress . progressPaused = false ;
InterpolationProgress . currentFactor = factor ;
if ( InterpolationProgress . progCheckRunning )
InterpolationProgress . targetFrames = target ;
else
InterpolationProgress . GetProgressFromFfmpegLog ( logFile , target ) ;
}
2022-06-09 00:30:58 +02:00
static async Task AiFinished ( string aiName , bool rt = false )
2021-08-23 16:50:18 +02:00
{
if ( Interpolate . canceled ) return ;
Program . mainForm . SetProgress ( 100 ) ;
AiProcessSuspend . SetRunning ( false ) ;
2022-06-01 15:46:34 +02:00
2022-06-09 00:30:58 +02:00
if ( rt )
{
Logger . Log ( $"Stopped running {aiName}." ) ;
return ;
}
2022-07-20 18:10:31 +02:00
int interpFramesFiles = IoUtils . GetAmountOfFiles ( Interpolate . currentSettings . interpFolder , false , "*" + Interpolate . currentSettings . interpExt ) ;
2021-08-23 16:50:18 +02:00
int interpFramesCount = interpFramesFiles + InterpolationProgress . deletedFramesCount ;
2022-06-01 15:46:34 +02:00
2022-07-20 18:10:31 +02:00
if ( ! Interpolate . currentSettings . ai . Piped )
2022-06-01 15:46:34 +02:00
InterpolationProgress . UpdateInterpProgress ( interpFramesCount , InterpolationProgress . targetFrames ) ;
2021-08-23 16:50:18 +02:00
string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}. Peak Output FPS: {InterpolationProgress.peakFpsOut.ToString(" 0.00 ")}" ;
2022-04-22 09:23:31 +02:00
2021-08-23 16:50:18 +02:00
if ( Interpolate . currentlyUsingAutoEnc & & AutoEncode . HasWorkToDo ( ) )
{
logStr + = " - Waiting for encoding to finish..." ;
Program . mainForm . SetStatus ( "Creating output video from frames..." ) ;
}
2023-01-31 11:41:39 +01:00
if ( Interpolate . currentSettings . outSettings . Format ! = Enums . Output . Format . Realtime )
Logger . Log ( logStr ) ;
2021-08-23 16:50:18 +02:00
processTime . Stop ( ) ;
2022-07-20 18:10:31 +02:00
if ( ! Interpolate . currentSettings . ai . Piped & & interpFramesCount < 3 )
2021-08-23 16:50:18 +02:00
{
2023-02-23 14:14:22 +01:00
string amount = interpFramesCount > 0 ? $"Only {interpFramesCount}" : "No" ;
if ( lastLogName . IsEmpty ( ) )
{
Interpolate . Cancel ( $"Interpolation failed - {amount} interpolated frames were created, and no log was written." ) ;
return ;
}
2021-08-23 16:50:18 +02:00
string [ ] logLines = File . ReadAllLines ( Path . Combine ( Paths . GetLogPath ( ) , lastLogName + ".txt" ) ) ;
string log = string . Join ( "\n" , logLines . Reverse ( ) . Take ( 10 ) . Reverse ( ) . Select ( x = > x . Split ( "]: " ) . Last ( ) ) . ToList ( ) ) ;
Interpolate . Cancel ( $"Interpolation failed - {amount} interpolated frames were created.\n\n\nLast 10 log lines:\n{log}\n\nCheck the log '{lastLogName}' for more details." ) ;
return ;
}
2021-12-07 22:22:57 +01:00
try
2021-08-23 16:50:18 +02:00
{
2021-12-07 22:22:57 +01:00
while ( Interpolate . currentlyUsingAutoEnc & & Program . busy )
2021-08-23 16:50:18 +02:00
{
2021-12-07 22:22:57 +01:00
if ( AvProcess . lastAvProcess ! = null & & ! AvProcess . lastAvProcess . HasExited )
{
2024-09-03 22:08:38 +02:00
if ( Logger . LastLogLine . Lower ( ) . Contains ( "frame: " ) )
Logger . Log ( FormatUtils . BeautifyFfmpegStats ( Logger . LastLogLine ) , false , Logger . LastUiLine . Lower ( ) . Contains ( "frame" ) ) ;
2021-12-07 22:22:57 +01:00
}
2021-08-23 16:50:18 +02:00
2021-12-07 22:22:57 +01:00
if ( AvProcess . lastAvProcess . HasExited & & ! AutoEncode . HasWorkToDo ( ) ) // Stop logging if ffmpeg is not running & AE is done
break ;
await Task . Delay ( 500 ) ;
}
}
2022-04-22 09:23:31 +02:00
catch ( Exception e )
2021-12-07 22:22:57 +01:00
{
Logger . Log ( $"AiFinished encoder logging error: {e.Message}\n{e.StackTrace}" , true ) ;
2021-08-23 16:50:18 +02:00
}
}
public static async Task RunRifeCuda ( string framesPath , float interpFactor , string mdl )
{
2022-07-27 14:10:29 +02:00
AI ai = Implementations . rifeCuda ;
2022-04-22 09:23:31 +02:00
if ( Interpolate . currentlyUsingAutoEnc ) // Ensure AutoEnc is not paused
2021-08-23 16:50:18 +02:00
AutoEncode . paused = false ;
try
{
2022-07-27 14:10:29 +02:00
string rifeDir = Path . Combine ( Paths . GetPkgPath ( ) , ai . PkgDir ) ;
2021-08-23 16:50:18 +02:00
string script = "rife.py" ;
if ( ! File . Exists ( Path . Combine ( rifeDir , script ) ) )
{
Interpolate . Cancel ( "RIFE script not found! Make sure you didn't modify any files." ) ;
return ;
}
string archFilesDir = Path . Combine ( rifeDir , "arch" ) ;
string archFilesDirModel = Path . Combine ( rifeDir , mdl , "arch" ) ;
if ( Directory . Exists ( archFilesDirModel ) )
{
Logger . Log ( $"Model {mdl} has architecture python files - copying to arch." , true ) ;
IoUtils . DeleteContentsOfDir ( archFilesDir ) ;
IoUtils . CopyDir ( archFilesDirModel , archFilesDir ) ;
}
await RunRifeCudaProcess ( framesPath , Paths . interpDir , script , interpFactor , mdl ) ;
}
catch ( Exception e )
{
2022-07-27 14:10:29 +02:00
Logger . Log ( $"Error running {ai.FriendlyName}: {e.Message}" ) ;
2022-04-22 09:23:31 +02:00
Logger . Log ( "Stack Trace: " + e . StackTrace , true ) ;
2021-08-23 16:50:18 +02:00
}
2022-07-27 14:10:29 +02:00
await AiFinished ( ai . NameShort ) ;
2021-08-23 16:50:18 +02:00
}
2022-04-22 09:23:31 +02:00
public static async Task RunRifeCudaProcess ( string inPath , string outDir , string script , float interpFactor , string mdl )
2021-08-23 16:50:18 +02:00
{
string outPath = Path . Combine ( inPath . GetParentDir ( ) , outDir ) ;
Directory . CreateDirectory ( outPath ) ;
string uhdStr = await InterpolateUtils . UseUhd ( ) ? "--UHD" : "" ;
string wthreads = $"--wthreads {2 * (int)interpFactor}" ;
string rbuffer = $"--rbuffer {Config.GetInt(Config.Key.rifeCudaBufferSize, 200)}" ;
//string scale = $"--scale {Config.GetFloat("rifeCudaScale", 1.0f).ToStringDot()}";
string prec = Config . GetBool ( Config . Key . rifeCudaFp16 ) ? "--fp16" : "" ;
2021-11-24 13:48:04 +01:00
string args = $" --input {inPath.Wrap()} --output {outDir} --model {mdl} --multi {interpFactor} {uhdStr} {wthreads} {rbuffer} {prec}" ;
2021-08-23 16:50:18 +02:00
Process rifePy = OsUtils . NewProcess ( ! OsUtils . ShowHiddenCmd ( ) ) ;
AiStarted ( rifePy , 3500 ) ;
2022-07-20 18:10:31 +02:00
SetProgressCheck ( Path . Combine ( Interpolate . currentSettings . tempFolder , outDir ) , interpFactor ) ;
2022-05-31 22:17:22 +02:00
rifePy . StartInfo . Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeCuda.PkgDir).Wrap()} & " +
2021-08-23 16:50:18 +02:00
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}" ;
Logger . Log ( $"Running RIFE (CUDA){(await InterpolateUtils.UseUhd() ? " ( UHD Mode ) " : " ")}..." , false ) ;
Logger . Log ( "cmd.exe " + rifePy . StartInfo . Arguments , true ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
2022-07-19 21:48:22 +02:00
rifePy . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( outLine . Data , Implementations . rifeCuda ) ; } ;
rifePy . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , Implementations . rifeCuda , true ) ; } ;
2021-08-23 16:50:18 +02:00
}
rifePy . Start ( ) ;
2022-04-22 09:23:31 +02:00
2021-08-23 16:50:18 +02:00
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
rifePy . BeginOutputReadLine ( ) ;
rifePy . BeginErrorReadLine ( ) ;
}
while ( ! rifePy . HasExited ) await Task . Delay ( 1 ) ;
}
public static async Task RunFlavrCuda ( string framesPath , float interpFactor , string mdl )
{
2022-07-27 14:10:29 +02:00
AI ai = Implementations . flavrCuda ;
2021-08-23 16:50:18 +02:00
if ( Interpolate . currentlyUsingAutoEnc ) // Ensure AutoEnc is not paused
AutoEncode . paused = false ;
try
{
2022-07-27 14:10:29 +02:00
string flavDir = Path . Combine ( Paths . GetPkgPath ( ) , ai . PkgDir ) ;
2021-08-23 16:50:18 +02:00
string script = "flavr.py" ;
if ( ! File . Exists ( Path . Combine ( flavDir , script ) ) )
{
Interpolate . Cancel ( "FLAVR script not found! Make sure you didn't modify any files." ) ;
return ;
}
await RunFlavrCudaProcess ( framesPath , Paths . interpDir , script , interpFactor , mdl ) ;
}
catch ( Exception e )
{
2022-07-27 14:10:29 +02:00
Logger . Log ( $"Error running {ai.FriendlyName}: {e.Message}" ) ;
2022-04-22 09:23:31 +02:00
Logger . Log ( "Stack Trace: " + e . StackTrace , true ) ;
2021-08-23 16:50:18 +02:00
}
2022-07-27 14:10:29 +02:00
await AiFinished ( ai . NameShort ) ;
2021-08-23 16:50:18 +02:00
}
public static async Task RunFlavrCudaProcess ( string inPath , string outDir , string script , float interpFactor , string mdl )
{
string outPath = Path . Combine ( inPath . GetParentDir ( ) , outDir ) ;
Directory . CreateDirectory ( outPath ) ;
string args = $" --input {inPath.Wrap()} --output {outPath.Wrap()} --model {mdl}/{mdl}.pth --factor {interpFactor}" ;
Process flavrPy = OsUtils . NewProcess ( ! OsUtils . ShowHiddenCmd ( ) ) ;
AiStarted ( flavrPy , 4000 ) ;
2022-07-20 18:10:31 +02:00
SetProgressCheck ( Path . Combine ( Interpolate . currentSettings . tempFolder , outDir ) , interpFactor ) ;
2022-05-31 22:17:22 +02:00
flavrPy . StartInfo . Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.flavrCuda.PkgDir).Wrap()} & " +
2021-08-23 16:50:18 +02:00
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}" ;
Logger . Log ( $"Running FLAVR (CUDA)..." , false ) ;
Logger . Log ( "cmd.exe " + flavrPy . StartInfo . Arguments , true ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
2022-07-19 21:48:22 +02:00
flavrPy . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( outLine . Data , Implementations . flavrCuda ) ; } ;
flavrPy . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , Implementations . flavrCuda , true ) ; } ;
2021-08-23 16:50:18 +02:00
}
flavrPy . Start ( ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
flavrPy . BeginOutputReadLine ( ) ;
flavrPy . BeginErrorReadLine ( ) ;
}
while ( ! flavrPy . HasExited ) await Task . Delay ( 1 ) ;
}
2022-04-22 09:23:31 +02:00
public static async Task RunRifeNcnn ( string framesPath , string outPath , float factor , string mdl )
2021-08-23 16:50:18 +02:00
{
2022-07-27 14:10:29 +02:00
AI ai = Implementations . rifeNcnn ;
2021-08-23 16:50:18 +02:00
processTimeMulti . Restart ( ) ;
try
{
Logger . Log ( $"Running RIFE (NCNN){(await InterpolateUtils.UseUhd() ? " ( UHD Mode ) " : " ")}..." , false ) ;
2022-04-05 23:13:48 +02:00
await RunRifeNcnnProcess ( framesPath , factor , outPath , mdl ) ;
2022-07-25 10:37:44 +02:00
await NcnnUtils . DeleteNcnnDupes ( outPath , factor ) ;
2021-08-23 16:50:18 +02:00
}
catch ( Exception e )
{
2022-07-27 14:10:29 +02:00
Logger . Log ( $"Error running {ai.FriendlyName}: {e.Message}" ) ;
2022-04-22 09:23:31 +02:00
Logger . Log ( "Stack Trace: " + e . StackTrace , true ) ;
2021-08-23 16:50:18 +02:00
}
2022-07-27 14:10:29 +02:00
await AiFinished ( ai . NameShort ) ;
2021-08-23 16:50:18 +02:00
}
2022-04-05 23:13:48 +02:00
static async Task RunRifeNcnnProcess ( string inPath , float factor , string outPath , string mdl )
2021-08-23 16:50:18 +02:00
{
Directory . CreateDirectory ( outPath ) ;
2022-05-31 22:17:22 +02:00
string logFileName = "rife-ncnn-log" ;
2021-08-23 16:50:18 +02:00
Process rifeNcnn = OsUtils . NewProcess ( ! OsUtils . ShowHiddenCmd ( ) ) ;
AiStarted ( rifeNcnn , 1500 , inPath ) ;
2022-04-05 23:13:48 +02:00
SetProgressCheck ( outPath , factor ) ;
2022-04-07 14:20:28 +02:00
int targetFrames = ( ( IoUtils . GetAmountOfFiles ( lastInPath , false , "*.*" ) * factor ) . RoundToInt ( ) ) ; // TODO: Maybe won't work with fractional factors ??
2021-08-23 16:50:18 +02:00
2022-04-17 18:39:32 +02:00
string frames = mdl . Contains ( "v4" ) ? $"-n {targetFrames}" : "" ;
2021-08-23 16:50:18 +02:00
string uhdStr = await InterpolateUtils . UseUhd ( ) ? "-u" : "" ;
string ttaStr = Config . GetBool ( Config . Key . rifeNcnnUseTta , false ) ? "-x" : "" ;
2022-05-31 22:17:22 +02:00
rifeNcnn . StartInfo . Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnn.PkgDir).Wrap()} & rife-ncnn-vulkan.exe " +
2024-09-03 22:08:38 +02:00
$" -v -i {inPath.Wrap()} -o {outPath.Wrap()} {frames} -m {mdl.Lower()} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {NcnnUtils.GetNcnnPattern()} -j {NcnnUtils.GetNcnnThreads(Implementations.rifeNcnn)}" ;
2022-04-22 09:23:31 +02:00
2021-08-23 16:50:18 +02:00
Logger . Log ( "cmd.exe " + rifeNcnn . StartInfo . Arguments , true ) ;
2022-04-22 09:23:31 +02:00
2021-08-23 16:50:18 +02:00
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
2022-07-19 21:48:22 +02:00
rifeNcnn . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , Implementations . rifeNcnn ) ; } ;
rifeNcnn . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , Implementations . rifeNcnn , true ) ; } ;
2021-08-23 16:50:18 +02:00
}
rifeNcnn . Start ( ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
rifeNcnn . BeginOutputReadLine ( ) ;
rifeNcnn . BeginErrorReadLine ( ) ;
}
while ( ! rifeNcnn . HasExited ) await Task . Delay ( 1 ) ;
}
2022-06-04 12:43:48 +02:00
public static async Task RunRifeNcnnVs ( string framesPath , string outPath , float factor , string mdl , bool rt = false )
2022-05-31 22:17:22 +02:00
{
2023-01-31 11:41:39 +01:00
if ( Interpolate . canceled ) return ;
2022-08-16 09:18:53 +02:00
2022-07-27 14:10:29 +02:00
AI ai = Implementations . rifeNcnnVs ;
2022-05-31 22:17:22 +02:00
processTimeMulti . Restart ( ) ;
try
{
2022-07-20 18:29:36 +02:00
Size scaledSize = await InterpolateUtils . GetOutputResolution ( Interpolate . currentSettings . inPath , false , false ) ;
2022-07-20 18:10:31 +02:00
Logger . Log ( $"Running RIFE (NCNN-VS){(InterpolateUtils.UseUhd(scaledSize) ? " ( UHD Mode ) " : " ")}..." , false ) ;
2022-05-31 22:17:22 +02:00
2022-07-20 18:10:31 +02:00
await RunRifeNcnnVsProcess ( framesPath , factor , outPath , mdl , scaledSize , rt ) ;
2022-05-31 22:17:22 +02:00
}
catch ( Exception e )
{
2022-07-27 14:10:29 +02:00
Logger . Log ( $"Error running {ai.FriendlyName}: {e.Message}" ) ;
2022-05-31 22:17:22 +02:00
Logger . Log ( "Stack Trace: " + e . StackTrace , true ) ;
}
2022-07-27 14:10:29 +02:00
await AiFinished ( ai . NameShort ) ;
2022-05-31 22:17:22 +02:00
}
2022-07-20 18:10:31 +02:00
static async Task RunRifeNcnnVsProcess ( string inPath , float factor , string outPath , string mdl , Size res , bool rt = false )
2022-05-31 22:17:22 +02:00
{
2022-06-04 12:43:48 +02:00
IoUtils . CreateDir ( outPath ) ;
2022-05-31 22:17:22 +02:00
Process rifeNcnnVs = OsUtils . NewProcess ( ! OsUtils . ShowHiddenCmd ( ) ) ;
2022-06-04 12:43:48 +02:00
string avDir = Path . Combine ( Paths . GetPkgPath ( ) , Paths . audioVideoDir ) ;
2022-08-04 23:02:52 +02:00
string pipedTargetArgs = $"{Path.Combine(avDir, " ffmpeg ").Wrap()} -y {await Export.GetPipedFfmpegCmd(rt)}" ;
2022-06-01 15:46:34 +02:00
string pkgDir = Path . Combine ( Paths . GetPkgPath ( ) , Implementations . rifeNcnnVs . PkgDir ) ;
2022-07-25 10:37:44 +02:00
int gpuId = Config . Get ( Config . Key . ncnnGpus ) . Split ( ',' ) [ 0 ] . GetInt ( ) ;
2022-06-01 15:46:34 +02:00
2022-05-31 23:47:18 +02:00
VapourSynthUtils . VsSettings vsSettings = new VapourSynthUtils . VsSettings ( )
2022-06-06 07:03:27 +02:00
{
2022-07-20 18:10:31 +02:00
InterpSettings = Interpolate . currentSettings ,
2022-06-06 07:03:27 +02:00
ModelDir = mdl ,
Factor = factor ,
2022-07-20 18:29:36 +02:00
Res = res ,
2022-07-20 18:10:31 +02:00
Uhd = InterpolateUtils . UseUhd ( res ) ,
2022-07-25 10:37:44 +02:00
GpuId = gpuId ,
2023-12-21 21:05:23 +01:00
GpuThreads = NcnnUtils . GetRifeNcnnGpuThreads ( res , gpuId , Implementations . rifeNcnnVs ) ,
2022-06-06 07:03:27 +02:00
SceneDetectSensitivity = Config . GetBool ( Config . Key . scnDetect ) ? Config . GetFloat ( Config . Key . scnDetectValue ) * 0.7f : 0f ,
Loop = Config . GetBool ( Config . Key . enableLoop ) ,
MatchDuration = Config . GetBool ( Config . Key . fixOutputDuration ) ,
Dedupe = Config . GetInt ( Config . Key . dedupMode ) ! = 0 ,
2022-08-16 09:18:53 +02:00
Realtime = rt ,
Osd = Config . GetBool ( Config . Key . vsRtShowOsd ) ,
2022-06-06 07:03:27 +02:00
} ;
2022-05-31 23:47:18 +02:00
2022-07-25 10:37:44 +02:00
if ( rt )
{
2023-01-31 11:51:46 +01:00
Logger . Log ( $"Starting. Use Space to pause, Left Arrow and Right Arrow to seek, though seeking can be slow." ) ;
2022-07-25 10:37:44 +02:00
AiStartedRt ( rifeNcnnVs , inPath ) ;
}
else
{
SetProgressCheck ( Interpolate . currentMediaFile . FrameCount , factor , Implementations . rifeNcnnVs . LogFilename ) ;
AiStarted ( rifeNcnnVs , 1000 , inPath ) ;
}
2022-07-22 01:26:47 +02:00
rifeNcnnVs . StartInfo . Arguments = $"{OsUtils.GetCmdArg()} cd /D {pkgDir.Wrap()} & vspipe {VapourSynthUtils.CreateScript(vsSettings).Wrap()} -c y4m - | {pipedTargetArgs}" ;
2022-05-31 22:17:22 +02:00
Logger . Log ( "cmd.exe " + rifeNcnnVs . StartInfo . Arguments , true ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
2022-07-19 21:48:22 +02:00
rifeNcnnVs . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , Implementations . rifeNcnnVs ) ; } ;
rifeNcnnVs . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , Implementations . rifeNcnnVs , true ) ; } ;
2022-05-31 22:17:22 +02:00
}
rifeNcnnVs . Start ( ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
rifeNcnnVs . BeginOutputReadLine ( ) ;
rifeNcnnVs . BeginErrorReadLine ( ) ;
}
while ( ! rifeNcnnVs . HasExited ) await Task . Delay ( 1 ) ;
}
2021-08-23 16:50:18 +02:00
public static async Task RunDainNcnn ( string framesPath , string outPath , float factor , string mdl , int tilesize )
{
2022-07-27 14:10:29 +02:00
AI ai = Implementations . dainNcnn ;
2021-08-23 16:50:18 +02:00
if ( Interpolate . currentlyUsingAutoEnc ) // Ensure AutoEnc is not paused
AutoEncode . paused = false ;
try
{
await RunDainNcnnProcess ( framesPath , outPath , factor , mdl , tilesize ) ;
2022-07-25 10:37:44 +02:00
await NcnnUtils . DeleteNcnnDupes ( outPath , factor ) ;
2021-08-23 16:50:18 +02:00
}
catch ( Exception e )
{
2022-07-27 14:10:29 +02:00
Logger . Log ( $"Error running {ai.FriendlyName}: {e.Message}" ) ;
2022-04-22 09:23:31 +02:00
Logger . Log ( "Stack Trace: " + e . StackTrace , true ) ;
2021-08-23 16:50:18 +02:00
}
2022-07-27 14:10:29 +02:00
await AiFinished ( ai . NameShort ) ;
2021-08-23 16:50:18 +02:00
}
2022-04-22 09:23:31 +02:00
public static async Task RunDainNcnnProcess ( string framesPath , string outPath , float factor , string mdl , int tilesize )
2021-08-23 16:50:18 +02:00
{
2022-05-31 22:17:22 +02:00
string dainDir = Path . Combine ( Paths . GetPkgPath ( ) , Implementations . dainNcnn . PkgDir ) ;
2021-08-23 16:50:18 +02:00
Directory . CreateDirectory ( outPath ) ;
Process dain = OsUtils . NewProcess ( ! OsUtils . ShowHiddenCmd ( ) ) ;
AiStarted ( dain , 1500 ) ;
SetProgressCheck ( outPath , factor ) ;
2022-04-15 13:29:28 +02:00
int targetFrames = ( ( IoUtils . GetAmountOfFiles ( lastInPath , false , "*.*" ) * factor ) . RoundToInt ( ) ) ;
2021-08-23 16:50:18 +02:00
2024-09-03 22:08:38 +02:00
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -m {mdl.Lower()}" +
2022-07-25 10:37:44 +02:00
$" -t {NcnnUtils.GetNcnnTilesize(tilesize)} -g {Config.Get(Config.Key.ncnnGpus)} -f {NcnnUtils.GetNcnnPattern()} -j 2:1:2" ;
2021-08-23 16:50:18 +02:00
dain . StartInfo . Arguments = $"{OsUtils.GetCmdArg()} cd /D {dainDir.Wrap()} & dain-ncnn-vulkan.exe {args}" ;
Logger . Log ( "Running DAIN..." , false ) ;
Logger . Log ( "cmd.exe " + dain . StartInfo . Arguments , true ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
2022-07-19 21:48:22 +02:00
dain . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , Implementations . dainNcnn ) ; } ;
dain . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , Implementations . dainNcnn , true ) ; } ;
2021-08-23 16:50:18 +02:00
}
dain . Start ( ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
dain . BeginOutputReadLine ( ) ;
dain . BeginErrorReadLine ( ) ;
}
while ( ! dain . HasExited )
await Task . Delay ( 100 ) ;
}
public static async Task RunXvfiCuda ( string framesPath , float interpFactor , string mdl )
{
2022-07-27 14:10:29 +02:00
AI ai = Implementations . xvfiCuda ;
2021-08-23 16:50:18 +02:00
if ( Interpolate . currentlyUsingAutoEnc ) // Ensure AutoEnc is not paused
AutoEncode . paused = false ;
try
{
2022-05-31 22:17:22 +02:00
string xvfiDir = Path . Combine ( Paths . GetPkgPath ( ) , Implementations . xvfiCuda . PkgDir ) ;
2021-08-23 16:50:18 +02:00
string script = "main.py" ;
if ( ! File . Exists ( Path . Combine ( xvfiDir , script ) ) )
{
Interpolate . Cancel ( "XVFI script not found! Make sure you didn't modify any files." ) ;
return ;
}
await RunXvfiCudaProcess ( framesPath , Paths . interpDir , script , interpFactor , mdl ) ;
}
catch ( Exception e )
{
2022-07-27 14:10:29 +02:00
Logger . Log ( $"Error running {ai.FriendlyName}: {e.Message}" ) ;
2022-04-22 09:23:31 +02:00
Logger . Log ( "Stack Trace: " + e . StackTrace , true ) ;
2021-08-23 16:50:18 +02:00
}
2022-07-27 14:10:29 +02:00
await AiFinished ( ai . NameShort ) ;
2021-08-23 16:50:18 +02:00
}
public static async Task RunXvfiCudaProcess ( string inPath , string outDir , string script , float interpFactor , string mdlDir )
{
2022-05-31 22:17:22 +02:00
string pkgPath = Path . Combine ( Paths . GetPkgPath ( ) , Implementations . xvfiCuda . PkgDir ) ;
2021-08-23 16:50:18 +02:00
string basePath = inPath . GetParentDir ( ) ;
string outPath = Path . Combine ( basePath , outDir ) ;
Directory . CreateDirectory ( outPath ) ;
string mdlArgs = File . ReadAllText ( Path . Combine ( pkgPath , mdlDir , "args.ini" ) ) ;
string args = $" --custom_path {basePath.Wrap()} --input {inPath.Wrap()} --output {outPath.Wrap()} --mdl_dir {mdlDir}" +
$" --multiple {interpFactor} --gpu 0 {mdlArgs}" ;
Process xvfiPy = OsUtils . NewProcess ( ! OsUtils . ShowHiddenCmd ( ) ) ;
AiStarted ( xvfiPy , 3500 ) ;
2022-07-20 18:10:31 +02:00
SetProgressCheck ( Path . Combine ( Interpolate . currentSettings . tempFolder , outDir ) , interpFactor ) ;
2021-08-23 16:50:18 +02:00
xvfiPy . StartInfo . Arguments = $"{OsUtils.GetCmdArg()} cd /D {pkgPath.Wrap()} & " +
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}" ;
Logger . Log ( $"Running XVFI (CUDA)..." , false ) ;
Logger . Log ( "cmd.exe " + xvfiPy . StartInfo . Arguments , true ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
2022-07-19 21:48:22 +02:00
xvfiPy . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( outLine . Data , Implementations . xvfiCuda ) ; } ;
xvfiPy . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , Implementations . xvfiCuda , true ) ; } ;
2021-08-23 16:50:18 +02:00
}
xvfiPy . Start ( ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
xvfiPy . BeginOutputReadLine ( ) ;
xvfiPy . BeginErrorReadLine ( ) ;
}
while ( ! xvfiPy . HasExited ) await Task . Delay ( 1 ) ;
}
2022-07-21 09:30:59 +02:00
public static async Task RunIfrnetNcnn ( string framesPath , string outPath , float factor , string mdl )
{
2022-07-27 14:10:29 +02:00
AI ai = Implementations . ifrnetNcnn ;
2022-07-21 09:30:59 +02:00
processTimeMulti . Restart ( ) ;
try
{
Logger . Log ( $"Running IFRNet (NCNN){(await InterpolateUtils.UseUhd() ? " ( UHD Mode ) " : " ")}..." , false ) ;
await RunIfrnetNcnnProcess ( framesPath , factor , outPath , mdl ) ;
2022-07-25 10:37:44 +02:00
await NcnnUtils . DeleteNcnnDupes ( outPath , factor ) ;
2022-07-21 09:30:59 +02:00
}
catch ( Exception e )
{
2022-07-27 14:10:29 +02:00
Logger . Log ( $"Error running {ai.FriendlyName}: {e.Message}" ) ;
2022-07-21 09:30:59 +02:00
Logger . Log ( "Stack Trace: " + e . StackTrace , true ) ;
}
2022-07-27 14:10:29 +02:00
await AiFinished ( ai . NameShort ) ;
2022-07-21 09:30:59 +02:00
}
static async Task RunIfrnetNcnnProcess ( string inPath , float factor , string outPath , string mdl )
{
Directory . CreateDirectory ( outPath ) ;
Process ifrnetNcnn = OsUtils . NewProcess ( ! OsUtils . ShowHiddenCmd ( ) ) ;
AiStarted ( ifrnetNcnn , 1500 , inPath ) ;
SetProgressCheck ( outPath , factor ) ;
//int targetFrames = ((IoUtils.GetAmountOfFiles(lastInPath, false, "*.*") * factor).RoundToInt()); // TODO: Maybe won't work with fractional factors ??
//string frames = mdl.Contains("v4") ? $"-n {targetFrames}" : "";
string uhdStr = "" ; // await InterpolateUtils.UseUhd() ? "-u" : "";
string ttaStr = "" ; // Config.GetBool(Config.Key.rifeNcnnUseTta, false) ? "-x" : "";
ifrnetNcnn . StartInfo . Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.ifrnetNcnn.PkgDir).Wrap()} & ifrnet-ncnn-vulkan.exe " +
2023-12-21 21:05:23 +01:00
$" -v -i {inPath.Wrap()} -o {outPath.Wrap()} -m {mdl} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {NcnnUtils.GetNcnnPattern()} -j {NcnnUtils.GetNcnnThreads(Implementations.ifrnetNcnn)}" ;
2022-07-21 09:30:59 +02:00
Logger . Log ( "cmd.exe " + ifrnetNcnn . StartInfo . Arguments , true ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
ifrnetNcnn . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , Implementations . ifrnetNcnn ) ; } ;
ifrnetNcnn . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , Implementations . ifrnetNcnn , true ) ; } ;
}
ifrnetNcnn . Start ( ) ;
if ( ! OsUtils . ShowHiddenCmd ( ) )
{
ifrnetNcnn . BeginOutputReadLine ( ) ;
ifrnetNcnn . BeginErrorReadLine ( ) ;
}
while ( ! ifrnetNcnn . HasExited ) await Task . Delay ( 1 ) ;
}
2022-07-19 21:48:22 +02:00
static void LogOutput ( string line , AI ai , bool err = false )
2021-08-23 16:50:18 +02:00
{
if ( string . IsNullOrWhiteSpace ( line ) | | line . Length < 6 )
return ;
Stopwatch sw = new Stopwatch ( ) ;
sw . Restart ( ) ;
2022-07-20 18:10:31 +02:00
lastLogName = ai . LogFilename ;
Logger . Log ( line , true , false , ai . LogFilename ) ;
2021-08-23 16:50:18 +02:00
2022-07-19 21:48:22 +02:00
string lastLogLines = string . Join ( "\n" , Logger . GetSessionLogLastLines ( lastLogName , 6 ) . Select ( x = > $"[{x.Split(" ] : [ ").Skip(1).FirstOrDefault()}" ) ) ;
2021-08-23 16:50:18 +02:00
2022-07-19 21:48:22 +02:00
if ( ai . Backend = = AI . AiBackend . Pytorch ) // Pytorch specific
2022-06-04 12:43:48 +02:00
{
2022-07-19 21:48:22 +02:00
if ( line . Contains ( "ff:nocuda-cpu" ) )
Logger . Log ( "WARNING: CUDA-capable GPU device is not available, running on CPU instead!" ) ;
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & err & & line . Lower ( ) . Contains ( "modulenotfounderror" ) )
2022-06-04 12:43:48 +02:00
{
hasShownError = true ;
2022-07-20 18:10:31 +02:00
UiUtils . ShowMessageBox ( $"A python module is missing.\nCheck {ai.LogFilename} for details.\n\n{line}" , UiUtils . MessageType . Error ) ;
2022-06-04 12:43:48 +02:00
}
2022-06-06 20:54:16 +02:00
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & line . Lower ( ) . Contains ( "no longer supports this gpu" ) )
2022-06-06 20:54:16 +02:00
{
hasShownError = true ;
2022-07-19 21:48:22 +02:00
UiUtils . ShowMessageBox ( $"Your GPU seems to be outdated and is not supported!\n\n{line}" , UiUtils . MessageType . Error ) ;
2022-06-06 20:54:16 +02:00
}
2022-06-04 12:43:48 +02:00
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & line . Lower ( ) . Contains ( "error(s) in loading state_dict" ) )
2022-07-19 21:48:22 +02:00
{
hasShownError = true ;
2022-07-21 10:08:53 +02:00
string msg = ( Interpolate . currentSettings . ai . NameInternal = = Implementations . flavrCuda . NameInternal ) ? "\n\nFor FLAVR, you need to select the correct model for each scale!" : "" ;
2022-07-19 21:48:22 +02:00
UiUtils . ShowMessageBox ( $"Error loading the AI model!\n\n{line}{msg}" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & line . Lower ( ) . Contains ( "unicodeencodeerror" ) )
2022-07-19 21:48:22 +02:00
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"It looks like your path contains invalid characters - remove them and try again!\n\n{line}" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
2022-07-19 21:48:22 +02:00
if ( ! hasShownError & & err & & ( line . Contains ( "RuntimeError" ) | | line . Contains ( "ImportError" ) | | line . Contains ( "OSError" ) ) )
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"A python error occured during interpolation!\nCheck the log for details:\n\n{lastLogLines}" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
}
2022-07-19 21:48:22 +02:00
if ( ai . Backend = = AI . AiBackend . Ncnn ) // NCNN specific
2021-08-23 16:50:18 +02:00
{
2022-07-19 21:48:22 +02:00
if ( ! hasShownError & & err & & line . MatchesWildcard ( "vk*Instance* failed" ) )
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"Vulkan failed to start up!\n\n{line}\n\nThis most likely means your GPU is not compatible." , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
2022-07-19 21:48:22 +02:00
if ( ! hasShownError & & err & & line . Contains ( "vkAllocateMemory failed" ) )
{
hasShownError = true ;
2022-07-21 10:08:53 +02:00
bool usingDain = ( Interpolate . currentSettings . ai . NameInternal = = Implementations . dainNcnn . NameInternal ) ;
2022-07-19 21:48:22 +02:00
string msg = usingDain ? "\n\nTry reducing the tile size in the AI settings." : "\n\nTry a lower resolution (Settings -> Max Video Size)." ;
UiUtils . ShowMessageBox ( $"Vulkan ran out of memory!\n\n{line}{msg}" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
2022-07-19 21:48:22 +02:00
if ( ! hasShownError & & err & & line . Contains ( "invalid gpu device" ) )
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"A Vulkan error occured during interpolation!\n\n{line}\n\nAre your GPU IDs set correctly?" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
2022-07-19 21:48:22 +02:00
if ( ! hasShownError & & err & & line . MatchesWildcard ( "vk* failed" ) )
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"A Vulkan error occured during interpolation!\n\n{lastLogLines}" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
}
2022-07-19 21:48:22 +02:00
if ( ai . Piped ) // VS specific
2021-08-23 16:50:18 +02:00
{
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & Interpolate . currentSettings . outSettings . Format ! = Enums . Output . Format . Realtime & & line . Lower ( ) . Contains ( "fwrite() call failed" ) )
2022-07-19 21:48:22 +02:00
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"VapourSynth interpolation failed with an unknown error. Check the log for details:\n\n{lastLogLines}" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & line . Lower ( ) . Contains ( "allocate memory failed" ) )
2022-07-19 21:48:22 +02:00
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"Out of memory!\nTry reducing your RAM usage by closing some programs.\n\n{line}" , UiUtils . MessageType . Error ) ;
}
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & line . Lower ( ) . Contains ( "vapoursynth.error:" ) )
2022-07-19 21:48:22 +02:00
{
hasShownError = true ;
UiUtils . ShowMessageBox ( $"VapourSynth Error:\n\n{line}" , UiUtils . MessageType . Error ) ;
}
2021-08-23 16:50:18 +02:00
}
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & err & & line . Lower ( ) . Contains ( "out of memory" ) )
2021-08-23 16:50:18 +02:00
{
hasShownError = true ;
2022-07-19 21:48:22 +02:00
UiUtils . ShowMessageBox ( $"Your GPU ran out of VRAM! Please try a video with a lower resolution or use the Max Video Size option in the settings.\n\n{line}" , UiUtils . MessageType . Error ) ;
2021-08-23 16:50:18 +02:00
}
2024-09-03 22:08:38 +02:00
if ( ! hasShownError & & line . Lower ( ) . Contains ( "illegal memory access" ) )
2021-08-23 16:50:18 +02:00
{
hasShownError = true ;
2022-07-19 21:48:22 +02:00
UiUtils . ShowMessageBox ( $"Your GPU appears to be unstable! If you have an overclock enabled, please disable it!\n\n{line}" , UiUtils . MessageType . Error ) ;
2021-08-23 16:50:18 +02:00
}
if ( hasShownError )
Interpolate . Cancel ( ) ;
InterpolationProgress . UpdateLastFrameFromInterpOutput ( line ) ;
}
2023-01-31 11:41:39 +01:00
2021-08-23 16:50:18 +02:00
}
}