I need to find a way to save ffmpeg frames into redis variable.
Currently I’m piping png images from ffmpeg to redis but it concatenate all images:
ffmpeg -re -i udp://127.0.0.1:5545 -c:v png -r 1 -update 1 – | redis-cli -x HSET sb4up
Is it possible to update the redis variable with a new frame every second?
2
Answers
I have been having a think about this. I am no expert in
ffmpeg
and there may be something much simpler, so if someone makes me aware of a better method I will likely delete this.For the moment, my thought is that if
ffmpeg
writes JPEG or PNG as output, you need a tool that is able to parse a concatenated stream and search for START-OF-IMAGE/END-OF-IMAGE or (JPEG SOI/EOI or PNG IHDR/IEND) markers and understand chunks and sections. So, I thought it might be simpler to forceffmpeg
to write fixed length images, then you can just readN
bytes knowing it corresponds to a frame and you don’t need a bunch of "glue" code to write and maintain – just standard tools.I don’t have your UDP stream, so I just used a
.mov
file. I then forcedRGB24
encoding and a fixed size, resized frame of 640×480. I then split that into chunks of 640x480x3 RGB bytes and ask ImageMagick to create a PNG from the raw video and whack it into Redis as a PNG:I then use OpenCV to grab the image every 0.5 seconds from Redis and display the result.
Note: I used
gsplit
for GNUsplit
because I am on a Mac. On Linux, just usesplit
.Note: Obviously you can use a differently sized frame as long as you update it in both parts of the code – i.e. both in
gsplit
and ImageMagick.Note: You don’t necessarily need to install ImageMagick and PNG-encode each image, because you will only have the one, single, latest image in Redis so space will not be an issue as there are not thousands of frames, so you could omit ImageMagick and just write the raw RGB24 data into Redis without ImageMagick. Then grab the raw data from Redis and use
np.reshape()
to make it into a correctly-shaped image.I am still thinking and may come up with something better… Perl might be good for splitting a binary stream on a pattern…
Another idea is to have
ffmpeg
writePNG
files with a sequential number likeframe-%03d.png
and runfswatch/inotify
to grab the individual frames and stuff them into Redis.For some unknown reason. I got the urge to write some Python to split a continuous stream of concatenated PNG files and send each one to Redis as it arrives.
The program reads a stream of PNG files in PNG chunks, rather than in 1MB blocks and looking for
IEND
markers which would result in a 30 image delay if your individual PNG images were 33kB each in size. Each PNG chunk has a "chunk size" (4 bytes in network byte order) and a "chunk type" (4 bytes). The first chunk is the 8-byte signature and the last one in an image is theIEND
chunk. As chunks arrive they are read and gathered in abytearray
calledwholePNG
. When the end of the PNG arrives, I send this to Redis:You can run it like this:
and it will send each PNG to Redis as
sb4up
as it arrives.I tested it like this in a directory with a load of random PNG images:
Keywords: Python, image processing, ffmpeg, video, stream, split, PNG chunk, concatenate.