মিডিয়া সোর্স এক্সটেনশন

ফ্রাঁসোয়া বিউফোর্ট
François Beaufort
জো মেডলি
Joe Medley

মিডিয়া সোর্স এক্সটেনশন (MSE) হল একটি JavaScript API যা আপনাকে অডিও বা ভিডিওর সেগমেন্ট থেকে প্লেব্যাকের জন্য স্ট্রিম তৈরি করতে দেয়। যদিও এই প্রবন্ধে কভার করা হয়নি, আপনি যদি আপনার সাইটে ভিডিও এম্বেড করতে চান তাহলে MSE বোঝা প্রয়োজন:

  • অভিযোজিত স্ট্রিমিং, যা ডিভাইসের ক্ষমতা এবং নেটওয়ার্ক অবস্থার সাথে মানিয়ে নেওয়ার আরেকটি উপায়
  • অ্যাডাপটিভ স্প্লিসিং, যেমন বিজ্ঞাপন সন্নিবেশ
  • সময় পরিবর্তন
  • কর্মক্ষমতা এবং ডাউনলোড আকার নিয়ন্ত্রণ
মৌলিক MSE ডেটা প্রবাহ
চিত্র 1 : মৌলিক MSE ডেটা প্রবাহ

আপনি প্রায় MSE কে একটি চেইন হিসাবে ভাবতে পারেন। চিত্রে যেমন দেখানো হয়েছে, ডাউনলোড করা ফাইল এবং মিডিয়া উপাদানগুলির মধ্যে কয়েকটি স্তর রয়েছে।

  • মিডিয়া চালানোর জন্য একটি <audio> বা <video> উপাদান।
  • মিডিয়া উপাদান খাওয়ানোর জন্য একটি SourceBuffer সহ একটি MediaSource উদাহরণ।
  • একটি Response অবজেক্টে মিডিয়া ডেটা পুনরুদ্ধার করতে একটি fetch() বা XHR কল।
  • MediaSource.SourceBuffer ফিড করার জন্য Response.arrayBuffer() এ একটি কল।

অনুশীলনে, চেইনটি এইরকম দেখায়:

var vidElement = document.querySelector('video');

if (window.MediaSource) {
  var mediaSource = new MediaSource();
  vidElement.src = URL.createObjectURL(mediaSource);
  mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
  console.log('The Media Source Extensions API is not supported.');
}

function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  var mime = 'video/webm; codecs="opus, vp09.00.10.08"';
  var mediaSource = e.target;
  var sourceBuffer = mediaSource.addSourceBuffer(mime);
  var videoUrl = 'droid.webm';
  fetch(videoUrl)
    .then(function (response) {
      return response.arrayBuffer();
    })
    .then(function (arrayBuffer) {
      sourceBuffer.addEventListener('updateend', function (e) {
        if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
          mediaSource.endOfStream();
        }
      });
      sourceBuffer.appendBuffer(arrayBuffer);
    });
}

আপনি যদি এখন পর্যন্ত ব্যাখ্যাগুলি থেকে জিনিসগুলি সাজাতে পারেন তবে এখনই পড়া বন্ধ করুন। আপনি যদি আরও বিস্তারিত ব্যাখ্যা চান, তাহলে অনুগ্রহ করে পড়তে থাকুন। আমি একটি মৌলিক MSE উদাহরণ তৈরি করে এই চেইনের মধ্য দিয়ে হাঁটতে যাচ্ছি। প্রতিটি বিল্ড ধাপ পূর্ববর্তী ধাপে কোড যোগ করবে।

স্বচ্ছতা সম্পর্কে একটি নোট

