HTML5-এ অডিও ও ভিডিও ক্যাপচার করুন

ভূমিকা

অডিও/ভিডিও ক্যাপচার করা অনেক দিন ধরে ওয়েব ডেভেলপমেন্টের একটি "পবিত্র গ্রেইল" হয়ে উঠেছে। বহু বছর ধরে এই কাজ করার জন্য আমাদের ব্রাউজার প্লাগ-ইন (Flash বা Silverlight) ব্যবহার করতে হয়েছে। চলে আসুন!

HTML5-এর মাধ্যমে সমস্যার সমাধান। এটি আপাতদৃষ্টিতে বোঝা না গেলেও, HTML5-এর উত্থানের ফলে ডিভাইস হার্ডওয়্যারের অ্যাক্সেস অনেক বেড়ে গেছে। জিওলোকেশন (জিপিএস), Orientation API (অ্যাকসেলেরোমিটার), WebGL (জিপিইউ) এবং Web Audio API (অডিও হার্ডওয়্যার) হল এর উপযুক্ত উদাহরণ। এইসব ফিচার অত্যন্ত শক্তিশালী, যা সিস্টেমের অন্তর্নিহিত হার্ডওয়্যার ক্ষমতার উপরে থাকা উচ্চ-স্তরের জাভাস্ক্রিপ্ট API-কে প্রকাশ করে।

এই টিউটোরিয়ালটি একটি নতুন API, GetUserMedia-এর সাথে পরিচয় করিয়ে দেয়, যা ওয়েব অ্যাপকে ব্যবহারকারীর ক্যামেরা ও মাইক্রোফোন অ্যাক্সেস করার অনুমতি দেয়।

getUserMedia() এর পথ

আপনি যদি এর ইতিহাস সম্পর্কে না জানেন, তাহলে জেনে রাখুন যে getUserMedia() API-এ পৌঁছানোর পথটি একটি আকর্ষণীয় গল্প।

গত কয়েক বছরে "মিডিয়া ক্যাপচার API"-এর বিভিন্ন ভার্সন তৈরি হয়েছে। অনেকেই ওয়েবে নেটিভ ডিভাইস অ্যাক্সেস করতে পারার প্রয়োজনীয়তা স্বীকার করেছেন, কিন্তু এর ফলে সবাই এবং তাদের মা একটি নতুন স্পেক একসাথে রাখতে পেরেছেন। জিনিসগুলি এত বিশৃঙ্খল হয়ে উঠেছে যে W3C অবশেষে একটি ওয়ার্কিং গ্রুপ গঠন করার সিদ্ধান্ত নিয়েছে। তাদের একমাত্র উদ্দেশ্য? এই পাগলামির মানে কী! ডিভাইস API নীতি (DAP) ওয়ার্কিং গ্রুপ-কে প্রচুর প্রস্তাব একত্রিত + স্ট্যান্ডার্ডাইজ করার দায়িত্ব দেওয়া হয়েছে।

২০১১ সালে কী ঘটেছিল তার সারসংক্ষেপ করার চেষ্টা করব…

রাউন্ড ১: HTML মিডিয়া ক্যাপচার

HTML মিডিয়া ক্যাপচার ছিল DAP-এর প্রথম প্রচেষ্টা ওয়েবে মিডিয়া ক্যাপচারকে স্ট্যান্ডার্ডাইজ করার জন্য। এটি <input type="file"> ওভারলোড করে এবং accept প্যারামিটারের জন্য নতুন ভ্যালু যোগ করে কাজ করে।

আপনি যদি ব্যবহারকারীদের ওয়েবক্যামের মাধ্যমে নিজেদের স্ন্যাপশট নেওয়ার সুবিধা দিতে চান, তাহলে capture=camera-এর মাধ্যমে তা করা সম্ভব:

<input type="file" accept="image/*;capture=camera">

ভিডিও বা অডিও রেকর্ড করার পদ্ধতি একই রকম:

<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">

