这是我的班级,我正在使用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。
我正在以某种方式做内存泄漏?
在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。
它没有创建我收到此警告/错误的视频文件:
答案 0 :(得分:1)
您似乎无休止地编码1920x1080视频(指代:-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \\.\pipe\mytestpipe
)。编码(以及解码)h264高质量视频需要大量的CPU能力。我建议阅读更多有关H.264编码的内容。
回答这个问题实际上不可能是:
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
。
FFmpeg根据输入和输出流而变化。例如,你会选择一个不同的编码器(比如改变:-c:v libx264
到:-c:v mpeg2video
)我可以保证一个显着的性能提升,因为mpeg2video是一个轻型编码器,但文件大小约为20倍大。