2020-11-23 16:51:05 +01:00
using Flowframes.IO ;
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
using System.Runtime.InteropServices ;
using System.Text ;
using System.Threading.Tasks ;
using Flowframes.OS ;
using Flowframes.UI ;
using Flowframes.Main ;
namespace Flowframes
{
class AiProcess
{
2020-11-24 12:28:47 +01:00
public static bool hasShownError ;
2020-11-23 16:51:05 +01:00
public static Process currentAiProcess ;
public static Stopwatch processTime = new Stopwatch ( ) ;
2020-11-26 00:07:45 +01:00
public static Stopwatch processTimeMulti = new Stopwatch ( ) ;
2020-11-23 16:51:05 +01:00
2020-11-25 14:04:31 +01:00
public static int lastStartupTimeMs = 1000 ;
2020-12-02 00:44:43 +01:00
public static Dictionary < string , string > filenameMap = new Dictionary < string , string > ( ) ; // TODO: Store on disk instead for crashes?
2020-11-30 20:32:33 +01:00
static void AiStarted ( Process proc , int startupTimeMs , string defaultExt = "png" )
2020-11-23 16:51:05 +01:00
{
2020-11-25 14:04:31 +01:00
lastStartupTimeMs = startupTimeMs ;
2020-11-25 12:40:17 +01:00
InterpolateUtils . lastExt = defaultExt ;
2020-11-23 16:51:05 +01:00
if ( Config . GetBool ( "jpegInterps" ) ) InterpolateUtils . lastExt = "jpg" ;
2020-11-24 12:28:47 +01:00
processTime . Restart ( ) ;
currentAiProcess = proc ;
hasShownError = false ;
}
2020-11-23 16:51:05 +01:00
2020-11-30 20:32:33 +01:00
static void AiFinished ( string aiName )
{
Program . mainForm . SetProgress ( 100 ) ;
string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}" ;
2020-12-01 16:54:12 +01:00
if ( Interpolate . currentlyUsingAutoEnc & & AutoEncode . HasWorkToDo ( ) )
2020-11-30 20:32:33 +01:00
logStr + = " - Waiting for encoding to finish..." ;
Logger . Log ( logStr ) ;
processTime . Stop ( ) ;
}
2020-11-24 12:28:47 +01:00
public static async Task RunDainNcnn ( string framesPath , string outPath , int targetFrames , int tilesize )
{
2020-11-23 16:51:05 +01:00
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -t {tilesize} -g {Config.Get(" ncnnGpus ")}" ;
string dainDir = Path . Combine ( Paths . GetPkgPath ( ) , Path . GetFileNameWithoutExtension ( Packages . dainNcnn . fileName ) ) ;
Process dain = OSUtils . NewProcess ( ! OSUtils . ShowHiddenCmd ( ) ) ;
2020-11-30 20:32:33 +01:00
AiStarted ( dain , 1500 ) ;
2020-11-26 20:52:11 +01:00
dain . StartInfo . Arguments = $"{OSUtils.GetCmdArg()} cd /D {dainDir.Wrap()} & dain-ncnn-vulkan.exe {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get(" ncnnThreads ")}:4" ;
2020-11-23 16:51:05 +01:00
Logger . Log ( "Running DAIN..." , false ) ;
Logger . Log ( "cmd.exe " + dain . StartInfo . Arguments , true ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
2020-11-25 17:27:15 +01:00
dain . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , "dain-ncnn-log.txt" ) ; } ;
2020-11-23 16:51:05 +01:00
dain . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , "dain-ncnn-log.txt" ) ; } ;
}
dain . Start ( ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
dain . BeginOutputReadLine ( ) ;
dain . BeginErrorReadLine ( ) ;
}
while ( ! dain . HasExited )
await Task . Delay ( 1 ) ;
2020-11-25 17:27:15 +01:00
if ( Interpolate . canceled ) return ;
Magick . MagickDedupe . ZeroPadDir ( outPath , InterpolateUtils . lastExt , 8 ) ;
2020-11-30 20:32:33 +01:00
AiFinished ( "DAIN" ) ;
2020-11-23 16:51:05 +01:00
}
public static async Task RunCainNcnnMulti ( string framesPath , string outPath , int tilesize , int times )
{
2020-11-26 00:07:45 +01:00
processTimeMulti . Restart ( ) ;
2020-11-23 16:51:05 +01:00
Logger . Log ( "Running CAIN..." , false ) ;
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get(" ncnnGpus ")}" ;
await RunCainPartial ( args ) ;
if ( times = = 4 | | times = = 8 ) // #2
{
2020-11-25 17:27:15 +01:00
if ( Interpolate . canceled ) return ;
2020-11-23 16:51:05 +01:00
Logger . Log ( "Re-Running CAIN for 4x interpolation..." , false ) ;
string run1ResultsPath = outPath + "-run1" ;
IOUtils . TryDeleteIfExists ( run1ResultsPath ) ;
Directory . Move ( outPath , run1ResultsPath ) ;
Directory . CreateDirectory ( outPath ) ;
args = $" -v -i {run1ResultsPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get(" ncnnGpus ")}" ;
await RunCainPartial ( args ) ;
2020-11-26 20:52:11 +01:00
IOUtils . TryDeleteIfExists ( run1ResultsPath ) ;
2020-11-23 16:51:05 +01:00
}
if ( times = = 8 ) // #3
{
2020-11-25 17:27:15 +01:00
if ( Interpolate . canceled ) return ;
2020-11-23 16:51:05 +01:00
Logger . Log ( "Re-Running CAIN for 8x interpolation..." , false ) ;
string run2ResultsPath = outPath + "-run2" ;
IOUtils . TryDeleteIfExists ( run2ResultsPath ) ;
Directory . Move ( outPath , run2ResultsPath ) ;
Directory . CreateDirectory ( outPath ) ;
args = $" -v -i {run2ResultsPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get(" ncnnGpus ")}" ;
await RunCainPartial ( args ) ;
2020-11-26 20:52:11 +01:00
IOUtils . TryDeleteIfExists ( run2ResultsPath ) ;
2020-11-23 16:51:05 +01:00
}
2020-11-25 17:27:15 +01:00
if ( Interpolate . canceled ) return ;
Magick . MagickDedupe . ZeroPadDir ( outPath , InterpolateUtils . lastExt , 8 ) ;
2020-11-30 20:32:33 +01:00
AiFinished ( "CAIN" ) ;
2020-11-23 16:51:05 +01:00
}
static async Task RunCainPartial ( string args )
{
string cainDir = Path . Combine ( Paths . GetPkgPath ( ) , Path . GetFileNameWithoutExtension ( Packages . cainNcnn . fileName ) ) ;
string cainExe = "cain-ncnn-vulkan.exe" ;
Process cain = OSUtils . NewProcess ( ! OSUtils . ShowHiddenCmd ( ) ) ;
2020-11-30 20:32:33 +01:00
AiStarted ( cain , 1500 ) ;
2020-11-26 20:52:11 +01:00
cain . StartInfo . Arguments = $"{OSUtils.GetCmdArg()} cd /D {cainDir.Wrap()} & {cainExe} {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get(" ncnnThreads ")}:4" ;
2020-11-23 16:51:05 +01:00
Logger . Log ( "cmd.exe " + cain . StartInfo . Arguments , true ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
2020-11-25 17:27:15 +01:00
cain . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , "cain-ncnn-log.txt" ) ; } ;
2020-11-23 16:51:05 +01:00
cain . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , "cain-ncnn-log.txt" ) ; } ;
}
cain . Start ( ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
cain . BeginOutputReadLine ( ) ;
cain . BeginErrorReadLine ( ) ;
}
while ( ! cain . HasExited ) await Task . Delay ( 1 ) ;
}
public static async Task RunRifeCuda ( string framesPath , int interpFactor )
{
string script = "interp-parallel.py" ;
2020-12-03 14:53:18 +01:00
//if(Config.GetInt("rifeMode") == 0 || IOUtils.GetAmountOfFiles(framesPath, false) < 6)
// script = "interp-basic.py";
2020-11-23 16:51:05 +01:00
string rifeDir = Path . Combine ( Paths . GetPkgPath ( ) , Path . GetFileNameWithoutExtension ( Packages . rifeCuda . fileName ) ) ;
2020-12-03 14:53:18 +01:00
string args = $" --input {framesPath.Wrap()} --times {(int)Math.Log(interpFactor, 2)}" ;
if ( File . Exists ( Path . Combine ( rifeDir , "inference_video.py" ) ) ) // Use updated script
{
script = "inference_video.py" ;
args = $" --img {framesPath.Wrap()} --exp {(int)Math.Log(interpFactor, 2)}" ;
}
2020-11-23 16:51:05 +01:00
Process rifePy = OSUtils . NewProcess ( ! OSUtils . ShowHiddenCmd ( ) ) ;
2020-11-30 20:32:33 +01:00
AiStarted ( rifePy , 3000 , "png" ) ;
2020-11-26 00:07:45 +01:00
rifePy . StartInfo . Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeCuda).Wrap()} & " +
2020-11-30 20:32:33 +01:00
$"set CUDA_VISIBLE_DEVICES={Config.Get(" torchGpus ")} & {Pytorch.GetPyCmd()} {script} {args} --imgformat {InterpolateUtils.lastExt} --output {Paths.interpDir}" ;
2020-11-23 16:51:05 +01:00
Logger . Log ( $"Running RIFE ({script})..." , false ) ;
Logger . Log ( "cmd.exe " + rifePy . StartInfo . Arguments , true ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
2020-11-25 17:27:15 +01:00
rifePy . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , "rife-cuda-log.txt" ) ; } ;
2020-11-23 16:51:05 +01:00
rifePy . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , "rife-cuda-log.txt" ) ; } ;
}
rifePy . Start ( ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
rifePy . BeginOutputReadLine ( ) ;
rifePy . BeginErrorReadLine ( ) ;
}
2020-11-26 00:07:45 +01:00
while ( ! rifePy . HasExited ) await Task . Delay ( 1 ) ;
2020-11-30 20:32:33 +01:00
AiFinished ( "RIFE" ) ;
2020-11-25 14:04:31 +01:00
}
2020-11-26 00:07:45 +01:00
public static async Task RunRifeNcnnMulti ( string framesPath , string outPath , int tilesize , int times )
{
processTimeMulti . Restart ( ) ;
Logger . Log ( "Running RIFE..." , false ) ;
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get(" ncnnGpus ")} -f {InterpolateUtils.lastExt} -j 4:{Config.Get(" ncnnThreads ")}:4" ;
await RunRifePartial ( args ) ;
if ( times = = 4 | | times = = 8 ) // #2
{
if ( Interpolate . canceled ) return ;
Logger . Log ( "Re-Running RIFE for 4x interpolation..." , false ) ;
string run1ResultsPath = outPath + "-run1" ;
IOUtils . TryDeleteIfExists ( run1ResultsPath ) ;
Directory . Move ( outPath , run1ResultsPath ) ;
Directory . CreateDirectory ( outPath ) ;
args = $" -v -i {run1ResultsPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get(" ncnnGpus ")} -f {InterpolateUtils.lastExt} -j 4:{Config.Get(" ncnnThreads ")}:4" ;
await RunRifePartial ( args ) ;
2020-11-26 20:52:11 +01:00
IOUtils . TryDeleteIfExists ( run1ResultsPath ) ;
2020-11-26 00:07:45 +01:00
}
if ( times = = 8 ) // #3
{
if ( Interpolate . canceled ) return ;
Logger . Log ( "Re-Running RIFE for 8x interpolation..." , false ) ;
string run2ResultsPath = outPath + "-run2" ;
IOUtils . TryDeleteIfExists ( run2ResultsPath ) ;
Directory . Move ( outPath , run2ResultsPath ) ;
Directory . CreateDirectory ( outPath ) ;
args = $" -v -i {run2ResultsPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get(" ncnnGpus ")} -f {InterpolateUtils.lastExt} -j 4:{Config.Get(" ncnnThreads ")}:4" ;
await RunRifePartial ( args ) ;
2020-11-26 20:52:11 +01:00
IOUtils . TryDeleteIfExists ( run2ResultsPath ) ;
2020-11-26 00:07:45 +01:00
}
if ( Interpolate . canceled ) return ;
Magick . MagickDedupe . ZeroPadDir ( outPath , InterpolateUtils . lastExt , 8 ) ;
2020-11-30 20:32:33 +01:00
AiFinished ( "RIFE" ) ;
2020-11-26 00:07:45 +01:00
}
static async Task RunRifePartial ( string args )
{
Process rifeNcnn = OSUtils . NewProcess ( ! OSUtils . ShowHiddenCmd ( ) ) ;
2020-11-30 20:32:33 +01:00
AiStarted ( rifeNcnn , 1500 ) ;
2020-11-26 00:07:45 +01:00
rifeNcnn . StartInfo . Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeNcnn).Wrap()} & rife-ncnn-vulkan.exe {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get(" ncnnThreads ")}:4" ;
Logger . Log ( "cmd.exe " + rifeNcnn . StartInfo . Arguments , true ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
rifeNcnn . OutputDataReceived + = ( sender , outLine ) = > { LogOutput ( "[O] " + outLine . Data , "rife-ncnn-log.txt" ) ; } ;
rifeNcnn . ErrorDataReceived + = ( sender , outLine ) = > { LogOutput ( "[E] " + outLine . Data , "rife-ncnn-log.txt" ) ; } ;
}
rifeNcnn . Start ( ) ;
if ( ! OSUtils . ShowHiddenCmd ( ) )
{
rifeNcnn . BeginOutputReadLine ( ) ;
rifeNcnn . BeginErrorReadLine ( ) ;
}
while ( ! rifeNcnn . HasExited ) await Task . Delay ( 1 ) ;
}
2020-11-23 16:51:05 +01:00
static void LogOutput ( string line , string logFilename )
{
2020-11-25 17:27:15 +01:00
if ( string . IsNullOrWhiteSpace ( line ) )
2020-11-23 16:51:05 +01:00
return ;
Logger . LogToFile ( line , false , logFilename ) ;
2020-11-25 17:27:15 +01:00
if ( line . Contains ( "ff:nocuda-cpu" ) )
Logger . Log ( "WARNING: CUDA-capable GPU device is not available, running on CPU instead!" ) ;
2020-11-24 12:28:47 +01:00
if ( ! hasShownError & & line . ToLower ( ) . Contains ( "out of memory" ) )
{
hasShownError = true ;
InterpolateUtils . ShowMessage ( $"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}" , "Error" ) ;
}
if ( ! hasShownError & & line . ToLower ( ) . Contains ( "modulenotfounderror" ) )
{
hasShownError = true ;
2020-11-26 23:47:09 +01:00
InterpolateUtils . ShowMessage ( $"A python module is missing. Check {logFilename} for details.\n\n{line}\n\nIf you don't want to install it yourself, use the Python package from the Package Installer." , "Error" ) ;
2020-11-24 12:28:47 +01:00
}
2020-11-23 16:51:05 +01:00
2020-11-24 12:28:47 +01:00
if ( ! hasShownError & & line . ToLower ( ) . Contains ( "no longer supports this gpu" ) )
{
hasShownError = true ;
2020-11-26 20:17:18 +01:00
InterpolateUtils . ShowMessage ( $"Your GPU seems to be outdated and is not supported!\n\n{line}" , "Error" ) ;
2020-11-24 12:28:47 +01:00
}
if ( ! hasShownError & & line . Contains ( "RuntimeError" ) )
{
hasShownError = true ;
InterpolateUtils . ShowMessage ( $"An error occured during interpolation!\n\n{line}" , "Error" ) ;
}
2020-11-26 20:17:18 +01:00
if ( ! hasShownError & & line . Contains ( "vkQueueSubmit failed" ) )
{
hasShownError = true ;
InterpolateUtils . ShowMessage ( $"A Vulkan error occured during interpolation!\n\n{line}" , "Error" ) ;
}
if ( hasShownError )
Interpolate . Cancel ( ) ;
2020-11-23 16:51:05 +01:00
}
}
}