simple-hls
Version:
A Multi-Bitrate Transcoding Library for NodeJS.
87 lines (86 loc) • 4.1 kB
JavaScript
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 child_process_1 = require("child_process");
const default_renditions_1 = __importDefault(require("./default-renditions"));
const fs_1 = __importDefault(require("fs"));
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', 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) => {
if (showLogs) {
console.log(`Child exited with code ${code}`);
}
if (code == 0)
return resolve(masterPlaylist);
return reject('Video Failed to Transcode');
});
}));
}
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`, '-c:a', 'aac', '-ar', '48000', '-c:v', 'h264', `-profile:v`, r.profile, '-crf', '20', '-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.height}.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.height}.m3u8`;
}
const m3u8Path = `${this.outputPath}/index.m3u8`;
fs_1.default.writeFileSync(m3u8Path, m3u8Playlist);
resolve(m3u8Path);
}));
}
}
exports.Transcoder = Transcode;
/*
const t = new Transcoder(`${__dirname}/test.mp4`, `${__dirname}/output`, {});
t.transcode();
*/
;