تسجيل فيديو من المستخدم

موازين سجادة

بإمكان العديد من المتصفحات الآن الوصول إلى إدخال الفيديو والصوت من المستخدم. ومع ذلك، قد يتم تقديم تجربة ديناميكية كاملة ومضمّنة استنادًا إلى المتصفّح، أو قد يتم تفويضها إلى تطبيق آخر على جهاز المستخدم.

البدء بطريقة بسيطة وبشكل تدريجي

أسهل شيء يمكنك القيام به هو ببساطة أن تطلب من المستخدم ملفًا مسجلًا مسبقًا. يمكنك إجراء ذلك من خلال إنشاء عنصر إدخال ملف بسيط وإضافة فلتر 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
  • رسم الإطارات في لوحة وتطبيق الفلاتر عليها

على الرغم من انتشار استخدام طريقة عناصر الإدخال للوصول إلى بيانات الفيديو، إلا أنّه الخيار الأقل جاذبية. نريد حقًا الوصول إلى الكاميرا وتقديم تجربة لطيفة مباشرةً في الصفحة.

الوصول إلى الكاميرا بشكل تفاعلي

يمكن أن تحتوي المتصفّحات الحديثة على خط مباشر للكاميرا، ما يتيح لنا إنشاء تجارب متكاملة تمامًا مع صفحة الويب ولن يغادر المستخدِم المتصفّح أبدًا.

الحصول على إذن بالوصول إلى الكاميرا

يمكننا الوصول إلى الكاميرا مباشرةً باستخدام واجهة برمجة تطبيقات في مواصفات WebRTC تُسمى getUserMedia(). ستطلب ميزة "getUserMedia()" من المستخدم الوصول إلى الميكروفونات والكاميرات المتصلة.

في حال نجاح واجهة برمجة التطبيقات، ستعرض واجهة برمجة التطبيقات Stream الذي سيحتوي على البيانات من الكاميرا أو الميكروفون، ويمكننا بعد ذلك إرفاقه بالعنصر <video> أو إرفاقه ببث WebRTC، أو حفظه باستخدام MediaRecorder API.

للحصول على البيانات من الكاميرا، تم ضبط السمة video: true في عنصر القيود الذي يتم تمريره إلى واجهة برمجة تطبيقات 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,
);

يُرجى العِلم أنّه سيتم في كلتا الحالتين استخدام الإطار الحالي للفيديو الذي يتم تشغيله. لمعالجة إطارات متعددة، تحتاج إلى إعادة رسم الفيديو إلى اللوحة في كل مرة.

يمكنك معرفة المزيد من المعلومات حول هذا الموضوع في مقالتنا حول تطبيق تأثيرات الوقت الفعلي على الصور والفيديوهات.

حفظ البيانات من الكاميرا

إنّ أسهل طريقة لحفظ البيانات من الكاميرا هي باستخدام 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.

كراهية المستخدم عندما يطلب الوصول إلى أجهزة قوية على جهازه، وفي كثير من الأحيان يحظر المستخدم الطلب، أو سيتجاهله إذا لم يفهم سياق إنشاء الطلب. من أفضل الممارسات ألا تطلب الوصول إلى الكاميرا إلا عند الحاجة إليها لأول مرة. بعد أن يمنح المستخدم المستخدم الإذن بالوصول، لن يُطلب منه مرة أخرى. ومع ذلك، إذا رفض إمكانية الوصول، لا يمكنك الحصول على إمكانية الوصول مرة أخرى لطلب الإذن من المستخدم.

استخدام واجهة برمجة التطبيقات للأذونات للتحقّق مما إذا كان لديك إذن الوصول

لا تمنحك واجهة برمجة التطبيقات getUserMedia أي معلومات عمّا إذا كان بإمكانك الوصول إلى الكاميرا أم لا. وهذا يمثل مشكلة. لتوفير واجهة مستخدم لطيفة لجعل المستخدم يمنحك حق الوصول إلى الكاميرا، يتعين عليك طلب الوصول إلى الكاميرا.

يمكن حل هذه المشكلة في بعض المتصفحات باستخدام Permission API. تتيح لك واجهة برمجة تطبيقات navigator.permission الاستعلام عن حالة إمكانية الوصول إلى واجهات برمجة تطبيقات معيّنة بدون الحاجة إلى إرسال طلب مرة أخرى.

لطلب الوصول إلى كاميرا المستخدم، يمكنك إدخال {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 () {};
});

إضافة ملاحظات