Package Exports
- mp4frag
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (mp4frag) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Parser that works with ffmpeg to read piped data and fragment mp4 into an initialization segment and media segments. It can also get the codec info and generate an fmp4 HLS m3u8 playlist. Must use the following flags with ffmpeg targeting the output: -f mp4 -movflags +faststart+frag_keyframe.
Currently being used in a media source extension project @ https://github.com/kevinGodell/mse-live-player
Options for instantiating new Mp4Frag
bufferListSize: unsigned int (2 - 10), setting this value will store specified number of media segments in the buffer
const mp4frag = new Mp4Frag({bufferListSize: 3});
hlsListSize: unsigned int (2 - 10), setting this along with hlsBase will generate a live fmp4 HLS m3u8 playlist
hlsBase: 'string', setting this along with hlsListSize will generate a live fmp4 HLS m3u8 playlist
const mp4frag = new Mp4Frag({hlsListSize: 4, hlsBase: 'myString'});
Possible usage examples
Example 1: Generate a live fmp4 HLS m3u8 playlist with ffmpeg
const { spawn } = require('child_process');
const Mp4Frag = require('mp4frag');
const mp4frag = new Mp4Frag({hlsListSize: 3, hlsBase: 'pool'});
const ffmpeg = spawn(
'ffmpeg',
['-loglevel', 'quiet', '-probesize', '64', '-analyzeduration', '100000', '-reorder_queue_size', '5', '-rtsp_transport', 'tcp', '-i', 'rtsp://216.4.116.29:554/axis-media/media.3gp', '-an', '-c:v', 'copy', '-f', 'mp4', '-movflags', '+frag_keyframe+empty_moov+default_base_moof', '-metadata', 'title="ip 216.4.116.29"', '-reset_timestamps', '1', 'pipe:1'],
{stdio: ['ignore', 'pipe', 'inherit']}
);
ffmpeg.stdio[1].pipe(mp4frag);
- m3u8 playlist will now be available via
mp4frag.m3u8
and can be served to a client browser via express - segments in playlist can be accessed by sequence number via
mp4frag.getHlsSegment(6)
, with6
being the current sequence number
Generated m3u8 playlist will look like the following example pulled from my live feed
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:6
#EXT-X-MAP:URI="init-pool.mp4"
#EXTINF:4.78,
pool6.m4s
#EXTINF:5.439,
pool7.m4s
#EXTINF:4.269,
pool8.m4s
Setting up some server routes to respond to http requests for playing live HLS feed
app.get('/pool.m3u8', (req, res) => {
if (mp4frag.m3u8) {
res.writeHead(200, {'Content-Type': 'application/vnd.apple.mpegurl'});
res.end(mp4frag.m3u8);
} else {
res.sendStatus(503);//todo maybe send 400
}
});
app.get('/init-pool.mp4', (req, res) => {
if (mp4frag.initialization) {
res.writeHead(200, {'Content-Type': 'video/mp4'});
res.end(mp4.initialization);
} else {
res.sendStatus(503);
}
});
app.get('/pool:id.m4s', (req, res) => {
const segment = mp4frag.getHlsSegment(req.params.id);
if (segment) {
res.writeHead(200, {'Content-Type': 'video/mp4'});
res.end(segment);
} else {
res.sendStatus(503);
}
});
See it in use @ https://github.com/kevinGodell/mse-live-player/blob/master/compare.js
Example 2: Create a buffer of past video to store for later recording
const { spawn } = require('child_process');
const Mp4Frag = require('mp4frag');
//3 past segments will be held in buffer for later access via mp4frag.buffer
//if each segment has a duration of 2 seconds, then buffer will contain 6 seconds of video
const mp4frag = new Mp4Frag({bufferListSize: 3});
const ffmpeg = spawn(
'ffmpeg',
['-loglevel', 'quiet', '-probesize', '64', '-analyzeduration', '100000', '-reorder_queue_size', '5', '-rtsp_transport', 'tcp', '-i', 'rtsp://131.95.3.162:554/axis-media/media.3gp', '-an', '-c:v', 'copy', '-f', 'mp4', '-movflags', '+frag_keyframe+empty_moov+default_base_moof', '-metadata', 'title="ip 131.95.3.162"', '-reset_timestamps', '1', 'pipe:1'],
{stdio: ['ignore', 'pipe', 'inherit']}
);
ffmpeg.stdio[1].pipe(mp4frag);
Moments later, some triggering event occurs such as motion detection and we need to record video including 6 seconds of buffered video from before motion was detected
const fs = require('fs');
const writeStream = fs.createWriteStream(`${Date.now()}.mp4`);
//write in the initialization fragment of mp4 file
writeStream.write(mp4frag.initialization);
//write the buffered segments
writeStream.write(mp4frag.buffer);
/*
//piping method as an alternative to passing data in "segment" event
//pipe fresh segments to writeStream
mp4frag.pipe(writeStream);
//when you need to stop recording
//unpipe
mp4frag.unpipe(writeStream);
//end
writeStream.end();
*/
See it in use @ https://github.com/kevinGodell/mse-live-player/blob/master/record2.js