Storing video as mp4

Hey Walter,
I really appreciate your help to test this feature!! All your feedback makes sense to me...

Besides the flow editor ui, I have also been playing with ideas to show the stored videos graphically in the dashboard on a tlmeline. Because when I'm not home, I want to be able to navigate through my recordings easily. And to be able to replay those recordings easily, to have a quick look about what has been going on in my house.

To make this timeline possible,our friend @hotNipi has added lots of functionality to his state trail node...

However it is not clear to me whether we can configure such a timeline based on the file names and file dates... Can you please share a screenshot of the files in your file explorer, so I can get an idea of how it looks like.

Damn it is so inconvenient that I cannot test this myself at the moment :worried:
Isn´t that the purpose of the second output, to store the footage e.g. via the File-out node? But now I'm confused whether the files will be stored in that case in two locations: files stored by the Frag-node and files stored by the File-out node? Because that would require quite some disk resources, or not?

Hello Bart, see below image of recordings. To check details i copied a recording file to a windows box, see second image below

For sure it would be fantastic now with a ui/dashboard component/node for viewing recordings with a timeline as you say, maybe with the latest "in focus". I would assume the timeline could be created using the creation date & time, all recordings seem to get a unique name, basically "r"+time.toString()+".mp4"

Best regards, Walter

1 Like

I must have added the naming feature right after you posted. You can pass "directory" and "name" separately in the action object.

I have them separate so that you can specify the directory or name which will be combined as "filename" which is passed to the file node. If you leave either one undefined, then it is dynamically generated. So, you can specify directory and not specify name, or vice versa.

The dynamic naming is not final. I had to come up with something, and that was the best thought at the time. The "directory" is based on mp4frag/unique_url_path and the "name" based on a timestamp.

For mp4 video playback, you can already send an mp4 url to the ui_mp4frag. As long as you have it hosted on an http server somewhere, it should play.

Perhaps we can create a flow that watches for new files to be added to a directory and updates your list of videos on some other ui node that has buttons or drop down list? a quick search found "node-red-contrib-watchdirectory", which I have not tried. Or, maybe there is another node that can be placed after the "file" node, which keeps track of the names and puts them into a ui list?

One other important note is that the mp4 arrives in pieces to the file node. It must arrive in pieces, otherwise the whole file would have to be buffered which would consume too much memory. This may make it tricky to re-use a name and overwrite an existing file, since the file node already had to be in "append" mode.

2 Likes

OK fully understood so far. Many good ideas! Working very well, all-in-all really impressive!!

Let's think about it, so many good ideas coming up here. I think Bart's idea with a time line, maybe combined with a sorted list in a drop down (if needed) I suppose the file naming could be "as is", the directory however is great it can be passed to the file node now, it then makes it easy to use a share or an external SSD with dedicated folders for each of your cameras

2 Likes

Walter,
I had hoped that other contributors would start buiding nodes to add extra video surveillance in Node-RED, since @kevinGodell is offering us the core functionality.

And I think the first one has arrived: node-red-contrib-timelapse-from-recordings. Can't test it... But if somebody else has used it, it would be nice to have a screenshot to get a feeling of how useful that node is, since it is related to mp4 recordings on disk. .

Hello Bart, just quickly tried it. I am not able to configure the directory, it jumps back to the default after deploy so it does not work right now. Issue reported on github

1 Like

Hi Kevin, can you give an example how to pass the directory? I've tried to pass it via the directory but still getting No filename specified in the file node but I'm sure the reason is me. Thanks for all the great and hard work you've done!

The api was changed so that you have to do that in the output of the mp4frag node in a function node. mp4frag -> function -> file or if doing post processing, mp4frag -> ffmpeg-spawn -> function -> file. Unfortunately, I don’t have access to my computer right now to share the flow example. I can get back to you in about 8 hours.

OK this is clear and works now. Tried it first with an inject node with the action object but it was obviously not the correct way of working.
Is there a possibility to keep the recording endlessly and not to stop after x seconds/file size?
When outputting to the buffer a file is created each buffer output. (after 2 secs) even if I passed
{
"subject": "write",
"command": "start",
"keyframe": -1,
"timeLimit": 500000,
"sizeLimit": 250000000
}

Many thanks

