FFmpeg에서 만든 비디오의 크기를 줄이려면 어떻게합니까


0

FFmpeg를 사용하여 이미지 장면에서 비디오를 만듭니다. 내 목적은 mov / mp4 형식의 투명한 배경을 가진 비디오를 만드는 것입니다.

"-c : v qtrle"또는 "-c : v png"를 사용하면 목적을 달성 할 수 있지만 "-c : v png"는 항상 매우 큰 크기의 비디오를 제공합니다.

일반적으로 500kb 정도이며 "-c : v png"를 사용하면 30 ~ 40MB로 증가합니다. 데이터 전송률이 비정상적으로 높으면 어떻게 해결할 수 있습니까?

여기 명령 ffmpeg -r 30 -i testImage_%03d.png -vcodec png test.mov
에 비트 전송률 최대 값을 추가하려고 시도했지만 작동하지 않았습니다.

BTW "-c : v qtrle"은 제대로 작동하지만 퀵타임에는 Windows에서 일부 문제가 있으므로 사용하지 않는 경향이 있습니다.


1
출력을 어떻게 사용할 계획입니까?
Gyan

After Effects에서 비디오를 편집하고 싶습니다.
Ives

1
이미지 시퀀스가있는 경우 단순히 AE로 이미지를 가져 오지 않습니까? 또한 대부분의 중간 코덱 (및 알파 채널을 허용하는 대부분의 코덱은 중간 채널로 사용하도록되어 있음)은 압축 용이 아니라 PNG와 같은 무손실을 위해 설계되었습니다 (최상의 예는 아님).
flolilo

@flolilolilo 아! 나는 당신이 옳다고 생각합니다. 나는 며칠 동안 해결책을 찾고 있었을 것입니다. 아마도 크기 문제를 떠나야합니다.
Ives

답변:


0

Png는 비디오가 아닌 개별 이미지를 압축하고 저장하기위한 형식입니다. 따라서 이미지 시퀀스를 test.mov 컨테이너의 이미지 시퀀스로 복사하기 만하면됩니다. 해당 컨테이너에서 각 이미지는 하드 디스크에 직접 저장할 때와 동일한 바이트가 필요합니다. 대부분의 일반적인 비디오 형식과 달리 png와 같은 이미지 형식은 더 높은 압축률을 얻기 위해 연속 이미지 간의 유사성을 이용하지 못하고 이용할 수 없기 때문입니다.

높은 압축률을 얻으려면 비디오 형식이 둘 이상의 이미지의 이미지 정보와 관련이 있어야합니다. 대부분의 이미지는 움직이는 이미지에서 그 점을 알지 못한다고 가정하면 상당히 많은 픽셀 색상 정보를 필터링합니다. 비디오 크기를 줄이는 두 가지 기술은 어느 픽셀이 어떤 투명성을 가지고 있는지 추적하기가 매우 어렵습니다.

따라서 투명성을 표시하는 대부분의 비디오 형식은 png와 같은 단일 이미지 형식에 의존합니다. 그럼에도 불구하고 널리 지원되는 유일한 형식은 Shockwave입니다. 높은 압축률과 투명도를 결합한 형식은없는 것 같습니다.

결론적으로, 작은 파일 크기, 넓은지지 또는 투명성 중 적어도 3 가지 항목을 제외해야합니다.


자세한 설명 감사합니다. 3 나열된 항목, 그들 각각은 저에게 중요합니다, 아마도 크기는 아마도 가장 중요하지 않지만 이제는 받아 들일 수 없습니다.
Ives

충격파는 여전히 주위에!? 지난번에 RealPlayer는 여전히 "좋은"것으로 간주되었습니다. ;-) 또한 잘 압축 된 알파 포함 코덱이 부풀린 알파 포함 코덱보다 덜 지원되는 방법을 알지 못합니다. 알파 포함 코덱은 일반적으로 무손실이므로 포스트 외부에서 사용되지 않습니다. -생산. 그러나 openEXR이 널리 지원되지 않는다고 말하는 것은 명백한 사실입니다.
flolilo

0

당신은 UT 비디오 를 시도 할 수 있습니다 . 알파 채널 (RGBA)을 지원하는 무료 무손실 압축 형식이며로 디코딩 및 인코딩이 기본적으로 지원되며 ffmpegAfter Effects, Adobe Media Encoder 등에 통합 할 수 있도록 쉽게 설치할 수 있습니다.

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

현재 AE에 액세스 할 수 없으므로 테스트하지 않았습니다. AE가 열려있는 동안 설치 한 경우 다시 시작하십시오.


고마워, 그러나 이것은 나에게 더 큰 크기를 준다-c:v png
Ives

@Ives 시도해 볼 가치가있었습니다. 나는 그 차이가별로 없을 것이라고 가정했습니다. -pred median파일 크기를 약간 줄이려면 출력 옵션을 추가 하십시오. 그러나 flolilolilo는 아마도 좋은 점을 제기 할 것입니다.
llogan

추가 -pred median해도 큰 변화는 없지만 약 5 % 감소했지만 감사합니다.
Ives

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_qahttps://stackoverflow.com/questions/30249101/windows 를 참조 하십시오. -how-to-get-the-process-group-of-a-process-that-is-is-al-y-running / 50311226 # 50311226https://www.youtube.com/watch?v=JEVlRqajKNI

참고로, 이전에는 7GB 또는 8GB의 mp4 파일로 끝나고 있었지만 이제 2 시간이 넘는 세션을 기록하기위한 위의 코드를 사용하면 파일 크기는 약 500MB에 불과합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.