Video streaming from file system - node.js

I am trying to make a video server, my scenario is users will upload there files and I have a screen that will play all the files of the day like advertisement that we usually watch in our televisions.
So far I have achieved .hls and .flv streaming through node media server.
I have found the best way to stream a file is through FFMPEG, but I am unable to stream multiple files on same output url for example localhost:8000/index.m3u8, Can any one suggest me the right way to stream the next file when FFMPEG ends streaming of a previous file.
Thanks in advance. :)
My node media service config
{
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 30,
ping_timeout: 60
},
http: {
port: 8000,
mediaroot: './media',
allow_origin: '*'
},
trans: {
ffmpeg: 'E:/Red Matrix/node-stream-master/node-stream-master/usr/bin/ffmpeg.exe',
tasks: [
{
app: 'live',
hls: true,
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 stream function
function ffmpegStream(stream){
var proc = ffmpeg()
.input('D:/Videos/1.MP4')
.on('error', function (err) {
console.log('An error occurred: ' + err.message);
})
.on('end', function (e) {
console.log('Processing end !' + JSON.stringify(this));
ffmpegStream('D:/Videos/2.MP4')
})
.on('done', function() {
console.log('Processing finished !');
})
.save('./media/live/abc/index.m3u8');
}

Related

ytdl-core no stream data

I am making a NodeJS Music bot for discord, and I suddenly encountered a problem. The bot properly joins the channel, lights up (indicating it is speaking), but then there's no audio. After trying to find the root cause of the problem, I believe it to be a problem with the ytdl() function from the ytdl-core module.
const stream = await ytdl(song.url, {
filter: 'audioonly',
type: 'opus',
highWaterMark: waterMark
});
Looking at the result of stream, I found this:
PassThrough {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 524288,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
...
Which meant that I am not getting any buffer/stream data. It is indeed playing, but because there's nothing-- there's only silence to be heard.
I tried using pipe() and it worked just fine, but I can't play it as it is through my Music Bot.
ytdl function is like synchronous function.
"ytdl-core": "^4.10.1"
const stream = await ytdl(song.url); pause code execution until ytdl finished downloading stream.
console.log("YTDL Start");
const stream = await ytdl(song.url, {
filter: 'audioonly',
type: 'opus',
highWaterMark: waterMark
});
console.log("Is it done?");
stream.on('close', () => {
console.log('Read stream closed');
});
stream.on('finish', () => {
console.log('Read stream Finished');
});

prevent ffmpeg from opening console window

I have a node/express server which is used to give streams from IP camera to a website. Everything is working well. I run that webserver with PM2 on a windows server.
The problem : for each stream I have a windows console opening with just nothing logged in. The console reopen when I try to close it.
Is there a way to prevent those console to open ?
Here is the related node.js code :
const { NodeMediaServer } = require('node-media-server');
private _initiate_streams(): void{
DatabaseProvider.instance.camerasDao.getCamerasList().pipe(
take(1)
).subscribe(
(databaseReadOperationResult: DatabaseReadOperationResult<ICamera[]>) => {
if (databaseReadOperationResult.successful === true){
const cameras = databaseReadOperationResult.result;
const tasks = [];
cameras.forEach( camera => {
tasks.push(
{
app : config.get('media_server.app_name'),
mode: 'static',
edge: camera.rtsp_url,
name: camera.stream_name,
rtsp_transport: 'tcp'
}
)
});
const configMediaServer = {
logType: 3, // 3 - Log everything (debug)
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 60,
ping_timeout: 30
},
http: {
port: config.get('media_server.port'),
allow_origin: '*'
},
auth: {
play: true,
api: true,
publish: true,
secret: config.get('salt'),
api_user: 'user',
api_pass: 'password',
},
relay: {
ffmpeg: 'C:\\FFmpeg\\bin\\ffmpeg.exe',
tasks: tasks
}
};
var nms = new NodeMediaServer(configMediaServer)
nms.run();
} else {
// catch exception
}
}
);
}

Celery (Django) + RabbitMQ + nodejs server exchange data

I have an Django project using Celery with RabbitMQ broker. And now I want to call django (celery) task from NodeJS server.
In my NodeJS I'm using amqplib. Which is allow me to send tasks to RabbitMQ:
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'celery';
ch.assertQueue(q, {durable: true});
ch.sendToQueue(q, new Buffer('What should I write here?'));
});
});
My question is what format celery use? What should I write to Buffer to call celery worker?
For example, in my CELERY_ROUTES (django settings) I have blabla.tasks.add:
CELERY_ROUTES = {
...
'blabla.tasks.add': 'high-priority',
}
how to call this blabla.tasks.add function?
I've tried many ways but celery worker giving me error: Received and deleted unknown message. Wrong destination?!?
I found solution http://docs.celeryproject.org/en/latest/internals/protocol.html here.
Example message format is:
{
"id": "4cc7438e-afd4-4f8f-a2f3-f46567e7ca77",
"task": "celery.task.PingTask",
"args": [],
"kwargs": {},
"retries": 0,
"eta": "2009-11-17T12:30:56.527191"
}
So code should be:
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'celery';
ch.assertQueue(q, {durable: true});
ch.sendToQueue(q, new Buffer('{"id": "this-is-soo-unique-id", "task": "blabla.tasks.add", "args": [1, 2], "kwargs": {}, "retries": 0}'), {
contentType: 'application/json',
contentEncoding: 'utf-8',
});
});
});

