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 ?
Related
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 -
Is it possible to remove the end of a video that has no sound?
: = Has Sound
. = No Sound
00:00 [::::::::::::::::::::::::::::........] 01:24
____________________^^^^^ Cut this
Thanks
Note time when sound ends, such as 00:01:23, then use:
ffmpeg -i input -c copy -t 00:01:23 output
You can use seconds if you prefer, such as -t 83.
Exact time is not guaranteed with stream copy mode (-c copy). If exactness is a requirement then remove -c copy.
If you want to automate it (you didn't specify) then integrate the silencedetect filter. It will output timestamps of detected silence, then use the supplied timestamps to create your ffmpeg command. See ffprobe/ffmpeg silence detection command for an example showing how to get the timestamps.
I'm trying to create a video quiz, that will contain small parts of other videos, concatenated together (with the purpose, that people will identify from where these short snips are taken from).
For this purpose I created a file that contain the URL of the video, the starting time of the "snip", and its length. for example:
https://www.youtube.com/watch?v=5-j6LLkpQYY 00:00 01:00
https://www.youtube.com/watch?v=b-DqO_D1g1g 14:44 01:20
https://www.youtube.com/watch?v=DPAgWKseVhg 12:53 01:00
Meaning that the first part should take the video from the first URL from its beginning and last for a minute, the second part should be taken from the second URL starting from 14:44 (minutes:seconds) and last one minute and 20 seconds and so forth.
Then all these parts should be concatenated to a single video.
I'm trying to write a script (I use ubuntu and fluent in several scripting languages) that does that, and I tried to use youtube-dl command line package and ffmpeg, but I couldn't find the right options to achieve what I need.
Any suggestions will be appreciated.
Considering the list of videos is in foo.txt, and the output video to be foo.mp4, this bash script should do the job:
eval $(cat foo.txt | while read u s d; do echo "cat <(youtube-dl -q -o - $u | ffmpeg -v error -hide_banner -i - -ss 00:$s -t 00:$d -c copy -f mpegts -);"; done | tee /dev/tty) | ffmpeg -i - -c copy foo.mp4
This is using a little trick with process substitution and eval to avoid intermediate files, container mpegts to enable simple concat protocol, and tee /dev/tty just for debugging.
I have tested with youtube-dl 2018.09.26-1 and ffmpeg 1:4.0.2-3.
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
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".