मीडिया सोर्स एक्सटेंशन

फ़्रैंसुआ बोफ़ोर्ट
फ़्रांस्वा ब्यूफ़ोर्ट
जो मेडले
जो मेडली

मीडिया सोर्स एक्सटेंशन (MSE) एक JavaScript API है. इसकी मदद से, ऑडियो या वीडियो के अलग-अलग हिस्सों से, प्लेबैक के लिए स्ट्रीम बनाई जा सकती हैं. हालांकि, इस लेख में इनके बारे में नहीं बताया गया है, लेकिन अगर आपको अपनी साइट में ऐसे वीडियो एम्बेड करने हैं जो इस तरह के काम करते हैं, तो 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 का Shaka Player भी इस्तेमाल करें. मैं सभी चीज़ों को जान-बूझकर आसान बनाने के काम में नोट करूंगा/करूंगी.

कुछ चीज़ें कवर नहीं की गई हैं

यहां, किसी भी क्रम में, कुछ ऐसी चीज़ों के बारे में नहीं बताया गया है जिनके बारे में मैं आपको नहीं बताऊंगी.

  • प्लेबैक कंट्रोल. HTML5 <audio> और <video> एलिमेंट इस्तेमाल करने पर, ये मुफ़्त में उपलब्ध होते हैं.
  • गड़बड़ी ठीक करना.

प्रोडक्शन एनवायरमेंट में इस्तेमाल करने के लिए

MSE से जुड़े एपीआई के प्रोडक्शन के इस्तेमाल के दौरान, हम इन चीज़ों का सुझाव देते हैं:

  • इन एपीआई पर कॉल करने से पहले, गड़बड़ी वाले किसी भी इवेंट या एपीआई के अपवाद को मैनेज करें. साथ ही, HTMLMediaElement.readyState और MediaSource.readyState की जांच करें. ये मान संबंधित इवेंट को डिलीवर किए जाने से पहले बदल सकते हैं.
  • पक्का करें कि पिछले appendBuffer() और remove() कॉल अब भी चालू न हों. इसके लिए, SourceBuffer के mode, timestampOffset, appendWindowStart appendWindowEnd को अपडेट करने या SourceBuffer पर appendBuffer() या remove() को कॉल करने से पहले, SourceBuffer.updating बूलियन वैल्यू की जांच करें.
  • आपके 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 का एक इंस्टेंस बनाएं. यह यूआरएल में बदल जाता है और मीडिया एलिमेंट के सोर्स एट्रिब्यूट को पास हो जाता है.

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.');
}
ब्लॉब के तौर पर सोर्स एट्रिब्यूट
पहली इमेज: ब्लॉब के तौर पर सोर्स एट्रिब्यूट

src एट्रिब्यूट में MediaSource ऑब्जेक्ट भेजा जा सकता है, यह थोड़ा अजीब लग सकता है. वे आम तौर पर स्ट्रिंग होती हैं, लेकिन वे ब्लॉब भी हो सकती हैं. अगर आप एम्बेड किए गए मीडिया वाले किसी पेज की जांच करते हैं और उसके मीडिया एलिमेंट की जांच करते हैं, तो आपको पता चलेगा कि मेरा मतलब क्या है.

क्या MediaSource इंस्टेंस तैयार है?

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 बनाने का समय है, जो असल में वह ऑब्जेक्ट है जो मीडिया सोर्स और मीडिया एलिमेंट के बीच डेटा को बंद करने का काम करता है. SourceBuffer, आपकी लोड की जा रही मीडिया फ़ाइल के हिसाब से होना चाहिए.

व्यावहारिक तौर पर, ऐसा करने के लिए, addSourceBuffer() को सही वैल्यू के साथ कॉल किया जा सकता है. ध्यान दें कि नीचे दिए गए MIME टाइप स्ट्रिंग में एक MIME टाइप और दो कोडेक शामिल हैं. यह किसी वीडियो फ़ाइल के लिए एक MIME स्ट्रिंग है. हालांकि, इसमें फ़ाइल के वीडियो और ऑडियो वाले हिस्से के लिए, अलग-अलग कोडेक का इस्तेमाल किया जाता है.

MSE की खास जानकारी के वर्शन 1 में उपयोगकर्ता एजेंट को यह तय करने की अनुमति मिलती है कि MIME टाइप और कोडेक, दोनों की ज़रूरत हो. कुछ उपयोगकर्ता एजेंट को ज़रूरत नहीं होती, लेकिन सिर्फ़ MIME टाइप की अनुमति होती है. उदाहरण के लिए, कुछ उपयोगकर्ता एजेंट को 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 का इस्तेमाल करके मीडिया फ़ाइलें वापस लाने वाली काफ़ी जानकारी मिलेगी. नए वर्शन के लिए, मैं फ़ेच एपीआई और इससे मिलने वाले प्रॉमिस का इस्तेमाल करूं. अगर आपने Safari में ऐसा करने की कोशिश की है, तो यह 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>;
}

अलग-अलग ब्राउज़र के साथ काम करने के लिए, प्रोडक्शन क्वालिटी वाले प्लेयर के कई वर्शन में एक ही फ़ाइल होगी. यह ऑडियो और वीडियो के लिए अलग-अलग फ़ाइलों का इस्तेमाल कर सकता है, ताकि भाषा की सेटिंग के आधार पर ऑडियो चुना जा सके.

रीयल वर्ल्ड कोड में अलग-अलग रिज़ॉल्यूशन पर मीडिया फ़ाइलों की कई कॉपी भी होती, ताकि यह डिवाइस की अलग-अलग क्षमताओं और नेटवर्क की स्थितियों के हिसाब से काम कर सके. ऐसा ऐप्लिकेशन, रेंज अनुरोध या सेगमेंट का इस्तेमाल करके, कई हिस्सों में वीडियो लोड कर सकता है और चला सकता है. मीडिया चलाने के दौरान, इसकी मदद से नेटवर्क की स्थितियों के हिसाब से ढल जाता है. ऐसा हो सकता है कि आपने DASH या HLS शब्दों के बारे में सुना हो, जो कि दो तरीके हैं. इस विषय पर पूरी चर्चा करना, इस परिचय के दायरे से बाहर है.

रिस्पॉन्स ऑब्जेक्ट को प्रोसेस करें

कोड करीब-करीब पूरा हो गया है, लेकिन मीडिया नहीं चलता. हमें Response ऑब्जेक्ट से SourceBuffer पर मीडिया डेटा लेना होगा.

रिस्पॉन्स ऑब्जेक्ट से 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);
    });
}

आखिरी वर्शन

यहां पूरे कोड का उदाहरण दिया गया है. उम्मीद है कि आपको MediaSource एक्सटेंशन के बारे में कुछ जानकारी मिली होगी.

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);
    });
}

सुझाव/राय दें या शिकायत करें