Extracting frame every 30 seconds using FFmpeg is slow - performance

We are extracting frame every 30 seconds from mp4 file with following FFmpeg command :
ffmpeg -vsync 0 -i file.mp4 -vf fps=1,select='not(mod(t,30))' -frame_pts 1 temp\file.%d.jpg
We are using vsync and frame_pts options since we need frame's position w.r.t. seconds in output file names. It is running slow. It takes around 90 seconds to extract around ~235 images from ~118 minutes (259 MB) mp4 file. CPU usage while running this command goes 100%.
We are using this command in multi-threaded java application. During load test, we found that with 10 threads running this command simultaneously, time to complete this command is 5-15 minutes.
Is there any way to improve performance of this FFmpeg command ?

Related

Am I missing a timeout param in FFMPEG?

I'm running an ffmpeg command like this:
ffmpeg -loglevel quiet -report -timelimit 15 -timeout 10 -protocol_whitelist file,http,https,tcp,tls,crypto -i ${inputFile} -vframes 1 ${outputFile} -y
This is running in an AWS Lambda function. My Lambda timeout is at 30 seconds. For some reason I am getting "Task timed out" messages still. I should note I log before and after the command, so I know it's timing out during this task.
Update
In terms of the entire lambda execution I do the following:
Invoke a lambda to get an access token. This lambda makes on API request. It has a timeout of 5 seconds. The max time was 660MS for one request.
Make another API request to verify data. The max time was 1.6 seconds.
Run FFMPEG
timelimit is supposed to Exit after ffmpeg has been running for duration seconds in CPU user time.. Theoretically this shouldn't run more than 15 seconds then, plus maybe 2-3 more before the other requests.
timeout is probably superfluous here. There were a lot of definitions for it in the manual, but I think that was mainly waiting on input? Either way, I'd think timelimit would cover my bases.
Update 2
I checked my debug log and saw this:
Reading option '-timelimit' ... matched as option 'timelimit' (set max runtime in seconds) with argument '15'.
Reading option '-timeout' ... matched as AVOption 'timeout' with argument '10'.
Seems both options are supported by my build
Update 2
I have updated my code with a lot of logs. I definitively see the FFMPEG command as the last thing that executes, before stalling out for the 30 second timeout
Update 3
I can reproduce the behavior by pointing at a track instead of full manifest. I have set the command to this:
ffmpeg -loglevel debug -timelimit 5 -timeout 5 -i 'https://streamprod-eastus-streamprodeastus-usea.streaming.media.azure.net/0c495135-95fa-48ec-a258-4ba40262e1be/23ab167b-9fec-439e-b447-d355ff5705df.ism/QualityLevels(200000)/Manifest(video,format=m3u8-aapl)' -vframes 1 temp.jpg -y
A few things here:
I typically point at the actual manifest (not the track), and things usually run much faster
I have lowered the timelimit and timeout to 5. Despite this, when i run a timer, the command runs for ~15 seconds every time. It outputs a bunch of errors, likely due to this being track rather than full manifest, and then spits out the desired image.
The full output is at https://gist.github.com/DaveStein/b3803f925d64dd96cd45ae9db5e5a4d0
timelimit is supposed to Exit after FFmpeg has been running for duration seconds in CPU user time.
This is true but you can't use this timing metric to determine when FFmpeg should be forcefully exited during its operation (See here).
Best to watch the process from outside and force kill it by sending a TERM or KILL signal.
I'd recommend the timeout command that's part of the GNU coreutils.
Here's an example
timeout 14s -t 1s <FFMPEG COMMAND LINE>
This would ensure that the FFmpeg command execution runs for as long as 14 seconds and forces it to be killed (SIGKILL) one second after that in case it didn't quit with the SIGTERM signal.
You can check the man pages for the timeout command.
you can try these things:
increase the timeout-limit of your lambda function.
increase the memory allocation to your lambda function. It speeds up your lambda function.
If you still gets timeout than check RequestTimeout and ConnectionTimeout of your lambda function.

Crontab task scheduled every hour stops running from 11am to 12am