এই নিবন্ধটি কি আপনাকে ওয়েব পৃষ্ঠায় মিডিয়া চালানোর বিষয়ে আপনার যা জানা দরকার তা বলবে? না, এটি শুধুমাত্র আপনাকে আরও জটিল কোড বুঝতে সাহায্য করার উদ্দেশ্যে যা আপনি অন্য কোথাও খুঁজে পেতে পারেন৷ স্বচ্ছতার জন্য, এই নথিটি অনেক কিছুকে সরল করে এবং বাদ দেয়। আমরা মনে করি আমরা এটি থেকে দূরে থাকতে পারি কারণ আমরা Google এর শাকা প্লেয়ারের মতো একটি লাইব্রেরি ব্যবহার করার পরামর্শ দিই। আমি যেখানে ইচ্ছাকৃতভাবে সরলীকরণ করছি সেখানে আমি নোট করব।

কিছু জিনিস কভার না

এখানে, কোন নির্দিষ্ট ক্রমে, কিছু জিনিস যা আমি কভার করব না।

  • প্লেব্যাক নিয়ন্ত্রণ। HTML5 <audio> এবং <video> উপাদানগুলি ব্যবহার করার কারণে আমরা সেগুলি বিনামূল্যে পাই৷
  • ত্রুটি পরিচালনা.

উৎপাদন পরিবেশে ব্যবহারের জন্য

এখানে কিছু জিনিস রয়েছে যা আমি MSE সম্পর্কিত API-এর উৎপাদন ব্যবহারের ক্ষেত্রে সুপারিশ করব:

  • এই APIগুলিতে কল করার আগে, যেকোন ত্রুটি ইভেন্ট বা API ব্যতিক্রমগুলি পরিচালনা করুন এবং HTMLMediaElement.readyState এবং MediaSource.readyState চেক করুন। সংশ্লিষ্ট ইভেন্টগুলি সরবরাহ করার আগে এই মানগুলি পরিবর্তিত হতে পারে।
  • SourceBuffer এর mode , timestampOffset , appendWindowStart , appendWindowEnd , অথবা SourceBufferappendBuffer() অথবা remove() কল করার আগে SourceBuffer.updating বুলিয়ান মান পরীক্ষা করে পূর্ববর্তী appendBuffer() এবং remove() কলগুলি এখনও চলছে না তা নিশ্চিত করুন। .
  • আপনার MediaSource এ যোগ করা সমস্ত SourceBuffer দৃষ্টান্তের জন্য, MediaSource.endOfStream() কল করার আগে বা MediaSource.duration আপডেট করার আগে নিশ্চিত করুন যে তাদের updating কোনো মানই সত্য নয়।
  • MediaSource.readyState মান ended হলে, appendBuffer() এবং remove() , অথবা SourceBuffer.mode বা SourceBuffer.timestampOffset সেট করার মত কলগুলি এই মানটিকে open স্থানান্তরিত করবে। এর মানে হল আপনি একাধিক sourceopen ইভেন্ট পরিচালনা করার জন্য প্রস্তুত থাকতে হবে।
  • HTMLMediaElement error ইভেন্টগুলি পরিচালনা করার সময়, MediaError.message এর বিষয়বস্তু ব্যর্থতার মূল কারণ নির্ধারণ করতে কার্যকর হতে পারে, বিশেষত পরীক্ষার পরিবেশে পুনরুত্পাদন করা কঠিন ত্রুটির জন্য।

একটি মিডিয়া উপাদানের সাথে একটি MediaSource দৃষ্টান্ত সংযুক্ত করুন

আজকাল ওয়েব ডেভেলপমেন্টের অনেক কিছুর মতো, আপনি বৈশিষ্ট্য সনাক্তকরণ দিয়ে শুরু করেন। এর পরে, একটি মিডিয়া উপাদান পান, হয় একটি <audio> বা <video> উপাদান। অবশেষে MediaSource একটি উদাহরণ তৈরি করুন। এটি একটি URL-এ পরিণত হয় এবং মিডিয়া উপাদানের উত্স বৈশিষ্ট্যে প্রেরণ করা হয়।

var vidElement = document.querySelector('video');

