2020-12-02 17:23:24 +01:00
using Flowframes.Data ;
using Flowframes.IO ;
2021-02-16 11:27:00 +01:00
using Flowframes.MiscUtils ;
2020-11-25 12:40:17 +01:00
using Flowframes.UI ;
using System ;
2020-11-24 02:23:19 +01:00
using System.Collections.Generic ;
2020-11-25 12:40:17 +01:00
using System.Diagnostics ;
2020-11-30 20:32:33 +01:00
using System.Globalization ;
2020-11-24 02:23:19 +01:00
using System.IO ;
using System.Linq ;
using System.Threading.Tasks ;
namespace Flowframes.Main
{
2021-01-14 20:32:42 +01:00
class FrameOrder
2020-11-24 02:23:19 +01:00
{
2021-02-08 11:03:17 +01:00
static Stopwatch benchmark = new Stopwatch ( ) ;
2021-02-16 11:27:00 +01:00
static FileInfo [ ] frameFiles ;
static FileInfo [ ] frameFilesWithoutLast ;
static List < string > sceneFrames = new List < string > ( ) ;
static string currentFormat = "D8" ;
static Dictionary < int , string > frameFileContents = new Dictionary < int , string > ( ) ;
static int lastOutFileCount = 0 ;
2020-12-29 16:01:24 +01:00
2021-02-01 18:05:50 +01:00
public static async Task CreateFrameOrderFile ( string framesPath , bool loopEnabled , float times )
2020-11-29 16:10:31 +01:00
{
2021-01-14 20:32:42 +01:00
Logger . Log ( "Generating frame order information..." ) ;
2021-02-08 21:11:25 +01:00
2021-01-02 16:20:21 +01:00
try
{
2021-02-08 21:11:25 +01:00
foreach ( FileInfo file in IOUtils . GetFileInfosSorted ( framesPath . GetParentDir ( ) , false , $"{Paths.frameOrderPrefix}*.*" ) )
file . Delete ( ) ;
2021-02-08 11:03:17 +01:00
benchmark . Restart ( ) ;
2021-02-16 11:27:00 +01:00
currentFormat = $"D{Padding.interpFrames}" ;
2021-01-21 09:40:11 +01:00
await CreateEncFile ( framesPath , loopEnabled , times , false ) ;
2021-01-14 20:32:42 +01:00
Logger . Log ( $"Generating frame order information... Done." , false , true ) ;
2021-02-08 11:03:17 +01:00
Logger . Log ( $"Generated frame order info file in {benchmark.ElapsedMilliseconds} ms" , true ) ;
2021-01-02 16:20:21 +01:00
}
catch ( Exception e )
{
2021-01-14 20:32:42 +01:00
Logger . Log ( $"Error generating frame order information: {e.Message}" ) ;
2021-01-02 16:20:21 +01:00
}
2020-11-29 16:10:31 +01:00
}
2021-01-02 16:20:21 +01:00
static Dictionary < string , int > dupesDict = new Dictionary < string , int > ( ) ;
2021-03-19 19:34:48 +01:00
static void LoadDupesFile ( string path )
2021-01-02 16:20:21 +01:00
{
dupesDict . Clear ( ) ;
2021-01-05 13:00:27 +01:00
if ( ! File . Exists ( path ) ) return ;
2021-01-02 16:20:21 +01:00
string [ ] dupesFileLines = IOUtils . ReadLines ( path ) ;
2021-03-19 19:34:48 +01:00
foreach ( string line in dupesFileLines )
2021-01-02 16:20:21 +01:00
{
string [ ] values = line . Split ( ':' ) ;
dupesDict . Add ( values [ 0 ] , values [ 1 ] . GetInt ( ) ) ;
}
}
2021-03-19 19:34:48 +01:00
public static async Task CreateEncFile ( string framesPath , bool loopEnabled , float interpFactor , bool notFirstRun )
2021-01-02 16:20:21 +01:00
{
if ( Interpolate . canceled ) return ;
2021-01-21 00:18:26 +01:00
Logger . Log ( $"Generating frame order information for {interpFactor}x..." , false , true ) ;
2021-01-02 16:20:21 +01:00
bool loop = Config . GetBool ( "enableLoop" ) ;
bool sceneDetection = true ;
string ext = InterpolateUtils . GetOutExt ( ) ;
2021-02-16 11:27:00 +01:00
frameFileContents . Clear ( ) ;
lastOutFileCount = 0 ;
frameFiles = new DirectoryInfo ( framesPath ) . GetFiles ( $"*.png" ) ;
frameFilesWithoutLast = frameFiles ;
Array . Resize ( ref frameFilesWithoutLast , frameFilesWithoutLast . Length - 1 ) ;
2021-02-08 20:57:37 +01:00
string vfrFile = Path . Combine ( framesPath . GetParentDir ( ) , Paths . GetFrameOrderFilename ( interpFactor ) ) ;
2021-01-02 16:20:21 +01:00
string fileContent = "" ;
string dupesFile = Path . Combine ( framesPath . GetParentDir ( ) , $"dupes.ini" ) ;
LoadDupesFile ( dupesFile ) ;
string scnFramesPath = Path . Combine ( framesPath . GetParentDir ( ) , Paths . scenesDir ) ;
2021-02-16 11:27:00 +01:00
sceneFrames . Clear ( ) ;
2021-02-25 14:57:57 +01:00
2021-01-02 16:20:21 +01:00
if ( Directory . Exists ( scnFramesPath ) )
sceneFrames = Directory . GetFiles ( scnFramesPath ) . Select ( file = > Path . GetFileNameWithoutExtension ( file ) ) . ToList ( ) ;
2021-01-21 00:18:26 +01:00
bool debug = Config . GetBool ( "frameOrderDebug" , false ) ;
2021-02-08 11:03:17 +01:00
int interpFramesAmount = ( int ) interpFactor ; // TODO: This code won't work with fractional factors
2021-02-16 11:27:00 +01:00
List < Task > tasks = new List < Task > ( ) ;
int linesPerTask = 400 / ( int ) interpFactor ;
int num = 0 ;
2021-03-19 19:34:48 +01:00
for ( int i = 0 ; i < frameFilesWithoutLast . Length ; i + = linesPerTask )
2021-02-16 11:27:00 +01:00
{
tasks . Add ( GenerateFrameLines ( num , i , linesPerTask , ( int ) interpFactor , loopEnabled , sceneDetection , debug ) ) ;
num + + ;
}
await Task . WhenAll ( tasks ) ;
for ( int x = 0 ; x < frameFileContents . Count ; x + + )
fileContent + = frameFileContents [ x ] ;
lastOutFileCount + + ;
fileContent + = $"file '{Paths.interpDir}/{lastOutFileCount.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'" ; // Last frame (source)
2021-03-19 19:34:48 +01:00
if ( loop )
2021-02-16 11:27:00 +01:00
fileContent = fileContent . Remove ( fileContent . LastIndexOf ( "\n" ) ) ;
File . WriteAllText ( vfrFile , fileContent ) ;
if ( notFirstRun ) return ; // Skip all steps that only need to be done once
if ( loop )
{
int lastFileNumber = frameFiles . Last ( ) . Name . GetInt ( ) + 1 ;
string loopFrameTargetPath = Path . Combine ( frameFilesWithoutLast . First ( ) . FullName . GetParentDir ( ) , lastFileNumber . ToString ( ) . PadLeft ( Padding . inputFrames , '0' ) + $".png" ) ;
if ( File . Exists ( loopFrameTargetPath ) )
{
if ( debug ) Logger . Log ( $"Won't copy loop frame - {Path.GetFileName(loopFrameTargetPath)} already exists." , true ) ;
return ;
}
File . Copy ( frameFilesWithoutLast . First ( ) . FullName , loopFrameTargetPath ) ;
if ( debug ) Logger . Log ( $"Copied loop frame to {loopFrameTargetPath}." , true ) ;
}
}
2021-03-19 19:34:48 +01:00
static async Task GenerateFrameLines ( int number , int startIndex , int count , int factor , bool loopEnabled , bool sceneDetection , bool debug )
2021-02-16 11:27:00 +01:00
{
int totalFileCount = ( startIndex ) * factor ;
int interpFramesAmount = factor ;
string ext = InterpolateUtils . GetOutExt ( ) ;
string fileContent = "" ;
2021-03-19 19:34:48 +01:00
2021-02-16 11:27:00 +01:00
for ( int i = startIndex ; i < ( startIndex + count ) ; i + + )
2021-01-02 16:20:21 +01:00
{
if ( Interpolate . canceled ) return ;
2021-02-16 11:27:00 +01:00
if ( i > = frameFilesWithoutLast . Length ) break ;
2021-03-14 20:34:35 +01:00
// if (debug && i == startIndex)
// fileContent += $"# NEW THREAD - {startIndex} to {startIndex + count}\n";
2021-03-01 17:34:47 +01:00
2021-02-16 11:27:00 +01:00
string inputFilenameNoExt = Path . GetFileNameWithoutExtension ( frameFilesWithoutLast [ i ] . Name ) ;
2021-01-02 16:20:21 +01:00
int dupesAmount = dupesDict . ContainsKey ( inputFilenameNoExt ) ? dupesDict [ inputFilenameNoExt ] : 0 ;
2021-03-16 18:21:12 +01:00
bool discardThisFrame = ( sceneDetection & & i < frameFilesWithoutLast . Length & & sceneFrames . Contains ( Path . GetFileNameWithoutExtension ( frameFiles [ i + 1 ] . Name ) ) ) ; // i+2 is in scene detection folder, means i+1 is ugly interp frame
2021-03-02 16:49:23 +01:00
2021-02-16 11:27:00 +01:00
if ( loopEnabled & & i = = ( frameFiles . Length - 2 ) ) // If loop is enabled, account for the extra frame for loop continuity
2021-01-02 16:20:21 +01:00
interpFramesAmount = interpFramesAmount * 2 ;
2021-02-16 11:27:00 +01:00
2021-02-08 11:03:17 +01:00
for ( int frm = 0 ; frm < interpFramesAmount ; frm + + ) // Generate frames file lines
2021-01-02 16:20:21 +01:00
{
2021-01-14 20:31:45 +01:00
if ( discardThisFrame ) // If frame is scene cut frame
2021-01-02 16:20:21 +01:00
{
2021-03-19 19:34:48 +01:00
string frameBeforeScn = Path . GetFileName ( ( frameFiles [ i ] . Name . GetInt ( ) + 1 ) . ToString ( ) . PadLeft ( Padding . inputFramesRenamed , '0' ) ) + frameFiles [ i ] . Extension ;
string frameAfterScn = Path . GetFileName ( ( frameFiles [ i + 1 ] . Name . GetInt ( ) + 1 ) . ToString ( ) . PadLeft ( Padding . inputFramesRenamed , '0' ) ) + frameFiles [ i + 1 ] . Extension ;
string scnChangeNote = $"SCN:{frameBeforeScn}>{frameAfterScn}" ;
fileContent = WriteFrameWithDupes ( dupesAmount , fileContent , totalFileCount , ext , debug , $"[In: {inputFilenameNoExt}] [{((frm == 0) ? " Source " : $" Interp { frm } ")}]" , scnChangeNote ) ;
2021-01-02 16:20:21 +01:00
2021-03-19 19:34:48 +01:00
if ( Config . GetInt ( "sceneChangeFillMode" ) = = 0 ) // Duplicate last frame
2021-01-02 16:20:21 +01:00
{
totalFileCount + + ;
2021-03-19 19:34:48 +01:00
int lastNum = totalFileCount ;
for ( int dupeCount = 1 ; dupeCount < interpFramesAmount ; dupeCount + + )
{
totalFileCount + + ;
fileContent = WriteFrameWithDupes ( dupesAmount , fileContent , lastNum , ext , debug , $"[In: {inputFilenameNoExt}] [DISCARDED]" ) ;
}
2021-01-02 16:20:21 +01:00
2021-03-19 19:34:48 +01:00
frm = interpFramesAmount ;
}
else
{
totalFileCount + + ;
fileContent = WriteFrameWithDupes ( dupesAmount , fileContent , totalFileCount , ext , debug , $"[In: {inputFilenameNoExt}] [DISCARDED - BLEND]" ) ;
frm + + ;
}
2021-01-02 16:20:21 +01:00
}
else
{
totalFileCount + + ;
2021-02-16 11:27:00 +01:00
fileContent = WriteFrameWithDupes ( dupesAmount , fileContent , totalFileCount , ext , debug , $"[In: {inputFilenameNoExt}] [{((frm == 0) ? " Source " : $" Interp { frm } ")}]" ) ;
2021-01-02 16:20:21 +01:00
}
}
}
2021-03-19 19:34:48 +01:00
if ( totalFileCount > lastOutFileCount )
2021-02-16 11:27:00 +01:00
lastOutFileCount = totalFileCount ;
2021-01-02 16:20:21 +01:00
2021-02-16 11:27:00 +01:00
frameFileContents [ number ] = fileContent ;
2021-01-02 16:20:21 +01:00
}
2021-01-05 23:55:16 +01:00
2021-03-19 19:34:48 +01:00
static string WriteFrameWithDupes ( int dupesAmount , string fileContent , int frameNum , string ext , bool debug , string debugNote = "" , string forcedNote = "" )
2021-01-05 23:55:16 +01:00
{
for ( int writtenDupes = - 1 ; writtenDupes < dupesAmount ; writtenDupes + + ) // Write duplicates
2021-03-19 19:34:48 +01:00
fileContent + = $"file '{Paths.interpDir}/{frameNum.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}' # {(debug ? ($" Dupe { ( writtenDupes + 1 ) . ToString ( "000" ) } { debugNote } ").Replace(" Dupe 000 ", " ") : " ")}{forcedNote}\n" ;
2021-02-16 11:27:00 +01:00
2021-01-05 23:55:16 +01:00
return fileContent ;
}
2020-11-24 02:23:19 +01:00
}
}