mirror of
https://git.waldn.net/git/knotteye/satyr.git
synced 2025-05-07 02:59:25 +00:00
Switch from transcode server in node-media-server to spawning ffmpeg processes
Change config to reflect that ffmpeg processes cleanup after themselves even on SIGINT now, cleanup.ts only cleans the database now Adaptive livestreaming!
This commit is contained in:
parent
f8b197502a
commit
7983b60f8d
@ -50,10 +50,4 @@ port = 8000
|
||||
record = false
|
||||
publicEndpoint = 'live'
|
||||
privateEndpoint = 'stream'
|
||||
ffmpeg = ''
|
||||
|
||||
[transcode]
|
||||
hls = false
|
||||
hlsFlags = '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]'
|
||||
dash = true
|
||||
dashFlags = '[f=dash:window_size=3:extra_window_size=5]'
|
||||
ffmpeg = ''
|
@ -1,23 +1,10 @@
|
||||
import * as db from "./database";
|
||||
import * as read from "recursive-readdir";
|
||||
import * as fs from "fs";
|
||||
|
||||
async function init(siteDir: string) {
|
||||
async function init() {
|
||||
//If satyr is restarted in the middle of a stream
|
||||
//it causes problems
|
||||
//Live flags in the database stay live
|
||||
await db.query('update user_meta set live=false');
|
||||
//and stray m3u8 files will play the last
|
||||
//few seconds of a stream back
|
||||
try {
|
||||
var files = await read(siteDir+'/live', ['!*.m3u8']);
|
||||
}
|
||||
catch (error) {}
|
||||
if(files === undefined || files.length == 0) return;
|
||||
for(let i=0;i<files.length;i++){
|
||||
fs.unlinkSync(files[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
export { init };
|
||||
export { init };
|
||||
|
@ -10,6 +10,7 @@ async function run() {
|
||||
const bcryptcfg: object = config.bcrypt;
|
||||
const satyr: object = {
|
||||
privateEndpoint: config.media.privateEndpoint,
|
||||
publicEndpoint: config.media.publicEndpoint,
|
||||
record: config.media.record,
|
||||
registration: config.satyr.registration,
|
||||
webFormat: config.satyr.webFormat,
|
||||
@ -18,7 +19,8 @@ async function run() {
|
||||
domain: config.satyr.domain,
|
||||
email: config.satyr.email,
|
||||
rootredirect: config.satyr.rootredirect,
|
||||
version: process.env.npm_package_version
|
||||
version: process.env.npm_package_version,
|
||||
directory: config.server.http.directory
|
||||
};
|
||||
const nms: object = {
|
||||
logType: config.server.logs,
|
||||
@ -29,7 +31,7 @@ async function run() {
|
||||
ping: config.server.rtmp.ping,
|
||||
ping_timeout: config.server.rtmp.ping_timeout,
|
||||
},
|
||||
http: {
|
||||
/*http: {
|
||||
port: config.server.http.port + 1,
|
||||
mediaroot: config.server.http.directory,
|
||||
allow_origin: config.server.http.allow_origin
|
||||
@ -45,7 +47,7 @@ async function run() {
|
||||
dashFlags: config.transcode.dashFlags
|
||||
}
|
||||
]
|
||||
},
|
||||
},*/
|
||||
auth: {
|
||||
api: config.server.api,
|
||||
api_user: config.server.api_user,
|
||||
@ -54,7 +56,7 @@ async function run() {
|
||||
|
||||
};
|
||||
db.init(dbcfg, bcryptcfg);
|
||||
await cleanup.init(config.server.http.directory);
|
||||
await cleanup.init();
|
||||
api.init(satyr);
|
||||
http.init(satyr, config.server.http.port, config.ircd);
|
||||
mediaserver.init(nms, satyr);
|
||||
|
@ -1,7 +1,8 @@
|
||||
import * as NodeMediaServer from "node-media-server";
|
||||
import { mkdir } from "fs";
|
||||
import { mkdir, fstat, access } from "fs";
|
||||
import * as db from "./database";
|
||||
const { exec } = require('child_process');
|
||||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
const { exec, execFile } = require('child_process');
|
||||
|
||||
function init (mediaconfig: any, satyrconfig: any) {
|
||||
const nms = new NodeMediaServer(mediaconfig);
|
||||
@ -18,7 +19,7 @@ function init (mediaconfig: any, satyrconfig: any) {
|
||||
session.reject();
|
||||
return false;
|
||||
}
|
||||
if(app === mediaconfig.trans.tasks[0].app) {
|
||||
if(app === satyrconfig.publicEndpoint) {
|
||||
if(session.ip.includes('127.0.0.1') || session.ip === '::1') {
|
||||
//only allow publish to public endpoint from localhost
|
||||
//this is NOT a comprehensive way of doing this, but I'm ignoring it
|
||||
@ -37,15 +38,15 @@ function init (mediaconfig: any, satyrconfig: any) {
|
||||
return db.query('select username,record_flag from users where username=\''+key+'\' limit 1').then((results) => {
|
||||
if(results[0].record_flag && satyrconfig.record){
|
||||
console.log('[NodeMediaServer] Initiating recording for stream:',id);
|
||||
mkdir(mediaconfig.http.mediaroot+'/'+mediaconfig.trans.tasks[0].app+'/'+results[0].username, { recursive : true }, (err) => {
|
||||
mkdir(satyrconfig.directory+'/'+satyrconfig.publicEndpoint+'/'+results[0].username, { recursive : true }, (err) => {
|
||||
if (err) throw err;
|
||||
let subprocess = exec('ffmpeg -i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+mediaconfig.trans.tasks[0].app+'/'+results[0].username+' -vcodec copy -acodec copy '+mediaconfig.http.mediaroot+'/'+mediaconfig.trans.tasks[0].app+'/'+results[0].username+'/$(date +%d%b%Y-%H%M).mp4',{
|
||||
let subprocess = exec('ffmpeg -i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.publicEndpoint+'/'+results[0].username+' -vcodec copy -acodec copy '+satyrconfig.directory+'/'+satyrconfig.publicEndpoint+'/'+results[0].username+'/$(date +%d%b%Y-%H%M).mp4',{
|
||||
detached : true,
|
||||
stdio : 'inherit'
|
||||
});
|
||||
subprocess.unref();
|
||||
//spawn an ffmpeg process to record the stream, then detach it completely
|
||||
//ffmpeg can then finalize the recording if satyr crashes mid-stream
|
||||
//ffmpeg can then (probably) finalize the recording if satyr crashes mid-stream
|
||||
});
|
||||
}
|
||||
else {
|
||||
@ -67,9 +68,18 @@ function init (mediaconfig: any, satyrconfig: any) {
|
||||
session.reject();
|
||||
return false;
|
||||
}
|
||||
db.query('select username from users where stream_key='+db.raw.escape(key)+' limit 1').then((results) => {
|
||||
db.query('select username from users where stream_key='+db.raw.escape(key)+' limit 1').then(async (results) => {
|
||||
if(results[0]){
|
||||
exec('ffmpeg -analyzeduration 0 -i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.privateEndpoint+'/'+key+' -vcodec copy -acodec copy -crf 18 -f flv rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+mediaconfig.trans.tasks[0].app+'/'+results[0].username);
|
||||
//push to rtmp
|
||||
exec('ffmpeg -analyzeduration 0 -i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.privateEndpoint+'/'+key+' -vcodec copy -acodec copy -crf 18 -f flv rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.publicEndpoint+'/'+results[0].username);
|
||||
//push to mpd after making sure directory exists
|
||||
mkdir(satyrconfig.directory+'/'+satyrconfig.publicEndpoint+'/'+results[0].username, { recursive : true }, (err) => {;});
|
||||
sleep(5000).then( () => {
|
||||
//wait for stream to initialize, but i'm not happy about this
|
||||
exec('ffmpeg -y -i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.privateEndpoint+'/'+key+' -map 0:2 -map 0:2 -map 0:2 -map 0:1 -c:a copy -c:v:0 copy -c:v:1 libx264 -c:v:2 libx264 -crf:1 33 -crf:2 40 -b:v:1 3000K -b:v:2 1500K -remove_at_exit 1 -seg_duration 1 -window_size 30 -f dash '+satyrconfig.directory+'/'+satyrconfig.publicEndpoint+'/'+results[0].username+'/index.mpd');
|
||||
});
|
||||
//switch to execFile at some point, it's safer
|
||||
//execFile('/usr/bin/ffmpeg',['-analyzeduration 0', '-i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.privateEndpoint+'/'+key, '-vcodec copy', '-acodec copy', '-crf 18', '-f flv', 'rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.publicEndpoint+'/'+results[0].username]);
|
||||
console.log('[NodeMediaServer] Stream key okay for stream:',id);
|
||||
}
|
||||
else{
|
||||
@ -81,7 +91,7 @@ function init (mediaconfig: any, satyrconfig: any) {
|
||||
nms.on('donePublish', (id, StreamPath, args) => {
|
||||
let app: string = StreamPath.split("/")[1];
|
||||
let key: string = StreamPath.split("/")[2];
|
||||
if(app === mediaconfig.trans.tasks[0].app) {
|
||||
if(app === satyrconfig.publicEndpoint) {
|
||||
db.query('update user_meta set live=false where username=\''+key+'\' limit 1');
|
||||
}
|
||||
});
|
||||
|
@ -7,7 +7,7 @@ function newPopup(url) {
|
||||
}
|
||||
</script>
|
||||
</br>
|
||||
<span style="float: left;font-size: large;"><a href="/live/{{ user }}/index.m3u8">{{ user }}</a> | {{ streamtitle | escape }}</b></span><span style="float: right;font-size: large;"> Links | <a href="rtmp://{{ domain }}/live/{{ user }}">Watch</a> <a href="JavaScript:newPopup('/chat?room={{ user }}');">Chat</a> <a href="/vods/{{ user }}">VODs</a></span>
|
||||
<span style="float: left;font-size: large;"><a href="/live/{{ user }}/index.mpd">{{ user }}</a> | {{ streamtitle | escape }}</b></span><span style="float: right;font-size: large;"> Links | <a href="rtmp://{{ domain }}/live/{{ user }}">Watch</a> <a href="JavaScript:newPopup('/chat?room={{ user }}');">Chat</a> <a href="/vods/{{ user }}">VODs</a></span>
|
||||
<div id="jscontainer">
|
||||
<div id="jschild" style="width: 70%;height: 100%;">
|
||||
<video controls poster="/thumbnail.jpg" class="video-js vjs-default-skin" id="live-video" style="width:100%;height:100%;"></video>
|
||||
|
Loading…
x
Reference in New Issue
Block a user