So, bit of an odd problem. I have a bunch of media files saved as base64 strings in mongo, some are images, some are videos.
I made an API for getting the media files:
app.get('/api/media/:media_id', function (req, res) {
media.findById(req.params.media_id)
.exec(function (err, media) {
if (err) {
res.send(err);
}
var file = new Buffer(media.file, 'base64');
res.writeHead(200, {'Content-Type': media.type, 'Content-Transfer-Encoding': 'BASE64', 'Content-Length': file.length});
res.end(file);
});
});
Now, images have no problems. They load just fine, both directly from the API, and when I call the API from a front-end (for example <img src="/api/media/23498423">
)
THE PROBLEM
If I fetch a video from a front-end, like the images - but with a video- or object-tag:
<video src="/api/media/3424525" controls></video>
there's no problem, but if I load the video in a browser directly from the API:
http://localhost:8080/api/media/3424525
the server process crashes, no errors. It simply just freezes up. And we're not talking about huge video files - it's a 1.5MB video.
The media type in the header for all the videos I'm testing with is video/mp4
. Oh, and just to be clear: if I do the same with images, everything works perfectly.
EDIT:
Okay, so as suggested by @idbehold and @zeeshan I took a look at gridfs and gridfs-stream, and for the purpose of my app, this certainly is what I should have used in the first place. However, after implementing gridfs in my app, the problem still persists.
app.get('/api/media/:media_id', function (req, res) {
gfs.findOne({ _id: req.params.media_id }, function (err, file) {
if (err) {
return res.status(400).send(err);
}
if (!file) {
return res.status(404).send('');
}
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'inline; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function (err) {
console.log("Got an error while processing stream: ", err.message);
res.end();
});
readstream.pipe(res);
});
});
When I call the media file (be it image or video) from a front-end, within a HTML tag, everything works out fine. But if I load a video (again, smallish videos from 1.5mb to max 6mb total size) directly in the browser, the server process freezes. To be a bit more clear: I am testing on windows, and the server app (server.js) is run in console. The console and the process it is running is what freezes. I cannot load any more pages/views in the node app, and I cannot even stop/kill/shutdown the node app or the console.
Streaming videos directly to/from GridFS using gridfs-stream either with mongodb-native db instance or mongoose.
var mongo = require('mongodb'),
Grid = require('gridfs-stream'),
db = new mongo.Db('yourDatabaseName', new mongo.Server("127.0.0.1", 27017)),
gfs = Grid(db, mongo);
//store
app.post('/video', function (req, res) {
req.pipe(gfs.createWriteStream({
filename: 'file_name_here'
}));
res.send("Success!");
});
//get
app.get('/video/:vid', function (req, res) {
gfs.createReadStream({
_id: req.params.vid // or provide filename: 'file_name_here'
}).pipe(res);
});
for complete files and running project:
Clone node-cheat direct_upload_gridfs, run node app
followed by npm install express mongodb gridfs-stream
.
Truly an odd problem...
I could be way off, but it's worth a shot:
One of the differences when opening a url directly from the browser is that the browser will also try to fetch http://localhost:8080/favicon.ico
(while trying to find the tab icon). Maybe the problem is not related to your video code, but rather to some other route, trying to handle the /favicon.ico
request?
Have you tried using wget
or curl
?
I don't know the answer, maybe this is a dumb suggestion, but what is the browser you are using? Maybe something from Microsoft causes the problem...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With