I have a Node.js process which outputs a video stream into my Node.js app.
On the client end, there is a <video> tag. I would like to stream the video from Node.js into the src attribute of the video tag. My previous experience tells me that we must use the blob object for this. However, I'm not a hundred percent certain how and why I would use it.
Another possible solution I'm thinking of is to create some sort of a temporary file on my server, then write the stream to that file, then serve that file as the source for the video. However, that doesn't seem intuitive. I was wondering, then, if there is a more established solution for an issue like this.
m3u8 format is commonly used for streaming.
Video streaming/transcoding is a resource intensive thing. I would suggest you to use third party service to do so, if you have that option.
Probably you might want to look at the following options:
BinaryJS. It's bidrectional realtime binary data transfer tool based on websockets.
JSMpeg stream-server (in case of capturing) from Phoboslab guys. All you need to do is start ffmpeg and point it to the domain and port where the nodejs script is running.
More info you can find here.
Pipe a stream directly. Good answer is posted here. In few words you just need to specify Accept-Ranges, Content-Range, Content-Length and Content-Type headers, then create relevant Read stream (with start and end options) and pipe it to the response object.
I've actually tried this at a hackathon two weeks ago. I ended up barely getting this flv stream to work, which I've posted below. My intent was to make a library to automate much of the processes this would entail.
As you can see, I've opened a new port on the server to handle the separate stream of data flowing to the client. This is reflected in the client's src tag.
THREE THINGS YOU NEED:
This Linux version of ffmpeg.
Flowplayer on the js side.
npm fluent-ffmpeg
// StreamServer.js
var express = require('express'),
app = express(),
ffmpeg = require('fluent-ffmpeg');
module.exports = function () {
app.stream(req, res)
{
res.contentType('flv');
// make sure you set the correct path to your video file storage
var pathToMovie = '/path/to/storage/' + req.params.filename;
var proc = ffmpeg(pathToMovie)
// use the 'flashvideo' preset (located in /lib/presets/flashvideo.js)
.preset('flashvideo')
// setup event handlers
.on('end', function () {
console.log('file has been converted succesfully');
})
.on('error', function (err) {
console.log('an error happened: ' + err.message);
})
// save to stream
.pipe(res, { end: true });
};
}
//routes.js
'use strict';
var stream = require('../controllers/streaming.server.controller'),
streamServer = require('../controllers/StreamServer.js'),
express = require('express');
//streaming.server.controller.js
module.exports = function (app) {
app.get('/api/stream', function (req, res) {
streamServer.stream(req, res);
});
};
var path = require('path'),
express = require('express'),
app = express(),
routes = require('../routes/routes.js')(app),
ffmpeg = require('fluent-ffmpeg');
app.listen(4000);
EDIT: Client side part:
https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/tree/master/examples/flowplayer
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="/flowplayer.min.js"></script>
<title>node-fluent-ffmpeg</title>
</head>
<body>
<!-- this A tag is where your Flowplayer will be placed. it can be anywhere -->
<a
href="http://localhost:4000/api/stream"
style="display:block;width:520px;height:330px"
id="player">
</a>
<!-- this will install flowplayer inside previous A- tag. -->
<script>
flowplayer("player", "/flowplayer.swf");
</script>
</body>
</html>
(Just change the href attribute)
Related
I have a page with several book covers and a button to download them all.
Book covers are in String format and are a Google Books URL. I'm populating like this:
<section ref="capture" id="my-node">
<figure v-for="book in books" :key="book.id">
<img :src="book.thumbnail" :alt="`Book ${book.title}`" />
</figure>
<button type="button" #click="download">html2canvas</button>
</section>
To download the book covers I'm calling the following function:
download() {
html2canvas(this.$refs["capture"], { allowTaint: true })
.then((canvas) => {
let link = document.createElement("a");
link.download = "Livrero.png";
link.href = canvas.toDataURL("image/png");
link.click();
})
},
Books is an object that contains a thumbnail property with values like this: https://books.google.com/books/content?id=_i6bDeoCQzsC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api
What makes me more confused is that if I were using values similar to this: https://images-na.ssl-images-amazon.com/images/I/41xShlnTZTL._SX218_BO1,204,203,200_QL40_FMwebp_.jpg everything would be working, but unfortunately the project does not allow this at the moment.
Previously I was using the property useCORS: true in html2canvas however it was returning a CORS policy error. So, when I removed it, I stopped having this error and started getting the following error:
DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement':
Tainted canvases may not be exported.
It was suggested that I use http://html2canvas.hertzen.com/proxy/ to succeed in the mission, but because I'm using Vue.js I don't know how to apply this.
This is a problem with browser's content policy. There is no simple solution.
The browser won't let you use content (images) from different origins which don't explicitly allow it.
With useCORS: true, it's expected that the server (with the remote resource) responds with the appropriate access-control-allow-origin headers. Your Amazon link does, that's why it works.
With allowTaint: true, it accepts the image, but then refuses to let you do anything with the resulting canvas image as it's now considered tainted.
Since you can't make 3rd party server send appropriate CORS headers, you will have to run your own CORS proxy.
To run html2canvas-proxy mentioned in the official documentation you need to install it
npm install html2canvas-proxy --save
make a start JavaScript file
var proxy = require('html2canvas-proxy');
var express = require('express');
const port = 8000;
var app = express();
app.use('/', proxy());
app.listen(port, () => {
console.log(`html2canvas-proxy listening on port ${port}`)
})
and then use the proxy option in html2canvas
html2canvas(this.$refs["capture"], {
proxy: "http://localhost:8000",
})
.then((canvas) => {
// ...
})
But for production, this simple proxy isn't good either as it allows anyone to use is as a CORS proxy and you might not want a separate server, if you aren't not already running an Express Node.js server.
So I've been searching for hours on this topic, and still have not found any real way to achieve what I'm trying to do here.
Simply, I just want to write some text to a text file through the use of a button in HTML. This is what I have:
<!DOCTYPE html>
<html>
<head>
<title>TEST</title>
</head>
<body>
<button onclick="write_text()">WRITE FILE</button>
<script>
function write_text(){
var fs = require('fs');
fs.writeFile("test.txt", "okay this is epic", function(err){
if (err) return console.log(err);
console.log("Nice");
});
};
</script>
</body>
</html>
I'm unsure as to why this doesn't work, do I need to make a separate .js file for the function that the button references?
Any help would be appreciated,
Thanks.
EDIT: I'm trying to save the file to my GoDaddy server so that I can access it later, not just download the file. Testing it locally, it should create a file in the directory of my html document.
As was stated before, you do not do it right.
it is very important to say that node.js is a runtime environment, and simply putting an HTML file with JS code on GoDaddy does not make it "server-side", since the code runs on the browser and not on the server.
What you really want to do is either using Blob as stated before or doing something like this (if you want to use node.js):
var express = require('express')
var app = express()
app.post('/<your_path>', function (req, res) {
writeToFilexx(/*Here you may want to pass data using body parser*/)
})
/*
Here you will start the server
*/
Please note, writeToFilexx is a function you have to implement using fs.
on the client side, you will have to send the server a request with the data you want to write to a file.
It goes like this:
1. client sends data to the server.
2. server gets data (handles the request).
3. server process, and stores data.
As you have probably guessed, the file will be saved on the server, not on client's PC.
You can't do it in the way you want (not server side, no node, then no fs in this context), but there is a workaround creating a blob:
function downloadURL(url, name) {
var link = document.createElement("a");
link.download = name;
link.href = url;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
function downloadFile() {
var data = "okay this is epic";
var blob = new Blob([data], {type: 'text/txt'});
var url = window.URL.createObjectURL(blob);
downloadURL(url, "test.txt");
}
Call downloadFile() in your button.
I have a toy react app that asks a toy nodejs server to do some image processing and return the result. The image processing server does this:
let result = path.join(__dirname, '/../../tmp/', name)
// .. write image to result
res.status(200).sendFile(result)
Logging this response on the client, I get:
{ data: "...binary image stuff...", status: 200, etc }
(1) How do I get that image data in data into an <img> tag in JSX? src={response.data}? that doesn't work
(2) Am I going about this wrong? Is the better way to just answer the filename in tmp then have the img src refer to that path? This idea seems better, except I'll get no chance to clean up the tmp file because I won't know when the img tag has finished getting it.
If there's a better way than (1) or (2) (like maybe a stream?) that would be great to understand, too. Thanks.
If you use express js you have send image files easily.
Example,
// server.js
var express = require('express');
var path = require('path');
app.use('/app', function(req, res){
res.sendFile(path.resolve(__dirname, './html/app.html'));
})
app.use('/image', function(req, res){
res.sendFile(path.resolve(__dirname, './images/img1.jpg'));
})
app.listen(9090, function(err){
if(err){
console.log(err);
}
console.log('Listening at localhost:9090');
})
// app.html html/app.html
<html>
<body>
<img src='/image'/>
</body>
</html>
// img1.jpg images/img1.jpg
Your images has inside this folder.
Run your server and hit http:localhost:9090/app the app.html is open with image.
I hope this is useful for you.
I have app on Heroku and I want to capture webpage and save as image or base64. Problem is: I have node.js script in that app and I want to use phantomjs, but phantom is not compatible with node.
So, I need to capture webpage and save output (image or base64 string) to variable so my primary (node) app can use that values.
I tried this but I can't figure how to use that: https://www.npmjs.com/package/phantom
This is what I have so far: (source)
app.get('/capture', function(request, response) {
var phantom = require('phantom');
phantom.create().then(function(ph) {
ph.createPage().then(function(page) {
page.open('https://stackoverflow.com/').then(function(status) {
console.log(status);
page.property('content').then(function(content) {
var base64 = page.renderBase64('PNG');
console.log(base64);
page.close();
ph.exit();
});
});
});
});
});
What I need on my heroku server (beside already installed node), what I need to install in node.js, how to use all that?
Thanks.
So: send request to capture page -> make image -> pass output to JS variable
I've searched for a while for a solution to this problem, but haven't found much.
My goal is to recieve a message from a udp client, which the server recieves and forwards to a web client, which plays an audio clip each time a message is recieved. However, for some reason the audio will not play. If I open the page straight from my directory, the audio can be played, but if I try and access it through localhost it fails to load. Does anyone know of a solution?
Here is the client side javascript.
var mySound = new Audio('/public/audio/Bloom.mp3');
mySound.load();
var socket = io.connect('http://localhost');
socket.on('message', function(data){
console.log(data);
$('#content').text(data);
mySound.play();
//document.getElementById('audiotag1').play();
});
This page is served by server.js, a node.js file using socket.io and express. I don't receive any errors from my console.log.
Here is the server.js
var app = require('express')()
, server = require('http').Server(app)
, io =require('socket.io')(server)
, dgram = require('dgram');
var httpPort = 1234;
var udpPort = 5000;
server.listen(httpPort);
app.use(server.express.static( __dirname + '/public'));
app.get('/', function(request, response){
var ipAddress = request.socket.remoteAddress;
console.log("New express connection from: " + ipAddress);
response.sendfile(__dirname + '/public/index.html');
});
var udpSocket = dgram.createSocket('udp4', function(msgBuffer){
var jsonMessage = JSON.parse(msgBuffer);
io.sockets.emit('message', JSON.stringify(jsonMessage));
});
udpSocket.bind(udpPort, '127.0.0.1');
You can go to this link to see the error chrome has.
http://postimg.org/image/xkv7a2kwb/
Does anyone have any ideas on how to fix this?
This error usually occurs when you have incorrect Express config for static files.
From your client-side JavaScript I can see that you store your static files in public folder.
So somewhere on the server-side you should have something like this:
app.use('/public', express.static('/path/to/public'));
Doing this way http://localhost/public/audio/Bloom.mp3 request will be served with /path/to/public/audio/Bloom.mp3 file.
Caveat:
Since Express 4 there is "no more app.use(app.router)" and "All routing methods will be added in the order in which they appear". This means that you have to put the above line of code before first app.get(...), app.post(...), etc.
Hope this information will help someone.
we can upload tone into cloud storage and then use that source like below
playAudio() {
let audio = new Audio()
audio.src ='https://res.cloudinary.com/Apple_Notification.mp3'
audio.load()
audio.play()
}
trigger this function in client-side whenever a new message comes in