Git Product home page Git Product logo

Comments (5)

nullorvoid avatar nullorvoid commented on May 30, 2024

At the moment you are logging an error here:
https://github.com/kefniark/UnityBarcodeScanner/blob/master/Assets/Scripts/Scanner/Scanner.cs#L217

This is throwing up in Unity (although it should not crash the application) because there is a special exception when Aborting a thread which can be thrown so that the running thread can choose whether to cancel the abort itself.

https://msdn.microsoft.com/en-us/library/system.threading.threadabortexception(v=vs.110).aspx

I think you will need to catch(ThreadAbortException e) if you are using abort and only log a warning or something not as serious as an error, and then exit out of the thread cleanly.

@kefniark I can create a PR for it if you want me to?
@dyoxyne I will show you how to fix this internally as you have a copy of the code in your project.

from unitybarcodescanner.

kefniark avatar kefniark commented on May 30, 2024

@nullorvoid yes if you can create a PR for that, that could be helpful

from unitybarcodescanner.

rswa000 avatar rswa000 commented on May 30, 2024

hello i fix scanner by below way

using BarcodeScanner.Parser;
using BarcodeScanner.Webcam;
using System;
using UnityEngine;
using Wizcorp.Utils.Logger;

#if !UNITY_WEBGL
using System.Threading;
#endif

namespace BarcodeScanner.Scanner
{
	/// <summary>
	/// This Scanner Is used to manage the Camera & the parser and provide:
	/// * Simple methods : Scan / Stop
	/// * Simple events : OnStatus / StatusChanged
	/// </summary>
	public class Scanner : IScanner
	{
		//
		public event EventHandler OnReady;
		public event EventHandler StatusChanged;

		//
		public IWebcam Camera { get; private set; }
		public IParser Parser { get; private set; }
		public ScannerSettings Settings { get; private set; }

		//
		private ScannerStatus status;
		public ScannerStatus Status {
			get { return status; }
			private set
			{
				status = value;
				if (StatusChanged != null)
				{
					StatusChanged.Invoke(this, EventArgs.Empty);
				}
			}
		}

		// Store information about last image / results (use the update loop to access camera and callback)
		private Color32[] pixels = null;
		private Action<string, string> Callback;
		private ParserResult Result;

		//
		private bool parserPixelAvailable = false;
		private float mainThreadLastDecode = 0;
		private int webcamFrameDelayed = 0;
		private int webcamLastChecksum = -1;


		public Scanner() : this(null, null, null) { }
		public Scanner(ScannerSettings settings) : this (settings, null, null) {}
		public Scanner(IParser parser, IWebcam webcam) : this(null, parser, webcam) {}

		public Scanner(ScannerSettings settings, IParser parser, IWebcam webcam)
		{
			// Check Device Authorization
			if (!Application.HasUserAuthorization(UserAuthorization.WebCam))
			{
				throw new Exception("This Webcam Library can't work without the webcam authorization");
			}

			Status = ScannerStatus.Initialize;

			// Default Properties
			Settings = (settings == null) ? new ScannerSettings() : settings;
			Parser = (parser == null) ? new ZXingParser(Settings) : parser;
			Camera = (webcam == null) ? new UnityWebcam(Settings): webcam;
		}

        bool forceStopScanning = true;
		/// <summary>
		/// Used to start Scanning
		/// </summary>
		/// <param name="callback"></param>
		public void Scan(Action<string, string> callback)
		{
			if (Callback != null)
			{
				Log.Warning(this + " Already Scan");
				return;
			}
			Callback = callback;

			Log.Info(this + " SimpleScanner -> Start Scan");
			Status = ScannerStatus.Running;

			#if !UNITY_WEBGL
			if (Settings.ScannerBackgroundThread)
			{
                forceStopScanning = false;
                CodeScannerThread = new Thread(ThreadDecodeQR);
				CodeScannerThread.Start();
			}
			#endif
		}

		/// <summary>
		/// Used to Stop Scanning
		/// </summary>
		public void Stop()
		{
			Stop(false);
		}

		/// <summary>
		/// Used to Stop Scanning internaly (can be forced)
		/// </summary>
		private void Stop(bool forced)
		{
			if (!forced && Callback == null)
			{
				Log.Warning(this + " No Scan running");
				return;
			}

			// Stop thread / Clean callback
			Log.Info(this + " SimpleScanner -> Stop Scan");
			#if !UNITY_WEBGL
			if (CodeScannerThread != null)
			{
                forceStopScanning = true;
                CodeScannerThread.Join();
			}
			#endif

			Callback = null;
			Status = ScannerStatus.Paused;
		}