বেশ ভালো, তাই না? আমি বিশেষ করে পছন্দ করি যে এটি একটি ফাইল ইনপুট পুনরায় ব্যবহার করে। শব্দার্থগতভাবে, এটি অনেক অর্থপূর্ণ। এই নির্দিষ্ট "API" রিয়েল-টাইম এফেক্ট দেখানোর ক্ষেত্রে পিছিয়ে আছে (যেমন, লাইভ ওয়েবক্যাম ডেটা <canvas>-এ রেন্ডার করা এবং WebGL ফিল্টার প্রয়োগ করা)। HTML মিডিয়া ক্যাপচার আপনাকে শুধু মিডিয়া ফাইল রেকর্ড করতে বা স্ন্যাপশট নিতে দেয়।

সহায়তা:

  • Android 3.0 ব্রাউজার - প্রথম দিকের প্রয়োগের মধ্যে একটি। এটি কীভাবে কাজ করে তা দেখতে এই ভিডিও দেখুন।
  • Android-এর জন্য Chrome (0.16)
  • Firefox Mobile 10.0
  • iOS6 Safari এবং Chrome (আংশিক কাজ করে)

রাউন্ড ২: ডিভাইস এলিমেন্ট

অনেকেই মনে করেন যে HTML মিডিয়া ক্যাপচার অনেক সীমাবদ্ধ, তাই একটি নতুন স্পেসিফিকেশন তৈরি করা হয়েছে যা যেকোনও ধরনের (ভবিষ্যতের) ডিভাইস সাপোর্ট করে। আশ্চর্যের কিছু নেই যে, ডিজাইনের জন্য একটি নতুন এলিমেন্ট, <device> এলিমেন্ট প্রয়োজন হয়েছিল, যা getUserMedia()-এর পূর্বসূরি হয়ে ওঠে।

<device> এলিমেন্টের উপর ভিত্তি করে ভিডিও ক্যাপচার করার প্রাথমিক প্রয়োগ যেসব ব্রাউজার প্রথম করে, Opera তাদের মধ্যে অন্যতম। শীঘ্রই (আরও নির্দিষ্ট করে বলতে গেলে একই দিনে), WhatWG, <device> ট্যাগ বাতিল করে অন্য একটি নতুন ও উদীয়মান ট্যাগ ব্যবহার করার সিদ্ধান্ত নেয়, এইবার navigator.getUserMedia() নামে একটি JavaScript API ব্যবহার করা হয়। এক সপ্তাহ পরে, Opera নতুন বিল্ড প্রকাশ করে যাতে আপডেট করা getUserMedia() স্পেসিফিকেশনের জন্য সহায়তা অন্তর্ভুক্ত ছিল। সেই বছরের শেষের দিকে, Microsoft নতুন স্পেসিফিকেশনকে সহায়তা করে এমন IE9-এর জন্য ল্যাব প্রকাশ করে এই পার্টিতে যোগ দেয়।

<device> কেমন দেখতে হত তা এখানে দেওয়া হল:

<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>
  function update(stream) {
    document.querySelector('video').src = stream.url;
  }
</script>

সহায়তা:

দুর্ভাগ্যবশত, রিলিজ করা কোনও ব্রাউজারে কখনও <device> অন্তর্ভুক্ত করা হয়নি। One less API to worry about I guess :) <device> did have two great things going for it though: 1.) it was semantic, and 2.) it was easily extendible to support more than just audio/video devices.

একটু জিরিয়ে নিন। এইসব জিনিস খুব দ্রুত পরিবর্তিত হয়!

রাউন্ড ৩: WebRTC

<device> এলিমেন্টটি অবশেষে ডোডোর মতো বিলুপ্ত হয়ে গেছে।

