别被"Windows Media Encoder"这种高大上名字忽悠了!
 今天咱不讲"如何用COM组件",
聊C#屏幕录制这种"祖传代码坟场"里,为啥总在"黑屏"边缘摇摇欲坠。
 (别急,看完这篇,你就能把屏幕录制"封神",而不是让测试妹子半夜被"黑屏"报警叫醒) 
	 
	当屏幕录制成了"黑屏"制造机 
	
		“用C#写了个屏幕录制功能,结果测试妹子一试,全是黑屏。”
 —— 某公司后端开发在茶水间吐血的原话 
	
	技术老炮儿的血泪史: 
	去年我接手一个教育平台的录屏功能,用C#写的。
为啥?
 因为团队觉得"Windows Media Encoder是微软的,肯定靠谱"。
 结果呢? 
	- 
		代码里全是WMEncoder,但一运行就是黑屏 
	
- 
		一录屏CPU飙到100%,用户直接投诉"卡成PPT" 
	
- 
		本地能录,但部署到服务器就报错"权限不足" 
	
- 
		一次性能优化,从"流畅录制"变成"卡顿到想砸键盘",
 测试妹子半夜被报警叫醒,产品经理发来"在吗?录屏崩了?"
	这不是C#的错,是设计的错。 
	今天,咱们就撕开屏幕录制的真相——
它不是"随便调个COM组件就行",而是"系统资源和权限的博弈场"。 
	 
	屏幕录制的"封神"三重境界 
	 
	第一重境界:别把屏幕录制当"黑盒" 
	错误示范(血泪代码): 
	
		// 错误:屏幕录制成了"黑盒",无状态、无错误处理 
	
	
		using WMEncLib;// 引用Windows Media Encoder  
	
	
		public class ScreenRecorder 
	
	
		{ 
	
	
		    private WMEncoder _encoder;      
	
	
		    public void StartRecording(string outputFilePath) 
	
	
		    { 
	
	
		        _encoder =new WMEncoder(); 
	
	
		        _encoder.AddVideoInputMedia(new WMVidSource(), 0, 0);// 没有检查输入源 
	
	
		        _encoder.AddOutputFile(outputFilePath,outIWMProfile profile,out IWMOutput MediaProps out Props); 
	
	
		        _encoder.Start(); 
	
	
		    }      
	
	
		    public void StopRecording() 
	
	
		    { 
	
	
		        _encoder.Stop(); 
	
	
		    } 
	
	
		} 
	
 
	为什么错? 
	- 
		无状态:_encoder 没有检查是否已启动,重复调用就崩溃 
	
- 
		无错误处理:AddVideoInputMedia 可能失败,但没处理异常 
	
