prepareCameraFrame function

CameraFrame? prepareCameraFrame({
  1. required int width,
  2. required int height,
  3. required List<CameraPlane> planes,
  4. CameraFrameRotation? rotation,
  5. bool isBgra = true,
})

Prepare a CameraFrame descriptor from raw camera planes, for use with a detector package's detectFromCameraFrame(...) method.

Auto-detects the layout based on plane count and pixel stride:

  • 1 plane, pixelStride >= 4 -> packed BGRA (or RGBA if isBgra is false). The planes buffer is referenced directly; no copy.
  • 2 planes -> NV12. Repacked tightly via packYuv420.
  • 3 planes -> NV21 or I420 (auto-detected from U pixel stride). Repacked tightly via packYuv420.

Returns null for unsupported shapes (empty planes, missing U plane for YUV, odd width/height for YUV420).

isBgra selects BGRA (macOS, default) vs. RGBA (Linux) for the desktop single-plane path; it is ignored for YUV input.

Typical usage:

camera.startImageStream((CameraImage image) async {
  final frame = prepareCameraFrame(
    width: image.width,
    height: image.height,
    planes: [
      for (final p in image.planes)
        (bytes: p.bytes, rowStride: p.bytesPerRow,
         pixelStride: p.bytesPerPixel ?? 1),
    ],
  );
  if (frame == null) return;
  final faces = await detector.detectFacesFromCameraFrame(frame);
});

Implementation

CameraFrame? prepareCameraFrame({
  required int width,
  required int height,
  required List<CameraPlane> planes,
  CameraFrameRotation? rotation,
  bool isBgra = true,
}) {
  if (planes.isEmpty) return null;

  // Desktop single-plane 4-channel BGRA/RGBA.
  if (planes.length == 1 && planes[0].pixelStride >= 4) {
    final p = planes[0];
    return CameraFrame(
      bytes: p.bytes,
      width: width,
      height: height,
      strideCols: p.rowStride ~/ 4,
      conversion: isBgra
          ? CameraFrameConversion.bgra2bgr
          : CameraFrameConversion.rgba2bgr,
      rotation: rotation,
    );
  }

  // YUV420 (2 planes for NV12, 3 for NV21 or I420).
  if (planes.length < 2) return null;
  final y = planes[0];
  final u = planes[1];
  final v = planes.length > 2 ? planes[2] : null;

  final packed = packYuv420(width: width, height: height, y: y, u: u, v: v);
  if (packed == null) return null;

  return CameraFrame(
    bytes: packed.bytes,
    width: packed.width,
    height: packed.height,
    strideCols: packed.width,
    conversion: switch (packed.layout) {
      YuvLayout.nv12 => CameraFrameConversion.yuv2bgrNv12,
      YuvLayout.nv21 => CameraFrameConversion.yuv2bgrNv21,
      YuvLayout.i420 => CameraFrameConversion.yuv2bgrI420,
    },
    rotation: rotation,
  );
}