How to make ffmpeg insert timestamp in filename - ffmpeg

I'm trying to make a bash script that grabs a still shot from an IP camera and than emails it.
Using
ffmpeg -i http://admin:Stupidpassword1#10.12.10.40/Streaming/channels/1/picture \
-f image2 -updatefirst 1 doorbell.jpg
From what I have read this should work but the output file name is still doorbell.jpg How can I make the filename TIMESTAMPdoorbell.jpg?

Use the "strftime" feature:
ffmpeg -i http://admin:Stupidpassword1#10.12.10.40/Streaming/channels/1/picture -vframes 1 -f image2 -strftime 1 "%Y-%m-%d_%H-%M-%S_doorbell.jpg"
"-vframes 1" will cause it to only process the first frame that it receives.
You can change the date/time format using a strftime compatible string:
http://man7.org/linux/man-pages/man3/strftime.3.html
Further documentation/examples:
https://www.ffmpeg.org/ffmpeg-formats.html#image2-2

Related

ffmpeg: How to save SSIM and PSNR to a file?

I'm a ffmpeg newbie.
I would like my script (on Windows) to output the average PSNR and average SSIM values to a file.
(but not the values for every frame)
I can output them to the standard output but not to a file.
I use this line:
ffmpeg -i ref.avi -i compressed.avi -lavfi "ssim;[0:v][1:v]psnr" -f null -
I understand I have to change something here: "-f null -" , but I cannot make it work.
Using ssim & psnr filters
On Linux and macOS you can use grep:
$ ffmpeg -i compressed.avi -i reference.avi -lavfi "[0][1]ssim;[0][1]psnr" -f null - |& grep Parsed_ > ff.log
Simple, but major downside is it won't show you the console output, so you may miss errors. To fix that add tee:
$ ffmpeg -i compressed.avi -i reference.avi -lavfi "[0][1]ssim;[0][1]psnr" -f null - |& tee >(grep Parsed_ > ff.log)
Example contents of ff.log from either command:
[Parsed_ssim_0 # 0x5579d7f17b40] SSIM Y:0.796135 (6.906565) U:0.843488 (8.054531) V:0.822424 (7.506157) All:0.820682 (7.463768)
[Parsed_psnr_1 # 0x5579d7f12b00] PSNR y:24.940925 u:23.938192 v:23.641771 average:24.138969 min:23.298059 max:26.880485
If you want to append to ff.log instead of overwrite use grep Parsed_ >> ff.log instead.
If |& does not work for you use 2>&1 instead.
Or use libvmaf
libvmaf filter is slower but will output a log file containing the VMAF, SSIM, and PSNR aggregate scores along with the per frame scores in XML or JSON. Your ffmpeg will need to be compiled with --enable-libvmaf to use this filter.
ffmpeg -i compressed.avi -i reference.avi -lavfi "[0][1]libvmaf=log_path=vmaf.xml:log_fmt=xml:ssim=1:psnr=1" -f null -

Subtract two timecodes in bash, for use in ffmpeg

I am running ffmpeg in terminal on a mac, to trim a movie file losslessly using the following in bash:
startPosition=00:00:14.9
endPosition=00:00:52.1
ffmpeg -i mymovie.mov -ss $startPosition -to $endPosition -c copy mymovie_trimmed.mov
But that doesn't seek the nearest keyframe and causes sync issues. See here: https://github.com/mifi/lossless-cut/pull/13
So I need to rearrange my code like this:
ffmpeg -ss $startPosition -i mymovie.mov -t $endPosition -c copy mymovie_trimmed.mov
(the -to property seems to get ignored, so I am using -t (duration) instead). My question is how can I reliably subtract the $startPosition variable from the $endPosition to get the duration?
EDIT: I used oguz-ismail's suggestion with using gdate instead of date (and brew install coreutils):
startPosition=00:00:10.1
endPosition=00:00:50.1
x=$(gdate -d"$endPosition" +'%s%N')
y=$(gdate -d"$startPosition" +'%s%N')
duration=$(bc -lq <<<"scale=1; ($x - $y) / 1000000000")
This gives me output of 40.1, how would I output it as 00:00:40.0 ?

Why isn't my bash script working?

I'm trying to get this bash script to work but am at a loss. I have a text file that contains a list of frame numbers line by line. ffmpeg reports the error:
Undefined constant or missing '(' in '$name)'
The script
#!/bin/bash
source text.txt
while read name
do
ffmpeg -i result.mp4 -vf "setpts=N+1,select='eq(n,\$name)'" -vframes 1 frame-$i.jpg
done <text.txt
You are escaping the $ before variable name i.e. $name, so the $name will be treated literally without any variable expansion being done.
Do:
ffmpeg -i result.mp4 -vf "setpts=N+1,select='eq(n,$name)'" -vframes 1 frame-$i.jpg

Load output of ffmpeg command in text file which detects silences

How can I load the output of below command into a text file?
ffmpeg -i units.wav -af silencedetect=noise=-20dB:d=0.2 -f null -
This command simply detects the silences from a video and I need to store this output in a text file.
I have also found this link but as I am newbie in ffmpeg I am not able to use it in my command.
Thanks..
Wanted to post this update for other people who've had this problem. I had the same problem with the > pipe command and found you can use 2> instead. Possible FFMpeg bug? Not sure.
ffmpeg -i units.wav -af silencedetect=noise=-20dB:d=0.2 -f null - 2> output.txt
You can pipe its output to a file like this:
ffmpeg -i units.wav -af silencedetect=noise=-20dB:d=0.2 -f null - > output.txt

Need explanation of details of ffmpeg and pipes command

Got the following from FFmpeg FAQ:
mkfifo intermediate1.mpg
mkfifo intermediate2.mpg
ffmpeg -i input1.avi -sameq -y intermediate1.mpg < /dev/null &
ffmpeg -i input2.avi -sameq -y intermediate2.mpg < /dev/null &
cat intermediate1.mpg intermediate2.mpg |\
ffmpeg -f mpeg -i - -sameq -vcodec mpeg4 -acodec libmp3lame output.avi
Before i use or modify it I would like to understand it completely.
What does the < /dev/null & do?
I understand | is pipe but why |\ ?
What is the -f mpeg after ffmpeg (Seems, it tells ffmpeg to accept the piped in output from the cat(?) )
< /dev/null &
This is actually two parts:
< /dev/null
&
1 (< /dev/null) is just a simple way to pass no input/EOF to a program. I'm not sure it's needed but it may be because you are using named pipes.
2 (&) simply pushes the command to the background and allows you to do other things. This is necessary because otherwise, ffmpeg would just sit there waiting for the other end of the named pipe to "open".
Backslash after pipe
The backslash after the pipe is simply there to allow you to enter the long command on multiple lines. If you want to write it on a single line, you should omit the backslash. You'll notice that the prompt changes from your usual [user#machine directory]$ (or whatever) to something like > after you enter the first line (ending with a backslash). This signifies that your command is being continued from an earlier line.
ffmpeg -f switch
The man page for ffmpeg indicates that the -f switch allows you to force a file format. In the example in the FAQ, you want to force an input format (read: tell ffmpeg what input format to expect) since your using piped bits as input. Usually, it would try to guess the input format based on the file extension and/or "file magic".

Resources