You can override the sizeLimit and timeLimit values in settings.js, which will allow you to pass bigger values in the action command. If you need ‘no limit’ because you want continuous recording, you could just have ffmpeg write the mp4 to disk directly. Perhaps if you let me know your goal, I could give a better answer that may satisfy your needs.

Edit. I think I will add an option to have no limit. this will not be default and would require you to pass an extra value opting in (since this could lead to a user unintentional filling their disk). I can see the value in that.

Kevin, tried too utput the ffmeg exec to a file an this works but the size of the video are here also about 2 seconds. Is this the way ffmeg works (outputs each 2 seconds) and thus cannot be clustered for example files with a longer duration?

So the inject node with
{
"subject": "write",
"command": "start",
"keyframe": -1,
"timeLimit": 500000,
"sizeLimit": 250000000
}

won't work and has to be passed via the settings. js In fact I don't see the setttings in the mp4frag node changing, so I suppose it does not work like this (any more)?

Final purpose is to record continously and have events (like a motion detection) to record/take pictures above the continiously recording so a timelapse of events can be shown.

ps when deploying following errors keeps to appear quite often in the mp4frag node Error: ftyp not found. A start stream solves the problem. But because the error is endlessly repeated can it be limited?
ps2 when outputting to a file multiple mp4 are created in one 'run' but only the first clip seems the be a correct mp4 file. the others can't be viewed.

Hey @kevinGodell,
Thanks for helping @geoffreydemaagd, because I have been bragging to him at work about your nodes :wink:

About passing input parameters to your nodes. I see here that output messages are being created from scratch (i.e. { xxx:yyy }). Often it is advised to reuse the input messages (i.e. msg.xxx=yyy) to enrich the input messages with new output data. That way 'most' input data remains intact: so if you e.g. inject a msg containing config for the file-out node, that information will be passed by your mp4frag node to the file-out node.

You can also add an extra TypedInput of type "msg" to your config screen, where people can decide in which field (of the output msg) the output will be stored. The default is "msg.payload". By doing it like that your users can even keep the original msg.payload unchanged, by storing the output in another msg field.

That way msg info runs through your node and the user can choose which data needs to be unchanged. But perhaps this is not possible/useful in your nodes for reason...

2 Likes

the ftyp error is when the mp4frag node receives Buffer, but not the correct type. Most likely you changed a setting in mp4frag node, causing it to reset its internal buffer, while still feeding the mp4 buffer from the exec node or ffmpeg-spawn node. mp4 is tricky because it is not like a stream of individual jpegs, but a slightly more complicated file type and the buffer has to be received in the correct order. It gives out an error message each time it is given the incorrect buffer, thus it was fed probably 100's of pieces, none of which it could use. The mp4frag node was in its correct state, but the ffmpeg streaming mp4 buffer must be restarted. Thats why I show the example of using the return code from exec to trigger a reset so that mp4frag can get ready for when you start ffmpeg again. I get that same error too because I forget to turn off ffmpeg before tweaking the mp4frag settings and if node-red is not set to restart the entire flow, then errorrrrrrrrs... That debug to console message will eventually go away before the release. deploy -> modified flows might help avoid this issue when tweaking settings.

2nd thought on that is that I might have to output the error so that it can be handled and used to restart the ffmpeg process. Although, that error should probably never happen on its own.

Thats a tricky thing to answer. Only 1 mp4 should be created each time a start command is given to mp4frag. When the mp4 gets output, the sinlge video arrives in many many pieces.

Please try to following flow (after tweaking ffmpeg to work with your camera source or use whats there) and see if you can create mp4 videos. delete what you dont need, but look closely at the mp4frag node and how it can output mp4 and remastered with ffmpeg to fix timestamps or saved as-is. I was able to override the default limits in settings.js and create longer videos.
Screen Shot 2021-05-04 at 8.38.39 PM