- 
		无资源管理:_encoder 用完没释放,内存泄漏 
	
	
		冷笑话:“屏幕录制不是‘黑盒’,是‘系统资源的博弈场’。
 你把黑盒当玩具,还指望它扛住1080P?” 
	
	 
	第二重境界:屏幕录制必须"有血有肉" 
	正确实现(封神代码): 
	
		// 正确:屏幕录制绑定资源管理,有血有肉 
	
	
		public interface IScreenRecorder 
	
	
		{ 
	
	
		    void StartRecording(string outputFilePath); 
	
	
		    void StopRecording(); 
	
	
		}  
	
	
		public class ScreenRecorder : IScreenRecorder, IDisposable 
	
	
		{ 
	
	
		    private WMEncoder _encoder; 
	
	
		    private bool _isRecording;      
	
	
		    public ScreenRecorder() 
	
	
		    { 
	
	
		        // 1. 初始化时检查依赖 
	
	
		        if(!IsWindowsMediaEncoderInstalled()) 
	
	
		            throw new InvalidOperationException("Windows Media Encoder 未安装"); 
	
	
		    }  
	
	
		    public void StartRecording(string outputFilePath) 
	
	
		    { 
	
	
		        // 1. 检查是否已在录制 
	
	
		        if(_isRecording) 
	
	
		            throw new InvalidOperationException("已处于录制状态");              
	
	
		        // 2. 创建编码器实例 
	
	
		        _encoder =new WMEncoder();          
	
	
		        // 3. 配置输入源(屏幕捕获) 
	
	
		        var inputProps = _encoder.AddVideoInputMedia(new WMVidSource(), 0, 0); 
	
	
		        if(inputProps ==null) 
	
	
		            throw new Exception("无法添加视频输入源");              
	
	
		        // 4. 配置输出文件 
	
	
		        IWMProfile profile; 
	
	
		        IWMOutputMediaProps outProps; 
	
	
		        var outputProps = _encoder.AddOutputFile(outputFilePath,outprofile,outoutProps); 
	
	
		        if(outputProps ==null) 
	
	
		            throw new Exception("无法添加输出文件");              
	
	
		        // 5. 启动录制 
	
	
		        _encoder.Start(); 
	
	
		        _isRecording =true; 
	
	
		    }  
	
	
		    public void StopRecording() 
	
	
		    { 
	
	
		        if(!_isRecording) 
	
	
		            throw new InvalidOperationException("当前未处于录制状态");              
	
	
		        _encoder.Stop(); 
	
	
		        _isRecording =false; 
	
	
		        _encoder.Dispose();// 释放资源,避免内存泄漏 
	
	
		    }  
	
	
		    public void Dispose() 
	
	
		    { 
	
	
		        if(_encoder !=null) 
	
	
		        { 
	
	
		            _encoder.Dispose(); 
	
	
		            _encoder =null; 
	
	
		        } 
	
	
		    }  
	
	
		    private bool IsWindowsMediaEncoderInstalled() 
	
	
		    { 
	
	
		        // 检查Windows Media Encoder是否安装 
	
	
		        try 
	
	
		        { 
	
	
		            var encoder =new WMEncoder(); 
	
	
		            return true; 
	
	
		        } 
	
	
		        catch 
	
	
		        { 
	
	
		            return false; 
	
	
		        } 
	
	
		    } 
	
	
		} 
	
 
	为什么对? 
	- 
		资源管理:IDisposable 确保 _encoder 被正确释放 
	
- 
		状态检查:_isRecording 防止重复启动/停止 
	
- 
		错误处理:每个关键步骤都有异常检查 
	
	
		吐槽:“你把屏幕录制写成’黑盒’,
 就像让外卖小哥自己去超市买菜——