আরও বড় WebRTC (ওয়েব রিয়েল টাইম কমিউনিকেশন) প্রচেষ্টার জন্য উপযুক্ত ক্যাপচার API খোঁজার গতি আরও বেড়েছে। সেই স্পেসিফিকেশন W3C WebRTC ওয়ার্কিং গ্রুপ তত্ত্বাবধান করে। Google, Opera, Mozilla এবং অন্যান্য কিছু ব্রাউজারে এটি প্রয়োগ করা হয়েছে।

getUserMedia(), WebRTC-এর সাথে সম্পর্কিত কারণ এটি হল API-এর সেই সেটের গেটওয়ে। এটি ব্যবহারকারীর লোকাল ক্যামেরা/মাইক্রোফোন স্ট্রিম অ্যাক্সেস করার উপায় প্রদান করে।

সহায়তা:

Chrome 21, Opera 18 এবং Firefox 17 থেকে getUserMedia() কাজ করে।

শুরু করা

navigator.mediaDevices.getUserMedia()-এর মাধ্যমে, আমরা অবশেষে প্লাগ-ইন ছাড়াই ওয়েবক্যাম এবং মাইক্রোফোন ইনপুট ব্যবহার করতে পারব। ক্যামেরা অ্যাক্সেস এখন একটি কল দূরে, ইনস্টল দূরে নয়। এটি সরাসরি ব্রাউজারে বেক করা হয়। এখনও উত্তেজিত?

ফিচার শনাক্তকরণ

ফিচার শনাক্তকরণ হল navigator.mediaDevices.getUserMedia-এর অস্তিত্বের জন্য একটি সহজ চেক:

if (navigator.mediaDevices?.getUserMedia) {
  // Good to go!
} else {
  alert("navigator.mediaDevices.getUserMedia() is not supported");
}

ইনপুট ডিভাইসে অ্যাক্সেস পাওয়া

ওয়েবক্যাম বা মাইক্রোফোন ব্যবহার করার জন্য আমাদের অনুমতি চাইতে হবে। navigator.mediaDevices.getUserMedia()-এর প্রথম প্যারামিটার হল একটি অবজেক্ট যা আপনি অ্যাক্সেস করতে চান এমন প্রতিটি ধরনের মিডিয়ার বিবরণ এবং প্রয়োজনীয়তা নির্দিষ্ট করে। যেমন, আপনি যদি ওয়েবক্যাম অ্যাক্সেস করতে চান, তাহলে প্রথম প্যারামিটার {video: true} হতে হবে। মাইক্রোফোন ও ক্যামেরা, দুটিই ব্যবহার করতে, {video: true, audio: true} পাস করুন:

<video autoplay></video>

<script>
  navigator.mediaDevices
    .getUserMedia({ video: true, audio: true })
    .then((localMediaStream) => {
      const video = document.querySelector("video");
      video.srcObject = localMediaStream;
    })
    .catch((error) => {
      console.log("Rejected!", error);
    });
</script>

ঠিক আছে। তাহলে এখানে কী হচ্ছে? মিডিয়া ক্যাপচার হল নতুন HTML5 API-এর একসাথে কাজ করার একটি নিখুঁত উদাহরণ। এটি আমাদের অন্যান্য HTML5 বাডি, <audio> এবং <video>-এর সাথে একসাথে কাজ করে। লক্ষ্য করুন যে আমরা <video> এলিমেন্টে src অ্যাট্রিবিউট সেট করছি না বা <source> এলিমেন্ট যোগ করছি না। ভিডিওতে মিডিয়া ফাইলের URL ফিড করার পরিবর্তে, আমরা ওয়েবক্যামকে উপস্থাপনকারী LocalMediaStream অবজেক্টে srcObject সেট করছি।

আমি <video>-কে autoplay করতেও বলছি, তা না হলে এটি প্রথম ফ্রেমে স্থির হয়ে থাকবে। controls যোগ করলেও আপনার প্রত্যাশা অনুযায়ী কাজ করে।

মিডিয়া কনস্ট্রেন্ট (রেজোলিউশন, উচ্চতা, প্রস্থ) সেট করা