[{"id":"93d74c4e.4c8fe","type":"ffmpeg-spawn","z":"5967c855.68b978","name":"","outputs":6,"migrate":2e-9,"cmdPath":"","cmdArgs":"[\"-version\"]","cmdOutputs":5,"killSignal":"SIGTERM","msgOutput":"split","x":340,"y":380,"wires":[["96b432b8.72f38","8715a99e.626858","c5674070.e26ec"],["96b432b8.72f38"],["a03a1b22.1f27a8"],["22984340.c40eac"],["45912098.31d65"],[]]},{"id":"96b432b8.72f38","type":"mp4frag","z":"5967c855.68b978","name":"","migrate":1e-9,"hlsPlaylistSize":"20","hlsPlaylistExtra":"10","basePath":"abc","x":640,"y":280,"wires":[["379420d.31038e"],["d4600315.dbc7d","97c44c17.d56ce"]]},{"id":"143a363a.17fc7a","type":"inject","z":"5967c855.68b978","name":"stop default","props":[{"p":"action","v":"{\"command\":\"stop\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":121,"y":453,"wires":[["93d74c4e.4c8fe"]]},{"id":"e90ee3ed.da535","type":"delay","z":"5967c855.68b978","name":"delay","pauseType":"delayv","timeout":"1","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":450,"y":55,"wires":[["93d74c4e.4c8fe"]]},{"id":"c5674070.e26ec","type":"function","z":"5967c855.68b978","name":"restart","func":"const { status, code, signal, killed } = msg.payload;\n\n\nif (status === 'close' && killed === false) {\n    return { action: { command: 'start' }, delay: 5000 };\n}\n\nreturn;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":330,"y":55,"wires":[["e90ee3ed.da535"]]},{"id":"ccf3b2e6.7f78f","type":"inject","z":"5967c855.68b978","name":"stop SIGKILL","props":[{"p":"action","v":"{\"command\":\"stop\",\"signal\":\"SIGKILL\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":121,"y":561,"wires":[["93d74c4e.4c8fe"]]},{"id":"2db4e64d.d4022a","type":"inject","z":"5967c855.68b978","name":"stop SIGTERM","props":[{"p":"action","v":"{\"command\":\"stop\",\"signal\":\"SIGTERM\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":131,"y":597,"wires":[["93d74c4e.4c8fe"]]},{"id":"1d5155f9.0f929a","type":"debug","z":"5967c855.68b978","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1339,"y":400,"wires":[]},{"id":"a03a1b22.1f27a8","type":"function","z":"5967c855.68b978","name":"errors","func":"const { payload } = msg;\n\nreturn { payload: payload.toString() };","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1219,"y":400,"wires":[["1d5155f9.0f929a"]]},{"id":"22984340.c40eac","type":"function","z":"5967c855.68b978","name":"progress","func":"const props = msg.payload.toString().split('\\n');\n\nconst progress = {};\n\nprops.forEach(item => {\n    \n    const [name, value] = item.split('=');\n    \n    if (name && value) {\n    \n        progress[name] = value;\n\n    }\n    \n});\n\nconst color = progress['progress'] === 'continue' ? 'green' : 'red';\n\nconst message = `fps: ${progress['fps']}, bitrate: ${progress['bitrate']}`;\n\nnode.status({ fill: color, shape: 'dot', text: message });\n\nreturn { payload: progress };","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1210,"y":498,"wires":[["21bb6347.11389c"]]},{"id":"21bb6347.11389c","type":"debug","z":"5967c855.68b978","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1340,"y":498,"wires":[]},{"id":"7f035cf8.c1f6d4","type":"function","z":"5967c855.68b978","name":"filename","func":"const { payload } = msg;\n\nif (Buffer.isBuffer(payload)) {\n\n    msg.filename = context.get('filename');\n    \n    return msg;\n}\n\nconst { status } = payload;\n\nif (status === 'spawn') {\n\n    context.set('filename', `videos/abc/p/${Date.now()}.mp4`);\n\n    \n} else if (status === 'close') {\n    \n    context.set('filename', undefined);\n\n}\n\nreturn;","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\n\ncontext.set('filename', undefined);","finalize":"// Code added here will be run when the\n// node is being stopped or re-deployed.\n\ncontext.set('filename', undefined);","x":1084,"y":198,"wires":[["fb03fea0.c6e59"]]},{"id":"d4600315.dbc7d","type":"ffmpeg-spawn","z":"5967c855.68b978","name":"","outputs":2,"migrate":2e-9,"cmdPath":"","cmdArgs":"[\"-f\",\"mp4\",\"-i\",\"pipe:0\",\"-c:v\",\"copy\",\"-c:a\",\"copy\",\"-f\",\"mp4\",\"-movflags\",\"+faststart+empty_moov\",\"pipe:1\"]","cmdOutputs":1,"killSignal":"SIGTERM","msgOutput":"split","x":923,"y":198,"wires":[["7f035cf8.c1f6d4"],["7f035cf8.c1f6d4"]]},{"id":"fb03fea0.c6e59","type":"file","z":"5967c855.68b978","name":"","filename":"","appendNewline":false,"createDir":true,"overwriteFile":"false","encoding":"none","x":1214,"y":198,"wires":[["9c69a6cf.45c9c8"]]},{"id":"1b3c5f.f19183a1","type":"inject","z":"5967c855.68b978","name":"write start default","props":[{"p":"action","v":"{\"subject\":\"write\",\"command\":\"start\",\"keyframe\":-1,\"timeLimit\":500000,\"sizeLimit\":250000000}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":131,"y":59,"wires":[["96b432b8.72f38"]]},{"id":"9c69a6cf.45c9c8","type":"debug","z":"5967c855.68b978","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1334,"y":198,"wires":[]},{"id":"97c44c17.d56ce","type":"function","z":"5967c855.68b978","name":"filename","func":"const { payload, action } = msg;\n\nif (Buffer.isBuffer(payload)) {\n\n    msg.filename = context.get('filename');\n    \n    return msg;\n}\n\nif (typeof action === 'object') {\n    const { command } = action;\n    \n    if (command === 'start') {\n        \n        context.set('filename', `videos/abc/r/${Date.now()}.mp4`);\n        \n    } else if (command === 'stop') {\n        \n        context.set('filename', undefined);\n        \n    }\n}\n\nreturn;","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\n\ncontext.set('filename', undefined);","finalize":"// Code added here will be run when the\n// node is being stopped or re-deployed.\n\ncontext.set('filename', undefined);","x":1085,"y":298,"wires":[["9c6dad2f.e4165"]]},{"id":"9c6dad2f.e4165","type":"file","z":"5967c855.68b978","name":"","filename":"","appendNewline":false,"createDir":true,"overwriteFile":"false","encoding":"none","x":1215,"y":298,"wires":[["92473934.4b74b8"]]},{"id":"92473934.4b74b8","type":"debug","z":"5967c855.68b978","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1335,"y":298,"wires":[]},{"id":"45912098.31d65","type":"pipe2jpeg","z":"5967c855.68b978","name":"","x":934,"y":595,"wires":[["e382fb4.ce83a08"]]},{"id":"e382fb4.ce83a08","type":"image","z":"5967c855.68b978","name":"jpeg preview","width":"200","data":"payload","dataType":"msg","thumbnail":false,"active":true,"pass":false,"outputs":0,"x":1084,"y":595,"wires":[]},{"id":"e27f974a.0ef868","type":"comment","z":"5967c855.68b978","name":"start args","info":"","x":111,"y":106,"wires":[]},{"id":"36953f1b.fdbac","type":"comment","z":"5967c855.68b978","name":"- - - - - daemonize - - - - -","info":"","x":390,"y":20,"wires":[]},{"id":"d9f21b53.703b28","type":"comment","z":"5967c855.68b978","name":"- - - - - - - - - - jpegs - - - - - - - - - -","info":"","x":1013,"y":560,"wires":[]},{"id":"8b84ea34.3465f8","type":"comment","z":"5967c855.68b978","name":"- - - - - progress logs - - - - -","info":"","x":1269,"y":463,"wires":[]},{"id":"e1ae8181.29ed6","type":"comment","z":"5967c855.68b978","name":"- - - - - error logs - - - - -","info":"","x":1277,"y":365,"wires":[]},{"id":"4220195.ce45ae8","type":"comment","z":"5967c855.68b978","name":"- - - - - - - - - save raw mp4 files - - - - - - - - - -","info":"","x":1204,"y":263,"wires":[]},{"id":"1640592.c4917a7","type":"comment","z":"5967c855.68b978","name":"- - - - - - - - - - - - - - - - - save processed mp4 files - - - - - - - - - - - - - - - - - ","info":"","x":1113,"y":163,"wires":[]},{"id":"ec9153b3.c3be6","type":"comment","z":"5967c855.68b978","name":"stop ffmpeg","info":"","x":121,"y":417,"wires":[]},{"id":"2e0fa25d.f5878e","type":"comment","z":"5967c855.68b978","name":"- output mp4 -","info":"","x":130,"y":24,"wires":[]},{"id":"fd12ad4d.89379","type":"comment","z":"5967c855.68b978","name":"- view mp4 -","info":"","x":650,"y":140,"wires":[]},{"id":"42cda3a1.8f558c","type":"inject","z":"5967c855.68b978","name":"start args","props":[{"p":"action","v":"{\"command\":\"start\",\"args\":[\"-loglevel\",\"fatal\",\"-nostats\",\"-f\",\"hls\",\"-http_multiple\",\"1\",\"-re\",\"-i\",\"https://weather-lh.akamaihd.net/i/twc_1@92006/index_1200_av-p.m3u8?sd=10&rebase=on\",\"-c:v\",\"copy\",\"-c:a\",\"aac\",\"-f\",\"mp4\",\"-movflags\",\"+frag_keyframe+empty_moov+default_base_moof\",\"pipe:1\",\"-progress\",\"pipe:3\",\"-f\",\"image2pipe\",\"-vf\",\"select='eq(pict_type,PICT_TYPE_I)',scale=trunc(iw/4):-2\",\"-vsync\",\"vfr\",\"pipe:4\"]}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":112,"y":141,"wires":[["93d74c4e.4c8fe"]]},{"id":"6b35f3b5.48ffcc","type":"inject","z":"5967c855.68b978","name":"restart args","props":[{"p":"action","v":"{\"command\":\"restart\",\"args\":[\"-loglevel\",\"fatal\",\"-nostats\",\"-f\",\"hls\",\"-http_multiple\",\"1\",\"-re\",\"-i\",\"https://dcunilive30-lh.akamaihd.net/i/dclive_1@535229/master.m3u8\",\"-c:v\",\"copy\",\"-c:a\",\"aac\",\"-f\",\"mp4\",\"-movflags\",\"+frag_keyframe+empty_moov+default_base_moof\",\"pipe:1\",\"-progress\",\"pipe:3\",\"-f\",\"image2pipe\",\"-vf\",\"select='eq(pict_type,PICT_TYPE_I)',scale=trunc(iw/4):-2\",\"-vsync\",\"vfr\",\"pipe:4\"]}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":121,"y":277,"wires":[["93d74c4e.4c8fe"]]},{"id":"4ebc8cba.dedf34","type":"comment","z":"5967c855.68b978","name":"restart args","info":"","x":121,"y":242,"wires":[]},{"id":"9c2eceaf.c223b","type":"inject","z":"5967c855.68b978","name":"restart args","props":[{"p":"action","v":"{\"command\":\"restart\",\"args\":[\"-loglevel\",\"error\",\"-nostats\",\"-f\",\"hls\",\"-http_multiple\",\"1\",\"-re\",\"-i\",\"https://travelxp-travelxp-1-au.samsung.wurl.com/manifest/playlist.m3u8\",\"-c:v\",\"copy\",\"-c:a\",\"aac\",\"-f\",\"mp4\",\"-movflags\",\"+frag_keyframe+empty_moov+default_base_moof\",\"pipe:1\",\"-progress\",\"pipe:3\",\"-f\",\"image2pipe\",\"-vf\",\"select='eq(pict_type,PICT_TYPE_I)',scale=trunc(iw/4):-2\",\"-vsync\",\"vfr\",\"pipe:4\"]}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":121,"y":313,"wires":[["93d74c4e.4c8fe"]]},{"id":"ac4cc611.cee8f8","type":"inject","z":"5967c855.68b978","name":"start args","props":[{"p":"action","v":"{\"command\":\"start\",\"args\":[\"-loglevel\",\"fatal\",\"-nostats\",\"-f\",\"hls\",\"-http_multiple\",\"1\",\"-re\",\"-c:v\",\"h264_mmal\",\"-i\",\"https://weather-lh.akamaihd.net/i/twc_1@92006/index_1200_av-p.m3u8?sd=10&rebase=on\",\"-c:v\",\"copy\",\"-c:a\",\"aac\",\"-f\",\"mp4\",\"-movflags\",\"+frag_keyframe+empty_moov+default_base_moof\",\"pipe:1\",\"-progress\",\"pipe:3\",\"-f\",\"image2pipe\",\"-vf\",\"fps=fps=2,scale=trunc(iw/4):-2\",\"-vsync\",\"vfr\",\"pipe:4\"]}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":112,"y":177,"wires":[["93d74c4e.4c8fe"]]},{"id":"76df19c4.773f28","type":"exec","z":"5967c855.68b978","command":"top -b -d 5 -p","addpay":true,"append":"","useSpawn":"true","timer":"","oldrc":false,"name":"top -b -d 5 -p <pid>","x":844,"y":78,"wires":[["f0d2c43b.fe4c78"],[],[]]},{"id":"f0d2c43b.fe4c78","type":"function","z":"5967c855.68b978","name":"%CPU, %MEM","func":"const { payload } = msg;\n\nif (typeof payload === 'string') {\n    \n    const lines = payload.toString().trim().split(/[\\n]+/);\n    \n    if (lines.length >= 2) {\n        \n        const labels = lines[lines.length - 2].trim().split(/[\\s]+/);\n\n        const values = lines[lines.length - 1].trim().split(/[\\s]+/);\n        \n        const payload = {};\n        \n        for (let i = 0; i < labels.length; ++i) {\n            payload[labels[i]] = values[i] || '0.0';\n        }\n\n        const message = `%CPU ${payload['%CPU']}, %MEM ${payload['%MEM']}`;\n\n        node.status({ fill: 'green', shape: 'dot', text: message });\n\n        return { payload };\n    }\n\n}\n\nnode.status({});\n\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1045,"y":70,"wires":[["b933f67e.c39d78"]]},{"id":"b933f67e.c39d78","type":"debug","z":"5967c855.68b978","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1197,"y":70,"wires":[]},{"id":"8715a99e.626858","type":"function","z":"5967c855.68b978","name":"status pid","func":"const { payload = {} } = msg;\n\nconst { status, pid } = payload;\n\nconst timeout = context.get('timeout');\n\nclearTimeout(timeout);\n\nif (status === 'spawn') {\n    \n    const timeout = setTimeout(()=> node.send({ payload: pid }), 100);\n    \n    context.set('timeout', timeout);\n    \n} else if (status === 'close') {\n    \n    return { payload: 'kill', kill: 'SIGTERM'};\n    \n} else {\n    \n    return null;\n}","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\n\ncontext.set('timeout', undefined);","finalize":"// Code added here will be run when the\n// node is being stopped or re-deployed.\n\nconst timeout = context.get('timeout');\n\nclearTimeout(timeout);\n\ncontext.set('timeout', undefined);","x":664,"y":74,"wires":[["76df19c4.773f28"]]},{"id":"379420d.31038e","type":"ui_mp4frag","z":"5967c855.68b978","d":true,"name":"","group":"","order":1,"width":6,"height":4,"readyPoster":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAMAAACtqHJCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExODIyQUIzREQ3RTA0MDAyNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRkU5MkM4RDJCNTkxMUVCQjJCOTg0MEQ0QThCQ0YyQyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRkU5MkM4QzJCNTkxMUVCQjJCOTg0MEQ0QThCQ0YyQyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Rjc3RjExNzQwNzIwNjgxMTgyMkFDQTkzQjdGQkY1MzAiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMTgyMkFCM0REN0UwNDAwMjQiLz4gPC9yZGY6RGVzY3Jp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","errorPoster":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAMAAACtqHJCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExODIyQUIzREQ3RTA0MDAyNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRkU5MkM5MTJCNTkxMUVCQjJCOTg0MEQ0QThCQ0YyQyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRkU5MkM5MDJCNTkxMUVCQjJCOTg0MEQ0QThCQ0YyQyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Rjc3RjExNzQwNzIwNjgxMTgyMkFDQTkzQjdGQkY1MzAiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMTgyMkFCM0REN0UwNDAwMjQiLz4gPC9yZGY6RGVzY3Jp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","hlsJsConfig":"{\"liveDurationInfinity\":true,\"liveBackBufferLength\":5,\"maxBufferLength\":10,\"manifestLoadingTimeOut\":1000,\"manifestLoadingMaxRetry\":10,\"manifestLoadingRetryDelay\":500}","retry":true,"play":true,"unload":true,"threshold":0.5,"players":["socket.io","hls.js","hls","mp4"],"x":651,"y":175,"wires":[[]]},{"id":"f4c762bc.e407d","type":"comment","z":"5967c855.68b978","name":"- - - - - - - - - - - - - - - - - - - - - - use top to get cpu and mem - - - - - - - - - - - - - - - - - - - - - -","info":"","x":924,"y":31,"wires":[]},{"id":"c7c78a8d.180f48","type":"inject","z":"5967c855.68b978","name":"stop SIGINT","props":[{"p":"action","v":"{\"command\":\"stop\",\"signal\":\"SIGINT\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":121,"y":525,"wires":[["93d74c4e.4c8fe"]]},{"id":"781251e2.1e719","type":"inject","z":"5967c855.68b978","name":"stop SIGHUP","props":[{"p":"action","v":"{\"command\":\"stop\",\"signal\":\"SIGHUP\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":121,"y":489,"wires":[["93d74c4e.4c8fe"]]}]

When you say continuously, do you mean 1 endless video that may be 24 hours durations, or multiple videos made back to back 24/7? i am thinking you want to have continous recording that never stops, but broken into invidual videos that are possibly a couple minutes duration. If that is that case, ffmpeg can already do that without needing any complicated mp4frag nodes for that.

I can see the benefits of that, but then i can also see the complications. How shall it be treated when the node has multiple outputs or can receive inputs of varying types? Does the same msg get copied to all of the outputs? Will the node then have to manage different msgs for different outputs? I can see that working well when there is a node that has 1 input and 1 output, but... seems like it would be complicated and time consuming for my nodes. I will have to ponder that for a while to see if it could be incorporated to solve any real problems.

Currently, I am still trying to get that readme file done for ffmpeg-spawn. Now that I am all cut up from thumb and wrist surgery while also working and studying for an upcoming test for a job position change, my spare time is even less than usual. Definitely a good idea to be able to carry data across a flow like that. At the very least, i think my flow example shows how to save files while dynamically naming them, although it does feel a bit clumsly and needs improvement.

1 Like

I am considering changing the way the sizeLimit and timeLimit works. At the beginning, I set it up as a hard limit that had to be overridden in settings.js to protect end users from accidentally filling up their hard drive. As of now, I think that should be configured in the editor per node, while the settings.js will just be for setting a default value that can be used in the editor. If I have a chance to get to that this weekend, then there should be an option to "turn on" the mp4 buffer output indefinitely and it will be up to the end user to use caution. By default, it will use limits, so the unlimited option will be opt-in, maybe using the value Number.POSITIVE_INFINITY so that it was not set accidentally.

2 Likes

I think it sounds reasonable & good!

1 Like

One more thing I just would like to bring up for discussion related to "continuous" recording is what we call time lapse recording. In my world this is a continuous recording at a low fps and when an event occurs, the fps is increased to normal speed during the event. After a defined time, the oldest part of the video is "deleted" to avoid consumption of too much disk space so to say. Along with the video file a file or record is made where the events starting and ending times are registered so that a time line can be created

I do not know what is possible but it would be rather pretty if you could define a time lapse recording with total duration, normal fps rate, event fps rate and being able to control this via an event start/stop message. Somehow. If a separate file is needed for registering the time stamps for the events, I assume this would be a good starting point for creating a possible future clickable time line

Just my thoughts

1 Like

Hey Kevin,
Your private life is more important than this grumpy community :rofl:
You have already implemented a very cool set of very useful nodes for us, so get some time for yourself to get everything in place...
And meanwhile we keep posting questions for new features anyway :joy:
Hope you soon get better and get the daily job you deserve ...
Bart

2 Likes

Interesting thoughts

Altering the mp4's fps would require decoding and encoding, as of course, you already know. But, what about taking advantage of a camera's sub and main stream. With all of my cams, I have ffmpeg running and connected to main and sub (each one eventually going to a ui node for viewing and I can switch between my montage of main or sub streams). I could see you configuring the internal settings of the cam to output a very low fps on the sub stream and normal fps on the main. Do continuous recording on the sub and switch to the main when there is an event. Of course, that would be so that we don't have to re-encode the source video and modify its fps, which would be heavy on the cpu or gpu. The tradeoff is that you would have to keep 2 ffmpeg processes running and connected to both main and sub streams separately, and that will lead to extra memory and cpu usage, but should still be much lower cpu that re-encoding.

Thanks for the support. I just didn't want anybody to think i am ignoring their questions or comments due to a lack of interest, but instead a lack of time.

2 Likes

Had already tried the swapn node and here I'm getting the 10 seconds video instead of the 2 secs with the mp4frag. But my swap file is getting that large and I get the ENOMEM error in the spawn node almost instantly.