这是Form1中的代码:
namespace ScreenVideoRecorder
{
public partial class Form1 : Form
{
Magnifier20070401.MagnifierForm mf;
ScreenCapture sc;
Bitmap bitmap;
Ffmpeg ffmp;
public Form1()
{
InitializeComponent();
ffmp = new Ffmpeg();
sc = new ScreenCapture();
//bitmap = ScreenShotDemo.ScreenCapture.CaptureScreen(true);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void StartRecording_Click(object sender, EventArgs e)
{
//bitmap = ScreenShotDemo.ScreenCapture.CaptureScreen(true);
//bitmap.Save(@"c:\ffmpeg\test.bmp");
ffmp.Start("test.avi", 25);
for (int i = 0; i < 500; i++)
{
//bitmap = ScreenShotDemo.ScreenCapture.CaptureScreen(true);
bitmap = (Bitmap)sc.CaptureScreen();
ffmp.PushFrame(bitmap);
System.Threading.Thread.Sleep(35);
}
ffmp.Close();
这是我所做的ffmpeg类的代码:
using System;
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;
namespace ScreenVideoRecorder
{
class Ffmpeg
{
NamedPipeServerStream p;
String pipename = "mytestpipe";
byte[] b;
//int i, j;
System.Diagnostics.Process process;
public Ffmpeg()
{
}
public void Start(string FileName, int BitmapRate )
{
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
process = new System.Diagnostics.Process();
process.StartInfo.FileName = @"D:\pipetest\pipetest\ffmpegx86\ffmpeg.exe";
process.EnableRaisingEvents = false;
process.StartInfo.WorkingDirectory = @"D:\pipetest\pipetest\ffmpegx86";
process.StartInfo.Arguments = @"-f rawvideo -pix_fmt bgr0 -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v libx264 -r " + BitmapRate + " " + FileName;
process.Start();
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
p.WaitForConnection();
}
public void PushFrame(Bitmap bmp)
{
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);
/*for (j = 0; j < 25 * 10; j++) // put about 10 seconds of frames ( assumes 25 frames per second)
{
// put some data as rgb.. (rgb24bpp = 3 bytes per pixel)
for (i = 0; i < b.Length; i++)
{
if (((i) % 3) == 0)
b[i] = (byte)(i + j);
else
b[i] = 0;
}
p.Write(b, 0, b.Length); // send this rgb data to the pipe (ffmpeg.exe will read it..)
}*/
}
public void Close()
{
p.Close();
//process.Close();
}
}
}
这是ScreenShot的类,其中出现了内存异常。 该程序工作并且在几秒钟内没有记忆:
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
namespace ScreenShotDemo
{
/// <summary>
/// Provides functions to capture the entire screen, or a particular window, and save it to a file.
/// </summary>
public class ScreenCapture
{
/// <summary>
/// Creates an Image object containing a screen shot of the entire desktop
/// </summary>
/// <returns></returns>
public Image CaptureScreen()
{
return CaptureWindow(User32.GetDesktopWindow());
}
/// <summary>
/// Creates an Image object containing a screen shot of a specific window
/// </summary>
/// <param name="handle">The handle to the window. (In windows forms, this is obtained by the Handle property)</param>
/// <returns></returns>
public Image CaptureWindow(IntPtr handle)
{
// get te hDC of the target window
IntPtr hdcSrc = User32.GetWindowDC(handle);
// get the size
User32.RECT windowRect = new User32.RECT();
User32.GetWindowRect(handle, ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
// create a device context we can copy to
IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
// create a bitmap we can copy it to,
// using GetDeviceCaps to get the width/height
IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
// select the bitmap object
IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
// bitblt over
GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
// restore selection
GDI32.SelectObject(hdcDest, hOld);
// clean up
GDI32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
// get a .NET image object for it
Image img = Image.FromHbitmap(hBitmap);
// free up the Bitmap object
GDI32.DeleteObject(hBitmap);
return img;
}
/// <summary>
/// Captures a screen shot of a specific window, and saves it to a file
/// </summary>
/// <param name="handle"></param>
/// <param name="filename"></param>
/// <param name="format"></param>
public void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)
{
Image img = CaptureWindow(handle);
img.Save(filename, format);
}
/// <summary>
/// Captures a screen shot of the entire desktop, and saves it to a file
/// </summary>
/// <param name="filename"></param>
/// <param name="format"></param>
public void CaptureScreenToFile(string filename, ImageFormat format)
{
Image img = CaptureScreen();
img.Save(filename, format);
}
/// <summary>
/// Helper class containing Gdi32 API functions
/// </summary>
private class GDI32
{
public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
int nWidth, int nHeight, IntPtr hObjectSource,
int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
}
/// <summary>
/// Helper class containing User32 API functions
/// </summary>
private class User32
{
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
}
}
}
例外是来自ScreenCapture类的这一行:
Image img = Image.FromHbitmap(hBitmap);
这段代码在我的兄弟电脑上工作正常,但现在回到我家,我试试并得到这个例外。奇怪。
这是完整的异常错误消息:
System.OutOfMemoryException was unhandled
HResult=-2147024882
Message=Out of memory.
Source=System.Drawing
StackTrace:
at System.Drawing.Image.FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
at System.Drawing.Image.FromHbitmap(IntPtr hbitmap)
at ScreenShotDemo.ScreenCapture.CaptureWindow(IntPtr handle) in d:\C-Sharp\ScreenVideoRecorder\ScreenVideoRecorderWorkingVersion\ScreenCapture.cs:line 49
at ScreenShotDemo.ScreenCapture.CaptureScreen() in d:\C-Sharp\ScreenVideoRecorder\ScreenVideoRecorderWorkingVersion\ScreenCapture.cs:line 18
at ScreenVideoRecorder.Form1.StartRecording_Click(Object sender, EventArgs e) in d:\C-Sharp\ScreenVideoRecorder\ScreenVideoRecorderWorkingVersion\Form1.cs:line 48
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at ScreenVideoRecorder.Program.Main() in d:\C-Sharp\ScreenVideoRecorder\ScreenVideoRecorderWorkingVersion\Program.cs:line 18
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
答案 0 :(得分:4)
尝试在创建位图后释放DC参考。
// get a .NET image object for it
Image img = Image.FromHbitmap(hBitmap);
// clean up
GDI32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
修改强>
我认为你完成后需要处理位图。尝试用using
围绕它。
ffmp.Start("test.avi", 25);
for (int i = 0; i < 500; i++)
{
using(bitmap = (Bitmap)sc.CaptureScreen())
{
ffmp.PushFrame(bitmap);
System.Threading.Thread.Sleep(35);
}
}
ffmp.Close();