‘我来录屏了,别问为什么,问就是系统要求’。” 
	
	 
	第三重境界:C# vs 其他方案——屏幕录制的"双雄对决" 
	错误对比(血泪现场): 
	
		// 错误:C#屏幕录制,性能差,无错误处理 
	
	
		public class BadScreenRecorder 
	
	
		{ 
	
	
		    public void RecordScreen(string outputPath) 
	
	
		    { 
	
	
		        // 1. 用System.Drawing捕获屏幕,每帧都存 
	
	
		        for(int i = 0; i < 30; i++) 
	
	
		        { 
	
	
		            var bitmap =new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); 
	
	
		            using(var g = Graphics.FromImage(bitmap)) 
	
	
		            { 
	
	
		                g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size); 
	
	
		            } 
	
	
		            bitmap.Save($"frame{i}.bmp"); 
	
	
		        }          
	
	
		        // 2. 无编码,直接存BMP,文件巨大 
	
	
		    } 
	
	
		} 
	
 
	正确对比(C#企业级架构): 
	
		// 正确:C#屏幕录制,性能优,有错误处理 
	
	
		public class GoodScreenRecorder : IScreenRecorder, IDisposable 
	
	
		{ 
	
	
		    private WMEncoder _encoder; 
	
	
		    private bool _isRecording; 
	
	
		    private readonlyint_frameRate;      
	
	
		    public GoodScreenRecorder(intframeRate = 30) 
	
	
		    { 
	
	
		        _frameRate = frameRate; 
	
	
		        if(!IsWindowsMediaEncoderInstalled()) 
	
	
		            throw new InvalidOperationException("Windows Media Encoder 未安装"); 
	
	
		    }  
	
	
		    public void StartRecording(string outputFilePath) 
	
	
		    { 
	
	
		        if(_isRecording) 
	
	
		            throw new InvalidOperationException("已处于录制状态");              
	
	
		        _encoder =newWMEncoder();          
	
	
		        // 1. 配置输入源(屏幕捕获) 
	
	
		        var inputProps = _encoder.AddVideoInputMedia(new WMVidSource(), 0, 0); 
	
	
		        if(inputProps ==null) 
	
	
		            throw new Exception("无法添加视频输入源");              
	
	
		        // 2. 配置输出文件(WMV格式,压缩) 
	
	
		        IWMProfile profile; 
	
	
		        IWMOutputMediaProps outProps; 
	
	
		        var outputProps = _encoder.AddOutputFile(outputFilePath,outprofile,outoutProps); 
	
	
		        if(outputProps ==null) 
	
	
		            throw new Exception("无法添加输出文件");              
	
	
		        // 3. 配置编码参数(性能优化) 
	
	
		        _encoder.SetVideoBitrate(1000000);// 1Mbps 
	
	
		        _encoder.SetFrameRate(_frameRate);          
	
	
		        _encoder.Start(); 
	
	
		        _isRecording =true; 
	
	
		    }  
	
	
		    public void StopRecording() 
	
	
		    { 
	
	
		        if(!_isRecording) 
	
	
		            throw new InvalidOperationException("当前未处于录制状态");              
	
	
		        _encoder.Stop(); 
	
	
		        _isRecording =false; 
	
	
		        _encoder.Dispose(); 
	
	
		    }  
	
	
		    public void Dispose() 
	
	
		    { 
	
	
		        if(_encoder !=null) 
	
	
		        { 
	
	
		            _encoder.Dispose(); 
	
	
		            _encoder =null; 
	
	
		        } 
	
	
		    } 
	
	
		} 
	
 
	为什么C#胜出? 
	
		
			| 维度 | C# (Windows Media Encoder) | C# (System.Drawing) | 
	
	
		
			| 性能 | 编码优化,CPU占用低 | 每帧存BMP,CPU占用高 | 
		
			| 文件大小 | WMV格式压缩,文件小 | BMP格式,文件巨大 | 
		
			| 错误处理 | 详细异常检查 | 无错误处理 | 
		
			| 资源管理 | IDisposable | 无资源管理 | 
		
			| 企业级 | 适合生产环境 | 仅适合演示 | 
	
	
		自黑:
 “当年我也这么干过,用System.Drawing录屏,
 结果录个10分钟视频,文件10GB,
测试妹子问:‘为什么录屏文件这么大?’
 我:‘因为每帧都存成BMP啊兄弟,它没压缩。’” 
	
	 
	尾声:屏幕录制的"封神"真谛 
	屏幕录制不是"随便调个COM组件就行",是"系统资源和权限的博弈场"。
 它必须: 
	- 
		资源管理(IDisposable 确保释放) 
	
- 
		状态检查(防止重复启动/停止) 
	
- 
		错误处理(每个关键步骤都检查) 
	
	为什么你用C#屏幕录制总踩坑? 
	- 
		你把它当"黑盒",而不是"系统资源的博弈场"。 
	
- 
		你没用IDisposable,导致内存泄漏。 
	
- 
		你没做错误检查,导致运行时崩溃。 
	
	点睛:“屏幕录制的‘封神’,不靠代码多炫,靠的是系统资源不泄漏。
 你把编码器实例写在StartRecording里,
 就像把‘为什么不能录屏’写在食堂门口——
所有人都知道,但没人敢问。” 
	最后送你一句: 
	
		“Windows Media Encoder不是’万能的’,是’系统资源的博弈场’。
 你要是还把它当’黑盒’,
那你的系统,就是个’内存泄漏的黑屏制造机’。” 
	
	结语: 
	
		今天这文,没讲"Windows Media Encoder是微软的"这种废话。
 说人话——屏幕录制不是黑盒,是系统资源的博弈场。
 你要是还把它当"黑盒",
那你的系统,就是个’内存泄漏的黑屏制造机’。 
	
	以上就是C#屏幕录制中遇到黑屏问题的原因和解决方法的详细内容,更多关于C#屏幕录制中遇到黑屏的资料请关注脚本之家其它相关文章! 
	来源:https://www.jb51.net/program/352064uzg.htm