Crie vídeo a partir de uma sequência crescente de imagens usando FFMPEG

Crie vídeo a partir de uma sequência crescente de imagens usando FFMPEG

Estou planejando renderizar um projeto pessoal em 3D como uma sequência de imagens, onde cada quadro leva cerca de um minuto para ser criado e salvo como um arquivo de imagem.

Se eu usasse a sintaxe ffmpeg regular para converter esta sequência de imagens em um arquivo de vídeo ( ffmpeg -i image-%03d.png output.mp4) antes da conclusão da renderização, ela irá parar como esperado quando atingir o último arquivo de imagem. Mas como a lista de arquivos de imagem está crescendo com o tempo, usando essa sintaxe eu precisaria esperar até que o projeto terminasse a renderização para converter tudo em um arquivo de vídeo, o que vai demorar um pouco.

Fiquei curioso para saber se é possível deixar o ffmpeg"espere"para os próximos arquivos da sequência, e definindo um "último quadro" (ou cancelando usando Ctrl+C) ele saberia parar de esperar por mais arquivos e finalizar o arquivo de vídeo?

Considerei alimentar uma espécie de fluxo de vídeo como entrada, que seria gerado usando os arquivos de imagem e um programa externo, mas não tenho certeza se isso funcionaria e uma abordagem geral.

Responder1

Graças ao slhck, consegui criar um script C# que passa continuamente arquivos para o stdin do ffmpeg à medida que são criados, que pode ser cancelado pressionando qualquer tecla ou quando o quadro final especificado for atingido:

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 o image2pipeformato não suporta TGA, mas funciona bem com PNG, por exemplo.

informação relacionada