基于C#實(shí)現(xiàn)的高性能實(shí)時(shí)MP4錄屏方案
一、技術(shù)選型對(duì)比
| 方案 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場(chǎng)景 |
|---|---|---|---|
| GDI截圖+FFmpeg | 實(shí)現(xiàn)簡(jiǎn)單,兼容性強(qiáng) | CPU占用高(約30%-50%) | 低分辨率/非實(shí)時(shí)場(chǎng)景 |
| DXGI捕獲+MediaFoundation | 高性能(GPU加速),低CPU占用 | 開發(fā)復(fù)雜度高,需處理幀同步問(wèn)題 | 高幀率(60fps)/4K錄制 |
| SharpDX/D3D11 | 支持DirectX加速,畫質(zhì)最佳 | 需要DirectX開發(fā)經(jīng)驗(yàn) | 游戲直播/專業(yè)視頻制作 |
二、推薦實(shí)現(xiàn)方案(DXGI + MediaFoundation)
1. 核心代碼結(jié)構(gòu)
// 初始化捕獲設(shè)備
var factory = new SharpDX.Direct3D11.DeviceFactory();
var adapter = factory.GetAdapter1(0);
var device = new SharpDX.Direct3D11.Device(adapter);
// 創(chuàng)建DXGI輸出
var output = adapter.GetOutput(0);
var output1 = output.QueryInterface<SharpDX.DXGI.Output1>();
var duplication = output1.DuplicateOutput(device);
// 配置視頻編碼參數(shù)
var mediaType = new MediaFoundationEncoder.VideoMediaType(
width: 1920,
height: 1080,
frameRate: 30,
pixelFormat: SharpDX.WIC.PixelFormat.Format32bppBGRA,
codec: MediaFoundationEncoder.Codec.H264,
bitrate: 5000000 // 5Mbps
);
// 創(chuàng)建編碼器
var encoder = new MediaFoundationEncoder(mediaType);
encoder.StartEncoding("output.mp4");
// 錄制循環(huán)
while (isRecording)
{
var frame = duplication.AcquireNextFrame(1000);
var texture = frame.DesktopImage;
// 轉(zhuǎn)換為MediaFoundation可處理格式
using (var stream = new MemoryStream())
{
texture.CopyTo(stream);
encoder.EncodeFrame(stream.ToArray());
}
frame.Release();
}
2. 關(guān)鍵優(yōu)化點(diǎn)
- GPU加速編碼:使用MediaFoundation的硬件編碼(如NVIDIA NVENC),CPU占用可降低至5%以下
- 內(nèi)存映射文件:通過(guò)
MemoryMappedFile實(shí)現(xiàn)零拷貝寫入,提升IO性能 - 幀率控制:動(dòng)態(tài)調(diào)整捕獲間隔,避免丟幀或卡頓
// 自適應(yīng)幀率控制
var targetFrameTime = 1000 / targetFPS;
var lastFrameTime = Stopwatch.StartNew();
while (isRecording)
{
var frameTime = lastFrameTime.ElapsedMilliseconds;
if (frameTime >= targetFrameTime)
{
// 捕獲并編碼幀
lastFrameTime.Restart();
}
else
{
Thread.Sleep(targetFrameTime - (int)frameTime);
}
}
三、分段保存實(shí)現(xiàn)
// 自動(dòng)分段保存邏輯
private void CheckSegment()
{
if (encoder.TotalDuration >= _segmentDuration)
{
encoder.StopEncoding();
string newPath = GenerateSegmentPath();
encoder.StartEncoding(newPath);
}
}
// 文件名生成策略
private string GenerateSegmentPath()
{
var now = DateTime.Now;
return $"recording_{now:yyyyMMdd_HHmmss}_{Guid.NewGuid():N}.mp4";
}
四、完整實(shí)現(xiàn)步驟
1. 環(huán)境配置
<!-- NuGet依賴 --> <PackageReference Include="SharpDX" Version="4.3.0" /> <PackageReference Include="MediaFoundationEncoder" Version="1.2.0" />
2. 界面設(shè)計(jì)(WinForm)
<!-- 主窗體布局 -->
<DockPanel>
<StatusBar DockPanel.Dock="Bottom">
<TextBlock Text="{Binding Status}"/>
<TextBlock Text="{Binding FPS} FPS"/>
</StatusBar>
<Button Content="開始錄制" Command="{Binding StartCommand}"/>
<Button Content="停止錄制" Command="{Binding StopCommand}"/>
<Slider Minimum="1" Maximum="60" Value="{Binding FrameRate}" Width="200"/>
</DockPanel>
3. ViewModel實(shí)現(xiàn)
public class MainViewModel : INotifyPropertyChanged
{
private bool _isRecording;
private int _frameRate = 30;
private long _totalFrames;
public ICommand StartCommand => new RelayCommand(StartRecording);
public ICommand StopCommand => new RelayCommand(StopRecording);
public string Status => _isRecording ? "錄制中..." : "空閑";
public int FPS => (int)(_totalFrames / (Stopwatch.GetTimestamp() / 1e7));
private void StartRecording()
{
_isRecording = true;
_totalFrames = 0;
Task.Run(() =>
{
using (var recorder = new MediaRecorder())
{
recorder.Start(_frameRate);
while (_isRecording)
{
var frame = CaptureFrame();
recorder.Encode(frame);
_totalFrames++;
}
recorder.Stop();
}
});
}
private void StopRecording()
{
_isRecording = false;
}
}
五、性能優(yōu)化方案
1. 內(nèi)存管理
- 對(duì)象池:重用
Texture2D和MemoryStream對(duì)象
public class FramePool
{
private readonly Queue<Texture2D> _pool = new();
public Texture2D GetFrame(int width, int height)
{
return _pool.Count > 0 ? _pool.Dequeue() : new Texture2D(device, width, height);
}
public void ReturnFrame(Texture2D frame)
{
frame.Dispose();
}
}
2. 多線程處理
// 生產(chǎn)者-消費(fèi)者模型
BlockingCollection<Bitmap> _frameQueue = new();
Task.Run(() => EncodeWorker());
void EncodeWorker()
{
foreach (var frame in _frameQueue.GetConsumingEnumerable())
{
// 編碼處理
}
}
3. GPU內(nèi)存優(yōu)化
// 使用DX12的顯存直接訪問(wèn) var commandAllocator = new CommandAllocator(device, CommandListType.Copy); var commandList = new CommandList(device, commandAllocator); commandList.CopyBufferRegion(stagingBuffer, 0, gpuBuffer, 0, dataSize); commandAllocator.Reset(); commandList.Reset(commandAllocator, null);
六、擴(kuò)展功能實(shí)現(xiàn)
1. 鼠標(biāo)點(diǎn)擊高亮
// 在捕獲幀時(shí)疊加點(diǎn)擊標(biāo)記
void DrawClickMarker(Graphics g, Point position)
{
using (var pen = new Pen(Color.Red, 2))
{
g.DrawEllipse(pen, position.X - 5, position.Y - 5, 10, 10);
}
}
2. 音頻同步錄制
// 使用NAudio捕獲系統(tǒng)音頻
using (var waveIn = new WaveInEvent())
{
waveIn.DataAvailable += (s, e) =>
{
audioBuffer.Write(e.Buffer, 0, e.BytesRecorded);
};
waveIn.StartRecording();
}
七、測(cè)試與調(diào)試
1. 性能監(jiān)控
// 實(shí)時(shí)顯示資源占用
public class PerformanceMonitor
{
private readonly PerformanceCounter _cpuCounter = new("Processor", "% Processor Time", "_Total");
private readonly PerformanceCounter _ramCounter = new("Memory", "Available MBytes");
public string GetStatus()
{
return $"CPU: {_cpuCounter.NextValue()}% 內(nèi)存: {_ramCounter.NextValue()}MB";
}
}
2. 日志系統(tǒng)
public static class Logger
{
private static readonly RollingFileAppender _appender = new();
static Logger()
{
_appender.File = "log.txt";
_appender.Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline");
_appender.ActivateOptions();
}
public static void Log(string message)
{
_appender.DoAppend(new LoggingEvent(new LoggingEventData {
Message = message,
TimeStamp = DateTime.Now
}));
}
}
八、部署建議
安裝依賴
- 安裝Microsoft Visual C++ 2015-2022 Redistributable
- 部署FFmpeg動(dòng)態(tài)庫(kù)(ffmpeg.dll, avcodec-58.dll等)
代碼簽名
# 使用signtool進(jìn)行數(shù)字簽名 signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 MyApp.exe
安裝包制作
<!-- WiX安裝配置 -->
<Component Id="MainComponent" Guid="*">
<File Id="MainExe" Name="MyApp.exe" Source="..\bin\Release\MyApp.exe"/>
<RegistryValue Root="HKLM" Key="Software\MyCompany\MyApp"
Name="InstallDir" Value="[INSTALLDIR]" Type="string"/>
</Component>
參考代碼 C#實(shí)時(shí)錄屏軟件 MP4格式 www.youwenfan.com/contentcsr/93565.html
九、方案對(duì)比與選擇
| 場(chǎng)景 | 推薦方案 | 理由 |
|---|---|---|
| 企業(yè)級(jí)會(huì)議錄制 | MediaFoundation+DXGI | 低延遲,支持多路流輸入 |
| 游戲直播 | SharpDX+NVENC硬件編碼 | 最高支持8K 60fps,極致性能 |
| 簡(jiǎn)單錄屏工具 | GDI+FFmpeg命令行 | 開發(fā)周期短,維護(hù)成本低 |
| 跨平臺(tái)錄制 | AValon+FFmpeg.AutoGen | 支持Windows/macOS/Linux |
十、常見問(wèn)題解決方案
黑屏問(wèn)題
- 檢查DXGI輸出是否正確初始化
- 確保以管理員權(quán)限運(yùn)行程序
音頻不同步
- 設(shè)置
AVSyncMode.AudioMaster同步模式 - 添加音頻緩沖隊(duì)列(建議500ms)
文件損壞
mediaType.FFmpegOptions.Add("movflags", "faststart");
- 啟用
moov atom前置(快速啟動(dòng))
通過(guò)上述方案,可實(shí)現(xiàn)專業(yè)級(jí)的實(shí)時(shí)MP4錄屏軟件。開發(fā)者可根據(jù)具體需求選擇基礎(chǔ)方案或深度定制,建議優(yōu)先測(cè)試硬件加速編碼路徑以獲得最佳性能。
以上就是基于C#實(shí)現(xiàn)的高性能實(shí)時(shí)MP4錄屏方案的詳細(xì)內(nèi)容,更多關(guān)于C#實(shí)時(shí)MP4錄屏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C# WinForms控件拖動(dòng)實(shí)現(xiàn)技巧
C# Windows Forms中實(shí)現(xiàn)控件拖動(dòng)功能,主要依賴于MouseDown、MouseMove和MouseUp事件,通過(guò)精確的坐標(biāo)計(jì)算和狀態(tài)管理,實(shí)現(xiàn)流暢的控件拖動(dòng)體驗(yàn),下面就來(lái)詳細(xì)的介紹一下2026-03-03
C# Lambda表達(dá)式及Lambda表達(dá)式樹的創(chuàng)建過(guò)程
這篇文章主要介紹了C# Lambda表達(dá)式及Lambda表達(dá)式樹的創(chuàng)建過(guò)程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
C#實(shí)現(xiàn)合并多張圖片為GIF動(dòng)態(tài)圖
這篇文章主要為大家詳細(xì)介紹了C#如何將把一張又一張的圖片去拼合成一張GIF動(dòng)態(tài)圖片,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-12-12
C#在復(fù)雜多線程環(huán)境下使用讀寫鎖同步寫入文件
這篇文章介紹了C#在復(fù)雜多線程環(huán)境下使用讀寫鎖同步寫入文件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04

