הקלטת סרטון מהמשתמש

קנה מידה של משטח

לדפדפנים רבים יש עכשיו אפשרות לגשת לקלט וידאו ואודיו מהמשתמשים. עם זאת, בהתאם לדפדפן, יכול להיות שהחוויה תהיה דינמית מלאה ומוטבעת, או שהוא יכול להיות מוקצה לאפליקציה אחרת במכשיר של המשתמש.

להתחיל פשוט ובהדרגה

הדרך הקלה ביותר לעשות היא לבקש מהמשתמש קובץ מוקלט מראש. לשם כך, אפשר ליצור רכיב פשוט של קלט קובץ ולהוסיף מסנן accept שמציין שאנחנו יכולים לקבל רק קובצי וידאו ומאפיין capture שמציין שאנחנו רוצים לקבל אותו ישירות מהמצלמה.

<input type="file" accept="video/*" capture />

השיטה הזו פועלת בכל הפלטפורמות. במחשב, המשתמש יציג בקשה להעלות קובץ ממערכת הקבצים (ולהתעלם מהמאפיין capture). ב-Safari ב-iOS תיפתח אפליקציית המצלמה, שמאפשרת להקליט וידאו ולשלוח אותו בחזרה לדף האינטרנט. ב-Android, המשתמש יוכל לבחור באיזו אפליקציה להשתמש בצילום הסרטון לפני שהוא יישלח בחזרה לדף האינטרנט.

במכשירים ניידים רבים יש יותר ממצלמה אחת. אם רוצים, אפשר להגדיר את המאפיין capture לערך user כדי להגדיר את המצלמה שפונה אל המשתמש, או להגדיר את environment כשהמצלמה פונה כלפי חוץ.

<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />

שימו לב שזהו רמז בלבד – אם הדפדפן לא תומך באפשרות הזו, או שסוג המצלמה שביקשתם לא זמין, ייתכן שהדפדפן יבחר מצלמה אחרת.

אחרי שהמשתמש יסיים להקליט ויחזור לאתר, תצטרכו להשיג איכשהו את נתוני הקובץ. כדי לקבל גישה מהירה, אפשר לצרף אירוע onchange לרכיב הקלט ולאחר מכן לקרוא את המאפיין files של אובייקט האירוע.

<input type="file" accept="video/*" capture="camera" id="recorder" />
<video id="player" controls></video>
<script>
  var recorder = document.getElementById('recorder');
  var player = document.getElementById('player');

  recorder.addEventListener('change', function (e) {
    var file = e.target.files[0];
    // Do something with the video file.
    player.src = URL.createObjectURL(file);
  });
</script>

אחרי שתקבלו גישה לקובץ, תוכלו לעשות בו כל מה שתרצו. לדוגמה, אפשר:

  • כדי להפעיל אותו, צריך לחבר אותו ישירות לרכיב <video>
  • להוריד אותה למכשיר של המשתמש.
  • אפשר להעלות אותו לשרת על ידי צירוף אל XMLHttpRequest
  • משרטטים את המסגרות בתוך קנבס ומחילים עליו פילטרים

על אף שהשימוש בשיטת רכיב הקלט של קבלת גישה לנתוני וידאו נפוץ בכל מקום, זו האפשרות הכי פחות אטרקטיבית. אנחנו באמת רוצים לקבל גישה למצלמה ולספק חוויה נחמדה ישירות בדף.

גישה למצלמה באופן אינטראקטיבי

לדפדפנים מודרניים יכול להיות קו ישיר למצלמה, שמאפשר לנו ליצור חוויות המשולבות באופן מלא בדף האינטרנט, והמשתמש לעולם לא יעזוב את הדפדפן.

קבלת גישה למצלמה

יש לנו גישה ישירה למצלמה באמצעות API במפרט של WebRTC שנקרא getUserMedia(). המשתמש getUserMedia() יבקש גישה למיקרופונים ולמצלמות המחוברים.

אם הפעולה תתבצע בהצלחה, ה-API יחזיר Stream שמכיל את הנתונים מהמצלמה או מהמיקרופון, ואנחנו נוכל לחבר אותו לרכיב <video>, לצרף אותו ל-stream או לשמור אותו באמצעות MediaRecorder API.

כדי לקבל נתונים מהמצלמה, הגדרנו באובייקט האילוצים video: true את אובייקט האילוצים שמועבר ל-API של getUserMedia()

<video id="player" controls></video>
<script>
  var player = document.getElementById('player');

  var handleSuccess = function (stream) {
    player.srcObject = stream;
  };

  navigator.mediaDevices
    .getUserMedia({audio: true, video: true})
    .then(handleSuccess);
</script>

אם ברצונך לבחור מצלמה מסוימת, תחילה אפשר לפרט את רשימת המצלמות הזמינות.

navigator.mediaDevices.enumerateDevices().then((devices) => {
  devices = devices.filter((d) => d.kind === 'videoinput');
});

לאחר מכן אפשר להעביר את מזהה המכשיר שבו רוצים להשתמש בשיחה אל getUserMedia.

navigator.mediaDevices.getUserMedia({
  audio: true,
  video: {
    deviceId: devices[0].deviceId,
  },
});

