ericblade / quagga2

An advanced barcode-scanner written in Javascript and TypeScript - Continuation from https://github.com/serratus/quaggajs
MIT License
761 stars 84 forks source link

Failed to Load Video - Firefox Mobile #354

Open chobo2 opened 3 years ago

chobo2 commented 3 years ago

Hi

I installed the latest version of Firefox mobile on my website and sometimes when I switch between cameras, the cameras fails to load up. I then have to try again.

All I am getting is "failed to load video"

https://barcodes.z4.web.core.windows.net/

I have my example code here.

ericblade commented 3 years ago

maybe try awaiting Quagga.stop() before calling init again? Also might need to increase that timeout, or maybe do something explicit in Firefox that I'm not aware of to get it to release the resources correctly.

I'm not seeing anything obvious. I'm not a fan of using setTimeout() to bypass timing issues, but i know sometimes you just can't avoid it.

chobo2 commented 3 years ago

maybe try awaiting Quagga.stop() before calling init again? Also might need to increase that timeout, or maybe do something explicit in Firefox that I'm not aware of to get it to release the resources correctly.

I'm not seeing anything obvious. I'm not a fan of using setTimeout() to bypass timing issues, but i know sometimes you just can't avoid it.

I am not either but I found you need to do it when switching as the Stop takes some time to stop.

$(function () {
  Quagga.CameraAccess.request(null, {}).then(function () {
    Quagga.CameraAccess.release().then(function () {
      Quagga.CameraAccess.enumerateVideoDevices().then(function (devices) {
        start(devices);
      });
    });
  });

  function tryToDetermineRightCamera(devices) {
    var backDevices = devices.filter(function (device) {
      return device.label.toUpperCase().includes("BACK");
    });

    if (backDevices.length > 0) {
      return backDevices[0].deviceId;
    } else {
      return devices[0].deviceId;
    }
  }

  function start(devices) {
    var deviceId = tryToDetermineRightCamera(devices);

    Quagga.init(
      {
        inputStream: {
          name: "Live",
          type: "LiveStream",
          target: "#container",
          constraints: {
            width: { min: 640 },
            height: { min: 480 },
            deviceId: deviceId,
          },
        },
        decoder: {
          readers: ["upc_reader", "ean_reader"],
        },
      },
      function (err) {
        if (err) {
          console.log(err);
          alert(err);
          return;
        }
        $("#cameras-selection").empty();
        Quagga.start();
        possibleCameraOptions(deviceId);

      }
    );
  }

  function possibleCameraOptions(deviceId){
    setTimeout(function () {
      Quagga.CameraAccess.enumerateVideoDevices().then(function (devices2) {
        devices2.forEach((device2) => {
          function pruneText(text) {
            return text.length > 30 ? text.substr(0, 30) : text;
          }
          var selected = deviceId == device2.deviceId;

          if (selected) {
            $("#cameras-selection").append(
              `<option value="${
                device2.deviceId
              }" selected="selected">${pruneText(device2.label)}</option>`
            );
          } else {
            $("#cameras-selection").append(
              `<option value="${device2.deviceId}">${pruneText(
                device2.label
              )}</option>`
            );
          }
        });
      });
    }, 50);
  }

  function printObject(o) {
    var out = "";
    for (var p in o) {
      out += p + ": " + o[p] + "\n";
    }
    alert(out);
  }

  $("#cameras-selection").change(function () {
    var optionSelected = $(this).find("option:selected");
    var deviceId = optionSelected.val();

    Quagga.stop();

    setTimeout(function () {
        Quagga.init(
          {
            inputStream: {
              name: "Live",
              type: "LiveStream",
              target: "#container",
              constraints: {
                width: { min: 640 },
                height: { min: 480 },
                deviceId: deviceId,
              },
            },
            decoder: {
              readers: ["upc_reader", "ean_reader"],
            },
          },
          function (err) {
            if (err) {
              console.log(err);
              alert(err);
              return;
            }
            Quagga.start();
          }
        );
    }, 100);
  });

  Quagga.onDetected(function (result) {
    if (result.codeResult) {
      $(".search-box").val(result.codeResult.code);
    }
  });

  Quagga.onProcessed(function (result) {
    var drawingCtx = Quagga.canvas.ctx.overlay,
      drawingCanvas = Quagga.canvas.dom.overlay;

    if (result) {
      if (result.boxes) {
        drawingCtx.clearRect(
          0,
          0,
          parseInt(drawingCanvas.getAttribute("width")),
          parseInt(drawingCanvas.getAttribute("height"))
        );
        result.boxes
          .filter(function (box) {
            return box !== result.box;
          })
          .forEach(function (box) {
            Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, {
              color: "green",
              lineWidth: 2,
            });
          });
      }

      if (result.box) {
        Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, {
          color: "#00F",
          lineWidth: 2,
        });
      }

      if (result.codeResult && result.codeResult.code) {
        Quagga.ImageDebug.drawPath(
          result.line,
          { x: "x", y: "y" },
          drawingCtx,
          { color: "red", lineWidth: 3 }
        );
      }
    }
  });
});

I will try to make it higher but I am already at 100 milliseconds which I would hope is enough.

ericblade commented 3 years ago

If you're using the latest point release, you should be able to await Quagga.stop() although that might not necessarily wait until the browser is completely ready to restart the camera

chobo2 commented 3 years ago

If you're using the latest point release, you should be able to await Quagga.stop() although that might not necessarily wait until the browser is completely ready to restart the camera

latest point release? I am trying to avoid await as I not sure what kind of browser requirements I will have to handle and I know I doubt the site I am implementing into supports babel.

I just upped it 250millseconds, seems to work.

I been looking at your barcode validation but still not sure if I can implement it into my project since I am not using npm.

ericblade commented 3 years ago

Quagga.stop().then(...) would be same as await Quagga.stop()