2020-12-04 16:53:39 +01:00
using Flowframes.Data ;
using Flowframes.IO ;
2020-11-30 02:14:04 +01:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
namespace Flowframes.Main
{
class AutoEncode
{
static string interpFramesFolder ;
static string videoChunksFolder ;
2020-12-01 16:54:12 +01:00
public static int chunkSize = 125 ; // Encode every n frames
2020-12-15 14:46:33 +01:00
public static int safetyBufferFrames = 50 ; // Ignore latest n frames to avoid using images that haven't been fully encoded yet
2020-11-30 02:14:04 +01:00
public static List < string > encodedFrames = new List < string > ( ) ;
public static List < string > unencodedFrames = new List < string > ( ) ;
public static bool busy ;
2020-12-04 16:53:39 +01:00
public static bool paused ;
2020-11-30 02:14:04 +01:00
public static async Task MainLoop ( string interpFramesPath )
{
interpFramesFolder = interpFramesPath ;
2020-11-30 20:32:33 +01:00
videoChunksFolder = Path . Combine ( interpFramesPath . GetParentDir ( ) , Paths . chunksDir ) ;
2020-11-30 02:14:04 +01:00
encodedFrames . Clear ( ) ;
unencodedFrames . Clear ( ) ;
2020-12-17 11:32:45 +01:00
chunkSize = GetChunkSize ( IOUtils . GetAmountOfFiles ( Interpolate . current . framesFolder , false , "*.png" ) * Interpolate . current . interpFactor ) ;
safetyBufferFrames = Interpolate . current . ai . aiName . ToUpper ( ) . Contains ( "NCNN" ) ? 60 : 30 ; // Use bigger safety buffer for NCNN
2020-12-15 14:46:33 +01:00
Logger . Log ( $"Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames" , true ) ;
2020-11-30 02:14:04 +01:00
int videoIndex = 1 ;
while ( ! Interpolate . canceled & & GetInterpFramesAmount ( ) < 2 )
2020-12-04 16:53:39 +01:00
await Task . Delay ( 1000 ) ;
2020-11-30 02:14:04 +01:00
2020-11-30 20:32:33 +01:00
while ( HasWorkToDo ( ) ) // Loop while proc is running and not all frames have been encoded
2020-11-30 02:14:04 +01:00
{
if ( Interpolate . canceled ) return ;
2020-12-04 16:53:39 +01:00
if ( paused )
{
await Task . Delay ( 100 ) ;
continue ;
}
2020-12-10 16:37:33 +01:00
IOUtils . ZeroPadDir ( Directory . GetFiles ( interpFramesFolder , $"*.{InterpolateUtils.GetExt()}" ) . ToList ( ) , Padding . interpFrames , encodedFrames ) ;
string [ ] interpFrames = Directory . GetFiles ( interpFramesFolder , $"*.{InterpolateUtils.GetExt()}" ) ;
2020-11-30 02:14:04 +01:00
unencodedFrames = interpFrames . ToList ( ) . Except ( encodedFrames ) . ToList ( ) ;
Directory . CreateDirectory ( videoChunksFolder ) ;
bool aiRunning = ! AiProcess . currentAiProcess . HasExited ;
if ( unencodedFrames . Count > = ( chunkSize + safetyBufferFrames ) | | ! aiRunning ) // Encode every n frames, or after process has exited
{
busy = true ;
List < string > framesToEncode = aiRunning ? unencodedFrames . Take ( chunkSize ) . ToList ( ) : unencodedFrames ; // Take all remaining frames if process is done
2020-12-15 16:45:31 +01:00
Logger . Log ( $"Encoding Chunk #{videoIndex} using {Path.GetFileName(framesToEncode.First())} through {Path.GetFileName(framesToEncode.Last())}" , true , false , "ffmpeg.txt" ) ;
2020-12-04 16:53:39 +01:00
IOUtils . ZeroPadDir ( framesToEncode , Padding . interpFrames ) ; // Zero-pad frames before encoding to make sure filenames match with VFR file
2020-11-30 02:14:04 +01:00
2020-12-17 11:32:45 +01:00
string outpath = Path . Combine ( videoChunksFolder , $"{videoIndex.ToString().PadLeft(4, '0')}{InterpolateUtils.GetExt(Interpolate.current.outMode)}" ) ;
2020-11-30 02:14:04 +01:00
int firstFrameNum = Path . GetFileNameWithoutExtension ( framesToEncode [ 0 ] ) . GetInt ( ) ;
2020-12-15 16:45:31 +01:00
await CreateVideo . EncodeChunk ( outpath , firstFrameNum - 1 , framesToEncode . Count ) ;
2020-11-30 20:32:33 +01:00
if ( Interpolate . canceled ) return ;
2020-11-30 02:14:04 +01:00
2020-12-06 18:49:53 +01:00
if ( Config . GetInt ( "autoEncMode" ) = = 2 )
{
foreach ( string frame in framesToEncode )
File . WriteAllText ( frame , "THIS IS A DUMMY FILE - DO NOT DELETE ME" ) ; // Overwrite to save space without breaking progress counter
}
2020-11-30 02:14:04 +01:00
encodedFrames . AddRange ( framesToEncode ) ;
Logger . Log ( "Done Encoding Chunk #" + videoIndex , true , false , "ffmpeg.txt" ) ;
2020-11-30 20:32:33 +01:00
videoIndex + + ;
2020-11-30 02:14:04 +01:00
busy = false ;
}
await Task . Delay ( 50 ) ;
}
if ( Interpolate . canceled ) return ;
string concatFile = Path . Combine ( interpFramesPath . GetParentDir ( ) , "chunks-concat.ini" ) ;
string concatFileContent = "" ;
foreach ( string vid in Directory . GetFiles ( videoChunksFolder ) )
2020-11-30 20:32:33 +01:00
concatFileContent + = $"file '{Paths.chunksDir}/{Path.GetFileName(vid)}'\n" ;
2020-11-30 02:14:04 +01:00
File . WriteAllText ( concatFile , concatFileContent ) ;
2020-12-02 00:44:43 +01:00
IOUtils . ReverseRenaming ( AiProcess . filenameMap , true ) ; // Get timestamps back
2020-12-17 11:32:45 +01:00
await CreateVideo . ChunksToVideo ( videoChunksFolder , concatFile , Interpolate . current . outFilename ) ;
2020-11-30 02:14:04 +01:00
}
2020-11-30 20:32:33 +01:00
public static bool HasWorkToDo ( )
{
2020-12-01 16:54:12 +01:00
if ( Interpolate . canceled | | interpFramesFolder = = null ) return false ;
2020-11-30 20:32:33 +01:00
return ( ( AiProcess . currentAiProcess ! = null & & ! AiProcess . currentAiProcess . HasExited ) | | encodedFrames . Count < GetInterpFramesAmount ( ) ) ;
}
2020-11-30 02:14:04 +01:00
static int GetChunkSize ( int targetFramesAmount )
{
if ( targetFramesAmount > 50000 ) return 2000 ;
if ( targetFramesAmount > 5000 ) return 500 ;
if ( targetFramesAmount > 1000 ) return 200 ;
return 100 ;
}
static int GetInterpFramesAmount ( )
{
2020-12-10 16:37:33 +01:00
return IOUtils . GetAmountOfFiles ( interpFramesFolder , false , $"*.{InterpolateUtils.GetExt()}" ) ;
2020-11-30 02:14:04 +01:00
}
}
}