if (window.MediaSource) {
  var mediaSource = new MediaSource();
  vidElement.src = URL.createObjectURL(mediaSource);
  // Is the MediaSource instance ready?
} else {
  console.log('The Media Source Extensions API is not supported.');
}
একটি ব্লব হিসাবে একটি উত্স বৈশিষ্ট্য
চিত্র 1 : একটি ব্লব হিসাবে একটি উত্স বৈশিষ্ট্য

একটি MediaSource অবজেক্টকে একটি src অ্যাট্রিবিউটে পাস করা যেতে পারে তা কিছুটা অদ্ভুত বলে মনে হতে পারে। তারা সাধারণত স্ট্রিং হয়, কিন্তু তারা blobs হতে পারে . আপনি যদি এমবেডেড মিডিয়া সহ একটি পৃষ্ঠা পরিদর্শন করেন এবং এর মিডিয়া উপাদান পরীক্ষা করেন, আপনি দেখতে পাবেন আমি কী বলতে চাইছি।

মিডিয়াসোর্স উদাহরণ প্রস্তুত?

URL.createObjectURL() নিজেই সিঙ্ক্রোনাস; যাইহোক, এটি অ্যাসিঙ্ক্রোনাসভাবে সংযুক্তি প্রক্রিয়া করে। আপনি MediaSource ইনস্ট্যান্সের সাথে কিছু করতে পারার আগে এটি একটি সামান্য বিলম্ব ঘটায়। সৌভাগ্যবশত, এই জন্য পরীক্ষা করার উপায় আছে. সহজতম উপায় হল readyState নামক একটি MediaSource সম্পত্তি। readyState সম্পত্তি একটি MediaSource উদাহরণ এবং একটি মিডিয়া উপাদানের মধ্যে সম্পর্ক বর্ণনা করে। এটিতে নিম্নলিখিত মানগুলির মধ্যে একটি থাকতে পারে:

  • closed - MediaSource উদাহরণটি একটি মিডিয়া উপাদানের সাথে সংযুক্ত নয়৷
  • open - MediaSource দৃষ্টান্তটি একটি মিডিয়া উপাদানের সাথে সংযুক্ত এবং ডেটা গ্রহণের জন্য প্রস্তুত বা ডেটা গ্রহণ করছে৷
  • ended - MediaSource দৃষ্টান্তটি একটি মিডিয়া উপাদানের সাথে সংযুক্ত এবং এর সমস্ত ডেটা সেই উপাদানটিতে প্রেরণ করা হয়েছে৷

এই বিকল্পগুলি সরাসরি জিজ্ঞাসা করা নেতিবাচকভাবে কর্মক্ষমতা প্রভাবিত করতে পারে. সৌভাগ্যবশত, MediaSource ইভেন্টগুলিকেও গুলি করে যখন readyState পরিবর্তিত হয়, বিশেষত sourceopen , sourceclosed , sourceended । আমি যে উদাহরণটি তৈরি করছি, আমি sourceopen ইভেন্টটি ব্যবহার করতে যাচ্ছি যাতে ভিডিওটি কখন আনতে এবং বাফার করতে হয়।

var vidElement = document.querySelector('video');

if (window.MediaSource) {
  var mediaSource = new MediaSource();
  vidElement.src = URL.createObjectURL(mediaSource);
  <strong>mediaSource.addEventListener('sourceopen', sourceOpen);</strong>
} else {
  console.log("The Media Source Extensions API is not supported.")
}

<strong>function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  // Create a SourceBuffer and get the media file.
}</strong>

লক্ষ্য করুন যে আমি revokeObjectURL() কেও কল করেছি। আমি জানি এটি অকালে মনে হচ্ছে, কিন্তু মিডিয়া উপাদানের src বৈশিষ্ট্য একটি MediaSource উদাহরণের সাথে সংযুক্ত হওয়ার পরে আমি যে কোনো সময় এটি করতে পারি। এই পদ্ধতিতে কল করলে কোনো বস্তু ধ্বংস হয় না। এটি প্ল্যাটফর্মটিকে উপযুক্ত সময়ে আবর্জনা সংগ্রহ পরিচালনা করার অনুমতি দেয় , তাই আমি অবিলম্বে এটিকে কল করছি।

