2021-02-02 12:56:48 +01:00
using Flowframes.Media ;
2021-02-01 16:23:35 +01:00
using Flowframes.Data ;
2020-11-23 16:51:05 +01:00
using Flowframes.Forms ;
using Flowframes.IO ;
2020-12-27 22:52:14 +01:00
using Flowframes.MiscUtils ;
2020-11-23 16:51:05 +01:00
using Flowframes.OS ;
using Flowframes.UI ;
using System ;
using System.Collections.Generic ;
2020-12-23 00:07:06 +01:00
using System.Diagnostics ;
2020-11-23 16:51:05 +01:00
using System.Drawing ;
using System.IO ;
using System.Linq ;
using System.Text.RegularExpressions ;
2020-12-20 21:25:34 +01:00
using System.Threading.Tasks ;
2020-11-23 16:51:05 +01:00
using System.Windows.Forms ;
2021-02-12 00:44:37 +01:00
using I = Flowframes . Interpolate ;
2021-01-15 22:43:13 +01:00
using Padding = Flowframes . Data . Padding ;
2020-11-23 16:51:05 +01:00
namespace Flowframes.Main
{
class InterpolateUtils
{
2021-02-14 22:23:16 +01:00
public static async Task CopyLastFrame ( int lastFrameNum )
2021-01-15 22:43:13 +01:00
{
2021-03-01 22:38:38 +01:00
if ( I . canceled ) return ;
2021-01-15 22:43:13 +01:00
try
{
lastFrameNum - - ; // We have to do this as extracted frames start at 0, not 1
2021-02-12 00:44:37 +01:00
bool frameFolderInput = IOUtils . IsPathDirectory ( I . current . inPath ) ;
2021-04-22 16:15:17 +02:00
string targetPath = Path . Combine ( I . current . framesFolder , lastFrameNum . ToString ( ) . PadLeft ( Padding . inputFrames , '0' ) + I . current . framesExt ) ;
2021-01-15 22:43:13 +01:00
if ( File . Exists ( targetPath ) ) return ;
2021-02-12 00:44:37 +01:00
Size res = IOUtils . GetImage ( IOUtils . GetFilesSorted ( I . current . framesFolder , false ) . First ( ) ) . Size ;
2021-01-15 22:43:13 +01:00
if ( frameFolderInput )
{
2021-02-12 00:44:37 +01:00
string lastFramePath = IOUtils . GetFilesSorted ( I . current . inPath , false ) . Last ( ) ;
2021-02-01 16:23:35 +01:00
await FfmpegExtract . ExtractLastFrame ( lastFramePath , targetPath , res ) ;
2021-01-15 22:43:13 +01:00
}
else
{
2021-02-12 00:44:37 +01:00
await FfmpegExtract . ExtractLastFrame ( I . current . inPath , targetPath , res ) ;
2021-01-15 22:43:13 +01:00
}
}
catch ( Exception e )
{
Logger . Log ( "CopyLastFrame Error: " + e . Message ) ;
}
}
2020-11-23 16:51:05 +01:00
public static int GetProgressWaitTime ( int numFrames )
{
2021-01-07 11:02:43 +01:00
float hddMultiplier = ! Program . lastInputPathIsSsd ? 2f : 1f ;
2020-11-23 16:51:05 +01:00
int waitMs = 200 ;
if ( numFrames > 100 )
waitMs = 500 ;
if ( numFrames > 1000 )
waitMs = 1000 ;
if ( numFrames > 2500 )
waitMs = 1500 ;
if ( numFrames > 5000 )
waitMs = 2500 ;
return ( waitMs * hddMultiplier ) . RoundToInt ( ) ;
}
2021-02-14 22:23:16 +01:00
public static string GetTempFolderLoc ( string inPath , string outPath )
2020-11-23 16:51:05 +01:00
{
string basePath = inPath . GetParentDir ( ) ;
2021-01-07 11:02:43 +01:00
2021-02-14 22:23:16 +01:00
if ( Config . GetInt ( "tempFolderLoc" ) = = 1 )
2020-11-23 16:51:05 +01:00
basePath = outPath . GetParentDir ( ) ;
2021-01-07 11:02:43 +01:00
2020-11-23 16:51:05 +01:00
if ( Config . GetInt ( "tempFolderLoc" ) = = 2 )
basePath = outPath ;
2021-01-07 11:02:43 +01:00
2020-11-23 16:51:05 +01:00
if ( Config . GetInt ( "tempFolderLoc" ) = = 3 )
2021-02-18 14:30:56 +01:00
basePath = Paths . GetExeDir ( ) ;
2021-01-07 11:02:43 +01:00
2020-11-23 16:51:05 +01:00
if ( Config . GetInt ( "tempFolderLoc" ) = = 4 )
{
string custPath = Config . Get ( "tempDirCustom" ) ;
2021-02-14 22:23:16 +01:00
if ( IOUtils . IsDirValid ( custPath ) )
2020-11-23 16:51:05 +01:00
basePath = custPath ;
}
2020-12-04 16:53:39 +01:00
return Path . Combine ( basePath , Path . GetFileNameWithoutExtension ( inPath ) . StripBadChars ( ) . Remove ( " " ) . Trunc ( 30 , false ) + "-temp" ) ;
2020-11-23 16:51:05 +01:00
}
2021-04-05 12:04:23 +02:00
public static bool InputIsValid ( string inDir , string outDir , Fraction fpsOut , float factor , I . OutMode outMode )
2020-11-23 16:51:05 +01:00
{
2020-12-04 16:53:39 +01:00
bool passes = true ;
2020-11-23 16:51:05 +01:00
bool isFile = ! IOUtils . IsPathDirectory ( inDir ) ;
2020-12-06 18:49:53 +01:00
if ( ( passes & & isFile & & ! IOUtils . IsFileValid ( inDir ) ) | | ( ! isFile & & ! IOUtils . IsDirValid ( inDir ) ) )
2020-11-23 16:51:05 +01:00
{
ShowMessage ( "Input path is not valid!" ) ;
passes = false ;
}
2021-04-09 19:47:06 +02:00
2020-12-06 18:49:53 +01:00
if ( passes & & ! IOUtils . IsDirValid ( outDir ) )
2020-11-23 16:51:05 +01:00
{
ShowMessage ( "Output path is not valid!" ) ;
passes = false ;
}
2021-04-09 19:47:06 +02:00
2021-04-02 14:36:08 +02:00
if ( passes & & fpsOut . GetFloat ( ) < 1f | | fpsOut . GetFloat ( ) > 1000f )
2020-11-23 16:51:05 +01:00
{
2021-04-05 11:58:07 +02:00
ShowMessage ( $"Invalid output frame rate ({fpsOut.GetFloat()}).\nMust be 1-1000." ) ;
2020-11-23 16:51:05 +01:00
passes = false ;
}
2021-04-09 19:47:06 +02:00
if ( outMode = = I . OutMode . VidGif & & fpsOut . GetFloat ( ) > 50 & & ! ( Config . GetFloat ( "maxFps" ) ! = 0 & & Config . GetFloat ( "maxFps" ) < = 50 ) )
Logger . Log ( $"Warning: GIF will be encoded at 50 FPS instead of {fpsOut.GetFloat()} as the format doesn't support frame rates that high." ) ;
2020-11-23 16:51:05 +01:00
if ( ! passes )
2021-02-12 00:44:37 +01:00
I . Cancel ( "Invalid settings detected." , true ) ;
2021-04-09 19:47:06 +02:00
2020-11-23 16:51:05 +01:00
return passes ;
}
2021-02-14 22:23:16 +01:00
public static bool CheckAiAvailable ( AI ai )
2020-11-23 16:51:05 +01:00
{
2021-03-11 12:58:18 +01:00
if ( IOUtils . GetAmountOfFiles ( Path . Combine ( Paths . GetPkgPath ( ) , ai . pkgDir ) , true ) < 1 )
2020-11-23 16:51:05 +01:00
{
2021-02-18 14:30:56 +01:00
ShowMessage ( "The selected AI is not installed!" , "Error" ) ;
2021-02-12 00:44:37 +01:00
I . Cancel ( "Selected AI not available." , true ) ;
2020-11-23 16:51:05 +01:00
return false ;
}
2021-02-24 15:08:18 +01:00
if ( I . current . ai . aiName . ToUpper ( ) . Contains ( "CUDA" ) & & NvApi . gpuList . Count < 1 )
{
2021-04-02 22:26:44 +02:00
ShowMessage ( "Warning: No Nvidia GPU was detected. CUDA might fall back to CPU!\n\nTry an NCNN implementation instead if you don't have an Nvidia GPU." , "Error" ) ;
2021-04-10 00:35:54 +02:00
if ( ! Config . GetBool ( "allowCudaWithoutDetectedGpu" , true ) )
{
I . Cancel ( "No CUDA-capable graphics card available." , true ) ;
return false ;
}
2021-02-24 15:08:18 +01:00
}
2020-11-23 16:51:05 +01:00
return true ;
}
2021-02-14 22:23:16 +01:00
public static bool CheckDeleteOldTempFolder ( )
2020-11-23 16:51:05 +01:00
{
2021-02-12 00:44:37 +01:00
if ( ! IOUtils . TryDeleteIfExists ( I . current . tempFolder ) )
2020-11-23 16:51:05 +01:00
{
ShowMessage ( "Failed to remove an existing temp folder of this video!\nMake sure you didn't open any frames in an editor." , "Error" ) ;
2021-02-12 00:44:37 +01:00
I . Cancel ( ) ;
2020-11-23 16:51:05 +01:00
return false ;
}
return true ;
}
2021-02-14 22:23:16 +01:00
public static bool CheckPathValid ( string path )
2020-11-23 16:51:05 +01:00
{
if ( IOUtils . IsPathDirectory ( path ) )
{
if ( ! IOUtils . IsDirValid ( path ) )
{
ShowMessage ( "Input directory is not valid." ) ;
2021-02-12 00:44:37 +01:00
I . Cancel ( ) ;
2020-11-23 16:51:05 +01:00
return false ;
}
}
else
{
if ( ! IsVideoValid ( path ) )
{
ShowMessage ( "Input video file is not valid." ) ;
return false ;
}
}
return true ;
}
2021-02-21 21:18:31 +01:00
public static async Task < bool > CheckEncoderValid ( )
{
string enc = FFmpegUtils . GetEnc ( FFmpegUtils . GetCodec ( I . current . outMode ) ) ;
if ( ! enc . ToLower ( ) . Contains ( "nvenc" ) )
return true ;
if ( ! ( await FfmpegCommands . IsEncoderCompatible ( enc ) ) )
{
ShowMessage ( "NVENC encoding is not available on your hardware!\nPlease use a different encoder." , "Error" ) ;
I . Cancel ( ) ;
return false ;
}
return true ;
}
2020-11-23 16:51:05 +01:00
public static bool IsVideoValid ( string videoPath )
{
if ( videoPath = = null | | ! IOUtils . IsFileValid ( videoPath ) )
return false ;
2020-12-13 23:44:23 +01:00
return true ;
2020-11-23 16:51:05 +01:00
}
public static void ShowMessage ( string msg , string title = "Message" )
{
if ( ! BatchProcessing . busy )
MessageBox . Show ( msg , title ) ;
Logger . Log ( "Message: " + msg , true ) ;
}
2020-12-15 14:46:33 +01:00
2021-02-14 22:23:16 +01:00
public static async Task < Size > GetOutputResolution ( string inputPath , bool print , bool returnZeroIfUnchanged = false )
2020-12-15 14:46:33 +01:00
{
2021-04-18 18:11:47 +02:00
Size resolution = await GetMediaResolutionCached . GetSizeAsync ( inputPath ) ;
2021-01-27 11:41:05 +01:00
return GetOutputResolution ( resolution , print , returnZeroIfUnchanged ) ;
2020-12-22 23:45:07 +01:00
}
2021-01-27 11:41:05 +01:00
public static Size GetOutputResolution ( Size inputRes , bool print = false , bool returnZeroIfUnchanged = false )
2020-12-22 23:45:07 +01:00
{
2021-03-13 00:42:41 +01:00
int maxHeight = RoundDivisibleBy ( Config . GetInt ( "maxVidHeight" ) , FfmpegCommands . GetPadding ( ) ) ;
2020-12-22 23:45:07 +01:00
if ( inputRes . Height > maxHeight )
2020-12-15 14:46:33 +01:00
{
2020-12-22 23:45:07 +01:00
float factor = ( float ) maxHeight / inputRes . Height ;
Logger . Log ( $"Un-rounded downscaled size: {(inputRes.Width * factor).ToString(" 0.00 ")}x{Config.GetInt(" maxVidHeight ")}" , true ) ;
2021-03-13 00:42:41 +01:00
int width = RoundDivisibleBy ( ( inputRes . Width * factor ) . RoundToInt ( ) , FfmpegCommands . GetPadding ( ) ) ;
2020-12-22 23:45:07 +01:00
if ( print )
2020-12-21 15:03:31 +01:00
Logger . Log ( $"Video is bigger than the maximum - Downscaling to {width}x{maxHeight}." ) ;
2020-12-15 14:46:33 +01:00
return new Size ( width , maxHeight ) ;
}
else
{
2021-01-27 11:41:05 +01:00
if ( returnZeroIfUnchanged )
return new Size ( ) ;
else
return inputRes ;
2020-12-15 14:46:33 +01:00
}
}
2021-03-13 00:42:41 +01:00
public static int RoundDivisibleBy ( int number , int divisibleBy ) // Round to a number that's divisible by 2 (for h264 etc)
2020-12-15 14:46:33 +01:00
{
2021-03-13 00:42:41 +01:00
int a = ( number / divisibleBy ) * divisibleBy ; // Smaller multiple
int b = a + divisibleBy ; // Larger multiple
return ( number - a > b - number ) ? b : a ; // Return of closest of two
2020-12-15 14:46:33 +01:00
}
2020-12-23 00:07:06 +01:00
2021-02-14 22:23:16 +01:00
public static bool CanUseAutoEnc ( bool stepByStep , InterpSettings current )
2021-01-05 17:23:37 +01:00
{
2021-01-06 17:41:18 +01:00
AutoEncode . UpdateChunkAndBufferSizes ( ) ;
2021-01-05 17:23:37 +01:00
2021-01-18 15:32:45 +01:00
if ( current . alpha )
{
Logger . Log ( $"Not Using AutoEnc: Alpha mode is enabled." , true ) ;
return false ;
}
if ( ! current . outMode . ToString ( ) . ToLower ( ) . Contains ( "vid" ) | | current . outMode . ToString ( ) . ToLower ( ) . Contains ( "gif" ) )
2021-01-05 17:23:37 +01:00
{
Logger . Log ( $"Not Using AutoEnc: Out Mode is not video ({current.outMode.ToString()})" , true ) ;
return false ;
}
2021-02-14 22:23:16 +01:00
if ( stepByStep & & ! Config . GetBool ( "sbsAllowAutoEnc" ) )
2021-01-05 17:23:37 +01:00
{
Logger . Log ( $"Not Using AutoEnc: Using step-by-step mode, but 'sbsAllowAutoEnc' is false." , true ) ;
return false ;
}
if ( ! stepByStep & & Config . GetInt ( "autoEncMode" ) = = 0 )
{
Logger . Log ( $"Not Using AutoEnc: 'autoEncMode' is 0." , true ) ;
return false ;
}
int inFrames = IOUtils . GetAmountOfFiles ( current . framesFolder , false ) ;
if ( inFrames * current . interpFactor < ( AutoEncode . chunkSize + AutoEncode . safetyBufferFrames ) * 1.2f )
{
2021-01-06 17:41:18 +01:00
Logger . Log ( $"Not Using AutoEnc: Input frames ({inFrames}) * factor ({current.interpFactor}) is smaller than (chunkSize ({AutoEncode.chunkSize}) + safetyBufferFrames ({AutoEncode.safetyBufferFrames}) * 1.2f)" , true ) ;
2021-01-05 17:23:37 +01:00
return false ;
}
return true ;
}
2021-04-18 18:11:47 +02:00
public static async Task < bool > UseUhd ( )
2021-01-05 17:23:37 +01:00
{
2021-02-12 00:44:37 +01:00
return ( await GetOutputResolution ( I . current . inPath , false ) ) . Height > = Config . GetInt ( "uhdThresh" ) ;
2021-01-05 17:23:37 +01:00
}
2021-02-14 22:23:16 +01:00
public static void FixConsecutiveSceneFrames ( string sceneFramesPath , string sourceFramesPath )
2020-12-23 00:07:06 +01:00
{
2020-12-23 12:42:06 +01:00
if ( ! Directory . Exists ( sceneFramesPath ) | | IOUtils . GetAmountOfFiles ( sceneFramesPath , false ) < 1 )
return ;
2020-12-23 00:07:06 +01:00
List < string > sceneFrames = IOUtils . GetFilesSorted ( sceneFramesPath ) . Select ( x = > Path . GetFileNameWithoutExtension ( x ) ) . ToList ( ) ;
List < string > sourceFrames = IOUtils . GetFilesSorted ( sourceFramesPath ) . Select ( x = > Path . GetFileNameWithoutExtension ( x ) ) . ToList ( ) ;
List < string > sceneFramesToDelete = new List < string > ( ) ;
2021-02-14 22:23:16 +01:00
foreach ( string scnFrame in sceneFrames )
2020-12-23 00:07:06 +01:00
{
if ( sceneFramesToDelete . Contains ( scnFrame ) )
continue ;
int sourceIndexForScnFrame = sourceFrames . IndexOf ( scnFrame ) ; // Get source index of scene frame
2020-12-23 16:13:04 +01:00
if ( ( sourceIndexForScnFrame + 1 ) = = sourceFrames . Count )
continue ;
2020-12-23 00:07:06 +01:00
string followingFrame = sourceFrames [ sourceIndexForScnFrame + 1 ] ; // Get filename/timestamp of the next source frame
if ( sceneFrames . Contains ( followingFrame ) ) // If next source frame is in scene folder, add to deletion list
sceneFramesToDelete . Add ( followingFrame ) ;
}
foreach ( string frame in sceneFramesToDelete )
2021-04-22 16:15:17 +02:00
IOUtils . TryDeleteIfExists ( Path . Combine ( sceneFramesPath , frame + I . current . framesExt ) ) ;
2020-12-23 00:07:06 +01:00
}
2020-11-23 16:51:05 +01:00
}
}