Como posso reduzir o tamanho do vídeo criado a partir do FFmpeg

0

Estou usando o FFmpeg para fazer um vídeo a partir de imagens de imagem. Meu objetivo é criar um vídeo com um fundo transparente no formato mov / mp4.

Usar "-c: v qtrle" ou "-c: v png" pode alcançar meu objetivo, no entanto "-c: v png" está sempre me dando um vídeo com o tamanho super grande.

Normalmente, em torno de 500kb, o uso de "-c: v png" aumentará para 30 ~ 40MB. A taxa de dados é excepcionalmente alta, como posso corrigi-la?

Aqui está o meu comando ffmpeg -r 30 -i testImage_%03d.png -vcodec png test.mov
Eu tentei adicionar o máximo de taxa de bits ao comando, não funcionou.

BTW "-c: v qtrle" funciona bem, mas o quicktime tem alguns problemas no Windows, por isso não uso.

    
por Ives 28.11.2017 / 07:27

3 respostas

0

Você pode tentar o vídeo UT . É um formato comprimido livre de perdas que suporta um canal alfa (como RGBA), decodificação e codificação é suportado nativamente por ffmpeg , e é fácil de instalar para permitir integração ao After Effects, Adobe Media Encoder, etc.

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

Eu não tenho acesso ao AE no momento, então não testei isso. Certifique-se de reiniciar o AE se você o instalou enquanto estava aberto.

    
por 29.11.2017 / 04:25
0

Aqui está a minha solução para criar um arquivo ffmpeg que não seja muito grande.

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

Então, na verdade, executando o processo e enviando o CTRL-C no meu aplicativo principal:

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

Para mais detalhes, consulte link e link e link

FYI, anteriormente eu estava terminando com arquivos mp4 que eram 7 ou 8 GB, mas agora com o código acima para gravar uma sessão com mais de 2 horas, o tamanho do arquivo é de apenas 500 MB.

    
por 13.05.2018 / 00:49
-1

O png é um formato para compactar e armazenar imagens individuais, não para vídeo. Então você acabou de copiar sua sequência de imagens para uma sequência de imagens no contêiner test.mov. Nesse contêiner, cada imagem precisa de tantos bytes quanto seria armazenada diretamente no disco rígido. Porque, ao contrário da maioria dos formatos de vídeo comuns, um formato de imagem como o png faz e não pode explorar semelhanças entre imagens sucessivas para obter taxas de compactação mais altas.

Agora, para obter uma alta taxa de compactação, os formatos de vídeo precisam relacionar as informações da imagem de duas ou mais imagens. A maioria deles também filtra bastante informação de cor de pixel, assumindo que você não notará isso em imagens em movimento. Ambas as técnicas para reduzir o tamanho do vídeo dificultam bastante o rastreamento de qual pixel tem qual transparência.

Assim, a maioria dos formatos de vídeo que mostram a transparência dependem do formato de imagem única, como png. E mesmo assim, talvez o único formato amplamente suportado seja o Shockwave. Parece não haver um formato que combine alta compactação com transparência.

A conclusão é que você terá que deixar de fora pelo menos 1 de 3 itens: tamanho pequeno de arquivo, suporte amplo ou transparência.

    
por 28.11.2017 / 12:11