		/// <summary>
		/// Used to be sure that everything is properly clean
		/// </summary>
		public void Destroy()
		{
			// clean events
			OnReady = null;
			StatusChanged = null;

			// Stop it
			Stop(true);

			// clean returns
			Callback = null;
			Result = null;
			pixels = null;
			parserPixelAvailable = false;

			// clean camera
			Camera.Destroy();
			Camera = null;
			Parser = null;
		}

		#region Unthread

		/// <summary>
		/// Process Image Decoding in the main Thread
		/// Background Thread : OFF
		/// </summary>
		public void DecodeQR()
		{
			// Wait
			if (Status != ScannerStatus.Running || !parserPixelAvailable || Camera.Width == 0)
			{
				return;
			}

			// Process
			Log.Debug(this + " SimpleScanner -> Scan ... " + Camera.Width + " / " + Camera.Height);
			try
			{
				Result = Parser.Decode(pixels, Camera.Width, Camera.Height);
				parserPixelAvailable = false;
			}
			catch (Exception e)
			{
				Log.Error(e);
			}
		}

		#endregion

		#region Background Thread

		#if !UNITY_WEBGL
		private Thread CodeScannerThread;

		/// <summary>
		/// Process Image Decoding in a Background Thread
		/// Background Thread : OFF
		/// </summary>
		public void ThreadDecodeQR()
		{
			while (forceStopScanning == false && Result == null)
			{
				// Wait
				if (Status != ScannerStatus.Running || !parserPixelAvailable || Camera.Width == 0)
				{
					Thread.Sleep(Mathf.FloorToInt(Settings.ScannerDecodeInterval * 1000));
					continue;
				}

				// Process
				Log.Debug(this + " SimpleScanner -> Scan ... " + Camera.Width + " / " + Camera.Height);
				try
				{
					Result = Parser.Decode(pixels, Camera.Width, Camera.Height);
					parserPixelAvailable = false;

                    if (Result == null) {
                        // Sleep a little bit and set the signal to get the next frame
                        Thread.Sleep(Mathf.FloorToInt(Settings.ScannerDecodeInterval * 1000));
                    }
				}
				catch (Exception e)
				{
					Log.Error(e);
				}
			}
		}
		#endif

		#endregion

		/// <summary>
		/// Be sure that the camera metadata is stable (thanks Unity) and wait until then (increment delayFrameWebcam)
		/// </summary>
		/// <returns></returns>
		private bool WebcamInitialized()
		{
			// If webcam information still change, reset delayFrame
			if (webcamLastChecksum != Camera.GetChecksum())
			{
				webcamLastChecksum = Camera.GetChecksum();
				webcamFrameDelayed = 0;
				return false;
			}

			// Increment delayFrame
			if (webcamFrameDelayed < Settings.ScannerDelayFrameMin)
			{
				webcamFrameDelayed++;
				return false;
			}

			Camera.SetSize();
			webcamFrameDelayed = 0;
			return true;
		}

		/// <summary>
		/// This Update Loop is used to :
		/// * Wait the Camera is really ready
		/// * Bring back Callback to the main thread when using Background Thread
		/// * To execute image Decoding When not using the background Thread
		/// </summary>
		public void Update()
		{
			// If not ready, wait
			if (!Camera.IsReady())
			{
				Log.Warning(this + " Camera Not Ready Yet ...");
				if (status != ScannerStatus.Initialize)
				{
					Status = ScannerStatus.Initialize;
				}
				return;
			}

			// If the app start for the first time (select size & onReady Event)
			if (Status == ScannerStatus.Initialize)
			{
				if (WebcamInitialized())
				{
					Log.Info(this + " Camera is Ready ", Camera);

					Status = ScannerStatus.Paused;

					if (OnReady != null)
					{
						OnReady.Invoke(this, EventArgs.Empty);
					}
				}
			}

			if (Status == ScannerStatus.Running)
			{
				// Call the callback if a result is there
				if (Result != null)
				{
					//
					Log.Info(Result);
					Callback(Result.Type, Result.Value);

					// clean and return
					Result = null;
					parserPixelAvailable = false;
					return;
				}

				// Get the image as an array of Color32
				pixels = Camera.GetPixels(pixels);
				parserPixelAvailable = true;

				// If background thread OFF, do the decode main thread with 500ms of pause for UI
				if (!Settings.ScannerBackgroundThread && mainThreadLastDecode < Time.realtimeSinceStartup - Settings.ScannerDecodeInterval)
				{
					DecodeQR();
					mainThreadLastDecode = Time.realtimeSinceStartup;
				}
			}
		}

		public override string ToString()
		{
			return "[UnityBarcodeScanner]";
		}
	}
}

from unitybarcodescanner.

kefniark avatar kefniark commented on May 30, 2024

@rswa000 Created a PR with your code modification: #21

from unitybarcodescanner.

rswa000 avatar rswa000 commented on May 30, 2024

there is another issue when you scan multiple times in a function
it will create many threads.
I fix it in my fork.

from unitybarcodescanner.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.