I'm trying to stream MKV video as MP4 on the fly with out saving the converted file
first I've tried without conversion:
public async streamById(req: Request, res: Response) {
const movieId = req.params.id;
const movie = await MovieModel.findById(movieId);
if (!movie) {
return res.status(404).send({ message: 'Movie not found' });
}
const filePath = movie.path;
const stat = fs.statSync(filePath);
const fileSize = stat.size;
const range = req.headers.range;
if (range) {
const parts = range.replace(/bytes=/, '').split('-');
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunksize = end - start + 1;
const file = fs.createReadStream(filePath, { start, end });
const head = {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4',
};
res.writeHead(206, head);
file.pipe(res);
} else {
const head = {
'Content-Length': fileSize,
'Content-Type': 'video/mp4',
};
res.writeHead(200, head);
fs.createReadStream(filePath).pipe(res);
}
}
which is working but without audio
With ffmpeg I'm getting error : "Error during conversion: Output stream closed"
const command = ffmpeg(file)
.format('mp4')
.audioCodec('aac')
.videoCodec('libx264')
.outputOptions('-movflags frag_keyframe+empty_moov')
.outputOptions('-preset veryfast')
.on('error', (err: any) => {
console.error('Error during conversion:', err.message);
res.end();
})
.on('end', () => {
console.log('Conversion complete ');
res.end();
});
// Pipe ffmpeg output directly to the response
command.pipe(res, { end: true });
Yeah, well, that isn't going to work. MP4/ISOBMFF is completely different than WebM/MKV/Matroska.
It isn't "working" so much as it is that the browser is ignoring your
Content-Typeand has "sniffed" the format itself. So, why doesn't the video work as well? It's likely that whatever codec is used inside of your MKV file is not supported by the browser.Even if you could just go with this static hosting method, you probably won't want to use Node.js for this. Any normal webserver like Nginx can handle it just fine.
There isn't enough code to try to reproduce your problem... but firstly, try piping that MP4 output to a file and see if you can do it, to narrow down the issue.
If that works, then one thing to keep in mind is that the browser will often make several requests for a media stream if it thinks it can seek ahead to get the MOOV and what not. Make sure you're using regular chunked transfer encoding, rather than specifying a size.