<!DOCTYPE html>
<html>
<head>
  <script src="face-api.js"></script>
  <script src="commons.js"></script>
  <link rel="stylesheet" href="styles.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
  <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
</head>
<body>
  <div id="navbar"></div>
  <div class="center-content page-container">
    <div class="progress" id="loader">
      <div class="indeterminate"></div>
    </div>
    <div style="position: relative" class="margin">
      <video onplay="onPlay(this)" id="inputVideo" autoplay muted></video>
      <canvas id="overlay" />
    </div>
    <div class="row side-by-side">
      <div class="row">
        <label for="minFaceSize">Minimum Face Size:</label>
        <input disabled value="200" id="minFaceSize" type="text" class="bold">
      </div>
      <button
        class="waves-effect waves-light btn"
        onclick="onDecreaseMinFaceSize()"
      >
        <i class="material-icons left">-</i>
      </button>
      <button
        class="waves-effect waves-light btn"
        onclick="onIncreaseMinFaceSize()"
      >
        <i class="material-icons left">+</i>
      </button>
    </div>
    <div class="row side-by-side">
      <div class="row">
        <label for="time">Time:</label>
        <input disabled value="-" id="time" type="text" class="bold">
      </div>
      <div class="row">
        <label for="fps">Estimated Fps:</label>
        <input disabled value="-" id="fps" type="text" class="bold">
      </div>
    </div>
  </div>

  <script>
    let modelLoaded = false
    let minFaceSize = 200
    let minConfidence = 0.9
    let forwardTimes = []

    function onIncreaseMinFaceSize() {
      minFaceSize = Math.min(faceapi.round(minFaceSize + 50), 300)
      $('#minFaceSize').val(minFaceSize)
    }

    function onDecreaseMinFaceSize() {
      minFaceSize = Math.max(faceapi.round(minFaceSize - 50), 50)
      $('#minFaceSize').val(minFaceSize)
    }

    function updateTimeStats(timeInMs) {
      forwardTimes = [timeInMs].concat(forwardTimes).slice(0, 30)
      const avgTimeInMs = forwardTimes.reduce((total, t) => total + t) / forwardTimes.length
      $('#time').val(`${Math.round(avgTimeInMs)} ms`)
      $('#fps').val(`${faceapi.round(1000 / avgTimeInMs)}`)
    }

    async function onPlay(videoEl) {
      if(videoEl.paused || videoEl.ended || !modelLoaded)
        return false

      const { width, height } = faceapi.getMediaDimensions(videoEl)
      const canvas = $('#overlay').get(0)
      canvas.width = width
      canvas.height = height

      const mtcnnParams = {
        minFaceSize
      }

      const { results, stats } = await faceapi.nets.mtcnn.forwardWithStats(videoEl, mtcnnParams)
      updateTimeStats(stats.total)

      if (results) {
        results.forEach(({ faceDetection, faceLandmarks }) => {
          if (faceDetection.score < minConfidence) {
            return
          }
          faceapi.drawDetection('overlay', faceDetection.forSize(width, height))
          faceapi.drawLandmarks('overlay', faceLandmarks.forSize(width, height), { lineWidth: 4, color: 'red' })
        })
      }
      setTimeout(() => onPlay(videoEl))
    }

    async function run() {
      await faceapi.loadMtcnnModel('/')
      modelLoaded = true

      const videoEl = $('#inputVideo').get(0)
      navigator.getUserMedia(
        { video: {} },
        stream => videoEl.srcObject = stream,
        err => console.error(err)
      )
      $('#loader').hide()
    }

    $(document).ready(function() {
      renderNavBar('#navbar', 'mtcnn_face_detection_webcam')
      run()
    })
  </script>
</body>
</html>