Hapijs getting started good good-console error reporter must specify events to filter on

I'm just starting to learn Hapijs
following getting started tutorial
with this example:
var Hapi = require('hapi');
var Good = require('good');
var server = new Hapi.Server();
server.connection({ port: 3000 });
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply('Hello, world!');
}
});
server.route({
method: 'GET',
path: '/{name}',
handler: function (request, reply) {
reply('Hello, ' + encodeURIComponent(request.params.name) + '!');
}
});
server.register({
register: Good,
options: {
reporters: [{
reporter: require('good-console'),
args:[{ log: '*', response: '*' }]
}]
}
}, function (err) {
if (err) {
throw err; // something bad happened loading the plugin
}
server.start(function () {
server.log('info', 'Server running at: ' + server.info.uri);
});
});
when I run
node server
I've got
/home/user/hapi/node_modules/good/node_modules/hoek/lib/index.js:683
throw new Error(msgs.join(' ') || 'Unknown error');
^
Error: reporter must specify events to filter on
Can you help me, please ?
The documentation is outdated. There were some breaking changes in good 6.0.0. The module good-console has a new version, however it is not published on npm yet. You can use the master branch though by specifying the GitHub repository in package.json:
"good-console": "hapijs/good-console"
You will also need to change the configuration to:
options: {
reporters: [{
reporter: require('good-console'),
events: {
response: '*',
log: '*'
}
}]
}
EDIT: Version 5.0.0 of good-console has been released. The documentation was also updated.

Executing `ls` on docker with a shared volume results in "No such file or directory"

I'm writing a node program that uses dockernode as the Docker client. The program creates a container with a volume that is bound to a directory on the host when the container is started. One started, I attempt to print the contents of the shared volume to prove that it's working properly. However, I keep getting (ls: /tmp/app: No such file or directory.
Here is my code...
var Docker = require('dockerode'),
docker = new Docker(),
mkdirp = require('mkdirp'),
volume = (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE) + '/' + Date.now();
function handleError(action, err) {
if (err) {
console.error('error while ' + action + '...');
console.error(err);
}
}
mkdirp.sync(volume);
docker.createContainer({
Image: 'ubuntu',
Volumes: {
'/tmp/app': {}
}
}, function(err, container) {
handleError('building', err);
container.start({
Binds: [volume + ':/tmp/app']
}, function(err, data) {
handleError('starting', err);
container.exec({
AttachStdout: true,
AttachStderr: true,
Tty: false,
Cmd: ['/bin/ls', '/tmp/app']
}, function(err, exec) {
handleError('executing `ls /tmp/app`', err);
exec.start(function(err, stream) {
handleError('handling response from `ls /tmp/app`', err);
stream.setEncoding('utf8');
stream.pipe(process.stdout);
});
});
});
});
I've succeeded by doing this without exec, where I create the container, attach to it, start it with the ls command, wait for it to finish, and then kill it and remove it. But I'm looking to use exec so I can issue multiple commands once the container is running. I've been trying to piece this together from the examples in the dockerode library and the Docker remote API documentation. I just don't know where I'm going wrong.
For reference, here is the code without exec...
docker.createContainer({
Image: 'ubuntu',
Cmd: ['/bin/ls', '/tmp/app'],
Volumes: {
'/tmp/app': {}
}
}, function(err, container) {
console.log('attaching to... ' + container.id);
container.attach({stream: true, stdout: true, stderr: true, tty: true}, function(err, stream) {
handleError('attaching', err);
stream.pipe(process.stdout);
console.log('starting... ' + container.id);
container.start({
Binds: [volume + ':/tmp/app']
}, function(err, data) {
handleError('starting', err);
});
container.wait(function(err, data) {
handleError('waiting', err);
console.log('killing... ' + container.id);
container.kill(function(err, data) {
handleError('killing', err);
console.log('removing... ' + container.id);
container.remove(function(err, data) {
handleError('removing', err);
});
});
});
});
});
I had struggled with same issue for some time,but I found solution. It seems that Remote API do not accept command with arguments as one string, but you have to split each argument as new token in Cmd property array; for example with gcc:
"Cmd":["/bin/bash","-c","gcc -Wall -std=c99 hello.c -o hello.bin"]
After this modification it works correctly.
Official documentation could be better for Remote API configuration.

Resources