привет у меня есть 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;
}
}
}
}