[英]Im using this screen capture code to take a screenshot of the screen but sometimes it's returning null why?
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace ScreenShotDemo
{
public class ScreenCapture
{
[StructLayout(LayoutKind.Sequential)]
struct CURSORINFO
{
public Int32 cbSize;
public Int32 flags;
public IntPtr hCursor;
public POINTAPI ptScreenPos;
}
[StructLayout(LayoutKind.Sequential)]
struct POINTAPI
{
public int x;
public int y;
}
[DllImport("user32.dll")]
static extern bool GetCursorInfo(out CURSORINFO pci);
[DllImport("user32.dll")]
static extern bool DrawIcon(IntPtr hDC, int X, int Y, IntPtr hIcon);
const Int32 CURSOR_SHOWING = 0x00000001;
public static Bitmap CaptureScreen(bool CaptureMouse)
{
Bitmap result = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
try
{
using (Graphics g = Graphics.FromImage(result))
{
g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
if (CaptureMouse)
{
CURSORINFO pci;
pci.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(CURSORINFO));
if (GetCursorInfo(out pci))
{
if (pci.flags == CURSOR_SHOWING)
{
DrawIcon(g.GetHdc(), pci.ptScreenPos.x, pci.ptScreenPos.y, pci.hCursor);
g.ReleaseHdc();
}
}
}
}
}
catch
{
result = null;
}
return result;
}
}
我的PC上有6GB内存ram,所以它永远不会达到零位。 但是我的兄弟只有2gb的内存,他无法使用。
我的程序使用此代码在Form1中使用计时器每40ms截取一个屏幕截图:
private void timer1_Tick(object sender, EventArgs e)
{
{
using (bitmap = (Bitmap)ScreenCapture.CaptureScreen(true))
ffmp.PushFrame(bitmap);
}
}
我该怎么做才能解决这个问题? 为什么会发生?
这是我有的ffmpeg类:
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 ScreenVideoRecorder
{
class Ffmpeg
{
NamedPipeServerStream p;
String pipename = "mytestpipe";
byte[] b;
System.Diagnostics.Process process;
string ffmpegFileName = "ffmpeg.exe";
string workingDirectory;
public Ffmpeg()
{
workingDirectory = Path.GetDirectoryName(Application.ExecutablePath);//System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);//Application.StartupPath; //Path.GetDirectoryName(Application.ExecutablePath);// +@"\workingDirectory";
Logger.Write("workingDirectory: " + workingDirectory);
if (!Directory.Exists(workingDirectory))
{
Directory.CreateDirectory(workingDirectory);
}
ffmpegFileName = Path.Combine(workingDirectory, ffmpegFileName);//@"\ffmpeg.exe";
Logger.Write("FfmpegFilename: " + ffmpegFileName);
}
public void Start(string pathFileName, int BitmapRate)
{
try
{
string outPath = pathFileName;
Logger.Write("Output Video File Directory: " + outPath);
Logger.Write("Frame Rate: " + BitmapRate.ToString());
p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte);
b = new byte[1920 * 1080 * 3]; // some buffer for the r g and b of pixels of an image of size 720p
ProcessStartInfo psi = new ProcessStartInfo();
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.FileName = ffmpegFileName;
Logger.Write("psi.FileName: " + psi.FileName);
psi.WorkingDirectory = workingDirectory;
Logger.Write("psi.WorkingDirectory: " + psi.WorkingDirectory);
psi.Arguments = @"-f rawvideo -pix_fmt bgr0 -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v libx264 -r " + BitmapRate + " " + outPath;
Logger.Write("ProcessStartInfo Arguments" + @"-f rawvideo -pix_fmt bgr0 -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v libx264 -r " + BitmapRate + " " + outPath);
//psi.RedirectStandardOutput = true;
process = Process.Start(psi);
process.EnableRaisingEvents = false;
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());
}
我每40ms在Form1中截屏一次,并将位图推送到ffmpeg类中的Pipe。 ffmpeg.exe首先使用参数作为进程启动,然后等待连接。
当我在任务管理器上查看时,我发现ffmpeg.exe以800-900mb的内存开始,并且很快跳到1020 mb或更多的内存。
我应该如何处理像我的兄弟这样的用户只有2GB内存的情况? 当他的内存不足时,屏幕捕获类将null返回给他,程序崩溃。
编辑
我为测试更改了计时器代码:
private void timer1_Tick(object sender, EventArgs e)
{
Image mScreenImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
ffmp.PushFrame((Bitmap)mScreenImage);
mScreenImage.Dispose();
}
因此,现在我在不连接屏幕捕获类的情况下拍摄了一个屏幕截图,并将此图像每40ms发送到管道。 而且我在任务管理器中看到ffmpeg.exe的内存超过1gb。 因此,难怪我的兄弟在他的PC上只有2GB RAM时会遇到问题。
如果您想知道为什么会发生异常,建议您处理在捕获中发现的任何异常。
所以代替
catch
{
result = null;
}
尝试
catch (Exception ex)
{
// log the value of ex.ToString() to a file, the screen, something.
System.IO.File.AppendAllText("debug.log",ex.ToString());
result = null;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.