একটি সোর্সবাফার তৈরি করুন

এখন সময় এসেছে SourceBuffer তৈরি করার, যেটি বস্তুটি আসলে মিডিয়া উত্স এবং মিডিয়া উপাদানগুলির মধ্যে ডেটা শাটল করার কাজ করে৷ আপনি যে ধরনের মিডিয়া ফাইল লোড করছেন তার জন্য একটি SourceBuffer নির্দিষ্ট হতে হবে।

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

MSE স্পেকের সংস্করণ 1 ব্যবহারকারী এজেন্টদের একটি মাইম টাইপ এবং একটি কোডেক উভয়ের প্রয়োজন কিনা তা ভিন্ন হতে দেয়। কিছু ব্যবহারকারী এজেন্ট প্রয়োজন হয় না, কিন্তু শুধুমাত্র mime ধরনের অনুমতি দেয়. কিছু ব্যবহারকারী এজেন্ট, উদাহরণস্বরূপ, ক্রোম, মাইম ধরণের জন্য একটি কোডেক প্রয়োজন যা তাদের কোডেকগুলি স্ব-বর্ণনা করে না। এই সব বাছাই করার চেষ্টা করার পরিবর্তে, উভয়ই অন্তর্ভুক্ত করা ভাল।

var vidElement = document.querySelector('video');

if (window.MediaSource) {
  var mediaSource = new MediaSource();
  vidElement.src = URL.createObjectURL(mediaSource);
  mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
  console.log('The Media Source Extensions API is not supported.');
}

function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  <strong>
    var mime = 'video/webm; codecs="opus, vp09.00.10.08"'; // e.target refers to
    the mediaSource instance. // Store it in a variable so it can be used in a
    closure. var mediaSource = e.target; var sourceBuffer =
    mediaSource.addSourceBuffer(mime); // Fetch and process the video.
  </strong>;
}

মিডিয়া ফাইল পান

আপনি যদি MSE উদাহরণগুলির জন্য একটি ইন্টারনেট অনুসন্ধান করেন, আপনি প্রচুর পরিমাণে পাবেন যা XHR ব্যবহার করে মিডিয়া ফাইল পুনরুদ্ধার করে। আরও অত্যাধুনিক হওয়ার জন্য, আমি ফেচ এপিআই ব্যবহার করতে যাচ্ছি এবং প্রতিশ্রুতি এটি ফেরত দেয়। আপনি যদি সাফারিতে এটি করার চেষ্টা করেন তবে এটি একটি fetch() পলিফিল ছাড়া কাজ করবে না।

function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  var mime = 'video/webm; codecs="opus, vp09.00.10.08"';
  var mediaSource = e.target;
  var sourceBuffer = mediaSource.addSourceBuffer(mime);
  var videoUrl = 'droid.webm';
  <strong>
    fetch(videoUrl) .then(function(response){' '}
    {
      // Process the response object.
    }
    );
  </strong>;
}

বিভিন্ন ব্রাউজার সমর্থন করার জন্য একটি প্রোডাকশন কোয়ালিটি প্লেয়ারের একাধিক সংস্করণে একই ফাইল থাকবে। ভাষা সেটিংসের উপর ভিত্তি করে অডিও নির্বাচন করার অনুমতি দিতে এটি অডিও এবং ভিডিওর জন্য পৃথক ফাইল ব্যবহার করতে পারে।

রিয়েল ওয়ার্ল্ড কোডে বিভিন্ন রেজোলিউশনে মিডিয়া ফাইলের একাধিক কপি থাকবে যাতে এটি বিভিন্ন ডিভাইসের ক্ষমতা এবং নেটওয়ার্ক অবস্থার সাথে মানিয়ে নিতে পারে। এই ধরনের একটি অ্যাপ্লিকেশন পরিসীমা অনুরোধ বা বিভাগ ব্যবহার করে খণ্ডে ভিডিও লোড এবং প্লে করতে সক্ষম। মিডিয়া চালানোর সময় এটি নেটওয়ার্ক অবস্থার সাথে অভিযোজনের অনুমতি দেয়। আপনি হয়ত ড্যাশ বা এইচএলএস শব্দটি শুনেছেন, যা এটি সম্পন্ন করার দুটি পদ্ধতি। এই বিষয়ের একটি সম্পূর্ণ আলোচনা এই ভূমিকার সুযোগের বাইরে।

