在Avalonia(wpf应该原理一样)中怎么快速的把视频或者画面渲染到image
传统的方法比较多,很多是重新生成一个Bitmap再赋值,其实这步可以略做简化。
public static void DrawImage(this Avalonia.Controls.Image uiimg, Image<Rgb24> imageSharpImage) { //首先要用到他的tag对象 var width = imageSharpImage.Width; var height = imageSharpImage.Height; WriteableBitmap wbmp = null; if (uiimg.Tag is WriteableBitmap oldwbmp) { //如果宽高不等,就重新创建 if (oldwbmp.PixelSize.Width != width || oldwbmp.PixelSize.Height != height) { uiimg.Source = null; oldwbmp.Dispose(); uiimg.Tag = null; wbmp = new WriteableBitmap(new PixelSize(width, height), new Vector(96, 96), PixelFormat.Rgba8888, AlphaFormat.Premul); uiimg.Tag = wbmp; uiimg.Source = wbmp; } else { //否则直接赋值 wbmp = oldwbmp; } } else { //没有也是重新创建 wbmp = new WriteableBitmap(new PixelSize(width, height), new Vector(96, 96), PixelFormat.Rgba8888, AlphaFormat.Premul); uiimg.Tag = wbmp; uiimg.Source = wbmp; } using var rgba32img = imageSharpImage.CloneAs<Rgba32>(); if (rgba32img.DangerousTryGetSinglePixelMemory(out var memory)) { // 3. 锁住内存,直接进行内存块高速拷贝(零解码开销) using (var handle = memory.Pin()) using (var lockedBuffer = wbmp.Lock()) { unsafe { long totalBytes = width * height * 4; // 使用 Buffer.MemoryCopy 高速复制内存 Buffer.MemoryCopy(handle.Pointer, (void*)lockedBuffer.Address, totalBytes, totalBytes); } } uiimg.InvalidateVisual(); } else { Log.Error("无法获取 ImageSharp 的连续内存缓冲区。"); } }
代码比较简单,使用rgb8888是因为写代码相对简单,否复制的时候得考虑更多的东西,这样做还有个前提是sixlabor的image需要连续,这个可以在启动的时候
Configuration.Default.PreferContiguousImageBuffers = true; 进行配置。
wpf应该也差不多。当时还想到用两个writeablebitmap进行swap,avalonia可以在其他线程渲染好bitmap,再到前台线程赋值 给image,按理也是可以的。
最后:没有实测效率和内存占用。
浙公网安备 33010602011771号