function CameraQrScanner(previewContainer) {
  var self = this;

  this.stream = null;

  var cameraElement = document.createElement('video');
  cameraElement.setAttribute('autoplay', 'autoplay');
  previewContainer.appendChild(cameraElement);

  var canvas = document.createElement('canvas');
  canvas.style.display = 'none';

  this.onResult = function () { };

  this.getCameras = function (callback) {
    navigator.mediaDevices.enumerateDevices()
      .then(function (devices) {
        var results = devices
          .filter(d => d.kind === 'videoinput')
          .map(d => { return { id: d.deviceId, name: d.label }; });

        callback(results);
      });
  };

  this.start = function (cameraId) {
    this.stop();

    var constraints = {
      audio: false,
      video: {
        mandatory: {
          minWidth: 400,
          maxWidth: 600,
          minAspectRatio: 1.6
        },
        optional: []
      }
    };

    if (cameraId) {
      constraints.video.mandatory.sourceId = cameraId;
    }

    navigator.webkitGetUserMedia(constraints, function (stream) {
      self.stream = stream;
      cameraElement.src = window.URL.createObjectURL(stream);
      startScan();
    }, function (err) {
    });
  };

  this.stop = function () {
    this.scanActive = false;

    if (this.stream) {
      for (let stream of this.stream.getVideoTracks()) {
        stream.stop();
      }

      this.stream = null;
    }
  };

  var image;
  var context;
  var scanActive = false;

  var sensorLeft;
  var sensorTop;
  var sensorWidth;
  var sensorHeight;

  var lastResult = null;

  var ZXing = window.ZXing();

  var decodeCallback = ZXing.Runtime.addFunction(function (ptr, len, resultIndex, resultCount) {
    var result = new Uint8Array(ZXing.HEAPU8.buffer, ptr, len);
    var str = String.fromCharCode.apply(null, result);
    if (resultIndex === 0) {
      window.zxDecodeResult = '';
    }
    window.zxDecodeResult += str;
  });

  function startScan() {
    this.scanActive = true;
    requestAnimationFrame(scan);
  }

  var frameCount = 0;
  function scan() {
    if (!this.scanActive) {
      return;
    }

    requestAnimationFrame(scan);

    if (++frameCount !== 5) {
      return;
    } else {
      frameCount = 0;
    }

    if (!cameraElement.videoWidth) {
      return;
    }

    if (!image) {
      var videoWidth = cameraElement.videoWidth;
      var videoHeight = cameraElement.videoHeight;

      sensorWidth = videoWidth;
      sensorHeight = videoHeight;
      sensorLeft = Math.floor((videoWidth / 2) - (sensorWidth / 2));
      sensorTop = Math.floor((videoHeight / 2) - (sensorHeight / 2));
      canvas.width = sensorWidth;
      canvas.height = sensorHeight;

      context = canvas.getContext('2d');
      image = ZXing._resize(sensorWidth, sensorHeight);
      return;
    }

    context.drawImage(cameraElement, sensorLeft, sensorTop, sensorWidth, sensorHeight, 0, 0, sensorWidth, sensorHeight);
    var data = context.getImageData(0, 0, sensorWidth, sensorHeight).data;

    for (var i = 0, j = 0; i < data.length; i += 4, j++) {
      ZXing.HEAPU8[image + j] = data[i];
    }

    var err = ZXing._decode_qr_multi(decodeCallback);
    if (!err) {
      var result = window.zxDecodeResult;
      if (lastResult != result) {
        lastResult = result;
        self.onResult(result);
      }
    }
  }
}

@@ -71,32 +71,118 @@
 s.stream = null;
+%0A  this.scanActive = false;%0A  this.lastResult = null;%0A  this.refractoryTimeout = null;
 %0A%0A  var cameraEl
@@ -1551,34 +1551,8 @@
 ext;
-%0A  var scanActive = false;
 %0A%0A  
@@ -1628,34 +1628,8 @@
 t;%0A%0A
-  var lastResult = null;%0A%0A
   va
@@ -3284,61 +3284,291 @@
 if (
-lastResult != result) %7B%0A        lastResult = result;%0A
+(result !== null) && (result !== self.lastResult)) %7B%0A        clearTimeout(self.refractoryTimeout);%0A        self.refractoryTimeout = setTimeout(function () %7B%0A          self.lastResult = null;%0A        %7D, 5 * 1000);%0A%0A        self.lastResult = result;%0A        setTimeout(function () %7B%0A  
     
@@ -3590,24 +3590,39 @@
 lt(result);%0A
+        %7D, 0);%0A
       %7D%0A    

Add a 5 second refractory period between consecutive duplicate scan detection/acceptance.