VOD প্ল্যাটফর্ম আসলে কী
একটা ভিডিও আপলোড হওয়া থেকে দর্শকের স্ক্রিনে চলা পর্যন্ত পুরো পথ এক পাতায়: প্রতিটা ধাপ কী করে, কোথায় sync আর কোথায় async, অ্যাসেটের state machine, আর নিজে বানাবেন নাকি কিনবেন।
গল্পে বুঝি
রূপগঞ্জের এক জামদানি কারখানা চালায় খোয়ারিজমি। সকালে নারায়ণগঞ্জ থেকে সুতার বস্তা আসে। গেটে বসা ফাতিমা প্রতিটা বস্তা খুলে দেখে: সুতা ভেজা কিনা, রং ঠিক আছে কিনা, ওজন রসিদের সাথে মেলে কিনা। ভেজা বা পচা সুতা সে সেখানেই ফেরত পাঠায়, কারণ তাঁতে উঠে যাওয়ার পর ভুল ধরা পড়লে একটা শাড়ির তিন সপ্তাহের কাজ নষ্ট। ঠিক সুতা গেলে সে একটা খাতায় লেখে, “বস্তা ৪২, লাল রেশম, এসেছে”, আর বস্তার গায়ে একটা নম্বর লাগিয়ে দেয়।
তারপর সুতা যায় তাঁতঘরে। সেখানে দশটা তাঁত, দশজন কারিগর, আর একটা লম্বা তালিকা, কোন অর্ডার আগে বুনতে হবে। একজন ক্রেতা অর্ডার দিয়ে তাঁতের পাশে দাঁড়িয়ে থাকে না; খোয়ারিজমি বলে দেয়, “শাড়ি তৈরি হলে আপনাকে ফোন করব।” বোনা শেষ হলে শাড়ি যায় ধোয়া আর মাড় দেওয়ার ঘরে, তারপর ভাঁজ করা হয় তিন রকমভাবে: দোকানের তাকের জন্য বড় ভাঁজ, কুরিয়ারের জন্য ছোট প্যাকেট, প্রদর্শনীর জন্য খোলা ঝুলিয়ে রাখা। প্রতিটা শাড়ির গায়ে একটা ট্যাগ বসে: নকশার নাম, দাম, সুতার ধরন, কোন কারিগর বুনেছে। শেষে শাড়ি ওঠে ঢাকার শোরুমের তাকে আর চট্টগ্রাম-সিলেটের এজেন্টদের কাছে, যাতে ক্রেতাকে রূপগঞ্জ পর্যন্ত আসতে না হয়।
খাতাটাই পুরো কারখানার মেরুদণ্ড। কোনো ক্রেতা ফোন করে জিজ্ঞেস করলে খোয়ারিজমি খাতা খুলে বলতে পারে, “আপনার শাড়ি এখন ধোয়ার ঘরে, কাল ভাঁজ হবে।” কোনো শাড়ি তাঁতে গিয়ে সুতা ছিঁড়ে আটকে গেলে খাতায় লাল কালিতে লেখা হয় “আটকে আছে, কারণ: সুতা ছেঁড়া”, আর কেউ গিয়ে খোঁজ নেয়। খাতা না থাকলে শাড়ি হারায় না, কিন্তু কেউ জানে না সেটা কোথায়।
মিলিয়ে নিই: সুতার বস্তা আসা হলো আপলোড, গেটে ফাতিমার পরীক্ষা হলো ইনজেস্ট ও ভ্যালিডেশন, আর বস্তার নম্বর হলো অ্যাসেট আইডি। তাঁতের অর্ডার তালিকা হলো জব কিউ, কারিগররা এনকোডিং ওয়ার্কার, আর “তৈরি হলে ফোন করব” হলো async প্রসেসিং আর webhook। তিন রকম ভাঁজ হলো রেন্ডিশন আর প্যাকেজিং (HLS, DASH, MP4 ডাউনলোড), শাড়ির ট্যাগ হলো মেটাডেটা ও ক্যাটালগ, আর ঢাকা-চট্টগ্রামের তাক হলো স্টোরেজ আর CDN। খোয়ারিজমির খাতা হলো অ্যাসেটের state machine, যা প্রতিটা ভিডিও ঠিক এখন কোন অবস্থায় আছে সেটা বলে দেয়। YouTube, Netflix থেকে শুরু করে একটা কোচিং সেন্টারের ভিডিও পোর্টাল পর্যন্ত, সবাই এই একই কারখানা চালায়, শুধু আকারে আলাদা।
VOD মানে কী, আর কী নয়
VOD (Video on Demand) মানে দর্শক যখন চায় তখন ভিডিও চলে: আগে থেকে রেকর্ড করা, আগে থেকে প্রসেস করা, স্টোরেজে রাখা। লাইভ স্ট্রিমিংয়ে ভিডিও তৈরি হচ্ছে ঠিক এখন, তাই প্রতিটা ধাপ সেকেন্ডের হিসাবে চলে। VOD-তে প্রসেসিংয়ের জন্য মিনিট, এমনকি ঘণ্টাও হাতে থাকে, আর এই সময়টাই VOD-এর সবচেয়ে বড় সুবিধা: আপনি ধীরে, ভালো করে, কয়েকবার চেষ্টা করে এনকোড করতে পারেন।
| VOD | লাইভ | |
|---|---|---|
| ভিডিও কখন তৈরি | আগে থেকে | ঠিক এখন |
| প্রসেসিংয়ের সময় | মিনিট থেকে ঘণ্টা | সেকেন্ডের ভগ্নাংশ |
| এনকোডিং | ধীর preset, two-pass, per-title সম্ভব | রিয়েল-টাইম, এক পাসে |
| ব্যর্থ হলে | আবার চালাও | মুহূর্তটা চলে গেছে |
| স্টোরেজ | পুরো লাইব্রেরি, বছরের পর বছর | সাধারণত একটা রোলিং উইন্ডো |
| মূল চ্যালেঞ্জ | খরচ, লাইব্রেরির আকার, বিচিত্র ইনপুট ফাইল | লেটেন্সি, রিলায়েবিলিটি |
লাইভের দিকটা আছে লাইভ স্ট্রিমিং ট্র্যাকে। লাইভ শেষ হলে রেকর্ডিংটা সাধারণত এই VOD পাইপলাইনেই ঢোকে।
পুরো পথ এক নজরে
একটা VOD প্ল্যাটফর্মের সাতটা ধাপ, আর চারটা পাশের সিস্টেম যেগুলো প্রতিটা ধাপকে ছুঁয়ে যায়।
| ধাপ | কী করে | কোথায় বিস্তারিত |
|---|---|---|
| ১. আপলোড | বড় ফাইল নির্ভরযোগ্যভাবে স্টোরেজে তোলা | চ্যাপ্টার ২ |
| ২. ইনজেস্ট | ফাইলটা আসলে কী, চালানো যায় কিনা, যাচাই | চ্যাপ্টার ৩ |
| ৩. এনকোডিং | একটা সোর্স থেকে অনেকগুলো রেন্ডিশন | চ্যাপ্টার ৪, আর ট্রান্সকোডিং পাইপলাইন |
| ৪. স্টোরেজ | রেন্ডিশনগুলো কোথায়, কোন নামে, কতদিন | চ্যাপ্টার ৫ |
| ৫. প্যাকেজিং | HLS/DASH সেগমেন্ট আর ম্যানিফেস্ট | চ্যাপ্টার ৬, আর স্ট্রিমিংয়ের জন্য প্যাকেজিং |
| ৬. ডেলিভারি | origin আর CDN | চ্যাপ্টার ১১, আর CDN ট্র্যাক |
| ৭. প্লেব্যাক | প্লেয়ার ম্যানিফেস্ট পড়ে চালায় | ভিডিও প্লেয়ার ট্র্যাক |
পাশের চারটা সিস্টেম: ক্যাটালগ ও মেটাডেটা (চ্যাপ্টার ৯), অথ ও সিকিউরিটি (চ্যাপ্টার ৮), থাম্বনেইল ও ক্যাপশন (চ্যাপ্টার ৭), আর অ্যানালিটিক্স ও খরচ (চ্যাপ্টার ১০)।
প্রথমবার ডিজাইন করার সময় সবচেয়ে বেশি যে ভুল হয়: আপলোড API নিজেই ফাইলটা রিসিভ করে, সেখানেই ffmpeg চালায়, আর কাজ শেষ হলে রেসপন্স দেয়। ১০ সেকেন্ডের ক্লিপে এটা চলে। এক ঘণ্টার লেকচার ভিডিওতে রিকোয়েস্ট টাইমআউট হয়, সার্ভারের CPU আটকে যায়, আর ইউজার রিফ্রেশ করলে কাজটা আবার শুরু হয়। নিচের sync/async অংশটা এই ভুলটা ঠেকানোর জন্যই।
অ্যাসেট: পুরো সিস্টেমের কেন্দ্র
প্ল্যাটফর্মের সবকিছু একটা ধারণার চারপাশে ঘোরে: অ্যাসেট (asset)। অ্যাসেট মানে “একটা ভিডিও”, তার সোর্স ফাইল, তার সব রেন্ডিশন, তার মেটাডেটা, আর সে এখন কোন অবস্থায় আছে। ইউজার ভিডিও আপলোড করে না, ইউজার একটা অ্যাসেট তৈরি করে আর তাতে ফাইল তোলে। এই ছোট পার্থক্যটা পুরো ডিজাইন সহজ করে দেয়, কারণ আপলোড শুরু হওয়ার আগেই অ্যাসেটের একটা আইডি থাকে, যেটা দিয়ে সব ধাপ একে অপরকে চেনে।
State machine
create
│
▼
┌───────────┐ upload starts ┌───────────┐
│ created │ ─────────────────▶ │ uploading │
└───────────┘ └───────────┘
│ expires (no upload) │ upload complete
▼ ▼
┌───────────┐ ┌───────────┐
│ expired │ │ processing│ ◀── retry (transient)
└───────────┘ └───────────┘
│ │
all done │ │ permanent failure
▼ ▼
┌────────┐ ┌─────────┐
│ ready │ │ errored │
└────────┘ └─────────┘
│
▼ user deletes
┌──────────┐
│ deleted │
└──────────┘ PostgreSQL-এ এটা সবচেয়ে সরলভাবে একটা status কলাম আর একটা CHECK constraint:
CREATE TABLE assets (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
owner_id uuid NOT NULL REFERENCES users(id),
status text NOT NULL DEFAULT 'created'
CHECK (status IN ('created','uploading','processing','ready','errored','expired','deleted')),
error_code text, -- stable code, e.g. 'source_no_video_stream'
source_key text, -- object key of the original upload
duration_ms integer,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
-- Transitions are guarded in SQL, so two workers cannot both move the same asset.
UPDATE assets
SET status = 'processing', updated_at = now()
WHERE id = $1 AND status = 'uploading'
RETURNING id; শেষের WHERE ... AND status = 'uploading' লাইনটাই আসল কাজ করে। দুটো ওয়ার্কার একই “আপলোড শেষ” ইভেন্ট পেলে (কিউগুলো প্রায় সবসময় at-least-once দেয়), একজনের UPDATE একটা row ফেরত দেবে, অন্যজনেরটা শূন্য। শূন্য পেলে সে চুপচাপ থেমে যায়। এতে কোনো লক বা আলাদা কোঅর্ডিনেশন লাগে না।
errored অবস্থায় শুধু “failed” লিখে রাখবেন না। একটা স্থির error code রাখুন (source_no_video_stream, source_too_long, source_corrupt), যেটা UI নিজের ভাষায় ইউজারকে বোঝাবে। ffmpeg-এর কাঁচা stderr কখনো ইউজারকে দেখাবেন না: “moov atom not found” কারো কাজে আসে না, “ফাইলটা পুরোপুরি আপলোড হয়নি, আবার চেষ্টা করুন” আসে।
Sync আর async: কোথায় রেখা টানবেন
নিয়মটা সরল: যে কাজ এক সেকেন্ডের কম আর প্রায় কখনো ব্যর্থ হয় না, সেটা রিকোয়েস্টের ভেতরে। বাকি সব কিউতে।
| কাজ | কোথায় | কেন |
|---|---|---|
| অ্যাসেট তৈরি, আপলোড URL দেওয়া | sync (API) | কয়েক মিলিসেকেন্ড, শুধু DB রো আর একটা সাইন |
| ফাইল আপলোড | ক্লায়েন্ট থেকে সরাসরি স্টোরেজে | API সার্ভারকে গিগাবাইট ধরে রাখতে হয় না |
| প্রোবিং | async | বড় ফাইলে কয়েক সেকেন্ড, নেটওয়ার্ক থেকে পড়তে হয় |
| এনকোডিং | async | মিনিট থেকে ঘণ্টা |
| প্যাকেজিং, থাম্বনেইল | async | এনকোডিংয়ের পরে, আলাদা রিট্রাই |
| “তৈরি হয়েছে” জানানো | async (webhook / ইমেইল) | ইউজার অপেক্ষা করে না |
| প্লেব্যাক URL দেওয়া | sync (API) | দ্রুত, ক্যাশ করা যায় |
async অংশ চালানোর জন্য একটা জব কিউ লাগে। এই ট্র্যাকে আমরা River ব্যবহার করব (PostgreSQL-এর উপর Go জব কিউ), কারণ অ্যাসেটের রো আর জব একই ট্রানজ্যাকশনে লেখা যায়: অ্যাসেট processing হলো কিন্তু জব কিউতে ঢুকল না, এমন অবস্থা তৈরিই হতে পারে না। বিস্তারিত চ্যাপ্টার ৪-এ, সাধারণ ধারণা আছে ব্যাকগ্রাউন্ড জব কেন চ্যাপ্টারে।
“তৈরি হয়েছে” কীভাবে জানাবেন
ইউজার বা ইন্টিগ্রেট করা অ্যাপ জানতে চায় কখন ভিডিও চালানো যাবে। তিনটা উপায়:
- পোলিং: ক্লায়েন্ট প্রতি কয়েক সেকেন্ডে
GET /assets/:idকরে। সবচেয়ে সরল, কিন্তু হাজার অ্যাসেটে অপচয়। - webhook: স্ট্যাটাস বদলালে প্ল্যাটফর্ম ক্লায়েন্টের সার্ভারে একটা সাইন করা POST পাঠায়। সার্ভার-টু-সার্ভার ইন্টিগ্রেশনের জন্য সঠিক উপায়।
- ব্রাউজারে লাইভ আপডেট: Server-Sent Events বা WebSocket, যাতে আপলোড পেজ নিজেই “প্রসেস হচ্ছে… তৈরি!” দেখায়।
webhook পাঠানোর নিয়মগুলো (সাইনিং, রিট্রাই, আইডেম্পোটেন্সি) আলাদা একটা পুরো ট্র্যাক: Webhooks। এখানে শুধু ইভেন্টের আকারটা:
{
"id": "evt_01JB8Z5Q2T9KX",
"type": "asset.ready",
"created_at": "2026-10-25T06:12:44Z",
"data": {
"asset_id": "5b0e7c1a-2f3d-4c6e-9a1b-7d8e9f0a1b2c",
"duration_ms": 3612480,
"playback_id": "pb_baytalhikma_lecture_07",
"renditions": ["1080p", "720p", "480p", "360p"]
}
} ইভেন্টে পুরো অ্যাসেট না পাঠিয়ে আইডি আর দরকারি কয়েকটা ফিল্ড পাঠান। রিসিভার দরকার হলে API থেকে টাটকা অবস্থা পড়ে নেবে, তাতে দুটো ইভেন্ট উল্টো ক্রমে পৌঁছালেও ক্ষতি হয় না।
একটা ছোট প্ল্যাটফর্মের সংখ্যা
ধরুন বায়তুল হিকমা নামে একটা অনলাইন শিক্ষা প্ল্যাটফর্ম, মাসে ৫০০টা লেকচার আপলোড হয়, প্রতিটা গড়ে ৪৫ মিনিট। মোটামুটি হিসাবটা দেখতে এরকম (আনুমানিক সংখ্যা, শুধু অনুপাত বোঝার জন্য):
uploads per month : 500 videos × 45 min = 22,500 min of source
source size : ~1 GB per 45-min phone/OBS recording → ~500 GB/month
renditions : 1080p + 720p + 480p + 360p, total ~2.5 Mbps average
output size : 45 min × 60 s × 2.5 Mbps / 8 ≈ 0.85 GB per video
→ ~420 GB/month of renditions
encode time : with a fast preset, ~0.5–1× real time per rendition set
on a decent 8-core VPS → 11,000–22,000 min of CPU/month
egress : 2,000 students × 10 hours/month × ~1.5 Mbps watched
≈ 13.5 TB/month ← this is the bill শেষ লাইনটাই বেশিরভাগ নতুন প্ল্যাটফর্মকে চমকে দেয়। এনকোডিং একবার হয়, স্টোরেজ ধীরে বাড়ে, কিন্তু ডেলিভারি (egress) প্রতিবার দেখার সাথে বাড়ে। চ্যাপ্টার ১০-এ এই হিসাবটা বিস্তারিত।
নিজে বানাবেন নাকি কিনবেন
এই প্রশ্নটা সৎভাবে উত্তর দেওয়া দরকার, কারণ পুরো ট্র্যাকটাই নিজে বানানো শেখায়, আর সেটা সবসময় সঠিক উত্তর না।
ম্যানেজড ভিডিও সার্ভিস (Mux, Cloudflare Stream, Bunny Stream এবং আরও অনেকে) একটা API দেয়: ফাইল দিন, প্লেব্যাক আইডি নিন। আপলোড, এনকোডিং, প্যাকেজিং, CDN, প্লেয়ার, অ্যানালিটিক্স সব তাদের। দাম সাধারণত মিনিট-ভিত্তিক (কত মিনিট স্টোর করা আছে, কত মিনিট দেখা হয়েছে), আর এই মডেল ও হার নিয়মিত বদলায়, তাই নিজের হিসাবের আগে প্রতিটার প্রাইসিং পেজ দেখে নিন।
| কিনলে | নিজে বানালে | |
|---|---|---|
| প্রথম ভিডিও চালু হতে | এক বিকেল | কয়েক সপ্তাহ |
| অদ্ভুত ইনপুট ফাইল সামলানো | তাদের মাথাব্যথা | আপনার (চ্যাপ্টার ৩) |
| খরচ বাড়ে | দেখার মিনিটের সাথে, সরলরেখায় | মূলত ব্যান্ডউইথ আর CPU-র সাথে, ধাপে ধাপে |
| নিয়ন্ত্রণ | তাদের ফিচার আর সীমার মধ্যে | পুরোটা |
| ডেটা কোথায় থাকে | তাদের সার্ভারে | আপনার সার্ভারে |
| লক-ইন | প্লেব্যাক আইডি, প্লেয়ার, অ্যানালিটিক্স সব তাদের | নেই |
| কাদের দরকার | ছোট টিম, ভিডিও মূল প্রোডাক্ট না | ভিডিও-ই প্রোডাক্ট, বা ভলিউম বড়, বা ডেটা দেশে রাখতে হবে |
একটা মাঝামাঝি পথও আছে: এনকোডিং আর স্টোরেজ নিজের VPS-এ, শুধু ডেলিভারি একটা CDN দিয়ে। VOD খরচের বড় অংশ যেহেতু ডেলিভারি, আর এনকোডিং একবারের কাজ, তাই অনেক ছোট প্ল্যাটফর্মের জন্য এটাই সবচেয়ে ভালো ভারসাম্য। চ্যাপ্টার ১২-এ ঠিক এই আকারের একটা প্ল্যাটফর্ম বানাব।
কখন কিনবেন, এক লাইনে: যদি ভিডিও আপনার প্রোডাক্টের একটা ফিচার মাত্র (একটা SaaS-এ টিউটোরিয়াল ভিডিও, একটা ই-কমার্সে প্রোডাক্ট ক্লিপ), কিনুন। যদি ভিডিও-ই আপনার প্রোডাক্ট (একটা কোর্স প্ল্যাটফর্ম, একটা স্ট্রিমিং সার্ভিস), এই ট্র্যাকের সবকিছু আপনার জানা দরকার, কিনলেও।
প্রতিটা ধাপের নিজস্ব ব্যর্থতা
পরের চ্যাপ্টারগুলো একেকটা ধাপ ধরে এগোবে। প্রতিটা ধাপ আলাদা কারণে ভাঙে, আর ডিবাগিং মানেই প্রথমে খুঁজে বের করা কোন ধাপে ভেঙেছে।
| ধাপ | সাধারণ ব্যর্থতা |
|---|---|
| আপলোড | মোবাইল নেটওয়ার্কে মাঝপথে কেটে যাওয়া, presigned URL-এর মেয়াদ শেষ, CORS |
| ইনজেস্ট | ফাইল ভাঙা, অডিও নেই, ভিডিও কাত, HDR, অদ্ভুত ফ্রেম রেট |
| এনকোডিং | ওয়ার্কার মেমরি শেষ, একটা ভাঙা ফাইল বারবার রিট্রাই, কিউ জমে যাওয়া |
| স্টোরেজ | ভুল কী, অর্ধেক লেখা আউটপুট, মুছে ফেলা ফাইল এখনো রেফার করা |
| প্যাকেজিং | কীফ্রেম না মেলা, ম্যানিফেস্টে ভুল কোডেক স্ট্রিং |
| ডেলিভারি | CORS, ক্যাশে পুরনো ম্যানিফেস্ট, origin-এ ভিড় |
| প্লেব্যাক | ডিভাইস কোডেক সাপোর্ট করে না, টোকেনের মেয়াদ শেষ |
ডিবাগিং: এই চ্যাপ্টারের সমস্যাগুলো
এই চ্যাপ্টারের সমস্যাগুলো ধাপের না, পুরো সিস্টেমের: অ্যাসেট কোথাও আটকে আছে, বা স্টেট মিথ্যা বলছে।
| লক্ষণ | নিশ্চিত করুন | সমাধান |
|---|---|---|
অ্যাসেট ঘণ্টার পর ঘণ্টা processing-এ | SELECT id, status, updated_at FROM assets WHERE status = 'processing' AND updated_at < now() - interval '2 hours'; তারপর ওই অ্যাসেটের জব কিউতে আছে কিনা দেখুন | প্রতিটা স্টেটের জন্য সর্বোচ্চ সময় ঠিক করুন; একটা পিরিয়ডিক জব সেটা পার হলে অ্যাসেটকে errored করে বা জব আবার চালায় |
অ্যাসেট uploading-এ, কিন্তু ফাইল স্টোরেজে আছে | aws s3api head-object --endpoint-url $S3_ENDPOINT --bucket vod-source --key SOURCE_KEY দিয়ে ফাইল আছে কিনা দেখুন | “আপলোড শেষ” ইভেন্ট হারিয়েছে। ক্লায়েন্টের complete কলের উপর একা নির্ভর না করে, স্টোরেজের নোটিফিকেশন বা পিরিয়ডিক রিকনসিলিয়েশনও রাখুন (চ্যাপ্টার ২) |
| একই ভিডিও দুবার এনকোড হলো | জব টেবিলে একই অ্যাসেটের দুটো জব খুঁজুন | স্টেট ট্রানজিশন SQL-এ গার্ড করুন (WHERE status = 'uploading') আর জবকে ইউনিক করুন (চ্যাপ্টার ৪) |
ready কিন্তু প্লেয়ারে ৪০৪ | ম্যানিফেস্ট URL curl -I করুন | ready সেট করার আগে আউটপুট সত্যিই আছে কিনা যাচাই করুন; প্যাকেজিং শেষ না হলে ready না |
| webhook পৌঁছায়নি | পাঠানোর লগে স্ট্যাটাস কোড আর রিট্রাই সংখ্যা দেখুন | webhook-কেও একটা জব বানান, নিজস্ব রিট্রাই আর ডেড-লেটারসহ (webhook রিট্রাই) |
| ইউজার দেখছে “কিছু একটা ভুল হয়েছে” | error_code কলাম দেখুন | প্রতিটা স্থায়ী ব্যর্থতার জন্য একটা স্থির কোড, আর UI-তে কোড থেকে মানুষের ভাষার মেসেজ |
মূল শিক্ষা
- VOD একটা কারখানা: আপলোড, ইনজেস্ট, এনকোড, প্যাকেজ, স্টোর, ডেলিভার, প্লে। প্রতিটা ধাপ আলাদাভাবে ব্যর্থ হয় আর আলাদাভাবে রিট্রাই করা উচিত।
- অ্যাসেট কেন্দ্রে: আপলোড শুরুর আগেই অ্যাসেটের আইডি থাকে, আর একটা state machine জানে প্রতিটা ভিডিও এখন কোথায়।
- স্টেট ট্রানজিশন SQL-এ গার্ড করুন:
WHERE status = 'from'দিয়ে, যাতে duplicate ইভেন্ট নিরীহ থাকে। - এক সেকেন্ডের বেশি যা লাগে, তা কিউতে: API সার্ভার কখনো ffmpeg চালায় না বা গিগাবাইট ফাইল ধরে রাখে না।
- “তৈরি হয়েছে” জানাতে webhook: ছোট ইভেন্ট, আইডি সহ, সাইন করা আর রিট্রাই করা।
- খরচের বড় অংশ ডেলিভারি: এনকোডিং একবার, দেখা হাজারবার।
- কিনবেন নাকি বানাবেন নির্ভর করে ভিডিও আপনার প্রোডাক্টের ফিচার নাকি প্রোডাক্ট নিজেই, তার উপর।