ruby wont read output of ffmpeg - ruby

running
a = `ffmpeg -i video.mp4`
does not seem to give the output of the command into a... Why is that? how do override it?

Quick answer:
a = `ffmpeg -i video.mp4 2>&1`
Detailed answer:
When I ran ffmpeg -i blah.avi on a handy file, I noticed that none of its output when out to standard out; instead, all the output when to standard error. You can check yourself at the shell by running:
ffmpeg -i video.mp4 > /tmp/standard_out 2> /tmp/standard_error
Then look at both /tmp/standard_out and /tmp/standard_error. You'll see which one is which quickly. You can quickly 'fix' this by using ffmpeg -i video.mp4 2>&1 in your script, which will ask the shell to redirect stderr along with stdout. You won't be able to tell the difference between stderr and stdout, but you can get the output you 'see' easily enough.
You'll have to use popen3 if you want to keep stdout and stderr separate.

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 ?

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

Create a video from jpeg with avconv => corrupted video

Im trying to make a video (whatever the format) from a directory full of jpeg frames.
I tried with avconv (v0.8), as seen on many topics on the internet, and the libav documentation as well :
avconv -i samples/*.jpeg output.mpeg
It seems to work nicely and create the output.mpeg file.
But the file can't be read by any reader (vlc, banshee, totem,...). No error, but nothing happend when I press Play.
If I check the video file size, it is about 20kB, whereas the original video is 10MB. So we can assume the data has not been stored into the file (it is about 20kB no matter the number of frames given on input)
I made a pastebin of the debug log of the processing. I am not familiar with codec world, so I don't understand many things : http://pastebin.com/9dfxFWZe.
I also try a lot of combinations with -s, -r, -b, -vcodec, -f format, etc.. but the probleme is still there.
Am I doing anything wrong ?
Ask me anything that could help you, I will answer very quickly.
Thank you for your help :)
avconv expects you to give the input filenames in a printf-like syntax. Simply using shell wildcards (such as samles/*.jpeg) is not enough.
Your samples seem to be named sample/lapinsnipermin/.jpeg, so try the following command line:
avconv -f image2 -i samples/lapinsnipermin/%03d.jpeg output.mpeg
Does this work? You might also want to add options for the bitrate (e.g -r 25).
Resurrecting this since it came up when Googling for a solution. I finally got it working using this:
knoppix#Microknoppix:~$ avconv -r 1 -i /tmp/photo%d.jpg -r 24 -s 320x240 -vsync cfr /tmp/video.mpg
I couldn't get avconv to recognize the input files in the original names; this shows why:
knoppix#Microknoppix:~$ strace avconv -i /media/sdb1/DCIM/188_0408/IMGP%04d.JPG /tmp/video.mpg 2>&1 | grep 188_0408
execve("/usr/bin/avconv", ["avconv", "-i", "/media/sdb1/DCIM/188_0408/IMGP%0"..., "/tmp/video.mpg"], [/* 36 vars */]) = 0
stat64("/media/sdb1/DCIM/188_0408/IMGP0000.JPG", 0xbf925b00) = -1 ENOENT (No such file or directory)
stat64("/media/sdb1/DCIM/188_0408/IMGP0001.JPG", 0xbf925b00) = -1 ENOENT (No such file or directory)
stat64("/media/sdb1/DCIM/188_0408/IMGP0002.JPG", 0xbf925b00) = -1 ENOENT (No such file or directory)
stat64("/media/sdb1/DCIM/188_0408/IMGP0003.JPG", 0xbf925b00) = -1 ENOENT (No such file or directory)
stat64("/media/sdb1/DCIM/188_0408/IMGP0004.JPG", 0xbf925b00) = -1 ENOENT (No such file or directory)
write(2, "/media/sdb1/DCIM/188_0408/IMGP%0"..., 66/media/sdb1/DCIM/188_0408/IMGP%04d.JPG: No such file or directory
I didn't see an option for setting the starting number, so I did this:
i=0; for file in /media/sdb1/DCIM/188_0408/IMGP28*.JPG; do cp $file /tmp/photo$i.jpg; i=$((i+1)); done
The end result is a video of my photos, showing one for each second; the -vsync cfr tells avconv to pad the input frames to match the output framerate.
I found it better to pipe the jpg file in you want so you can control the selection with standard wildcards, try something like this. This also outputs a video that you can user on the web and mobile (ie. using the standard browser tag):
cat samples/*.jpeg | avconv -r 30 -f image2pipe -codec:v mjpeg -i - -pix_fmt yuvj420p -r 30 -c:v libx264 -vf scale=480:300 -y output.mp4

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