Я использую FFmpeg, чтобы сделать видео из изображений. Моя цель - создать видео с прозрачным фоном в формате mov/mp4.

Использование «-c:v qtrle» или «-c:v png» может достичь моей цели, однако «-c:v png» всегда дает мне видео с очень большим размером.

Обычно составляет около 500 КБ, использование «-c:v png» увеличится до 30 ~ 40 МБ. Скорость передачи данных необычно высока, как я могу это исправить?

Вот моя команда ffmpeg -r 30 -i testImage_%03d.png -vcodec png test.mov
Я попытался добавить битрейт максимум к команде, это не сработало.

Кстати, "-c:v qtrle" работает нормально, но у quicktime есть некоторые проблемы в Windows, поэтому я склонен не использовать его.

3 ответа3

0

Вы можете попробовать видео UT. Это бесплатный сжатый формат без потерь, который поддерживает альфа-канал (например, RGBA), декодирование и кодирование изначально поддерживаются ffmpeg , и его легко установить, чтобы обеспечить интеграцию в After Effects, Adobe Media Encoder и т.д.

ffmpeg -framerate 30 -i testImage_%03d.png -c:v utvideo test.avi

У меня нет доступа к AE в данный момент, поэтому я не проверял это. Обязательно перезапустите AE, если вы установили его, когда он был открыт.

0

Png - это формат сжатия и хранения отдельных изображений, а не видео. Таким образом, вы просто копируете последовательность изображений в последовательность изображений в контейнере test.mov. В этом контейнере каждому изображению требуется столько же байтов, сколько было бы при сохранении непосредственно на жестком диске. Потому что, в отличие от большинства распространенных видеоформатов, формат изображения, такой как png, использует и не может использовать сходства между последовательными изображениями для получения более высоких коэффициентов сжатия.

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

Поэтому большинство форматов видео, которые показывают прозрачность, полагаются на один формат изображения, такой как png. И даже тогда, возможно, единственный широко поддерживаемый формат - это Shockwave. Кажется, не существует формата, который сочетал бы высокое сжатие с прозрачностью.

Вывод: вам нужно пропустить как минимум 1 из 3 пунктов: небольшой размер файла, широкая поддержка или прозрачность.

0