প্রতিক্রিয়া বস্তু প্রক্রিয়া

কোড প্রায় সম্পন্ন দেখায়, কিন্তু মিডিয়া প্লে হয় না. SourceBuffer Response অবজেক্ট থেকে আমাদের মিডিয়া ডেটা পেতে হবে।

রেসপন্স অবজেক্ট থেকে MediaSource ইনস্ট্যান্সে ডেটা পাস করার সাধারণ উপায় হল রেসপন্স অবজেক্ট থেকে একটি ArrayBuffer পাওয়া এবং এটি SourceBuffer এ পাস করা। response.arrayBuffer() কল করে শুরু করুন, যা বাফারে একটি প্রতিশ্রুতি প্রদান করে। আমার কোডে, আমি এই প্রতিশ্রুতিটিকে একটি সেকেন্ড then() ক্লজে পাস করেছি যেখানে আমি এটি SourceBuffer এ যোগ করি।

function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  var mime = 'video/webm; codecs="opus, vp09.00.10.08"';
  var mediaSource = e.target;
  var sourceBuffer = mediaSource.addSourceBuffer(mime);
  var videoUrl = 'droid.webm';
  fetch(videoUrl)
    .then(function(response) {
      <strong>return response.arrayBuffer();</strong>
    })
    <strong>.then(function(arrayBuffer) {
      sourceBuffer.appendBuffer(arrayBuffer);
    });</strong>
}

endOfStream() কে কল করুন

সমস্ত ArrayBuffers যুক্ত হওয়ার পরে, এবং আর কোন মিডিয়া ডেটা প্রত্যাশিত না হলে, MediaSource.endOfStream() এ কল করুন। এটি MediaSource.readyState পরিবর্তিত করে ended এবং sourceended ইভেন্ট ফায়ার করবে।

function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  var mime = 'video/webm; codecs="opus, vp09.00.10.08"';
  var mediaSource = e.target;
  var sourceBuffer = mediaSource.addSourceBuffer(mime);
  var videoUrl = 'droid.webm';
  fetch(videoUrl)
    .then(function(response) {
      return response.arrayBuffer();
    })
    .then(function(arrayBuffer) {
      <strong>sourceBuffer.addEventListener('updateend', function(e) {
        if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
          mediaSource.endOfStream();
        }
      });</strong>
      sourceBuffer.appendBuffer(arrayBuffer);
    });
}

চূড়ান্ত সংস্করণ

এখানে সম্পূর্ণ কোড উদাহরণ. আমি আশা করি আপনি মিডিয়া সোর্স এক্সটেনশন সম্পর্কে কিছু শিখেছেন।

var vidElement = document.querySelector('video');

if (window.MediaSource) {
  var mediaSource = new MediaSource();
  vidElement.src = URL.createObjectURL(mediaSource);
  mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
  console.log('The Media Source Extensions API is not supported.');
}

function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  var mime = 'video/webm; codecs="opus, vp09.00.10.08"';
  var mediaSource = e.target;
  var sourceBuffer = mediaSource.addSourceBuffer(mime);
  var videoUrl = 'droid.webm';
  fetch(videoUrl)
    .then(function (response) {
      return response.arrayBuffer();
    })
    .then(function (arrayBuffer) {
      sourceBuffer.addEventListener('updateend', function (e) {
        if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
          mediaSource.endOfStream();
        }
      });
      sourceBuffer.appendBuffer(arrayBuffer);
    });
}

প্রতিক্রিয়া