כשלעצמה, זה לא ממש מועיל. כל מה שאנחנו יכולים לעשות הוא לקחת את נתוני הסרטון ולהפעיל אותם.

גישה לנתונים הגולמיים מהמצלמה

כדי לגשת לנתוני הווידאו הגולמיים מהמצלמה, אפשר לשרטט כל פריים לתוך <canvas> ולשנות את הפיקסלים ישירות.

בגרסת קנבס דו-ממדית, אפשר להשתמש בשיטה drawImage של ההקשר כדי לשרטט את המסגרת הנוכחית של רכיב <video> באזור העריכה.

context.drawImage(myVideoElement, 0, 0);

באזור העריכה של WebGL אפשר להשתמש ברכיב <video> כמקור למרקם.

gl.texImage2D(
  gl.TEXTURE_2D,
  0,
  gl.RGBA,
  gl.RGBA,
  gl.UNSIGNED_BYTE,
  myVideoElement,
);

בכל מקרה, ייעשה שימוש בפריים הנוכחי של הסרטון שמופעל. כדי לעבד מספר פריימים, צריך לצייר מחדש את הסרטון על קנבס בכל פעם.

ניתן לקרוא מידע נוסף על כך במאמר שלנו בנושא הוספת אפקטים בזמן אמת לתמונות ולסרטונים.

שמירת הנתונים מהמצלמה

הדרך הקלה ביותר לשמור את הנתונים מהמצלמה היא להשתמש ב-API MediaRecorder.

ה-API של MediaRecorder לוקח את השידור שנוצר על ידי getUserMedia, ולאחר מכן שומר בהדרגה את הנתונים מהשידור ליעד המועדף עליך.

<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
  let shouldStop = false;
  let stopped = false;
  const downloadLink = document.getElementById('download');
  const stopButton = document.getElementById('stop');

  stopButton.addEventListener('click', function() {
    shouldStop = true;
  })

  var handleSuccess = function(stream) {
    const options = {mimeType: 'video/webm'};
    const recordedChunks = [];
    const mediaRecorder = new MediaRecorder(stream, options);

    mediaRecorder.addEventListener('dataavailable', function(e) {
      if (e.data.size > 0) {
        recordedChunks.push(e.data);
      }

      if(shouldStop === true && stopped === false) {
        mediaRecorder.stop();
        stopped = true;
      }
    });

    mediaRecorder.addEventListener('stop', function() {
      downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
      downloadLink.download = 'acetest.webm';
    });

    mediaRecorder.start();
  };

  navigator.mediaDevices.getUserMedia({ audio: true, video: true })
      .then(handleSuccess);
</script>

במקרה שלנו אנחנו שומרים את הנתונים ישירות במערך, שאותו נוכל להגיש בהמשך למערך Blob, שבו אחר כך אפשר לשמור בשרת האינטרנט שלנו או ישירות באחסון במכשיר של המשתמש.

צריך לבקש הרשאה להשתמש במצלמה באופן אחראי

אם המשתמש לא העניק לאתר שלכם גישה למצלמה בעבר, ברגע שתתקשרו ל-getUserMedia, הדפדפן יתבקש להעניק לאתר שלכם הרשאת גישה למצלמה.

שנאת משתמש שמבקשת גישה למכשירים חזקים במחשב שלהם, והרבה פעמים יחסמו את הבקשה, או שהוא יתעלם ממנה אם הוא לא יבין את ההקשר שבו נוצרה ההנחיה. מומלץ לבקש גישה למצלמה רק במקרה הצורך. לאחר שהמשתמש יאשר את הגישה, הוא לא יתבקש לגשת אליו שוב. עם זאת, אם הוא ידחה את הגישה, לא תוכלו לקבל שוב גישה על מנת לבקש ממנו הרשאה.

איך משתמשים ב-Permissions API כדי לבדוק אם כבר יש לכם גישה

ה-API של getUserMedia לא מאפשר לדעת אם כבר יש לכם גישה למצלמה. הפעולה הזו יוצרת בעיה. כדי לספק ממשק משתמש נחמד שמאפשר למשתמש להעניק לכם גישה למצלמה, עליכם לבקש גישה למצלמה.

ניתן לפתור זאת בדפדפנים מסוימים באמצעות Permission API. ה-API navigator.permission מאפשר להריץ שאילתות על מצב היכולת לגשת לממשקי API ספציפיים בלי לשלוח בקשות נוספות.

כדי לשלוח שאילתה אם יש לכם גישה למצלמה של המשתמש, אפשר להעביר את הערך {name: 'camera'} לשיטת השאילתה, והיא תחזיר:

  • granted – המשתמש העניק לך בעבר גישה למצלמה;
  • prompt – המשתמש לא נתן לכם גישה ותתבקשו להתקשר ל-getUserMedia.
  • denied – המערכת או המשתמש חסמו באופן מפורש את הגישה למצלמה ולא ניתן יהיה לקבל גישה אליה.

עכשיו אפשר לבדוק במהירות אם צריך לשנות את ממשק המשתמש כך שיתאים לפעולות שהמשתמש צריך לבצע.

navigator.permissions.query({name: 'camera'}).then(function (result) {
  if (result.state == 'granted') {
  } else if (result.state == 'prompt') {
  } else if (result.state == 'denied') {
  }
  result.onchange = function () {};
});

משוב