I have a rather weird issue. My aim is to use ffmpeg to grab a screenshot from a home CCTV cameras rtsp stream every hour. I want to do this in order to make a timelapse. However everyday from 11am to 12am (the next day) there are no snapshots saved.
On an always on Debian machine, this is the shell script I have that crontab calls:
dt=$(date +"%d%m%2y%I%M%S")
ffmpeg -rtsp_transport tcp -i "rtsp://IP:554/..." -frames 1 /user/snapshots/ch1/$dt.jpg
Running it by itself works fine and saves a jpg snapshot successfully to the right folders.
In crontab -e I have the following line:
0 * * * * /bin/sh //user/snap.sh
Thanks.
%I is the hour on a 12-hour clock (intended to be used with %p), so your afternoon files are overwriting the morning ones. Use %H instead.
You should add something like
0 11-0 * * * /bin/sh //user/snap.sh
Mean task will start every minute 0 from every hour from 11AM to 12AM

How to stop FFMPEG from running if connection to input stream is lost?

I am capturing thumbnails from a webcam RTMP stream every 1 second to JPG files. Here's my command line:
ffmpeg -i rtsp://192.168.1.89:554/11 -f image2 -r 1 thumb%03d.jpg
How can I make FFMPEG die with an error if the input RTMP stream is lost for a given timeout period? Currently, if I lose connection to the webcam, FFMPEG starts throwing "Unknown error" messages, but when the network reconnects, ffmpeg appears to reconnect to the stream, but does not output any more captured frames. I have to manually kill the process and restart it to again start capturing frames.
It would be nice to simply have ffmpeg die when it loses connection for a specific timeout period. Then I could monitor the process and restart when it ends.
Any ideas?
You can set ffmpeg timeout for RTSP :
timeout Set maximum timeout (in seconds) to wait for incoming
connections.
A value of -1 means infinite (default). This option implies the
rtsp_flags set to ‘listen’.
stimeout Set socket TCP I/O timeout in
microseconds.
The solution is actually to put a timeout on the socket connection:
[...] -rtsp_transport tcp -stimeout 30000000 -i rtsp://192.168.1.89:554/11 [...]
(30 seconds in this case)

Recording from online stream and listening to it at the same time (ffmpeg / ffplay)

Sometimes I like to record programmes from online radio channels, live or archived streams too. When there is no interesting actual programmes in the radios, I also would like listening to it at the same time while recording. I am using such command lines, which is called from Ruby script - to help parsing radios' timetables / programme pages and constructing the proper URLs of archived programmes which usually contains some timecode, such as 20160616_083000.mp3, etc.
So my command line to call from Ruby script looks like:
programmes.each{|datepart,programme_length|
cmd=%Q{ffmpeg -y -i http://example.com/stream/#{datepart}.mp3 -t #{programme_length} -c:a libmp3lame -b:a 160k "#{fname}" -c copy -t #{programme_length} -f mp3 -f rtp rtp://127.0.0.1:8888}
system cmd
}
It resides in a loop to record the previously parsed and selected programmes. Of cource the programmes are recorded properly and at the same time ffmpeg streams it as an mp3 rtp stream as well on localhost at the given port. In another terminal window I connect to the streamed data with one-liner as follows:
while true; do ffplay -i rtp://127.0.0.1:8888 -autoexit; done
I am using the -autoexit switch which should be stop playing the stream when it is ended and the "while" loop should be connect again to the new stream which is served by the programme recording "each" loop. Unfortunately it keeps playing after the end, and doesn't initiate a new connection to the newly started stream. How to use ffplay properly to stop playing after rtp stream is ended and let it connect again to the new stream?

FFMPEG - Display time taken to convert

How is it possible to display the time taken to convert a video using FFMPEG ?
i am using the below command and the time returned as benchmark is not exactly the time taken to complete the conversion.. i am confused how can it be missing in a such nice tool.
ffmpeg -cpuflags -sse-sse2-sse3-sse3slow-sse4.1-sse4.2+mmx -i E:/MSC/test.flv ^
-benchmark E:/MSC/testmmx.mp4
If you can use Bash it has the time command
time: time [-p] pipeline
Report time consumed by pipeline's execution.
Execute PIPELINE and print a summary of the real time, user CPU time,
and system CPU time spent executing PIPELINE when it terminates.
Example
$ time ffmpeg -i infile outfile
real 0m3.682s
user 0m0.015s
sys 0m0.000s
I offer Cygwin for Windows, which includes Bash and time
bitbucket.org/svnpenn/a/downloads

Resources