You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MAUI中如何将YUV/RGB格式byte[]绘制到视图?

在MAUI中绘制YUV/RGB格式的byte[]到视图

要直接绘制YUV/RGB格式的byte[]到MAUI视图,你可以基于SkiaSharp和Microsoft.Maui.Graphics.Skia实现,核心思路是通过SKBitmap直接操作像素缓冲区,再将其转换为MAUI Graphics可用的IImage,并确保帧更新后触发视图重绘。

你的代码存在的关键问题

  1. SkiaImage基于SKBitmap创建后,SKBitmap的像素更新不会自动同步到SkiaImage,导致绘制的始终是初始帧
  2. 未在帧更新后触发GraphicsView的重绘操作,新帧无法显示
  3. 像素格式可能不匹配(比如你用了Rgb888x但转成了RGBA数据)

修正后的实现代码

using Microsoft.Maui.Graphics.Skia;
using SkiaSharp;

namespace MauiSample
{
    internal class VideoDrawable : IDrawable, IDisposable
    {
        private SKBitmap? _skBitmap;
        private IImage? _mauiImage;
        private uint _currentWidth;
        private uint _currentHeight;
        private readonly GraphicsView _graphicsView;

        // 传入关联的GraphicsView,用于触发重绘
        public VideoDrawable(GraphicsView graphicsView)
        {
            _graphicsView = graphicsView;
        }

        public void Draw(ICanvas canvas, RectF dirtyRect)
        {
            if (_mauiImage == null) return;
            
            // 按视图尺寸缩放绘制
            canvas.DrawImage(_mauiImage, 0, 0, dirtyRect.Width, dirtyRect.Height);
        }

        private void EnsureBitmap(uint width, uint height)
        {
            if (_currentWidth == width && _currentHeight == height && _skBitmap != null)
                return;

            _currentWidth = width;
            _currentHeight = height;

            // 释放旧资源
            _skBitmap?.Dispose();
            _mauiImage?.Dispose();

            // 创建匹配RGBA8888格式的Bitmap(对应YUV转RGBA后的4字节像素)
            _skBitmap = new SKBitmap((int)width, (int)height, SKColorType.Rgba8888, SKAlphaType.Premul);
            _mauiImage = new SkiaImage(_skBitmap);
        }

        public void UpdateVideoFrame(byte[] yuvFrame, uint width, uint height)
        {
            EnsureBitmap(width, height);
            if (_skBitmap == null) return;

            // 将YUV转换为RGBA像素
            byte[] rgbaPixels = new byte[width * height * 4];
            VideoFrameConverter.YUV2RGBA(yuvFrame, rgbaPixels, width, height);

            // 将像素数据写入SKBitmap
            unsafe
            {
                fixed (byte* ptr = rgbaPixels)
                {
                    _skBitmap.SetPixels((nint)ptr);
                }
            }

            // 触发GraphicsView重绘,显示新帧
            _graphicsView.Invalidate();
        }

        #region IDisposable实现
        private bool _disposed;

        ~VideoDrawable() => Dispose(false);

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed) return;

            if (disposing)
            {
                _skBitmap?.Dispose();
                _mauiImage?.Dispose();
            }

            _disposed = true;
        }
        #endregion
    }
}

使用方式

在你的MAUI页面中:

  1. 添加GraphicsView控件:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiSample.VideoPage">
    <GraphicsView x:Name="VideoGraphicsView" />
</ContentPage>
  1. 在后台代码中初始化Drawable并绑定:
public VideoPage()
{
    InitializeComponent();
    var videoDrawable = new VideoDrawable(VideoGraphicsView);
    VideoGraphicsView.Drawable = videoDrawable;

    // 假设你从某个回调中获取YUV帧数据
    // 示例:当收到帧时调用
    // videoDrawable.UpdateVideoFrame(yuvFrameData, frameWidth, frameHeight);
}

注意事项

  • 确保VideoFrameConverter.YUV2RGBA方法输出的像素格式与SKBitmap创建时的SKColorType.Rgba8888完全匹配,否则会出现画面失真或乱码
  • 频繁更新帧时,建议在后台线程处理YUV转RGBA的操作,避免阻塞UI线程
  • 对于不同的YUV格式(如NV12、YUV420P等),需要确保转换逻辑正确对应

内容的提问来源于stack exchange,提问作者Cade Huang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:09:29