2020-12-23 17:15:42 +01:00
using Flowframes.AudioVideo ;
using Flowframes.Data ;
2020-12-04 16:53:39 +01:00
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
2021-01-05 17:23:37 +01:00
public static int safetyBufferFrames = 90 ; // Ignore latest n frames to avoid using images that haven't been fully encoded yet
2021-01-03 22:37:06 +01:00
public static string [ ] interpFramesLines ;
public static List < int > encodedFrameLines = new List < int > ( ) ;
public static List < int > unencodedFrameLines = new List < int > ( ) ;
2020-11-30 02:14:04 +01:00
public static bool busy ;
2020-12-04 16:53:39 +01:00
public static bool paused ;
2021-01-06 17:41:18 +01:00
public static void UpdateChunkAndBufferSizes ( )
2021-01-05 17:23:37 +01:00
{
2021-01-06 17:41:18 +01:00
chunkSize = GetChunkSize ( IOUtils . GetAmountOfFiles ( Interpolate . current . framesFolder , false , "*.png" ) * Interpolate . current . interpFactor ) ;
2021-01-05 17:23:37 +01:00
safetyBufferFrames = Interpolate . current . ai . aiName . ToUpper ( ) . Contains ( "NCNN" ) ? 60 : 30 ; // Use bigger safety buffer for NCNN
}
2020-11-30 02:14:04 +01:00
public static async Task MainLoop ( string interpFramesPath )
{
2021-01-06 17:41:18 +01:00
UpdateChunkAndBufferSizes ( ) ;
2021-01-05 17:23:37 +01:00
2020-11-30 02:14:04 +01:00
interpFramesFolder = interpFramesPath ;
2020-11-30 20:32:33 +01:00
videoChunksFolder = Path . Combine ( interpFramesPath . GetParentDir ( ) , Paths . chunksDir ) ;
2021-01-06 17:41:18 +01:00
if ( Interpolate . currentlyUsingAutoEnc )
Directory . CreateDirectory ( videoChunksFolder ) ;
2020-11-30 02:14:04 +01:00
2021-01-03 22:37:06 +01:00
encodedFrameLines . Clear ( ) ;
unencodedFrameLines . Clear ( ) ;
2020-11-30 02:14:04 +01:00
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 ;
2021-01-03 22:37:06 +01:00
string encFile = Path . Combine ( interpFramesPath . GetParentDir ( ) , $"vfr-{Interpolate.current.interpFactor}x.ini" ) ;
interpFramesLines = IOUtils . ReadLines ( encFile ) . Select ( x = > x . Split ( '/' ) . Last ( ) . Remove ( "'" ) ) . ToArray ( ) ; // Array with frame filenames
2020-11-30 02:14:04 +01:00
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 ;
}
2021-01-03 22:37:06 +01:00
//IOUtils.ZeroPadDir(Directory.GetFiles(interpFramesFolder, $"*.{InterpolateUtils.GetOutExt()}").ToList(), Padding.interpFrames, encodedFrames);
//string[] interpFrames = IOUtils.GetFilesSorted(interpFramesFolder, $"*.{InterpolateUtils.GetOutExt()}");
//unencodedFrameLines = interpFramesLines.Select(x => x.GetInt()).ToList().Except(encodedFrameLines).ToList();
2021-01-05 13:00:27 +01:00
//Logger.Log($"{unencodedFrameLines.Count} unencoded frame lines, {encodedFrameLines.Count} encoded frame lines", true, false, "ffmpeg");
2021-01-04 14:27:34 +01:00
2021-01-03 22:37:06 +01:00
unencodedFrameLines . Clear ( ) ;
for ( int vfrLine = 0 ; vfrLine < interpFramesLines . Length ; vfrLine + + )
{
2021-01-04 14:27:34 +01:00
if ( File . Exists ( Path . Combine ( interpFramesPath , interpFramesLines [ vfrLine ] ) ) & & ! encodedFrameLines . Contains ( vfrLine ) )
2021-01-03 22:37:06 +01:00
unencodedFrameLines . Add ( vfrLine ) ;
}
2020-11-30 02:14:04 +01:00
bool aiRunning = ! AiProcess . currentAiProcess . HasExited ;
2021-01-03 22:37:06 +01:00
if ( unencodedFrameLines . Count > = ( chunkSize + safetyBufferFrames ) | | ! aiRunning ) // Encode every n frames, or after process has exited
2020-11-30 02:14:04 +01:00
{
busy = true ;
2021-01-03 22:37:06 +01:00
List < int > frameLinesToEncode = aiRunning ? unencodedFrameLines . Take ( chunkSize ) . ToList ( ) : unencodedFrameLines ; // Take all remaining frames if process is done
2021-01-05 13:00:27 +01:00
//Logger.Log($"{unencodedFrameLines.Count} unencoded frame lines, {IOUtils.GetAmountOfFiles(interpFramesFolder, false)} frames in interp folder", true, false, "ffmpeg");
2020-12-15 16:45:31 +01:00
2021-01-06 17:41:18 +01:00
string outpath = Path . Combine ( videoChunksFolder , "chunks" , $"{videoIndex.ToString().PadLeft(4, '0')}{FFmpegUtils.GetExt(Interpolate.current.outMode)}" ) ;
2021-01-03 22:37:06 +01:00
int firstFrameNum = frameLinesToEncode [ 0 ] ;
2021-01-06 17:41:18 +01:00
Logger . Log ( $"Encoding Chunk #{videoIndex} to '{outpath}' using {Path.GetFileName(interpFramesLines[frameLinesToEncode.First()])} through {Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))}" , true , false , "ffmpeg" ) ;
2021-01-05 13:00:27 +01:00
await CreateVideo . EncodeChunk ( outpath , Interpolate . current . outMode , firstFrameNum , frameLinesToEncode . 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 )
{
2021-01-03 22:37:06 +01:00
foreach ( int frame in frameLinesToEncode )
{
2021-01-03 22:38:32 +01:00
// TODO: Make sure frames are no longer needed (e.g. for dupes) before deleting!!
continue ;
2021-01-03 22:37:06 +01:00
string framePath = Path . Combine ( interpFramesPath , interpFramesLines [ frame ] ) ;
File . WriteAllText ( framePath , "THIS IS A DUMMY FILE - DO NOT DELETE ME" ) ; // Overwrite to save space without breaking progress counter
}
2020-12-06 18:49:53 +01:00
}
2020-11-30 02:14:04 +01:00
2021-01-03 22:37:06 +01:00
encodedFrameLines . AddRange ( frameLinesToEncode ) ;
2021-01-05 13:00:27 +01:00
//Logger.Log($"Adding {frameLinesToEncode.Count} frameLinesToEncode to encodedFrameLines, new count is {encodedFrameLines.Count}");
2020-11-30 02:14:04 +01:00
2020-12-27 22:52:14 +01:00
Logger . Log ( "Done Encoding Chunk #" + videoIndex , true , false , "ffmpeg" ) ;
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 ;
2020-12-02 00:44:43 +01:00
IOUtils . ReverseRenaming ( AiProcess . filenameMap , true ) ; // Get timestamps back
2021-01-06 17:41:18 +01:00
await CreateVideo . ChunksToVideos ( Interpolate . current . tempFolder , videoChunksFolder , 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 ;
2021-01-05 13:00:27 +01:00
//Logger.Log($"HasWorkToDo - Process Running: {(AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited)} - encodedFrameLines.Count: {encodedFrameLines.Count} - interpFramesLines.Length: {interpFramesLines.Length}");
2021-01-03 22:37:06 +01:00
return ( ( AiProcess . currentAiProcess ! = null & & ! AiProcess . currentAiProcess . HasExited ) | | encodedFrameLines . Count < interpFramesLines . Length ) ;
2020-11-30 20:32:33 +01:00
}
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-20 21:25:34 +01:00
return IOUtils . GetAmountOfFiles ( interpFramesFolder , false , $"*.{InterpolateUtils.GetOutExt()}" ) ;
2020-11-30 02:14:04 +01:00
}
}
}