
Estoy planeando renderizar un proyecto personal en 3D como una secuencia de imágenes, donde cada fotograma tarda aproximadamente un minuto en crearse y guardarse como un archivo de imagen.
Si tuviera que usar la sintaxis normal de ffmpeg para convertir esta secuencia de imágenes en un archivo de video ( ffmpeg -i image-%03d.png output.mp4
) antes de que finalice el renderizado, se detendrá como se esperaba una vez que llegue al último archivo de imagen. Pero como la lista de archivos de imagen crece con el tiempo, al usar esta sintaxis necesitaría esperar hasta que el proyecto termine de renderizarse para convertirlo todo en un archivo de video, lo que llevará bastante tiempo.
Tenía curiosidad por saber si es posible dejar ffmpeg."esperar"para los siguientes archivos de la secuencia, y al definir un "último fotograma" (o cancelar usando Ctrl+C), ¿sabría que debe dejar de esperar por más archivos y finalizar el archivo de video?
He considerado alimentar una especie de flujo de video como entrada, que se generaría usando los archivos de imagen y un programa externo, pero no estoy seguro de si esto funcionaría y de un enfoque general.
Respuesta1
Gracias a slhck, logré crear un script C# que pasa continuamente archivos al stdin de ffmpeg a medida que se crean, lo cual se puede cancelar presionando cualquier tecla o cuando se alcanza el cuadro final especificado:
static void Main()
{
//Async main method
AsyncMain().GetAwaiter().GetResult();
}
static async Task AsyncMain()
{
Console.WriteLine("Press any key to quit prematurely.");
var maintask = RunFFMPEG();
var readtask = Task.Run(() => Console.Read());
await Task.WhenAny(maintask, readtask);
}
static async Task RunFFMPEG()
{
await Task.Run(() =>
{
const int fps = 30;
const string outfile = "out.mp4";
const string args = "-y -framerate {0} -f image2pipe -i - -r {0} -c:v libx264 -movflags +faststart -pix_fmt yuv420p -crf 19 -preset veryslow {1}";
const string dir = @"C:\testrender\";
const string pattern = "{0}.png";
const string path = dir + pattern;
const int startNum = 0;
const int endNum = 100;
var pinf = new ProcessStartInfo("ffmpeg", string.Format(args, fps, outfile));
pinf.UseShellExecute = false;
pinf.RedirectStandardInput = true;
pinf.WorkingDirectory = dir;
Console.WriteLine("Starting ffmpeg...");
var proc = Process.Start(pinf);
using (var stream = new BinaryWriter(proc.StandardInput.BaseStream))
{
for (var i = startNum; i < endNum; i++)
{
//"D4" turns 5 to 0005 - change depending on pattern of input files
var file = string.Format(path, i.ToString("D4"));
System.Threading.SpinWait.SpinUntil(() => File.Exists(file) && CanReadFile(file));
Console.WriteLine("Found file: " + file);
stream.Write(File.ReadAllBytes(file));
}
}
proc.WaitForExit();
Console.WriteLine("Closed ffmpeg.");
});
bool CanReadFile(string file)
{
//Needs to be able to read file
FileStream fs = null;
try
{
fs = File.OpenRead(file);
return true;
}
catch (IOException)
{
return false;
}
finally
{
if (fs != null)
fs.Close();
}
}
}
Parece que el image2pipe
formato no es compatible con TGA, pero funciona bien con PNG, por ejemplo.