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

Mat Scales

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

מתחילים בקטן ומתקדמים בהדרגה

הדרך הכי פשוטה היא לבקש מהמשתמש קובץ שהוקלט מראש. כדי לעשות את זה, יוצרים רכיב פשוט של קלט קובץ ומוסיפים מסנן 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>, לצרף אותו לסטרימינג של WebRTC או לשמור אותו באמצעות ה-API של MediaRecorder.

כדי לקבל נתונים מהמצלמה, הגדרנו את 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');
});

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

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

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

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

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

ב-canvas דו-ממדי, אפשר להשתמש ב-method‏ drawImage של ההקשר כדי לצייר את הפריים הנוכחי של רכיב <video> ב-canvas.

context.drawImage(myVideoElement, 0, 0);

באמצעות רכיב canvas של WebGL, אפשר להשתמש ברכיב <video> כמקור לטקסטורה.

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

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

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

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

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

‫MediaRecorder API יקבל את הסטרימינג שנוצר על ידי 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, הדפדפן יבקש מהמשתמש לתת לאתר שלכם הרשאה למצלמה.

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

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

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

בדפדפנים מסוימים אפשר לפתור את הבעיה הזו באמצעות Permission API. ‫navigator.permission API מאפשר לשלוח שאילתות לגבי מצב היכולת לגשת לממשקי 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 () {};
});

משוב