The old unpublished node-red-contrib-pipe2jpeg
has been re-built as @kevingodell/node-red-pipe2jpeg.
This node is similar to @BartButenaers' node-red-contrib-multipart-stream-encoder (node) - Node-RED, but serves a different purpose.
It is mostly a wrapper around the lib pipe2jpeg, which handles jpeg chunks that are piped from ffmpeg. An extra option to host image.jpeg
and video.mjpeg
http routes was added for convenience.
If you have used @kevingodell/node-red-mp4frag
, you may notice some similarities.
You may only need this node if you are piping jpegs from ffmpeg. The reason is that the jpeg can be broken into buffer chunks to fit within your system's pipe if it is too big to fit as a single piece. It can arrive in 2 or more chunks and need to be re-assembled in some situations. Other times, there may be more than 1 jpeg packed into a single chunk. The internal dependency pipe2jpeg
handles that buffer marker searching. To get further into the weeds, the start marker ff d8
and end markerff d9
may arrive at the beginning, middle, end of a chunk, or even have the ff
arrive at the end of 1 chunk, with the d8
arrive in the next chunk.
You can set the option to output the buffer as an array of buffers or a single concatenated buffer. Array is preferred so that there is no extra memory allocation. The http routes can handle either setting with no problem. Buffer concatenation should be avoided to prevent an increase in memory usage, but you can do whatever you prefer.
If you are using @kevingodell/node-red-ui-mp4frag
to view fragmented mp4 video from @kevingodell/node-red-mp4frag
, then you can set the ready poster url to be the http path to /pipe2jpeg/<basePath>/image.jpeg
and you will see the most recent jpeg right before the mp4 video loads.
As always, the documents are sparse. Import the example:
I would suggest that you do not directly send the jpegs to node-red-dashboard
. The problem will be that even when you are not viewing a tab that is meant for showing the image, the jpeg will still be delivered and waste much bandwidth. Instead, send the playlist
to the dashboard and have the front end widget request the jpegs on an interval.
[{"id":"0c43334e64655a4c","type":"ui_template","z":"0eb5dd623a753eb1","group":"a33e942d5385de1d","name":"jpeg reloader widget","order":14,"width":"6","height":"4","format":"<img ng-src=\"{{src}}\" ng-on-load=\"onLoad()\" class=\"jpeg-img\"/>\n\n<script>\n((scope) => {\n\n scope.destroy = () => {\n\n clearInterval(scope.reloader);\n\n scope.src = ' '; // angular bug, give it some whitespace to clear img src\n\n }\n\n scope.$watch('msg', (msg) => {\n\n scope.destroy();\n\n if (msg && msg.payload && msg.payload.jpegImage) {\n\n const { jpegImage } = msg.payload;\n\n scope.src = jpegImage;\n\n scope.reloader = setInterval(() => {\n\n scope.src = `${jpegImage}?t=${Date.now()}`;\n\n },\n\n 2000\n\n );\n\n }\n\n });\n\n scope.$on('$destroy', scope.destroy);\n\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"jpeg-widget","x":1680,"y":500,"wires":[[]]},{"id":"a33e942d5385de1d","type":"ui_group","name":"Group 1","tab":"8d2f4135ad04d074","order":1,"disp":true,"width":"6","collapse":false,"className":"jpeg-group"},{"id":"8d2f4135ad04d074","type":"ui_tab","name":"jpeg montage","icon":"dashboard","order":2,"disabled":false,"hidden":false}]