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

Flutter2空安全迁移后YUV转RGB出现RangeError索引越界问题

问题原因分析

这是Flutter Camera插件处理YUV420图像的常见坑,报错提示的数值错配是因为Dart跨Isolate抛出异常时的信息显示异常,实际报错不是来自Y平面的数组访问,核心原因有3个:

  • 索引计算逻辑没有考虑YUV平面的行步长:绝大多数安卓设备为了内存对齐,Camera输出的YUV420图像每个平面的bytesPerRow(每行实际字节数)会大于图像的width,你之前用h * width + w计算Y分量索引的逻辑,仅在行步长等于宽度时有效,一旦行步长更大就会出现越界。
  • 异常信息错位:你看到的报错里的index 10实际是U/V平面的访问索引,U/V平面的总长度仅为Y平面的1/4左右,错误提示里的上限值345600是Y平面的长度,Dart跨Isolate传递异常时错误复用了之前的长度参数,才出现了看起来逻辑矛盾的提示。
  • 跨Isolate传递CameraImage导致数据损坏:CameraImage是绑定原生内存的对象,直接通过Isolate端口传递时,字节数组的视图会被截断或偏移,导致实际可用长度远小于预期值。

修复方案

1. 修正索引计算逻辑,增加边界校验

调整Y分量索引的计算方式,同时访问每个平面前先校验索引合法性,避免越界:

static imageLib.Image convertYUV420ToImage(CameraImage cameraImage) {
  final int width = cameraImage.width;
  final int height = cameraImage.height;

  final yPlane = cameraImage.planes[0];
  final uPlane = cameraImage.planes[1];
  final vPlane = cameraImage.planes[2];

  final int yRowStride = yPlane.bytesPerRow;
  final int uvRowStride = uPlane.bytesPerRow;
  final int? uvPixelStride = uPlane.bytesPerPixel;

  final image = imageLib.Image(width, height);

  // 外层循环遍历高度,内存访问更连续,性能更好
  for (int h = 0; h < height; h++) {
    for (int w = 0; w < width; w++) {
      // 用Y平面行步长计算Y分量索引
      final int yIndex = h * yRowStride + w;
      if (yIndex >= yPlane.bytes.length) continue;
      final y = yPlane.bytes[yIndex];

      final int uvIndex = uvPixelStride! * (w ~/ 2) + uvRowStride * (h ~/ 2);
      if (uvIndex >= uPlane.bytes.length || uvIndex >= vPlane.bytes.length) continue;
      final u = uPlane.bytes[uvIndex];
      final v = vPlane.bytes[uvIndex];

      final int pixelIndex = h * width + w;
      if (pixelIndex >= image.data.length) continue;
      image.data[pixelIndex] = ImageUtils.yuv2rgb(y, u, v);
    }
  }
  return image;
}

2. 修正Isolate传参逻辑

不要直接传递CameraImage对象,把需要的基础数据和字节数组打包成Map传递,避免原生对象序列化异常:

// 发送到Isolate前的打包逻辑
Map<String, dynamic> imageParams = {
  'yBytes': cameraImage.planes[0].bytes,
  'uBytes': cameraImage.planes[1].bytes,
  'vBytes': cameraImage.planes[2].bytes,
  'width': cameraImage.width,
  'height': cameraImage.height,
  'yRowStride': cameraImage.planes[0].bytesPerRow,
  'uvRowStride': cameraImage.planes[1].bytesPerRow,
  'uvPixelStride': cameraImage.planes[1].bytesPerPixel,
};

Isolate内部直接使用打包的参数处理图像即可,不需要再依赖CameraImage对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 20:12:02