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
Related
I'm trying to get the basename (without file extension) so that I can process a directory of audio files (.flac -> .m4a) quickly and and up with proper filenames.
So this works:
for i in *.flac;do ffmpeg -i $i -c:a libfdk_aac -vbr 3 $i.m4a; done
But it leaves me with a file like like this:
audiofile.flac.m4a
What I would like to do is just grab the "audiofile" part of the filename so that this works:
for i in *.flac;do ffmpeg -i $i.flac -c:a libfdk_aac -vbr 3 $i.m4a; done
But I don't understand modifiers (apparently a ":t" modifier might get me the results?) or how to define variables on the for loop (for each file). Also, I see that there are many examples of how to do this with BASH, but I'm looking for something that works with zsh.
Any ideas?
Thanks!
In zsh you can use the Modifiers from History Expansion with Parameter Expansions. Each modifier is preceded by a colon: ${name:modifier}. Thermodifier removes the extension, i.e. everything from - including - the last.` to the end of the file name:
for i in *.flac; do
ffmpeg -i $i -c:a libfdk_aac -vbr 3 ${i:r}.m4a
done
Note: the modifier r will remove any extension, not only ".flac".
A more portable (read: should work in any POSIX-compliant shell) and specific solution would be to use the Parameter Expansion ${name%pattern}, which will remove the smallest string matching pattern from the end of the value of name. If pattern does not match the end of the value of name, the value will be returned unchanged:
for i in *.flac; do
ffmpeg -i $i -c:a libfdk_aac -vbr 3 ${i%.flac}.m4a
done
This will remove only ".flac" specifically from the end of the file names.
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
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
I have these variables:
$reel = XF_1
$base = AA000201
$output_dir = directory
This command isn't working. It produces a file called directory/AA000201.mp4
ffmpeg -i $1 $output_dir"/$reel_$base.mp4
This command works. It produces a file called directory/XF_1_AA000201.mp4.
ffmpeg -i $1 $output_dir"/"$reel"_"$base".mp4"
But it gives this error: /Volumes/RAID/LIGHTS/RawFootage/Day01/B_Camera/XF_1/CONTENTS/CLIPS001/AA0002/AA000201.MXF: line 5: continue: only meaningful in a for',while', or `until' loop
Note: I have shortened directory names here for simplicity.
ffmpeg -i "${1}" "${output_dir}/${reel}_${base}.mp4"
Polbrelkey gave you the answer, but i'm still gonna add this.
Lets see why ffmpeg -i $1 $output_dir"/$reel_$base.mp4 is un-interpretable unambiguously :
Look at those three variables :
reel="A"
reel_="B" #Nothing prevents you from ending a variable with an underscore
base="C"
Now, let's interpret ffmpeg -i $1 $output_dir"/$reel_$base.mp4 :
Depending on how your decompose the string, you get either :
#ffmpeg -i $1 $output_dir"/${reel_}${base}.mp4
ffmpeg -i $1 $output_dir"/BC.mp4
#ffmpeg -i $1 $output_dir"/${reel}_${base}.mp4
ffmpeg -i $1 $output_dir"/A_C.mp4
In your case, Bash is actually interpreting the first one (actually, he looks for the longest possible variable name) and since reel_="" is not assigned, outputs directory/AA000201.mp4.
You don't have these kind of problems with base.mp4 since a variable name can't have a dot.
Source : Parameter Expansion on Bash-Hackers
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".