উন্নত ব্রাউজার-ভিত্তিক ভিডিও প্রসেসিং আনলক করুন। কাস্টম ইফেক্ট এবং বিশ্লেষণের জন্য WebCodecs API ব্যবহার করে সরাসরি র ভিডিওফ্রেম প্লেন ডেটা অ্যাক্সেস এবং ম্যানিপুলেট করতে শিখুন।
WebCodecs ভিডিওফ্রেম প্লেন অ্যাক্সেস: র ভিডিও ডেটা ম্যানিপুলেশনের একটি গভীর বিশ্লেষণ
বছরের পর বছর ধরে, ওয়েব ব্রাউজারে হাই-পারফরম্যান্স ভিডিও প্রসেসিং একটি দূরবর্তী স্বপ্নের মতো মনে হয়েছিল। ডেভেলপাররা প্রায়শই <video> এলিমেন্ট এবং 2D Canvas API-এর সীমাবদ্ধতার মধ্যে আবদ্ধ থাকতেন, যা শক্তিশালী হলেও, পারফরম্যান্সের ক্ষেত্রে বাধা সৃষ্টি করত এবং মূল র ভিডিও ডেটাতে সীমিত অ্যাক্সেস দিত। WebCodecs API-এর আগমন এই পরিস্থিতিকে মৌলিকভাবে পরিবর্তন করেছে, যা ব্রাউজারের বিল্ট-ইন মিডিয়া কোডেকগুলিতে নিম্ন-স্তরের অ্যাক্সেস প্রদান করে। এর সবচেয়ে বিপ্লবী বৈশিষ্ট্যগুলির মধ্যে একটি হলো VideoFrame অবজেক্টের মাধ্যমে সরাসরি পৃথক ভিডিও ফ্রেমের র ডেটা অ্যাক্সেস এবং ম্যানিপুলেট করার ক্ষমতা।
এই নিবন্ধটি সেইসব ডেভেলপারদের জন্য একটি বিস্তারিত গাইড, যারা সাধারণ ভিডিও প্লেব্যাকের বাইরে যেতে চান। আমরা VideoFrame প্লেন অ্যাক্সেসের জটিলতাগুলো অন্বেষণ করব, কালার স্পেস এবং মেমরি লেআউটের মতো ধারণাগুলো সহজবোধ্য করব, এবং আপনাকে রিয়েল-টাইম ফিল্টার থেকে শুরু করে অত্যাধুনিক কম্পিউটার ভিশন টাস্ক পর্যন্ত পরবর্তী প্রজন্মের ইন-ব্রাউজার ভিডিও অ্যাপ্লিকেশন তৈরি করতে সক্ষম করার জন্য ব্যবহারিক উদাহরণ দেব।
পূর্বশর্ত
এই গাইড থেকে সর্বাধিক সুবিধা পেতে, আপনার নিম্নলিখিত বিষয়গুলিতে একটি দৃঢ় ধারণা থাকা উচিত:
- আধুনিক জাভাস্ক্রিপ্ট: অ্যাসিঙ্ক্রোনাস প্রোগ্রামিং (
async/await, Promises) সহ। - বেসিক ভিডিও কনসেপ্ট: ফ্রেম, রেজোলিউশন এবং কোডেকের মতো শব্দগুলির সাথে পরিচিতি সহায়ক হবে।
- ব্রাউজার এপিআই: Canvas 2D বা WebGL-এর মতো এপিআইগুলির সাথে অভিজ্ঞতা সুবিধাজনক হবে তবে কঠোরভাবে প্রয়োজনীয় নয়।
ভিডিও ফ্রেম, কালার স্পেস, এবং প্লেন বোঝা
এপিআই-তে প্রবেশ করার আগে, আমাদের প্রথমে একটি ভিডিও ফ্রেমের ডেটা আসলে কেমন দেখতে সে সম্পর্কে একটি পরিষ্কার মানসিক মডেল তৈরি করতে হবে। একটি ডিজিটাল ভিডিও হলো স্থির চিত্র বা ফ্রেমের একটি ক্রম। প্রতিটি ফ্রেম পিক্সেলের একটি গ্রিড, এবং প্রতিটি পিক্সেলের একটি রঙ আছে। সেই রঙটি কীভাবে সংরক্ষণ করা হয় তা কালার স্পেস এবং পিক্সেল ফরম্যাট দ্বারা সংজ্ঞায়িত হয়।
RGBA: ওয়েবের নিজস্ব ভাষা
বেশিরভাগ ওয়েব ডেভেলপার RGBA কালার মডেলের সাথে পরিচিত। প্রতিটি পিক্সেল চারটি উপাদান দ্বারা উপস্থাপিত হয়: লাল (Red), সবুজ (Green), নীল (Blue), এবং আলফা (স্বচ্ছতা)। ডেটা সাধারণত মেমরিতে ইন্টারলিভড (interleaved) ভাবে সংরক্ষণ করা হয়, যার অর্থ একটি পিক্সেলের জন্য R, G, B, এবং A মানগুলি পরপর সংরক্ষণ করা হয়:
[R1, G1, B1, A1, R2, G2, B2, A2, ...]
এই মডেলে, পুরো ছবিটি মেমরির একটি একক, অবিচ্ছিন্ন ব্লকে সংরক্ষণ করা হয়। আমরা এটিকে ডেটার একটি একক "প্লেন" হিসেবে ভাবতে পারি।
YUV: ভিডিও কম্প্রেশনের ভাষা
তবে, ভিডিও কোডেকগুলি খুব কমই সরাসরি RGBA নিয়ে কাজ করে। তারা YUV (বা আরও সঠিকভাবে, Y'CbCr) কালার স্পেস পছন্দ করে। এই মডেলটি ছবির তথ্যকে বিভক্ত করে:
- Y (Luma): উজ্জ্বলতা বা গ্রেস্কেল তথ্য। মানুষের চোখ লুমা পরিবর্তনে সবচেয়ে বেশি সংবেদনশীল।
- U (Cb) এবং V (Cr): ক্রোমিন্যান্স বা রঙের পার্থক্য সম্পর্কিত তথ্য। মানুষের চোখ উজ্জ্বলতার বিবরণের চেয়ে রঙের বিবরণে কম সংবেদনশীল।
এই বিভাজন দক্ষ কম্প্রেশনের জন্য অত্যন্ত গুরুত্বপূর্ণ। U এবং V উপাদানগুলির রেজোলিউশন কমিয়ে—একটি কৌশল যাকে ক্রোমা সাবস্যাম্পলিং বলা হয়—আমরা গুণমানের ন্যূনতম লক্ষণীয় ক্ষতি সহ ফাইলের আকার উল্লেখযোগ্যভাবে হ্রাস করতে পারি। এর ফলে প্ল্যানার পিক্সেল ফরম্যাট তৈরি হয়, যেখানে Y, U, এবং V উপাদানগুলি পৃথক মেমরি ব্লক বা "প্লেন"-এ সংরক্ষণ করা হয়।
একটি সাধারণ ফরম্যাট হলো I420 (YUV 4:2:0-এর একটি প্রকার), যেখানে প্রতি 2x2 পিক্সেল ব্লকের জন্য চারটি Y স্যাম্পল থাকে কিন্তু শুধুমাত্র একটি U এবং একটি V স্যাম্পল থাকে। এর মানে হলো U এবং V প্লেনগুলির প্রস্থ এবং উচ্চতা Y প্লেনের অর্ধেক।
এই পার্থক্য বোঝা অত্যন্ত গুরুত্বপূর্ণ কারণ WebCodecs আপনাকে সরাসরি এই প্লেনগুলিতে অ্যাক্সেস দেয়, ঠিক যেমন ডিকোডার সেগুলি সরবরাহ করে।
VideoFrame অবজেক্ট: পিক্সেল ডেটার প্রবেশদ্বার
এই ধাঁধার কেন্দ্রীয় অংশ হলো VideoFrame অবজেক্ট। এটি একটি ভিডিওর একক ফ্রেমকে প্রতিনিধিত্ব করে এবং এতে কেবল পিক্সেল ডেটাই নয়, গুরুত্বপূর্ণ মেটাডেটও থাকে।
VideoFrame-এর মূল বৈশিষ্ট্য
format: একটি স্ট্রিং যা পিক্সেল ফরম্যাট নির্দেশ করে (যেমন, 'I420', 'NV12', 'RGBA')।codedWidth/codedHeight: মেমরিতে সংরক্ষিত ফ্রেমের সম্পূর্ণ মাত্রা, কোডেকের জন্য প্রয়োজনীয় যেকোনো প্যাডিং সহ।displayWidth/displayHeight: ফ্রেম প্রদর্শনের জন্য যে মাত্রা ব্যবহার করা উচিত।timestamp: মাইক্রোসেকেন্ডে ফ্রেমের উপস্থাপনা টাইমস্ট্যাম্প।duration: মাইক্রোসেকেন্ডে ফ্রেমের সময়কাল।
জাদুকরী মেথড: copyTo()
র পিক্সেল ডেটা অ্যাক্সেস করার প্রাথমিক মেথড হলো videoFrame.copyTo(destination, options)। এই অ্যাসিঙ্ক্রোনাস মেথডটি ফ্রেমের প্লেন ডেটা আপনার সরবরাহ করা একটি বাফারে কপি করে।
destination: একটিArrayBufferবা একটি টাইপড অ্যারে (যেমনUint8Array) যা ডেটা রাখার জন্য যথেষ্ট বড়।options: একটি অবজেক্ট যা নির্দিষ্ট করে কোন প্লেনগুলি কপি করতে হবে এবং তাদের মেমরি লেআউট। যদি এটি বাদ দেওয়া হয়, তবে এটি সমস্ত প্লেন একটি একক অবিচ্ছিন্ন বাফারে কপি করে।
মেথডটি একটি Promise প্রদান করে যা PlaneLayout অবজেক্টের একটি অ্যারের সাথে রিজলভ হয়, ফ্রেমের প্রতিটি প্লেনের জন্য একটি করে। প্রতিটি PlaneLayout অবজেক্টে দুটি গুরুত্বপূর্ণ তথ্য থাকে:
offset: বাইট অফসেট যেখানে এই প্লেনের ডেটা ডেস্টিনেশন বাফারের মধ্যে শুরু হয়।stride: পিক্সেলের একটি সারির শুরু থেকে সেই প্লেনের পরবর্তী সারির শুরুর মধ্যে বাইটের সংখ্যা।
একটি গুরুত্বপূর্ণ ধারণা: স্ট্রাইড বনাম প্রস্থ
নিম্ন-স্তরের গ্রাফিক্স প্রোগ্রামিংয়ে নতুন ডেভেলপারদের জন্য এটি বিভ্রান্তির সবচেয়ে সাধারণ উৎসগুলির মধ্যে একটি। আপনি ধরে নিতে পারবেন না যে পিক্সেল ডেটার প্রতিটি সারি একে অপরের সাথে শক্তভাবে প্যাক করা আছে।
- প্রস্থ (Width) হলো একটি ছবির সারিতে পিক্সেলের সংখ্যা।
- স্ট্রাইড (Stride) (পিচ বা লাইন স্টেপও বলা হয়) হলো মেমরিতে এক সারির শুরু থেকে পরবর্তী সারির শুরুর মধ্যে বাইটের সংখ্যা।
প্রায়শই, stride-এর মান width * bytes_per_pixel থেকে বেশি হবে। এর কারণ হলো সিপিইউ বা জিপিইউ দ্বারা দ্রুত প্রসেসিংয়ের জন্য মেমরি প্রায়শই হার্ডওয়্যারের সীমানার সাথে (যেমন, 32- বা 64-বাইট বাউন্ডারি) অ্যালাইন করার জন্য প্যাড করা হয়। একটি নির্দিষ্ট সারিতে একটি পিক্সেলের মেমরি ঠিকানা গণনা করার জন্য আপনাকে সর্বদা স্ট্রাইড ব্যবহার করতে হবে।
স্ট্রাইড উপেক্ষা করলে ছবি বিকৃত বা ভুল ডেটা অ্যাক্সেসের কারণ হবে।
ব্যবহারিক উদাহরণ ১: একটি গ্রেস্কেল প্লেন অ্যাক্সেস এবং প্রদর্শন
আসুন একটি সহজ কিন্তু শক্তিশালী উদাহরণ দিয়ে শুরু করি। ওয়েবের বেশিরভাগ ভিডিও I420-এর মতো একটি YUV ফরম্যাটে এনকোড করা হয়। 'Y' প্লেনটি কার্যকরভাবে ছবির একটি সম্পূর্ণ গ্রেস্কেল উপস্থাপনা। আমরা কেবল এই প্লেনটি এক্সট্রাক্ট করে একটি ক্যানভাসে রেন্ডার করতে পারি।
async function displayGrayscale(videoFrame) {
// আমরা ধরে নিচ্ছি ভিডিওফ্রেমটি 'I420' বা 'NV12' এর মতো একটি YUV ফরম্যাটে আছে।
if (!videoFrame.format.startsWith('I4')) {
console.error('This example requires a YUV 4:2:0 planar format.');
videoFrame.close();
return;
}
const yPlaneInfo = videoFrame.layout[0]; // Y প্লেন সবসময় প্রথমে থাকে।
// শুধুমাত্র Y প্লেনের ডেটা রাখার জন্য একটি বাফার তৈরি করুন।
const yPlaneData = new Uint8Array(yPlaneInfo.stride * videoFrame.codedHeight);
// Y প্লেনটি আমাদের বাফারে কপি করুন।
await videoFrame.copyTo(yPlaneData, {
rect: { x: 0, y: 0, width: videoFrame.codedWidth, height: videoFrame.codedHeight },
layout: [yPlaneInfo]
});
// এখন, yPlaneData-তে র গ্রেস্কেল পিক্সেল রয়েছে।
// আমাদের এটি রেন্ডার করতে হবে। আমরা ক্যানভাসের জন্য একটি RGBA বাফার তৈরি করব।
const canvas = document.getElementById('my-canvas');
canvas.width = videoFrame.displayWidth;
canvas.height = videoFrame.displayHeight;
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(canvas.width, canvas.height);
// ক্যানভাস পিক্সেলগুলির উপর দিয়ে পুনরাবৃত্তি করুন এবং Y প্লেন ডেটা থেকে সেগুলি পূরণ করুন।
for (let y = 0; y < videoFrame.displayHeight; y++) {
for (let x = 0; x < videoFrame.displayWidth; x++) {
// গুরুত্বপূর্ণ: সঠিক উৎস ইনডেক্স খুঁজে পেতে স্ট্রাইড ব্যবহার করুন!
const yIndex = y * yPlaneInfo.stride + x;
const luma = yPlaneData[yIndex];
// RGBA ImageData বাফারে গন্তব্য ইনডেক্স গণনা করুন।
const rgbaIndex = (y * canvas.width + x) * 4;
imageData.data[rgbaIndex] = luma; // Red
imageData.data[rgbaIndex + 1] = luma; // Green
imageData.data[rgbaIndex + 2] = luma; // Blue
imageData.data[rgbaIndex + 3] = 255; // Alpha
}
}
ctx.putImageData(imageData, 0, 0);
// ক্রিটিক্যাল: ভিডিওফ্রেমের মেমরি রিলিজ করার জন্য সর্বদা এটি বন্ধ করুন।
videoFrame.close();
}
এই উদাহরণটি কয়েকটি মূল পদক্ষেপ তুলে ধরে: সঠিক প্লেন লেআউট সনাক্ত করা, একটি ডেস্টিনেশন বাফার বরাদ্দ করা, ডেটা এক্সট্রাক্ট করার জন্য copyTo ব্যবহার করা, এবং একটি নতুন ছবি তৈরি করতে stride ব্যবহার করে ডেটার উপর সঠিকভাবে পুনরাবৃত্তি করা।
ব্যবহারিক উদাহরণ ২: ইন-প্লেস ম্যানিপুলেশন (সেপিয়া ফিল্টার)
এখন আসুন একটি সরাসরি ডেটা ম্যানিপুলেশন করা যাক। সেপিয়া ফিল্টার একটি ক্লাসিক ইফেক্ট যা প্রয়োগ করা সহজ। এই উদাহরণের জন্য, একটি RGBA ফ্রেমের সাথে কাজ করা সহজ, যা আপনি একটি ক্যানভাস বা একটি WebGL কনটেক্সট থেকে পেতে পারেন।
async function applySepiaFilter(videoFrame) {
// এই উদাহরণটি ধরে নেয় যে ইনপুট ফ্রেমটি 'RGBA' বা 'BGRA'।
if (videoFrame.format !== 'RGBA' && videoFrame.format !== 'BGRA') {
console.error('Sepia filter example requires an RGBA frame.');
videoFrame.close();
return null;
}
// পিক্সেল ডেটা রাখার জন্য একটি বাফার বরাদ্দ করুন।
const frameDataSize = videoFrame.allocationSize();
const frameData = new Uint8Array(frameDataSize);
await videoFrame.copyTo(frameData);
const layout = videoFrame.layout[0]; // RGBA একটি একক প্লেন
// এখন, বাফারের মধ্যে ডেটা ম্যানিপুলেট করুন।
for (let y = 0; y < videoFrame.codedHeight; y++) {
for (let x = 0; x < videoFrame.codedWidth; x++) {
const pixelIndex = y * layout.stride + x * 4; // প্রতি পিক্সেল ৪ বাইট (R,G,B,A)
const r = frameData[pixelIndex];
const g = frameData[pixelIndex + 1];
const b = frameData[pixelIndex + 2];
const tr = 0.393 * r + 0.769 * g + 0.189 * b;
const tg = 0.349 * r + 0.686 * g + 0.168 * b;
const tb = 0.272 * r + 0.534 * g + 0.131 * b;
frameData[pixelIndex] = Math.min(255, tr);
frameData[pixelIndex + 1] = Math.min(255, tg);
frameData[pixelIndex + 2] = Math.min(255, tb);
// আলফা (frameData[pixelIndex + 3]) অপরিবর্তিত থাকে।
}
}
// পরিবর্তিত ডেটা দিয়ে একটি *নতুন* VideoFrame তৈরি করুন।
const newFrame = new VideoFrame(frameData, {
format: videoFrame.format,
codedWidth: videoFrame.codedWidth,
codedHeight: videoFrame.codedHeight,
timestamp: videoFrame.timestamp,
duration: videoFrame.duration
});
// আসল ফ্রেমটি বন্ধ করতে ভুলবেন না!
videoFrame.close();
return newFrame;
}
এটি একটি সম্পূর্ণ রিড-মডিফাই-রাইট চক্র প্রদর্শন করে: ডেটা কপি করা, স্ট্রাইড ব্যবহার করে তার উপর লুপ চালানো, প্রতিটি পিক্সেলের উপর একটি গাণিতিক রূপান্তর প্রয়োগ করা, এবং ফলস্বরূপ ডেটা দিয়ে একটি নতুন VideoFrame তৈরি করা। এই নতুন ফ্রেমটি তখন একটি ক্যানভাসে রেন্ডার করা যেতে পারে, একটি VideoEncoder-এ পাঠানো যেতে পারে, বা অন্য কোনো প্রসেসিং ধাপে পাস করা যেতে পারে।
পারফরম্যান্সের গুরুত্ব: জাভাস্ক্রিপ্ট বনাম ওয়েবঅ্যাসেম্বলি (WASM)
প্রতিটি ফ্রেমের জন্য লক্ষ লক্ষ পিক্সেলের উপর (একটি 1080p ফ্রেমে ২ মিলিয়নেরও বেশি পিক্সেল, বা RGBA-তে ৮ মিলিয়ন ডেটা পয়েন্ট) জাভাস্ক্রিপ্টে পুনরাবৃত্তি করা ধীর হতে পারে। যদিও আধুনিক জেএস ইঞ্জিনগুলি অবিশ্বাস্যভাবে দ্রুত, হাই-রেজোলিউশন ভিডিওর (HD, 4K) রিয়েল-টাইম প্রসেসিংয়ের জন্য, এই পদ্ধতিটি সহজেই মূল থ্রেডকে অভিভূত করতে পারে, যা একটি খণ্ডিত ব্যবহারকারীর অভিজ্ঞতার দিকে পরিচালিত করে।
এইখানেই ওয়েবঅ্যাসেম্বলি (WASM) একটি অপরিহার্য সরঞ্জাম হয়ে ওঠে। WASM আপনাকে C++, Rust, বা Go-এর মতো ভাষায় লেখা কোড ব্রাউজারের ভিতরে প্রায় নেটিভ গতিতে চালাতে দেয়। ভিডিও প্রসেসিংয়ের ওয়ার্কফ্লো হয়ে ওঠে:
- জাভাস্ক্রিপ্টে: র পিক্সেল ডেটা একটি
ArrayBuffer-এ পেতেvideoFrame.copyTo()ব্যবহার করুন। - WASM-এ পাস করুন: এই বাফারের একটি রেফারেন্স আপনার কম্পাইল করা WASM মডিউলে পাস করুন। এটি একটি খুব দ্রুত অপারেশন কারণ এতে ডেটা কপি করা জড়িত নয়।
- WASM-এ (C++/Rust): মেমরি বাফারে সরাসরি আপনার অত্যন্ত অপ্টিমাইজ করা ইমেজ প্রসেসিং অ্যালগরিদমগুলি চালান। এটি একটি জাভাস্ক্রিপ্ট লুপের চেয়ে বহুগুণ দ্রুত।
- জাভাস্ক্রিপ্টে ফিরে আসুন: WASM-এর কাজ শেষ হয়ে গেলে, নিয়ন্ত্রণ জাভাস্ক্রিপ্টে ফিরে আসে। তারপরে আপনি পরিবর্তিত বাফারটি ব্যবহার করে একটি নতুন
VideoFrameতৈরি করতে পারেন।
যেকোনো গুরুতর, রিয়েল-টাইম ভিডিও ম্যানিপুলেশন অ্যাপ্লিকেশনের জন্য—যেমন ভার্চুয়াল ব্যাকগ্রাউন্ড, অবজেক্ট ডিটেকশন, বা জটিল ফিল্টার—ওয়েবঅ্যাসেম্বলির ব্যবহার কেবল একটি বিকল্প নয়; এটি একটি প্রয়োজনীয়তা।
বিভিন্ন পিক্সেল ফরম্যাট হ্যান্ডলিং (যেমন, I420, NV12)
যদিও RGBA সহজ, আপনি প্রায়শই একটি VideoDecoder থেকে প্ল্যানার YUV ফরম্যাটে ফ্রেম পাবেন। আসুন দেখি কিভাবে I420-এর মতো একটি সম্পূর্ণ প্ল্যানার ফরম্যাট হ্যান্ডেল করতে হয়।
I420 ফরম্যাটের একটি VideoFrame-এর layout অ্যারেতে তিনটি লেআউট বর্ণনাকারী থাকবে:
layout[0]: Y প্লেন (লুমা)। মাত্রা হলোcodedWidthxcodedHeight।layout[1]: U প্লেন (ক্রোমা)। মাত্রা হলোcodedWidth/2xcodedHeight/2।layout[2]: V প্লেন (ক্রোমা)। মাত্রা হলোcodedWidth/2xcodedHeight/2।
এখানে আপনি কীভাবে তিনটি প্লেনকে একটি একক বাফারে কপি করবেন:
async function extractI420Planes(videoFrame) {
const totalSize = videoFrame.allocationSize({ format: 'I420' });
const allPlanesData = new Uint8Array(totalSize);
const layouts = await videoFrame.copyTo(allPlanesData);
// layouts হলো ৩টি PlaneLayout অবজেক্টের একটি অ্যারে
console.log('Y Plane Layout:', layouts[0]); // { offset: 0, stride: ... }
console.log('U Plane Layout:', layouts[1]); // { offset: ..., stride: ... }
console.log('V Plane Layout:', layouts[2]); // { offset: ..., stride: ... }
// আপনি এখন `allPlanesData` বাফারের মধ্যে প্রতিটি প্লেন অ্যাক্সেস করতে পারেন
// তার নির্দিষ্ট অফসেট এবং স্ট্রাইড ব্যবহার করে।
const yPlaneView = new Uint8Array(
allPlanesData.buffer,
layouts[0].offset,
layouts[0].stride * videoFrame.codedHeight
);
// লক্ষ্য করুন ক্রোমা মাত্রা অর্ধেক!
const uPlaneView = new Uint8Array(
allPlanesData.buffer,
layouts[1].offset,
layouts[1].stride * (videoFrame.codedHeight / 2)
);
const vPlaneView = new Uint8Array(
allPlanesData.buffer,
layouts[2].offset,
layouts[2].stride * (videoFrame.codedHeight / 2)
);
console.log('Accessed Y plane size:', yPlaneView.byteLength);
console.log('Accessed U plane size:', uPlaneView.byteLength);
videoFrame.close();
}
আরেকটি সাধারণ ফরম্যাট হলো NV12, যা সেমি-প্ল্যানার। এর দুটি প্লেন আছে: একটি Y-এর জন্য, এবং একটি দ্বিতীয় প্লেন যেখানে U এবং V মানগুলি ইন্টারলিভ করা হয় (যেমন, [U1, V1, U2, V2, ...])। WebCodecs API এটি স্বচ্ছভাবে হ্যান্ডেল করে; NV12 ফরম্যাটের একটি VideoFrame-এর layout অ্যারেতে কেবল দুটি লেআউট থাকবে।
চ্যালেঞ্জ এবং সেরা অনুশীলন
এই নিম্ন স্তরে কাজ করা শক্তিশালী, কিন্তু এর সাথে দায়িত্বও আসে।
মেমরি ম্যানেজমেন্ট সবচেয়ে গুরুত্বপূর্ণ
একটি VideoFrame একটি উল্লেখযোগ্য পরিমাণ মেমরি ধরে রাখে, যা প্রায়শই জাভাস্ক্রিপ্ট গার্বেজ কালেক্টরের হিপের বাইরে পরিচালিত হয়। আপনি যদি এই মেমরিটি স্পষ্টভাবে রিলিজ না করেন, তবে আপনি একটি মেমরি লিক ঘটাবেন যা ব্রাউজার ট্যাবটি ক্র্যাশ করতে পারে।
সর্বদা, একটি ফ্রেমের কাজ শেষ হলে videoFrame.close() কল করুন।
অ্যাসিঙ্ক্রোনাস প্রকৃতি
সমস্ত ডেটা অ্যাক্সেস অ্যাসিঙ্ক্রোনাস। আপনার অ্যাপ্লিকেশনের আর্কিটেকচারকে রেস কন্ডিশন এড়াতে এবং একটি মসৃণ প্রসেসিং পাইপলাইন নিশ্চিত করতে Promises এবং async/await-এর প্রবাহ সঠিকভাবে পরিচালনা করতে হবে।
ব্রাউজার সামঞ্জস্যতা
WebCodecs একটি আধুনিক API। যদিও সমস্ত প্রধান ব্রাউজারে সমর্থিত, সর্বদা এর প্রাপ্যতা পরীক্ষা করুন এবং যেকোনো বিক্রেতা-নির্দিষ্ট বাস্তবায়ন বিবরণ বা সীমাবদ্ধতা সম্পর্কে সচেতন থাকুন। API ব্যবহার করার চেষ্টা করার আগে ফিচার ডিটেকশন ব্যবহার করুন।
উপসংহার: ওয়েব ভিডিওর জন্য একটি নতুন দিগন্ত
WebCodecs API-এর মাধ্যমে একটি VideoFrame-এর র প্লেন ডেটা সরাসরি অ্যাক্সেস এবং ম্যানিপুলেট করার ক্ষমতা ওয়েব-ভিত্তিক মিডিয়া অ্যাপ্লিকেশনগুলির জন্য একটি দৃষ্টান্ত পরিবর্তন। এটি <video> এলিমেন্টের ব্ল্যাক বক্স সরিয়ে দেয় এবং ডেভেলপারদের সেই দানাদার নিয়ন্ত্রণ দেয় যা আগে নেটিভ অ্যাপ্লিকেশনগুলির জন্য সংরক্ষিত ছিল।
ভিডিও মেমরি লেআউটের মূল বিষয়গুলি—প্লেন, স্ট্রাইড, এবং কালার ফরম্যাট—বোঝার মাধ্যমে এবং পারফরম্যান্স-ক্রিটিক্যাল অপারেশনের জন্য ওয়েবঅ্যাসেম্বলির শক্তি ব্যবহার করে, আপনি এখন সরাসরি ব্রাউজারে অবিশ্বাস্যভাবে অত্যাধুনিক ভিডিও প্রসেসিং সরঞ্জাম তৈরি করতে পারেন। রিয়েল-টাইম কালার গ্রেডিং এবং কাস্টম ভিজ্যুয়াল ইফেক্ট থেকে শুরু করে ক্লায়েন্ট-সাইড মেশিন লার্নিং এবং ভিডিও বিশ্লেষণ পর্যন্ত, সম্ভাবনাগুলি বিশাল। ওয়েবে হাই-পারফরম্যান্স, লো-লেভেল ভিডিওর যুগ সত্যিই শুরু হয়েছে।