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-11 11:45:38 +01:00
try
{
UpdateChunkAndBufferSizes ( ) ;
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
interpFramesFolder = interpFramesPath ;
videoChunksFolder = Path . Combine ( interpFramesPath . GetParentDir ( ) , Paths . chunksDir ) ;
if ( Interpolate . currentlyUsingAutoEnc )
Directory . CreateDirectory ( videoChunksFolder ) ;
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
encodedFrameLines . Clear ( ) ;
unencodedFrameLines . Clear ( ) ;
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
Logger . Log ( $"Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames" , true ) ;
int videoIndex = 1 ;
string encFile = Path . Combine ( interpFramesPath . GetParentDir ( ) , $"vfr-{Interpolate.current.interpFactor}x.ini" ) ;
interpFramesLines = IOUtils . ReadLines ( encFile ) . Select ( x = > x . Split ( '/' ) . Last ( ) . Remove ( "'" ) . Split ( '#' ) . First ( ) ) . ToArray ( ) ; // Array with frame filenames
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
while ( ! Interpolate . canceled & & GetInterpFramesAmount ( ) < 2 )
2020-12-04 16:53:39 +01:00
{
2021-01-11 11:45:38 +01:00
// Logger.Log("autoenc waiting for 2s because GetInterpFramesAmount() < 2");
await Task . Delay ( 2000 ) ;
2020-12-04 16:53:39 +01:00
}
2021-01-11 11:45:38 +01:00
while ( HasWorkToDo ( ) ) // Loop while proc is running and not all frames have been encoded
2021-01-03 22:37:06 +01:00
{
2021-01-11 11:45:38 +01:00
if ( Interpolate . canceled ) return ;
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
if ( paused )
{
Logger . Log ( "autoenc paused" ) ;
await Task . Delay ( 100 ) ;
continue ;
}
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
unencodedFrameLines . Clear ( ) ;
for ( int vfrLine = 0 ; vfrLine < interpFramesLines . Length ; vfrLine + + )
{
if ( File . Exists ( Path . Combine ( interpFramesPath , interpFramesLines [ vfrLine ] ) ) & & ! encodedFrameLines . Contains ( vfrLine ) )
unencodedFrameLines . Add ( vfrLine ) ;
}
2020-12-15 16:45:31 +01:00
2021-01-11 11:45:38 +01:00
// Logger.Log($"{unencodedFrameLines.Count} unencoded frame lines, {encodedFrameLines.Count} encoded frame lines", false, false, "ffmpeg");
2020-11-30 20:32:33 +01:00
2021-01-11 11:45:38 +01:00
bool aiRunning = ! AiProcess . currentAiProcess . HasExited ;
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
if ( unencodedFrameLines . Count > 0 & & ( unencodedFrameLines . Count > = ( chunkSize + safetyBufferFrames ) | | ! aiRunning ) ) // Encode every n frames, or after process has exited
2020-12-06 18:49:53 +01:00
{
2021-01-11 11:45:38 +01:00
busy = true ;
Logger . Log ( "unencodedFrameLines: " + unencodedFrameLines . Count , true , false , "autoenc" ) ;
List < int > frameLinesToEncode = aiRunning ? unencodedFrameLines . Take ( chunkSize ) . ToList ( ) : unencodedFrameLines ; // Take all remaining frames if process is done
Logger . Log ( "frameLinesToEncode: " + frameLinesToEncode . Count , true , false , "autoenc" ) ;
string outpath = Path . Combine ( videoChunksFolder , "chunks" , $"{videoIndex.ToString().PadLeft(4, '0')}{FFmpegUtils.GetExt(Interpolate.current.outMode)}" ) ;
int firstFrameNum = frameLinesToEncode [ 0 ] ;
Logger . Log ( $"Encoding Chunk #{videoIndex} to '{outpath}' using {Path.GetFileName(interpFramesLines[frameLinesToEncode.First()])} through {Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))}" , true , false , "ffmpeg" ) ;
await CreateVideo . EncodeChunk ( outpath , Interpolate . current . outMode , firstFrameNum , frameLinesToEncode . Count ) ;
if ( Interpolate . canceled ) return ;
if ( Config . GetInt ( "autoEncMode" ) = = 2 )
2021-01-03 22:37:06 +01:00
{
2021-01-11 11:45:38 +01:00
foreach ( int frame in frameLinesToEncode )
2021-01-07 11:02:43 +01:00
{
2021-01-11 11:45:38 +01:00
if ( ! FrameIsStillNeeded ( interpFramesLines [ frame ] , frame ) ) // Make sure frames are no longer needed (e.g. for dupes) before deleting!
{
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
}
2021-01-07 11:02:43 +01:00
}
2021-01-03 22:37:06 +01:00
}
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
encodedFrameLines . AddRange ( frameLinesToEncode ) ;
//Logger.Log($"Adding {frameLinesToEncode.Count} frameLinesToEncode to encodedFrameLines, new count is {encodedFrameLines.Count}");
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
Logger . Log ( "Done Encoding Chunk #" + videoIndex , true , false , "ffmpeg" ) ;
videoIndex + + ;
busy = false ;
}
await Task . Delay ( 50 ) ;
2020-11-30 02:14:04 +01:00
}
2021-01-11 11:45:38 +01:00
if ( Interpolate . canceled ) return ;
2020-11-30 02:14:04 +01:00
2021-01-11 11:45:38 +01:00
IOUtils . ReverseRenaming ( AiProcess . filenameMap , true ) ; // Get timestamps back
await CreateVideo . ChunksToVideos ( Interpolate . current . tempFolder , videoChunksFolder , Interpolate . current . outFilename ) ;
}
catch ( Exception e )
{
Logger . Log ( $"AutoEnc Error: {e.Message}. Stack Trace:\n{e.StackTrace}" ) ;
Interpolate . Cancel ( "Auto-Encode encountered an error." ) ;
}
2020-11-30 02:14:04 +01:00
}
2021-01-06 18:02:14 +01:00
static bool FrameIsStillNeeded ( string frameName , int frameIndex )
{
2021-01-07 11:02:43 +01:00
if ( ( frameIndex + 1 ) < interpFramesLines . Length & & interpFramesLines [ frameIndex + 1 ] . Contains ( frameName ) )
2021-01-07 01:34:55 +01:00
return true ;
2021-01-06 18:02:14 +01:00
return false ;
}
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-11 11:45:38 +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
}
}
}