为什么在使用ffmpeg实时创建视频文件时ffmpeg.exe会占用1GB内存?

时间:2015-06-30 22:39:51

标签: c# .net winforms ffmpeg

这是我的班级,我正在使用ffmpeg.exe。

using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using DannyGeneral;

namespace Manager
{
    public class Ffmpeg
    {
        NamedPipeServerStream p;
        String pipename = "mytestpipe";
        System.Diagnostics.Process process;
        string ffmpegFileName = "ffmpeg.exe";
        string workingDirectory;

        public Ffmpeg()
        {
            workingDirectory = Path.GetDirectoryName(Application.ExecutablePath);
            Logger.Write("workingDirectory: " + workingDirectory);
            if (!Directory.Exists(workingDirectory))
            {
                Directory.CreateDirectory(workingDirectory);
            }
            ffmpegFileName = Path.Combine(workingDirectory, ffmpegFileName);
            Logger.Write("FfmpegFilename: " + ffmpegFileName);
        }

        public void Start(string pathFileName, int BitmapRate)
        {
            try
            {

                string outPath = pathFileName;
                p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte);

                ProcessStartInfo psi = new ProcessStartInfo();
                psi.WindowStyle = ProcessWindowStyle.Hidden;
                psi.UseShellExecute = false;
                psi.CreateNoWindow = false;
                psi.FileName = ffmpegFileName;
                psi.WorkingDirectory = workingDirectory;
                psi.Arguments = @"-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \\.\pipe\mytestpipe -c:v libx264 -crf 20 -r " + BitmapRate + " " + outPath;
                process = Process.Start(psi);
                process.EnableRaisingEvents = false;
                psi.RedirectStandardError = true;
                p.WaitForConnection();
            }
            catch (Exception err)
            {
                Logger.Write("Exception Error: " + err.ToString());
            }
        }

        public void PushFrame(Bitmap bmp)
        {
            try
            {
                int length;
                // Lock the bitmap's bits.
                //bmp = new Bitmap(1920, 1080);
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                //Rectangle rect = new Rectangle(0, 0, 1280, 720);
                System.Drawing.Imaging.BitmapData bmpData =
                    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
                    bmp.PixelFormat);

                int absStride = Math.Abs(bmpData.Stride);
                // Get the address of the first line.
                IntPtr ptr = bmpData.Scan0;

                // Declare an array to hold the bytes of the bitmap.
                //length = 3 * bmp.Width * bmp.Height;
                length = absStride * bmpData.Height;
                byte[] rgbValues = new byte[length];

                //Marshal.Copy(ptr, rgbValues, 0, length);
                int j = bmp.Height - 1;
                for (int i = 0; i < bmp.Height; i++)
                {
                    IntPtr pointer = new IntPtr(bmpData.Scan0.ToInt32() + (bmpData.Stride * j));
                    System.Runtime.InteropServices.Marshal.Copy(pointer, rgbValues, absStride * (bmp.Height - i - 1), absStride);
                    j--;
                }
                p.Write(rgbValues, 0, length);
                bmp.UnlockBits(bmpData);
            }
            catch(Exception err)
            {
                Logger.Write("Error: " + err.ToString());
            }

        }

        public void Close()
        {
            p.Close();
        }
    }
}

ffmpegFileName包含ffmpeg.exe

然后我有另一种形式的计时器刻度事件:

ScreenShot shot = new ScreenShot();
    public static int counter = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {
        counter++;
        shot.GetScreenShot(@"e:\screenshots\", "screenshot");
        if (counter == 1200)
        {
            timer1.Stop();
            ScreenShot.fmpeg.Close();
            this.Close();
            ScreenShotsPlayer ssp = new ScreenShotsPlayer();
            ssp.Show();
        }
    }

此计时器间隔设置为100毫秒。 所以它每100毫秒拍一次截图。

在ScreenShot类我使用的是Ffmpeg类: 在顶部:

public static Ffmpeg fmpeg;

在构造函数中:

fmpeg = new Ffmpeg();
fmpeg.Start(@"e:\screenshots\test.mp4", 25);

然后在GetScreenShot方法中我调用了Ffmpeg PushFrame方法:

public Bitmap GetScreenShot(string folder, string name)
    {
        _screenShot = new Bitmap(GetScreen());
        System.GC.Collect();
        System.GC.WaitForPendingFinalizers();
        string ingName = folder + name + Elgato_Video_Capture.counter.ToString("D6") + ".bmp";
        _screenShot.Save(ingName,System.Drawing.Imaging.ImageFormat.Bmp);
        fmpeg.PushFrame(_screenShot);
        _screenShot.Dispose();
        return _screenShot;
    }

我无法弄清楚为什么一旦我启动定时器截取屏幕截图ffmpeg.exe吃了这么多内存,硬盘的工作量大约为53MB / s,内存超过90%且超过1GB。

我正在以某种方式做内存泄漏?

ffmpeg memory

在ScreenShot类中,当我为Ffmpeg类创建一次实例时,ffmpeg.exe的内存使用率非常低,硬盘使用率很低。

ffmpeg.exe的内存使用量仅为0.1MB。

fmpeg.Start(@"e:\screenshots\test.mp4", 25);

但是当我点击按钮时,启动计时器并每隔100毫秒获取一次屏幕截图并在几秒钟内调用PushFrame方法ffmpeg.exe后,内存使用量超过1GB。

修改

我试过这个论点:

psi.Arguments = @"-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \\.\pipe\mytestpipe -c:v libx264 -crf 20 -r 750k e:\screenshots\test.mp4";

内存使用量约为1gb ffmpeg.exe和cpu使用率99-100% 硬盘是0,但现在CPU使用率达到100%,内存超过1GB。

它没有创建我收到此警告/错误的视频文件:

Warnings/Errors

1 个答案:

答案 0 :(得分:1)

您似乎无休止地编码1920x1080视频(指代:-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \\.\pipe\mytestpipe)。编码(以及解码)h264高质量视频需要大量的CPU能力。我建议阅读更多有关H.264编码的内容。

回答这个问题实际上不可能是:

  1. FFmpeg片段在此代码实现中非常隐藏(基本上只运行系统shell命令)。导出正在执行的完整FFmpeg命令将是一个良好的开端。 ffmpeg命令应该类似于ffmpeg -f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \\.\pipe\mytestpipe -c:v libx264 -crf 20 -r 750k e:\screenshots\test.mp4

  2. FFmpeg根据输入和输出流而变化。例如,你会选择一个不同的编码器(比如改变:-c:v libx264到:-c:v mpeg2video)我可以保证一个显着的性能提升,因为mpeg2video是一个轻型编码器,但文件大小约为20倍大。

  3. 祝你好运。 -E