привет у меня есть 2 кода по сканированию qr для unity мне нужно их обьеденить  в один что, из одного взять многопоточное разделение из другого вывод на экран вот эти коды 
public class NewQRScan : MonoBehaviour
{
    [SerializeField]
    private RawImage _rawImageBackground;
    [SerializeField]
    private AspectRatioFitter _aspectRatioFitter;
    [SerializeField]
    private TextMeshProUGUI _textOut;
    [SerializeField]
    private RectTransform _scanZone;

    private bool _isCamAvaible;
    private WebCamTexture _cameraTexture;
    void Start()
    {
        SetUpCamera();
    }

    // Update is called once per frame
    void Update()
    {
        UpdateCameraRender();
    }

    private void SetUpCamera()
    {
        WebCamDevice[] devices = WebCamTexture.devices;
        if (devices.Length == 0)
        {
            _isCamAvaible = false;
            return;
        }
        for (int i = 0; i < devices.Length; i++)
        {
            if (devices[i].isFrontFacing == false)
            {
                _cameraTexture = new WebCamTexture(devices[i].name, (int)_scanZone.rect.width, (int)_scanZone.rect.height);
                break;
            }
        }
        _cameraTexture.Play();
        _rawImageBackground.texture = _cameraTexture;
        _isCamAvaible = true;
    }

    private void UpdateCameraRender()
    {
        if (_isCamAvaible == false)
        {
            return;
        }
        float ratio = (float)_cameraTexture.width / (float)_cameraTexture.height;
        _aspectRatioFitter.aspectRatio = ratio;

        int orientation = _cameraTexture.videoRotationAngle;
        orientation = orientation * 3;
        _rawImageBackground.rectTransform.localEulerAngles = new Vector3(0, 0, orientation);

    }
    public void OnClickScan()
    {
        Scan();
    }
    private void Scan()
    {
        try
        {
            IBarcodeReader barcodeReader = new BarcodeReader();
            Result result = barcodeReader.Decode(_cameraTexture.GetPixels32(), _cameraTexture.width, _cameraTexture.height);
            if (result != null)
            {
                _textOut.text = result.Text;
            }
            else
            {
                _textOut.text = "Failed to Read QR CODE";
            }
        }
        catch
        {
            _textOut.text = "FAILED IN TRY";
        }
    }
}
public class QRCodeScanner : MonoBehaviour
{
    [SerializeField]
    private string lastResult;

    private WebCamTexture camTexture;
    private Rect screenRect;
    private Color32[] cameraColorData;
    private int width, height;
    private CancellationTokenSource cts = new CancellationTokenSource();
    private bool startEncoding;
    private bool startDecoding;

    private BarcodeWriter writer;
    private Result result;

    public event Action<string> OnResult;

    private BarcodeReader barcodeReader = new BarcodeReader
    {
        AutoRotate = false,
        Options = new ZXing.Common.DecodingOptions
        {
            TryHarder = false
        }
    };

    public void ActiveScanner()
    {
        SetupWebcamTexture();
        PlayWebcamTexture();

        cameraColorData = new Color32[width * height];
        screenRect = new Rect(0, 0, Screen.width, Screen.height);

        if (cts != null)
        {
            cts.Dispose();
        }
        cts = new CancellationTokenSource();

        // Перезапуск работы с камерой и сканированием
        RestartScannerThreads();
    }
    private void OnEnable()
    {
        RestartScanner();
    }

    private void RestartScannerThreads()
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(GetCodeFromImageData), cts.Token);
        ThreadPool.QueueUserWorkItem(new WaitCallback(EncodeNewFromLastResult), cts.Token);
    }

    private void Update()
    {
        if (camTexture != null && camTexture.isPlaying && !startDecoding)
        {
            camTexture.GetPixels32(cameraColorData);
            startDecoding = true;
        }
    }

    private void OnGUI()
    {
        DrawCameraTexture();

        if (result != null)
        {
            HandleDecodedResult();
        }
    }

    private void DrawCameraTexture()
    {

        if (camTexture != null)
        {
            // Сохраняем текущую матрицу GUI, чтобы восстановить её позже
            Matrix4x4 matrixBackup = GUI.matrix;

            // Получаем угол поворота и проверяем на зеркальное отображение
            float rotationAngle = -camTexture.videoRotationAngle;

            // Добавляем 180 градусов для дополнительного поворота
            rotationAngle += 180;

            bool isVerticallyMirrored = camTexture.videoVerticallyMirrored;
            Rect rect = screenRect;

            if (isVerticallyMirrored)
            {
                // Если изображение отображается зеркально, корректируем положение rect
                rect.y = Screen.height - rect.y - rect.height;
            }

            // Высчитываем центр поворота
            Vector2 pivotPoint = new Vector2(rect.xMin + rect.width * 0.5f, rect.yMin + rect.height * 0.5f);

            // Применяем поворот вокруг центра поворота
            GUIUtility.RotateAroundPivot(rotationAngle, pivotPoint);

            // Рисуем текстуру с учётом поворота и зеркального отображения
            GUI.DrawTexture(rect, camTexture, ScaleMode.ScaleToFit);

            // Восстанавливаем матрицу GUI
            GUI.matrix = matrixBackup;
        }
    }

    private void HandleDecodedResult()
    {
        try
        {
            if (result != null)
            {
                // QR-код успешно считан
                Debug.Log("Decoded QR: " + result.Text);

                // Останавливаем сканирование и камеру
                camTexture.Stop();

                var resultURL = result.Text.Substring(0, result.Text.Length - 1);

                OnResult?.Invoke(resultURL);
                // Переходим по ссылке, если это нужно
                result = null;
                //Application.OpenURL(resultURL);
            }
        }
        catch (System.Exception ex)
        {
            Debug.LogWarning(ex.Message);
        }
    }


    private void OnDestroy()
    {
        // Вызывается при уничтожении объекта
        if (camTexture != null)
        {
            camTexture.Stop();
            camTexture = null;
        }

        cts.Cancel();
        cts.Dispose();
    }
    private void RestartScanner()
    {
        if (camTexture != null && !camTexture.isPlaying)
        {
            camTexture.Play();
        }
        startDecoding = false;
        startEncoding = false;
        ActiveScanner();
    }
    private void OnApplicationFocus(bool hasFocus)
    {
        if (hasFocus)
        {
            // Перезапускаем сканер, когда пользователь возвращается в приложение
            RestartScanner();
        }
    }

    private void SetupWebcamTexture()
    {
        camTexture = new WebCamTexture();
        camTexture.requestedHeight = Screen.height;
        camTexture.requestedWidth = Screen.width;
    }

    private void PlayWebcamTexture()
    {
        if (camTexture != null)
        {
            camTexture.Play();
            width = camTexture.width;
            height = camTexture.height;
        }
    }


    private void EncodeNewFromLastResult(object obj)
    {
        CancellationToken token = (CancellationToken)obj;

        while (!token.IsCancellationRequested)
        {
            if (startEncoding && lastResult != null)
            {
                startEncoding = !startEncoding;
            }
        }
    }

    private void GetCodeFromImageData(object obj)
    {
        CancellationToken token = (CancellationToken)obj;

        while (!token.IsCancellationRequested)
        {
            // decode the current frame
            if (startDecoding && cameraColorData != null)
            {
                result = barcodeReader.Decode(cameraColorData, width, height);
                if (result != null)
                {
                    lastResult = result.Text + " " + result.BarcodeFormat;
                    startEncoding = true;
                }
                startDecoding = !startDecoding;
            }
        }
    }
}