getUserMedia()-এর প্রথম প্যারামিটারটি রিটার্ন করা মিডিয়া স্ট্রিমে আরও প্রয়োজনীয়তা (বা সীমাবদ্ধতা) নির্দিষ্ট করতেও ব্যবহার করা যেতে পারে। যেমন, আপনি ভিডিওতে শুধু প্রাথমিক অ্যাক্সেস (যেমন {video: true}) চান তা উল্লেখ করার পরিবর্তে, HD স্ট্রিমও চাইতে পারেন:

const hdConstraints = {
  video: { width: { exact:  1280} , height: { exact: 720 } },
};

const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);
const vgaConstraints = {
  video: { width: { exact:  640} , height: { exact: 360 } },
};

const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);

আরও কনফিগারেশনের জন্য, constraints API দেখুন।

মিডিয়া সোর্স বেছে নেওয়া

MediaDevices ইন্টারফেসের enumerateDevices() পদ্ধতি উপলভ্য মিডিয়া ইনপুট ও আউটপুট ডিভাইসের তালিকা অনুরোধ করে, যেমন মাইক্রোফোন, ক্যামেরা, হেডসেট ইত্যাদি। ডিভাইসের বিবরণ সহ MediaDeviceInfo অবজেক্টের অ্যারে সহ রিটার্ন করা প্রমিস সমাধান করা হয়।

এই উদাহরণে, শেষ যে মাইক্রোফোন ও ক্যামেরা পাওয়া গেছে, সেটি মিডিয়া স্ট্রিম সোর্স হিসেবে বেছে নেওয়া হয়েছে:

if (!navigator.mediaDevices?.enumerateDevices) {
  console.log("enumerateDevices() not supported.");
} else {
  // List cameras and microphones.
  navigator.mediaDevices
    .enumerateDevices()
    .then((devices) => {
      let audioSource = null;
      let videoSource = null;

      devices.forEach((device) => {
        if (device.kind === "audioinput") {
          audioSource = device.deviceId;
        } else if (device.kind === "videoinput") {
          videoSource = device.deviceId;
        }
      });
      sourceSelected(audioSource, videoSource);
    })
    .catch((err) => {
      console.error(`${err.name}: ${err.message}`);
    });
}

async function sourceSelected(audioSource, videoSource) {
  const constraints = {
    audio: { deviceId: audioSource },
    video: { deviceId: videoSource },
  };
  const stream = await navigator.mediaDevices.getUserMedia(constraints);
}

ব্যবহারকারীদের কীভাবে মিডিয়া সোর্স বেছে নিতে দেওয়া যায়, সেই বিষয়ে Sam Dutton-এর দুর্দান্ত ডেমো দেখুন।

নিরাপত্তা

navigator.mediaDevices.getUserMedia() কল করার সময় ব্রাউজার একটি অনুমতি সংক্রান্ত ডায়ালগ দেখায়, যা ব্যবহারকারীদের ক্যামেরা/মাইক্রোফোন অ্যাক্সেস করার অনুমতি দেওয়া বা না দেওয়ার বিকল্প প্রদান করে। যেমন, এখানে Chrome-এর অনুমতি সংক্রান্ত ডায়ালগ দেখানো হয়েছে:

Chrome-এ অনুমতির ডায়ালগ
Chrome-এ অনুমতি সংক্রান্ত ডায়ালগ

ফলব্যাক প্রদান করা হচ্ছে

যেসব ব্যবহারকারীর navigator.mediaDevices.getUserMedia()-এর জন্য সহায়তা নেই, তাদের জন্য একটি বিকল্প হল আগে থেকে থাকা ভিডিও ফাইলে ফিরে যাওয়া, যদি API কাজ না করে এবং/অথবা কোনও কারণে কল ব্যর্থ হয়:

if (!navigator.mediaDevices?.getUserMedia) {
  video.src = "fallbackvideo.webm";
} else {
  const stream = await navigator.mediaDevices.getUserMedia({ video: true });
  video.srcObject = stream;
}