Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. spawn va argumentlar massivi
- 2.1 Nega exec emas
- 2.2 Kanonning ffmpeg yordamchisi
- 3. ffprobe: video haqida ma'lumot
- 4. Thumbnail
- 5. HLS: video bo'laklari
- 5.1 Nima uchun bo'laklash
- 5.2 Kanon topilmasi: 4 emas, 8.33
- 5.3 Bir nechta sifat
- 6. Audio
- 7. Progress va timeout
- 7.1 Progress
- 7.2 Timeout
- 8. fluent-ffmpeg va boshqa paketlar
- 9. Navbat va worker
- 10. Hujumchi nigohi
- 11. Ko'p uchraydigan xatolar
- 12. Mashqlar
- 1-mashq (oson): to'g'ri yoki noto'g'ri
- 2-mashq (o'rta): ffprobe xulosasi
- 3-mashq (qiyin): master playlist
- 13. Loyiha qadami: kanon tajribasi, loyihaga kirmaydi
- 14. Real ishda
- Xulosa
- Manbalar
Video va audio: ffmpeg'ni Node'dan xavfsiz ishga tushirish
Qisqacha: Video bilan ishlashning amaliy yagona vositasi — ffmpeg, alohida dastur. Node uni
child_process.spawnbilan ishga tushiradi: argumentlar massiv bo'lib beriladi (shell yo'q — fayl nomi orqali buyruq bajarib bo'lmaydi),-progress pipe:1dan foiz o'qiladi, osilib qolsa timeout bilan o'ldiriladi. Kanon tajribasida 20 soniyalik video 4 soniyalik HLS bo'laklarga emas, 8.33 soniyalik bo'laklarga kesildi — sabab keyframe. Video qayta ishlash — og'ir ish: faqat navbat va alohida worker'da.
Bu darsda
- ffmpeg'ni
spawnbilan ishga tushirasiz va negaexecemasligini injection misolida ko'rasiz. - ffprobe bilan video haqida ma'lumot olasiz, thumbnail yasaysiz.
- HLS segmentlash va keyframe bog'liqligini kanon chiqishi bilan tushunasiz.
- Audioni MP3 va Opus'ga o'tkazasiz, progress va timeout'ni boshqarasiz.
- Nega video ishlovi API jarayonida emas, worker'da bo'lishini bilasiz.
Oldin bilishingiz kerak: child_process: tashqi dasturlarni ishga tushirish, Rasmlarni qayta ishlash: sharp, Stream nima: to'rt turi va rejimlari, SSRF va tashqi URL'lar bilan ishlash.
Oldingi darsda rasmni sharp bilan qayta ishladik — kutubxona Node ichida ishladi. Video uchun bunday kutubxona yo'q: ishni tashqi dastur qiladi, Node uni boshqaradi.
1. Nega bu kerak?
Foydalanuvchi telefondan 2 daqiqalik video yukladi: 180 MB, HEVC kodek, 4K. Muammolar:
- Ko'rsatib bo'lmaydi. Ba'zi brauzerlar HEVC'ni o'ynatmaydi; 4K — telefon internetida to'xtab-to'xtab.
- Ro'yxatda nima ko'rsatiladi? Video uchun ham kichik rasm (thumbnail) kerak.
- Ovozli xabar (Telegram bot — shu qismning keyingi darslari) —
.oggkerak, foydalanuvchi.m4ayubordi.
Bularning hammasini ffmpeg qiladi: video va audioni o'qiydi, kodlaydi (transkodlash — transcoding), kesadi, bo'laklaydi. U C da yozilgan, juda tez, lekin juda og'ir: 1 daqiqalik videoni qayta kodlash protsessorni o'nlab soniya band qiladi.
Kanon mashinasidagi versiya:
ffmpeg version 9.0.2-full_build-www.gyan.dev Copyright (c) 2000-2026 the FFmpeg developers (winget, Gyan.dev full build)Windows'da winget, Linux'da paket menejeri yoki Docker image orqali o'rnatiladi. npm'dagi ffmpeg-static paketi tayyor binar beradi — kanonga kerak bo'lmadi.
2. spawn va argumentlar massivi
2.1 Nega exec emas
child_process darsidan eslang: exec buyruqni shell orqali bajaradi, spawn/execFile esa dasturni to'g'ridan, argumentlar massivi bilan. Video uchun bu farq — xavfsizlik masalasi. Foydalanuvchi faylini x.mp4; echo BUZILDI > pwned.txt deb nomladi:
function thumbnailArgs(kirish, chiqish, soniya = 5, eni = 320) {
return [
"-hide_banner", "-nostdin", "-y",
"-ss", String(soniya), "-i", kirish,
"-frames:v", "1", "-vf", `scale=${eni}:-2`, chiqish,
];
}
const nom = "x.mp4; echo BUZILDI > pwned.txt";
const args = thumbnailArgs(nom, "t.jpg");
console.log(args.length, JSON.stringify(args[6]));
const satr = `ffmpeg -ss 5 -i ${nom} t.jpg`;
console.log(satr.split(";").map((s) => s.trim()));Konsolda:
12 "x.mp4; echo BUZILDI > pwned.txt"
[ 'ffmpeg -ss 5 -i x.mp4', 'echo BUZILDI > pwned.txt t.jpg' ]Massivda nom — bitta element, ffmpeg uni fayl nomi deb oladi. Satrda esa shell ; ni buyruqlar ajratgichi deb ko'radi — ikkinchi buyruq bajariladi. Kanon massiv bilan haqiqatan sinadi:
yo'q fayl: ffmpeg kod=4294967294 signal=null: Error opening input files: No such file or directory
massiv argument: fayl nomi butunligicha ffmpeg'ga ketdi → ffmpeg kod=4294967274 signal=null: Error opening input files: Invalid argument
pwned.txt bor: falsepwned.txt yaratilmadi. ffmpeg nomni ochishga urindi va "Invalid argument" dedi (Windows'da ;, > fayl nomida taqiqlangan).
Kodlar g'alati ko'rinadi. Windows'da ffmpeg manfiy kod qaytaradi, Node esa uni 32 bitli ishorasiz son sifatida ko'rsatadi:
console.log(4294967294 | 0, 4294967274 | 0);Konsolda:
-2 -22-2 — "fayl yo'q" (ENOENT), -22 — "noto'g'ri argument" (EINVAL). Linux'da kod boshqacha bo'lishi mumkin (sinalmagan) — shuning uchun kodga emas, 0 yoki 0 emasligiga qarang, tafsilotni stderr'dan oling.
2.2 Kanonning ffmpeg yordamchisi
import { spawn } from "node:child_process";
/** argumentlar MASSIV (shell yo'q), stderr dan oxirgi xato,
* stdout dan progress, timeout → SIGKILL */
function ffmpeg(args, { timeoutMs = 60_000, progress } = {}) {
return new Promise((ok, yoq) => {
const p = spawn("ffmpeg", ["-hide_banner", "-nostdin", "-y",
"-progress", "pipe:1", "-nostats", ...args],
{ stdio: ["ignore", "pipe", "pipe"] });
let xato = "";
p.stderr.on("data", (b) => { xato = (xato + b).slice(-2000); });
p.stdout.on("data", (b) => {
for (const q of String(b).split("\n")) {
if (q.startsWith("out_time_ms=") && progress) {
progress(Number(q.slice(12)) / 1e6);
}
}
});
const t = setTimeout(() => { p.kill("SIGKILL"); }, timeoutMs);
p.on("close", (kod, signal) => {
clearTimeout(t);
if (kod === 0) ok();
else yoq(new Error(`ffmpeg kod=${kod} signal=${signal}: ` +
xato.trim().split("\n").at(-1)));
});
});
}Har bayroq nimaga:
| Bayroq / sozlama | Nega |
|---|---|
-nostdin |
ffmpeg klaviaturadan buyruq kutmasin (fonda osilib qoladi) |
-y |
chiqish fayli bo'lsa, so'ramasdan ustiga yozsin |
-progress pipe:1 |
holatni kalit=qiymat qatorlari bilan stdout'ga |
-nostats |
stderr'ni progress chiqindisi bilan to'ldirmasin |
| stderr oxirgi 2000 belgi | ffmpeg ko'p yozadi — xotira o'smasin, xato oxirida |
setTimeout + SIGKILL |
buzilgan fayl ffmpeg'ni osiltirib qo'yishi mumkin |
Telefon uchun qatorlarni bo'ldik — mantiq aynan kanondagidek.
3. ffprobe: video haqida ma'lumot
Videoni qayta ishlashdan oldin — nima ekanini bilish. ffmpeg bilan birga keladigan ffprobe JSON beradi:
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const pexec = promisify(execFile);
const { stdout } = await pexec("ffprobe", ["-v", "error",
"-print_format", "json", "-show_format", "-show_streams", video]);
const probe = JSON.parse(stdout);Kanon 20 soniyalik sinov videosi (testsrc2 — ffmpeg'ning o'zi yasaydigan rangli sinov tasviri + 440 Hz tovush; 1.6 s da yasaldi, 6.85 MB) uchun:
{
davomiylik: '20.000000',
format: 'mov,mp4,m4a,3gp,3g2,mj2',
bit_rate: '2874374',
oqimlar: [ 'video:h264 1280x720', 'audio:aac' ]
}Qiymatlar satr ('20.000000') — Number() bilan aylantiring. ffprobe natijasi bilan siz:
- juda uzun videoni rad etasiz (limit — masalan 10 daqiqa);
- video oqimi yo'q faylni (aslida audio) aniqlaysiz;
- qayta kodlash kerakmi (
h264+aac— brauzerlar uchun tayyor) hal qilasiz.
Diqqat: Fayl kengaytmasi (
.mp4) vaContent-Type— mijoz so'zi (Fayl yuklash xavfsizligi). ffprobe ham faylni o'qiydi — u ham kirish ma'lumotini qayta ishlovchi parser. ffprobe'ni ham timeout bilan, ishonchsiz faylga alohida jarayonda yurgizing.
4. Thumbnail
5-soniyadagi kadr, eni 320:
-ss oldin 160 ms
-ss keyin 177 ms-ss 5 -i video (kirishdan oldin) — ffmpeg 5-soniyaga tez "sakraydi" (yaqin keyframe'ga). -i video -ss 5 (keyin) — boshidan 5 soniyagacha hamma kadrni ochib boradi. 20 soniyalik videoda farq kichik (160 va 177 ms). 2 soatlik filmda 1-soatdagi kadr uchun "keyin" varianti butun birinchi soatni ochadi — farq soniyalar va daqiqalar.
scale=320:-2 — eni 320, bo'yi nisbat bo'yicha, juft son (-2): ko'p kodeklar toq o'lchamni qabul qilmaydi.
5. HLS: video bo'laklari
5.1 Nima uchun bo'laklash
Brauzer 200 MB videoni to'liq yuklab, keyin o'ynatishi shart emas. HLS (HTTP Live Streaming) videoni bir necha soniyalik bo'laklarga (segment, .ts) bo'ladi va ro'yxat fayli (.m3u8, playlist) yozadi. Pleyer ro'yxatni o'qiydi va bo'laklarni ketma-ket yuklaydi. Har bo'lak — oddiy fayl: S3 dan presigned yoki CDN orqali berish mumkin.
5.2 Kanon topilmasi: 4 emas, 8.33
Kanon -hls_time 4 (4 soniyalik bo'lak) so'radi:
986 ms; fayllar: index.m3u8 seg_000.ts seg_001.ts seg_002.ts
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:8.333333,
seg_000.ts
#EXTINF:8.333333,
seg_001.ts
#EXTINF:3.333333,
seg_002.ts
#EXT-X-ENDLISTRo'yxatni JS bilan tahlil qilamiz (kanon chiqishining o'zi kirish sifatida):
const m3u8 = `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:8.333333,
seg_000.ts
#EXTINF:8.333333,
seg_001.ts
#EXTINF:3.333333,
seg_002.ts
#EXT-X-ENDLIST`;
const seg = [...m3u8.matchAll(/#EXTINF:([\d.]+),\n(\S+)/g)]
.map((m) => ({ fayl: m[2], s: Number(m[1]) }));
console.log(seg);
const jami = seg.reduce((a, x) => a + x.s, 0);
console.log("jami:", jami.toFixed(2), "s");
console.log("GOP:", (250 / 30).toFixed(2), "s");Konsolda:
[
{ fayl: 'seg_000.ts', s: 8.333333 },
{ fayl: 'seg_001.ts', s: 8.333333 },
{ fayl: 'seg_002.ts', s: 3.333333 }
]
jami: 20.00 s
GOP: 8.33 sSabab — keyframe (kalit kadr). Videoda har kadr to'liq saqlanmaydi: faqat kalit kadr to'liq, qolganlari — undan farq. Bo'lakni faqat kalit kadrda boshlash mumkin. Kodlovchi x264 sukutda har 250 kadrda kalit kadr qo'yadi (GOP — kadrlar guruhi). 30 fps da bu 8.33 soniya. ffmpeg 4 soniyada kesmoqchi bo'ldi, lekin u yerda kalit kadr yo'q edi — keyingisigacha kutdi.
Kalit kadrlarni majburlash:
#EXTINF:4.000000, #EXTINF:4.000000, #EXTINF:4.000000, #EXTINF:4.000000, #EXTINF:4.000000,-force_key_frames "expr:gte(t,n_forced*4)" — "har 4 soniyada kalit kadr" — va bo'laklar aynan 4.000. Kalit kadr ko'paysa fayl biroz kattalashadi — bu kelishuv.
Tekshirib ko'ring: Video 25 fps, GOP 250 kadr,
-hls_time 4. Bo'laklar taxminan qancha bo'ladi?
Javob
250 / 25 = 10 soniya. Kalit kadr har 10 soniyada — ffmpeg 4 soniyada kesa olmaydi, bo'laklar ~10 soniyadan chiqadi (oxirgisi qoldiq). Aniq 4 soniya uchun yana -force_key_frames yoki -g 100 (25 × 4).
5.3 Bir nechta sifat
Kanon bitta sifat (480p) yasadi. Haqiqiy pleyerlar internet tezligiga qarab sifatni almashtiradi (adaptive bitrate): har sifat — alohida ro'yxat, ularni master playlist birlashtiradi. Buni 3-mashqda yasaysiz. Har qo'shimcha sifat — yana bir to'liq transkodlash, ya'ni CPU vaqti.
flowchart LR
V[Asl video] --> F1[ffmpeg 360p]
V --> F2[ffmpeg 720p]
F1 --> P1[360p/index.m3u8 + .ts]
F2 --> P2[720p/index.m3u8 + .ts]
P1 --> M[master.m3u8]
P2 --> M
M --> PL[Pleyer: tezlikka qarab tanlaydi]6. Audio
mp3 313.6 KB
ogg 116.0 KB20 soniyalik AAC ovoz: MP3 128 kbit/s — 313.6 KB, Opus 32 kbit/s (.ogg) — 116 KB. Opus — nutq uchun juda samarali kodek; Telegram Bot API hujjatiga ko'ra ovozli xabar (sendVoice) OPUS bilan kodlangan .ogg fayl bo'lishi kerak. Musiqa uchun 32 kbit/s kam — 96–128 tanlang.
Hisob: 128 000 bit/s × 20 s / 8 = 320 000 bayt ≈ 312.5 KB — kanon natijasiga juda yaqin (fayl sarlavhalari qo'shimcha).
7. Progress va timeout
7.1 Progress
-progress pipe:1 stdout'ga davriy ravishda (hujjatga ko'ra sukutda har 0.5 soniyada, -stats_period) va ish oxirida qatorlar yozadi: frame=…, out_time_ms=…, progress=continue, oxirida progress=end. Kanon 20 soniyalik videoni yasaganda 3 ta progress hodisasi oldi (oxirgisi 20.0 s). Foizni hisoblash (pastdagi kirish — ffmpeg formatidagi namuna, kanon chiqishi emas):
const namuna = [
"frame=150", "fps=0.00", "out_time_us=5000000",
"out_time_ms=5000000", "out_time=00:00:05.000000",
"speed=10.1x", "progress=continue",
].join("\n");
function foiz(bolak, davomiylik) {
for (const q of bolak.split("\n")) {
if (q.startsWith("out_time_ms=")) {
const s = Number(q.slice(12)) / 1e6;
return Math.min(100, Math.round((s / davomiylik) * 100));
}
}
return undefined;
}
console.log(foiz(namuna, 20), foiz("progress=end", 20));Konsolda:
25 undefinedNozik joy: out_time_ms nomiga qaramay mikrosoniyalarda — shuning uchun kanon 1e6 ga bo'ladi (out_time_us bilan bir xil qiymat). Davomiylik ffprobe'dan olinadi. Foizni bazaga yoki navbat vazifasining progress maydoniga yozasiz, frontend uni Server-Sent Events bilan ko'rsatadi.
7.2 Timeout
Kanon 10 daqiqalik 1080p videoni preset slow bilan kodlashni boshladi va 1 soniyada o'ldirdi:
ffmpeg kod=null signal=SIGKILLkod=null — jarayon o'zi tugamadi, signal=SIGKILL bilan o'ldirildi. Windows'da kill("SIGKILL") jarayonni majburan tugatadi (Linux'da signal; Windows'da Node ekvivalentini qiladi). Yarim yozilgan chiqish faylini keyin o'chiring.
Timeout qanday tanlanadi: videoning davomiyligi × "tezlik koeffitsienti" × zaxira. Masalan 2 daqiqalik video veryfast bilan ~10x tezlikda — 12 s; timeout — 2–3 daqiqa.
8. fluent-ffmpeg va boshqa paketlar
Internetdagi ko'p misollar fluent-ffmpeg paketi bilan: zanjirli API (ffmpeg(kirish).size("320x?").save(chiqish)). Kanon npm view bilan tekshirdi — paket npm'da deprecated ("Package no longer supported") va repozitoriya arxivlangan. Yangi loyihada ishlatmang: u ham ichida spawn qiladi, foydasi — faqat qulay API. Kanon yo'li — o'zingizning 20 qatorlik yordamchingiz («Kanonning ffmpeg yordamchisi» bo'limi).
| Variant | Holat | Izoh |
|---|---|---|
O'z spawn yordamchingiz |
kanon | to'liq nazorat, bog'liqliksiz |
| fluent-ffmpeg | deprecated | eski kodda uchraydi |
| ffmpeg-static | tayyor binar | serverga ffmpeg o'rnatib bo'lmasa |
| ffmpeg.wasm | brauzerda | sekin, kichik ishlar uchun |
9. Navbat va worker
ffmpeg — CPU yeyuvchi. API jarayonida chaqirsangiz:
- 3 ta parallel yuklash — 3 ta ffmpeg — barcha yadrolar band, API javob bermaydi;
- foydalanuvchi so'rovi 30 soniya kutadi va timeout oladi;
- server qayta yonsa — ish yo'qoladi.
To'g'ri tartib:
sequenceDiagram
participant B as Brauzer
participant A as API
participant Q as Navbat
participant W as Worker
participant S as Ombor
B->>A: Video yuklandi (kalit)
A->>Q: transkod vazifasi
A-->>B: 202 Qabul qilindi
W->>Q: vazifani oladi
W->>S: asl videoni yuklab oladi
W->>W: ffprobe, ffmpeg (timeout)
W->>S: HLS bo'laklari, thumbnail
W->>A: holat: tayyorAPI 202 Accepted qaytaradi (Bulk va uzoq davom etuvchi operatsiyalar). Worker — alohida jarayon (yoki alohida server), bir vaqtda 1–2 ta ffmpeg; navbat qayta urinish va ustuvorlikni boshqaradi (BullMQ asoslari).
10. Hujumchi nigohi
- Shell injection.
exec(\ffmpeg -i ${nom}`)— fayl nomi buyruqqa aylanadi. Himoya:spawn/execFile` + massiv; kirish fayli — server yasagan vaqtinchalik nom, foydalanuvchi nomi emas. - SSRF va fayl o'qish. ffmpeg faqat fayl emas,
http://,file:va boshqa protokollarni ham ochadi. Foydalanuvchi yuklagan.m3u8yokiconcatro'yxatidahttp://169.254.169.254/…yoki/etc/passwdbo'lsa — ffmpeg uni o'qiydi. Himoya (hujjat bo'yicha, kanonda sinalmagan):-protocol_whitelist fileva playlist turidagi kirishni umuman qabul qilmaslik (SSRF va tashqi URL'lar bilan ishlash). - Resurs tugashi. 10 soatlik yoki 8K video. Himoya: ffprobe bilan davomiylik/o'lcham limiti, timeout, worker parallelligi.
- Parser zaifliklari. ffmpeg katta C kod bazasi — vaqti-vaqti bilan zaifliklar topiladi. Himoya: yangilab turish, worker'ni cheklangan huquq (konteyner, alohida foydalanuvchi) bilan yurgizish.
11. Ko'p uchraydigan xatolar
| Xato | Sabab | Davosi |
|---|---|---|
| ffmpeg fonda osilib qoldi | stdin kutyapti | -nostdin |
spawn ffmpeg ENOENT |
ffmpeg o'rnatilmagan / PATH'da yo'q | o'rnating yoki ffmpeg-static |
| HLS bo'laklari so'ralgandan uzun | keyframe | -force_key_frames |
| Thumbnail sekin | -ss kirishdan keyin |
-ss ni -i dan oldin |
height not divisible by 2 |
toq o'lcham | scale=320:-2 |
| Jarayon xotirasi o'sdi | stderr to'liq yig'ildi | oxirgi N belgi |
| Progress 100 dan oshdi | davomiylik noto'g'ri | Math.min(100, …) |
| API sekinlashdi | ffmpeg so'rov ichida | navbat + worker |
12. Mashqlar
Mashqlar kurs/mashqlar/29/08-ffmpeg/ da.
1-mashq (oson): to'g'ri yoki noto'g'ri
execbilan fayl nomini satrga qo'yish xavfsiz, agar nom qo'shtirnoqda bo'lsa.- HLS bo'lagi faqat kalit kadrda boshlanadi.
-ssni-idan oldin qo'yish qidiruvni tezlashtiradi.- fluent-ffmpeg — yangi loyiha uchun tavsiya etilgan paket.
Yechim
- Noto'g'ri — nomning o'zida qo'shtirnoq bo'lishi mumkin; yagona to'g'ri yo'l — massiv.
- To'g'ri — shuning uchun 4 emas, 8.33 soniya chiqdi.
- To'g'ri — yaqin kalit kadrga sakraydi.
- Noto'g'ri — npm'da deprecated.
2-mashq (o'rta): ffprobe xulosasi
xulosa(probe, maksSoniya = 600) funksiyasini yozing: ffprobe JSON'idan { soniya, olcham, kodek, kbps } qaytarsin. Video oqimi yo'q bo'lsa { xato: "video oqimi yo'q" }, davomiylik 0 yoki limitdan katta bo'lsa { xato: "davomiylik: N" }. Audio yo'q bo'lsa kodekda ovozsiz. Kanon chiqishidagi qiymatlar bilan, limit 10 bilan va faqat audio oqimi bilan sinang.
const probe = {
format: { duration: "20.000000", bit_rate: "2874374" },
streams: [
{ codec_type: "video", codec_name: "h264",
width: 1280, height: 720 },
{ codec_type: "audio", codec_name: "aac" },
],
};Yechim
const probe = {
format: { duration: "20.000000", bit_rate: "2874374" },
streams: [
{ codec_type: "video", codec_name: "h264",
width: 1280, height: 720 },
{ codec_type: "audio", codec_name: "aac" },
],
};
function xulosa(p, maksSoniya = 600) {
const s = Number(p.format.duration);
const video = p.streams.find((x) => x.codec_type === "video");
const audio = p.streams.find((x) => x.codec_type === "audio");
if (!video) return { xato: "video oqimi yo'q" };
if (!(s > 0) || s > maksSoniya) return { xato: `davomiylik: ${s}` };
return {
soniya: s,
olcham: `${video.width}x${video.height}`,
kodek: video.codec_name + "+" + (audio?.codec_name ?? "ovozsiz"),
kbps: Math.round(Number(p.format.bit_rate) / 1000),
};
}
console.log(xulosa(probe));
console.log(xulosa(probe, 10));
console.log(xulosa({ ...probe, streams: [probe.streams[1]] }));Konsolda:
{ soniya: 20, olcham: '1280x720', kodek: 'h264+aac', kbps: 2874 }
{ xato: 'davomiylik: 20' }
{ xato: "video oqimi yo'q" }!(s > 0) — NaN ni ham ushlaydi (NaN > 0 — false). Davomiylik satri buzilgan bo'lsa Number NaN beradi va video rad etiladi.
3-mashq (qiyin): master playlist
master(variantlar) funksiyasini yozing: { nom, eni, boyi, bitreyt } massividan HLS master ro'yxatini yasasin — birinchi qator #EXTM3U, har variant uchun #EXT-X-STREAM-INF:BANDWIDTH=<bitreyt>,RESOLUTION=<eni>x<boyi> va keyingi qatorda <nom>/index.m3u8. 360p (640×360, 800 000) va 720p (1280×720, 2 800 000) bilan sinang.
Yechim
const variantlar = [
{ nom: "360p", eni: 640, boyi: 360, bitreyt: 800_000 },
{ nom: "720p", eni: 1280, boyi: 720, bitreyt: 2_800_000 },
];
function master(v) {
const q = ["#EXTM3U"];
for (const x of v) {
q.push(`#EXT-X-STREAM-INF:BANDWIDTH=${x.bitreyt},` +
`RESOLUTION=${x.eni}x${x.boyi}`);
q.push(`${x.nom}/index.m3u8`);
}
return q.join("\n");
}
console.log(master(variantlar));Konsolda:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
360p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720
720p/index.m3u8Pleyer master'ni o'qib, internet tezligiga mos variantni tanlaydi va keyin uning index.m3u8 sini yuklaydi. BANDWIDTH — bit/s, bayt emas. Format RFC 8216 da; kanon faqat bitta sifatli ro'yxat yasadi — master'ni haqiqiy pleyerda sinamadi.
13. Loyiha qadami: kanon tajribasi, loyihaga kirmaydi
Bu darsda vazifalar-api ga kod qo'shilmaydi. Sabablari:
vazifalarilovasida video yo'q: ilovalar ruxsat ro'yxati — rasm, PDF, matn (fayllar_mime_check).- ffmpeg — tashqi dastur: serverga o'rnatish, versiyasini kuzatish, worker kerak. Ehtiyojsiz murakkablik.
Kanon tajribasi — mustaqil skript: sinov videosini yasash, ffprobe, thumbnail, HLS (oddiy va majburiy kalit kadr bilan), MP3/Opus, timeout va injection sinovi. O'zingiz sinab ko'ring: ffmpeg o'rnating (winget install Gyan.FFmpeg yoki Linux paket menejeri), yuqoridagi ffmpeg yordamchisini faylga ko'chiring va testsrc2 bilan 20 soniyalik video yasang:
await ffmpeg(["-f", "lavfi", "-i",
"testsrc2=size=1280x720:rate=30:duration=20",
"-f", "lavfi", "-i", "sine=frequency=440:duration=20",
"-c:v", "libx264", "-preset", "veryfast", "-pix_fmt", "yuv420p",
"-c:a", "aac", "-shortest", "kirish.mp4"],
{ progress: (s) => console.log(`${s.toFixed(1)} s`) });Video kerak bo'lsa (masalan, 38-qism bozor loyihasida mahsulot videosi), naqsh tayyor: navbat vazifasi + shu yordamchi + ombor.
14. Real ishda
- Katta video platformalar odatda har yuklangan videoni bir nechta sifatga transkodlaydi va bo'laklab (HLS yoki DASH bilan) beradi.
- Bulut xizmatlari (AWS MediaConvert, Cloudflare Stream, Mux) — transkodlashni o'zlari qiladi; narxi daqiqaga. Kam video bo'lsa — o'z worker'ingiz arzon.
- Ovozli xabarlar — Opus; nutqni matnga aylantirish (Nutq va rasm bilan ishlovchi AI) uchun ham ffmpeg avval formatni moslaydi.
- Intervyuda: "Foydalanuvchi videosini qanday qayta ishlaysiz?", "exec va spawn farqi?", "HLS nima va nega bo'laklar?"
Xulosa
- ffmpeg — tashqi dastur; Node'dan
spawn+ argumentlar massivi (shell yo'q → injection yo'q). -nostdin,-y,-progress pipe:1, stderr oxiri, timeout →SIGKILL.- ffprobe — JSON ma'lumot; qiymatlar satr; limitlarni shu yerda tekshiring.
-sskirishdan oldin — tez thumbnail;scale=320:-2— juft o'lcham.- HLS bo'lagi faqat kalit kadrda: sukut GOP 250 kadr → 8.33 s;
-force_key_frames→ aynan 4 s. - fluent-ffmpeg deprecated; video ishlovi — navbat va worker'da.
Keyingi dars: PDF generatsiya — PDFKit, pdfmake va brauzerdan page.pdf(); o'zbek harflari va shrift.
Manbalar
- FFmpeg hujjati —
-ss,-progress,-force_key_frames, HLS muxer (-hls_time): https://ffmpeg.org/ffmpeg.html va https://ffmpeg.org/ffmpeg-formats.html#hls-2 - FFmpeg protokollari (
-protocol_whitelist): https://ffmpeg.org/ffmpeg-protocols.html - RFC 8216 — HTTP Live Streaming: https://www.rfc-editor.org/rfc/rfc8216
- Node.js
child_process.spawn: https://nodejs.org/api/child_process.html - fluent-ffmpeg (npm, deprecated): https://www.npmjs.com/package/fluent-ffmpeg
- Kanon tajribasi (IlmHamroh, 2026-10-27): ffmpeg 9.0.2 (Gyan.dev full build, winget), Node 24.21.0, i5-12500H, Windows 11. Linux, haqiqiy HLS pleyer,
-protocol_whitelist— sinalmagan. Argument, progress, m3u8 tahlili va mashq yechimlari — biz ishga tushirdik (2026-10-28).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!