开发者

C#屏幕录制中遇到黑屏问题的原因和解决方法

开发者 https://www.devze.com 2025-11-05 12:09 出处:网络 作者: 墨瑾轩
目录当屏幕录制成了"黑屏"制造机屏幕录制的"封神"三重境界第一重境界:别把屏幕录制当"黑盒"第二重境界:屏幕录制必须"有血有肉"第三重境界:C# vs 其他方案&mda
目录
  • 当屏幕录制成了"黑屏"制造机
  • 屏幕录制的"封神"三重境界
    • 第一重境界:别把屏幕录制当"黑盒"
    • 第二重境界:屏幕录制必须"有血有肉"
    • 第三重境界:C# vs 其他方案——屏幕录制的"双雄对决"
  • 尾声:屏幕录制的"封神"真谛

    别被"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, out IWMProfile profile, out IWMOutputMediaProps outProps);
            _encoder.Start();
        }
        
        public void StopRecording()
        {
            _encoder.Stop();
        }
    }
    

    为什么错?

    • 无状态_encoder 没有检查是否已启动,重复调用就崩溃
    • 无错误处理AddVideoInputMedia 可能失败,但没处理异常
    • 无资源管理_encoder 用完没释放,内存泄漏

    冷笑话:“屏幕录制不是‘黑盒’,是‘系统资源的博弈场’。

    你把黑盒当玩具,还指望它扛住1080P?”

    第二重境界:屏幕录制必须"有血有肉"

    正确实现(封神代码):

    // ✅ 正确:屏幕录制绑定资源管理,有血有肉
    public interface IScreenRecorder
    {
        void StartRecording(string outpuandroidtFilePath);
        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 outPropandroids;
            var outputProps = _encoder.AddOutputFile(outputFilePath, out profile, out outProps);
            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捕获屏幕,每帧都存
     http://www.devze.com       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 readonly int _frameRate;
        
        public GoodScreenRecorder(int frameRate = 30)
        {
            _frameRate = frameRate;
            if (!IsWindowsMediaEncoderInstalled())
                throw new InvalidOperationException("Windows Media Encoder 未安装");
        }
    
        public void StartRecording(string outputFilePath)
        {
            if (_isRecording)
                throw new InvalidOperationException("已处于录制状态");
                
            _encoder = new WMEncoder();
            
            // 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, out profile, out outProps);
            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组件就行",android是"系统资源和权限的博弈场"

    它必须:

    • 资源管理IDisposable 确保释放)
    • 状态检查(防止重复启动/停止)
    • 错误处理(每个关键步骤都检查)

    为什么你用C#屏幕录制总踩坑?

    • 你把它当"黑盒",而不是"系统资源的博弈场"。
    • 你没用IDisposable,导致内存泄漏。
    • 你没做错误检查,导致运行时崩溃。

    点睛:“屏幕录制的‘封神’,不靠代码多炫,靠的是系统资源不泄漏

    你把编码器实例写在StartRecording里,

    就像把‘为什么不能录屏’写在食堂门口——

    所有人都知道,但没人敢问。”

    最后送你一句:

    “Windows Media Encoder不是’万能的’,是’系统资源的博弈场’。

    你要是还把它当’黑盒’,

    那你的系统,就是个’内存泄漏的黑屏制造机’。”

    结语:

    今天这文,没讲"Windows Media Encoder是微软的"这种废话。

    说人话——屏幕录制不是黑盒,是系统资源的博弈场

    你要是还把它当"黑盒",

    那你的系统,就是个’内存泄漏的黑屏制造机’

    以上就是C#屏幕录制中遇到黑屏问题的原因和解决方法的详细内容,更多关于C#屏幕录制中遇到黑屏的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号