Я планирую визуализировать персональный 3D-проект в виде последовательности изображений, где создание каждого кадра занимает около минуты и сохраняется в виде файла изображения.

Если бы я использовал обычный синтаксис ffmpeg для преобразования этой последовательности изображений в видеофайл (ffmpeg -i image-%03d.png output.mp4) до завершения рендеринга, он, как и ожидалось, остановится, как только достигнет последнего файла изображения , Но так как список файлов изображений со временем растет, используя этот синтаксис, мне нужно подождать, пока проект не завершит рендеринг, чтобы преобразовать все это в видеофайл, что займет довольно много времени.

Мне было любопытно, можно ли позволить ffmpeg "ждать" следующих файлов в последовательности, и, определив "последний кадр" (или отменив нажатие Ctrl+C), он узнает, что нужно перестать ждать больше файлов и завершить видео файл?

Я рассмотрел подачу видеопотока в качестве входных данных, которые будут генерироваться с использованием файлов изображений и внешней программы, но я не уверен, сработает ли это и общий подход.

1 ответ1

2

Благодаря slhck мне удалось создать скрипт C #, который непрерывно передает файлы в stdin ffmpeg по мере их создания, что можно отменить нажатием любой клавиши или по достижении указанного конечного кадра:

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();
        }
    }
}

Кажется, что формат image2pipe не поддерживает TGA, но, к примеру, отлично работает с PNG.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .