XRCameraImagePlane plane = image.GetPlane(0);               // use the Y plane
#else
        public static void GetPlaneDataFast(ref IntPtr pixels, XRCpuImage image)
        {
            XRCpuImage.Plane plane = image.GetPlane(0);                 // use the Y plane
#endif
            int width = image.width, height = image.height;

            if (width == plane.rowStride)
            {
                unsafe
                {
                    pixels = (IntPtr)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(plane.data);
                }
            }
            else
            {
                unsafe
                {
                    ulong  handle;
                    byte[] data   = new byte[width * height];
                    byte * srcPtr = (byte *)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(plane.data);
                    byte * dstPtr = (byte *)UnsafeUtility.PinGCArrayAndGetDataAddress(data, out handle);
                    if (width > 0 && height > 0)
                    {
                        UnsafeUtility.MemCpyStride(dstPtr, width, srcPtr, plane.rowStride, width, height);
                    }
                    pixels = (IntPtr)dstPtr;
                    UnsafeUtility.ReleaseGCObject(handle);
                }
            }
        }
            XRCameraImagePlane plane = image.GetPlane(0);               // use the Y plane
#else
        public static void GetPlaneData(out byte[] pixels, XRCpuImage image)
        {
            XRCpuImage.Plane plane = image.GetPlane(0);                 // use the Y plane
#endif
            int width = image.width, height = image.height;

            pixels = new byte[width * height];

            if (width == plane.rowStride)
            {
                plane.data.CopyTo(pixels);
            }
            else
            {
                unsafe
                {
                    ulong handle;
                    byte *srcPtr = (byte *)NativeArrayUnsafeUtility.GetUnsafePtr(plane.data);
                    byte *dstPtr = (byte *)UnsafeUtility.PinGCArrayAndGetDataAddress(pixels, out handle);
                    if (width > 0 && height > 0)
                    {
                        UnsafeUtility.MemCpyStride(dstPtr, width, srcPtr, plane.rowStride, width, height);
                    }
                    UnsafeUtility.ReleaseGCObject(handle);
                }
            }
        }
    /// <summary>
    /// Converts a new CPU image into byte buffers and caches to be accessed later.
    /// </summary>
    /// <param name="image">The new CPU image to process.</param>
    private void OnImageAvailable(XRCpuImage image)
    {
        if (_cameraBufferY == null || _cameraBufferU == null || _cameraBufferV == null)
        {
            _cameraWidth   = image.width;
            _cameraHeight  = image.height;
            _rowStrideY    = image.GetPlane(0).rowStride;
            _rowStrideUV   = image.GetPlane(1).rowStride;
            _pixelStrideUV = image.GetPlane(1).pixelStride;
            _cameraBufferY = new byte[image.GetPlane(0).data.Length];
            _cameraBufferU = new byte[image.GetPlane(1).data.Length];
            _cameraBufferV = new byte[image.GetPlane(2).data.Length];
        }

        image.GetPlane(0).data.CopyTo(_cameraBufferY);
        image.GetPlane(1).data.CopyTo(_cameraBufferU);
        image.GetPlane(2).data.CopyTo(_cameraBufferV);
    }