2020-11-25 12:40:17 +01:00
using Flowframes.IO ;
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.Text ;
using System.Threading.Tasks ;
namespace Flowframes.Main
{
class VfrDedupe
{
2020-11-30 20:52:43 +01:00
public static async Task CreateTimecodeFiles ( string framesPath , bool loopEnabled , bool firstFrameFix , int times )
2020-11-29 16:10:31 +01:00
{
Logger . Log ( "Generating timecodes..." ) ;
2020-11-30 20:52:43 +01:00
if ( times < = 0 )
{
await CreateTimecodeFile ( framesPath , loopEnabled , 2 , firstFrameFix ) ;
await CreateTimecodeFile ( framesPath , loopEnabled , 4 , firstFrameFix ) ;
await CreateTimecodeFile ( framesPath , loopEnabled , 8 , firstFrameFix ) ;
}
else
{
await CreateTimecodeFile ( framesPath , loopEnabled , times , firstFrameFix ) ;
}
2020-11-29 16:10:31 +01:00
frameFiles = null ;
Logger . Log ( $"Generating timecodes... Done." , false , true ) ;
}
static FileInfo [ ] frameFiles ;
2020-11-25 12:40:17 +01:00
public static async Task CreateTimecodeFile ( string framesPath , bool loopEnabled , int interpFactor , bool firstFrameFix )
2020-11-24 02:23:19 +01:00
{
2020-11-30 20:32:33 +01:00
if ( Interpolate . canceled ) return ;
Logger . Log ( $"Generating timecodes for {interpFactor}x..." , false , true ) ;
2020-11-26 20:17:18 +01:00
bool sceneDetection = true ;
2020-11-25 12:40:17 +01:00
2020-11-29 16:10:31 +01:00
if ( frameFiles = = null | | frameFiles . Length < 1 )
frameFiles = new DirectoryInfo ( framesPath ) . GetFiles ( "*.png" ) ;
string vfrFile = Path . Combine ( framesPath . GetParentDir ( ) , $"vfr-x{interpFactor}.ini" ) ;
2020-11-25 12:40:17 +01:00
string fileContent = "" ;
2020-11-30 20:32:33 +01:00
string scnFramesPath = Path . Combine ( framesPath . GetParentDir ( ) , Paths . scenesDir ) ;
string interpPath = Paths . interpDir ; // framesPath.Replace(@"\", "/") + "-interpolated";
List < string > sceneFrames = Directory . GetFiles ( scnFramesPath ) . Select ( file = > Path . GetFileName ( file ) ) . ToList ( ) ;
2020-11-24 02:23:19 +01:00
int lastFrameDuration = 1 ;
// Calculate time duration between frames
int totalFileCount = 1 ;
for ( int i = 0 ; i < ( frameFiles . Length - 1 ) ; i + + )
{
2020-11-25 14:04:31 +01:00
if ( Interpolate . canceled ) return ;
2020-11-25 12:40:17 +01:00
2020-11-24 02:23:19 +01:00
string filename1 = frameFiles [ i ] . Name ;
string filename2 = frameFiles [ i + 1 ] . Name ;
2020-11-25 12:40:17 +01:00
2020-11-26 20:17:18 +01:00
2020-11-24 02:23:19 +01:00
int durationTotal = Path . GetFileNameWithoutExtension ( filename2 ) . GetInt ( ) - Path . GetFileNameWithoutExtension ( filename1 ) . GetInt ( ) ;
lastFrameDuration = durationTotal ;
float durationPerInterpFrame = ( float ) durationTotal / interpFactor ;
2020-11-25 12:40:17 +01:00
2020-11-26 20:17:18 +01:00
int interpFramesAmount = interpFactor ;
2020-11-30 20:32:33 +01:00
bool discardThisFrame = ( sceneDetection & & ( i + 2 ) < frameFiles . Length & & sceneFrames . Contains ( frameFiles [ i + 1 ] . Name ) ) ; // i+2 is in scene detection folder, means i+1 is ugly interp frame
2020-11-26 20:17:18 +01:00
2020-11-24 02:23:19 +01:00
// If loop is enabled, account for the extra frame added to the end for loop continuity
if ( loopEnabled & & i = = ( frameFiles . Length - 2 ) )
2020-11-26 20:17:18 +01:00
interpFramesAmount = interpFramesAmount * 2 ;
2020-11-24 02:23:19 +01:00
// Generate frames file lines
2020-11-26 20:17:18 +01:00
for ( int frm = 0 ; frm < interpFramesAmount ; frm + + )
2020-11-24 02:23:19 +01:00
{
2020-11-30 20:32:33 +01:00
string durationStr = ( ( durationPerInterpFrame / 1000f ) * 1 ) . ToString ( "0.00000" , CultureInfo . InvariantCulture ) ;
2020-11-26 20:17:18 +01:00
if ( discardThisFrame )
{
int lastNum = totalFileCount - 1 ;
2020-11-29 16:10:31 +01:00
for ( int dupeCount = 1 ; dupeCount < interpFramesAmount ; dupeCount + + )
2020-11-26 20:17:18 +01:00
{
fileContent + = $"file '{interpPath}/{lastNum.ToString().PadLeft(8, '0')}.png'\nduration {durationStr}\n" ;
totalFileCount + + ;
}
frm = interpFramesAmount - 1 ;
}
2020-11-25 12:40:17 +01:00
fileContent + = $"file '{interpPath}/{totalFileCount.ToString().PadLeft(8, '0')}.png'\nduration {durationStr}\n" ;
2020-11-30 20:32:33 +01:00
totalFileCount + + ;
2020-11-24 02:23:19 +01:00
}
2020-11-25 12:40:17 +01:00
2020-11-29 16:10:31 +01:00
if ( ( i + 1 ) % 100 = = 0 )
2020-11-25 12:40:17 +01:00
await Task . Delay ( 1 ) ;
}
File . WriteAllText ( vfrFile , fileContent ) ;
2020-11-29 16:10:31 +01:00
if ( interpFactor > 2 ) // Skip all steps that only need to be done once
return ;
2020-11-25 12:40:17 +01:00
if ( firstFrameFix )
{
string [ ] lines = IOUtils . ReadLines ( vfrFile ) ;
File . WriteAllText ( vfrFile , lines [ 0 ] . Replace ( "00000001.png" , "00000000.png" ) ) ;
File . AppendAllText ( vfrFile , "\n" + lines [ 1 ] + "\n" ) ;
File . AppendAllLines ( vfrFile , lines ) ;
}
if ( Config . GetBool ( "enableLoop" ) )
{
int lastFileNumber = frameFiles . Last ( ) . Name . GetInt ( ) ;
lastFileNumber + = lastFrameDuration ;
2020-11-29 16:10:31 +01:00
string loopFrameTargetPath = Path . Combine ( frameFiles . First ( ) . FullName . GetParentDir ( ) , lastFileNumber + ".png" ) ;
if ( File . Exists ( loopFrameTargetPath ) )
return ;
File . Copy ( frameFiles . First ( ) . FullName , loopFrameTargetPath ) ;
//Logger.Log("Copied loop frame to " + loopFrameTargetPath);
2020-11-24 02:23:19 +01:00
}
}
}
}