ضبط ویدیو از کاربر

Mat Scales

اکنون بسیاری از مرورگرها این امکان را دارند که به ورودی های صوتی و تصویری کاربر دسترسی داشته باشند. با این حال، بسته به مرورگر، ممکن است یک تجربه کامل پویا و درون خطی باشد، یا می‌تواند به برنامه دیگری در دستگاه کاربر واگذار شود.

ساده ترین کار این است که به سادگی از کاربر یک فایل از پیش ضبط شده بخواهید. این کار را با ایجاد یک عنصر ورودی فایل ساده و افزودن یک فیلتر accept که نشان می‌دهد فقط می‌توانیم فایل‌های ویدیویی را بپذیریم و یک ویژگی capture که نشان می‌دهد می‌خواهیم آن را مستقیماً از دوربین دریافت کنیم، انجام دهید.

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

این روش روی همه پلتفرم ها کار می کند. در دسکتاپ از کاربر می خواهد که یک فایل را از سیستم فایل آپلود کند (بدون توجه به ویژگی capture ). در Safari در iOS، برنامه دوربین را باز می‌کند و به شما امکان می‌دهد ویدیو ضبط کنید و سپس آن را به صفحه وب ارسال کنید. در اندروید به کاربر این امکان را می دهد که از کدام برنامه استفاده کند قبل از ارسال آن به صفحه وب، فیلم را ضبط کند.

بسیاری از دستگاه های تلفن همراه بیش از یک دوربین دارند. اگر ترجیحی دارید، می‌توانید ویژگی 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 متصل کنیم، یا با استفاده از MediaRecorder API ذخیره کنیم.

برای دریافت داده‌ها از دوربین، فقط ویدیو را در شیء constraints که به API getUserMedia() ارسال می‌شود، تنظیم کردیم video: true

<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 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 برای بررسی اینکه آیا از قبل دسترسی دارید یا خیر استفاده کنید

getUserMedia API به شما اطلاعی نمی دهد که آیا قبلاً به دوربین دسترسی دارید یا خیر. این شما را با یک مشکل روبرو می کند، برای ارائه یک رابط کاربری خوب برای اینکه کاربر به شما اجازه دسترسی به دوربین را بدهد، باید درخواست دسترسی به دوربین را داشته باشید.

این مشکل در برخی از مرورگرها با استفاده از 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 () {};
});

بازخورد