UNPKG

@m3u8/simple-hls

Version:

A Multi-Bitrate Transcoding Library for NodeJS.

96 lines (95 loc) 4.89 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Transcoder = void 0; const default_renditions_1 = __importDefault(require("./default-renditions")); const child_process_1 = require("child_process"); const ffmpeg_1 = __importDefault(require("@ffmpeg-installer/ffmpeg")); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); class Transcode { constructor(inputPath, outputPath, options) { this.inputPath = inputPath; this.outputPath = outputPath; this.options = options || {}; } transcode() { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { const commands = yield this.buildCommands(); const masterPlaylist = yield this.writePlaylist(); const ls = (0, child_process_1.spawn)(ffmpeg_1.default.path || 'ffmpeg', commands); let showLogs = true; if (this.options.showLogs == false) { showLogs = false; } ls.stdout.on('data', (data) => { if (showLogs) { console.log(data.toString()); } }); ls.stderr.on('data', (data) => { if (showLogs) { console.log(data.toString()); } }); ls.on('exit', (code) => __awaiter(this, void 0, void 0, function* () { if (showLogs) { console.log(`Child exited with code ${code}`); } if (code == 0) return resolve(masterPlaylist); yield this.deleteOutputPath(); return reject('Video Failed to Transcode'); })); })); } deleteOutputPath() { return __awaiter(this, void 0, void 0, function* () { for (const file of yield fs_1.default.promises.readdir(this.outputPath)) { yield fs_1.default.promises.unlink(path_1.default.join(this.outputPath, file)); } fs_1.default.promises.rmdir(this.outputPath); }); } buildCommands() { return new Promise((resolve, reject) => { let commands = ['-hide_banner', '-y', '-i', this.inputPath]; const renditions = this.options.renditions || default_renditions_1.default; for (let i = 0, len = renditions.length; i < len; i++) { const r = renditions[i]; commands = commands.concat(['-vf', `scale=w=${r.width}:h=${r.height}:force_original_aspect_ratio=decrease`, '-hls_flags', 'split_by_time', '-c:a', 'aac', '-ar', '48000', '-c:v', 'libx264', `-profile:v`, r.profile, '-crf', '10', '-sc_threshold', '0', '-g', '48', '-hls_time', r.hlsTime, '-hls_playlist_type', 'vod', '-b:v', r.bv, '-maxrate', r.maxrate, '-bufsize', r.bufsize, '-b:a', r.ba, '-hls_segment_filename', `${this.outputPath}/${r.ts_title}_%03d.ts`, `${this.outputPath}/${r.master_title}.m3u8`]); } resolve(commands); }); } writePlaylist() { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { let m3u8Playlist = `#EXTM3U #EXT-X-VERSION:3`; const renditions = this.options.renditions || default_renditions_1.default; for (let i = 0, len = renditions.length; i < len; i++) { const r = renditions[i]; m3u8Playlist += ` #EXT-X-STREAM-INF:BANDWIDTH=${r.bv.replace('k', '000')},RESOLUTION=${r.width}x${r.height} ${r.master_title}.m3u8`; } const m3u8Path = `${this.outputPath}/index.m3u8`; yield fs_1.default.promises.writeFile(m3u8Path, m3u8Playlist); resolve(m3u8Path); })); } } exports.Transcoder = Transcode; // const t = new Transcoder(`${process.cwd()}/src/__tests__/test.mp4`, `${process.cwd()}/src/__tests__/output`, {}); // t.transcode();