Вот мое решение для создания файла ffmpeg, который не слишком велик.

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class ConsoleAppManager
{
    private readonly string appName;
    private readonly Process process = new Process();
    private readonly object theLock = new object();
    private SynchronizationContext context;
    private string pendingWriteData;

    public ConsoleAppManager(string appName)
    {
        this.appName = appName;

        this.process.StartInfo.FileName = this.appName;
        this.process.StartInfo.RedirectStandardError = true;
        this.process.StartInfo.StandardErrorEncoding = Encoding.UTF8;

        this.process.StartInfo.RedirectStandardInput = true;
        this.process.StartInfo.RedirectStandardOutput = true;
        this.process.EnableRaisingEvents = true;
        this.process.StartInfo.CreateNoWindow = true;

        this.process.StartInfo.UseShellExecute = false;

        this.process.StartInfo.StandardOutputEncoding = Encoding.UTF8;

        this.process.Exited += this.ProcessOnExited;
    }

    public event EventHandler<string> ErrorTextReceived;
    public event EventHandler ProcessExited;
    public event EventHandler<string> StandartTextReceived;

    public int ExitCode
    {
        get { return this.process.ExitCode; }
    }

    public bool Running
    {
        get; private set;
    }

    public void ExecuteAsync(params string[] args)
    {
        if (this.Running)
        {
            throw new InvalidOperationException(
                "Process is still Running. Please wait for the process to complete.");
        }

        string arguments = string.Join(" ", args);

        this.process.StartInfo.Arguments = arguments;

        this.context = SynchronizationContext.Current;

        this.process.Start();
        this.Running = true;

        new Task(this.ReadOutputAsync).Start();
        new Task(this.WriteInputTask).Start();
        new Task(this.ReadOutputErrorAsync).Start();
    }

    public void Write(string data)
    {
        if (data == null)
        {
            return;
        }

        lock (this.theLock)
        {
            this.pendingWriteData = data;
        }
    }

    public void WriteLine(string data)
    {
        this.Write(data + Environment.NewLine);
    }

    protected virtual void OnErrorTextReceived(string e)
    {
        EventHandler<string> handler = this.ErrorTextReceived;

        if (handler != null)
        {
            if (this.context != null)
            {
                this.context.Post(delegate { handler(this, e); }, null);
            }
            else
            {
                handler(this, e);
            }
        }
    }

    protected virtual void OnProcessExited()
    {
        EventHandler handler = this.ProcessExited;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }

    protected virtual void OnStandartTextReceived(string e)
    {
        EventHandler<string> handler = this.StandartTextReceived;

        if (handler != null)
        {
            if (this.context != null)
            {
                this.context.Post(delegate { handler(this, e); }, null);
            }
            else
            {
                handler(this, e);
            }
        }
    }

    private void ProcessOnExited(object sender, EventArgs eventArgs)
    {
        this.OnProcessExited();
    }

    private async void ReadOutputAsync()
    {
        var standart = new StringBuilder();
        var buff = new char[1024];
        int length;

        while (this.process.HasExited == false)
        {
            standart.Clear();

            length = await this.process.StandardOutput.ReadAsync(buff, 0, buff.Length);
            standart.Append(buff.SubArray(0, length));
            this.OnStandartTextReceived(standart.ToString());
            Thread.Sleep(1);
        }

        this.Running = false;
    }

    private async void ReadOutputErrorAsync()
    {
        var sb = new StringBuilder();

        do
        {
            sb.Clear();
            var buff = new char[1024];
            int length = await this.process.StandardError.ReadAsync(buff, 0, buff.Length);
            sb.Append(buff.SubArray(0, length));
            this.OnErrorTextReceived(sb.ToString());
            Thread.Sleep(1);
        }
        while (this.process.HasExited == false);
    }

    private async void WriteInputTask()
    {
        while (this.process.HasExited == false)
        {
            Thread.Sleep(1);

            if (this.pendingWriteData != null)
            {
                await this.process.StandardInput.WriteLineAsync(this.pendingWriteData);
                await this.process.StandardInput.FlushAsync();

                lock (this.theLock)
                {
                    this.pendingWriteData = null;
                }
            }
        }
    }
}

Затем, фактически запустив процесс и отправив CTRL-C в моем основном приложении:

            DateTime maxStartDateTime = //... some date time;
            DateTime maxEndDateTime = //... some later date time
            var duration = maxEndDateTime.Subtract(maxStartDateTime);
            appManager = new ConsoleAppManager("ffmpeg.exe");
            string[] args = new string[] { "-rtbufsize 100M -f dshow -i video=\"screen-capture-recorder\":audio=\"virtual-audio-capturer\" -r 20 -timelimit " +
                Convert.ToString(duration.TotalSeconds) +
                " -vcodec libx264 -qp 0 -x264opts keyint=100:min_keyint=80 -acodec libmp3lame -ab 128k  -ac 1 -ar 44100 -async 30 C:\\Users\\Psalm3_3\\GDrive\\Workspace\\TutorApplication\\Videos\\out_vid.mp4" };

            appManager.ExecuteAsync(args);
            await Task.Delay(Convert.ToInt32(duration.TotalSeconds * 1000) + 20000);

            if (appManager.Running)
            {
                // If stilll running, send CTRL-C
                appManager.Write("\x3");
            }

Для получения дополнительной информации см. Https://stackoverflow.com/questions/21848271/redirecting-standard-input-of-console-application?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa и https://stackoverflow.com/quesw/302491 "как получить группу процессов, которая уже запущена" /50311226 # 50311226 и https://www.youtube.com/watch?v=JEVlRqajKNI

К вашему сведению, ранее у меня были файлы mp4 размером 7 или 8 ГБ, но теперь с приведенным выше кодом для записи сеанса, который длится более 2 часов, размер файла составляет всего около 500 МБ.

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