-1

Here is my beautifully working statement:

ffmpeg -loop 1 -i AlbumCover.png -i AnglersTunnel.flac -c:v libx264 -tune stillimage -c:a aac -strict experimental -b:a 192k -pix_fmt yuv420p -shortest AnglersTunnel.mp4

Now i want to run this on a folder of about 200 different .flac files with different names. Needing to use the same 'AlbumCover.png' image for every mp4 that is generated. I don't want to type in every different .flac file name by hand. How can i loop this? Additionally I need the name of the outputted mp4 file to be the same name as the .flac file that was converted.

Ridalgo
  • 651
  • 1
  • 6
  • 10
  • How is this question different from your other recent question [How to batch convert using ffmpeg from command line?](http://stackoverflow.com/q/27748899/1109017) – llogan Jan 03 '15 at 03:07

3 Answers3

3

You can loop through all .flac files, replacing the .flac suffix with .mp4 like this:

for input in *.flac; do
    output=${input%.flac}.mp4
    ffmpeg -loop 1 -i AlbumCover.png -i "$input" -c:v libx264 -tune stillimage -c:a aac -strict experimental -b:a 192k -pix_fmt yuv420p -shortest "$output"
done

${input%.flac} removes .flac from the end of the file name.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • All the .flac files have different names. Some have spaces in the names. that's helpful but i need the output file name to be the same name as the .flac it was converted from. – Ridalgo Jan 03 '15 at 01:16
1
for i in *flac; do
    ffmpeg -loop 1 -i AlbumCover.png -i "$i" -c:v libx264 -tune stillimage -c:a aac -strict experimental -b:a 192k -pix_fmt yuv420p -shortest "${i%.flac}.mp4"
done

This is a simple for loop and the use of bash parameter expansion

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • that's helpful but i need the output file name to be the same name as the .flac it was converted from. – Ridalgo Jan 03 '15 at 01:15
0

My way is typically to escape spaces with the magic $'\n' variable:

IFS=$'\n'; 
for i in `find . -iname '*flac'`; do 
  ffmpeg -loop 1 -i AlbumCover.png -i "%" -c:v libx264 -tune \
  stillimage -c:a aac -strict experimental -b:a 192k -pix_fmt yuv420p \
  -shortest "$(echo "$i" | sed s/\.flac$/.mp4/)"
done

finds all your flac files ( recursively ), and then executes the subshell to replace .flac with .mp4 in each filename. This subshell executes as part of the -c command.

I have a ffmpeg mocked up ffmpeg[1] that seems to verify the parameters are correctly escaped for the ffmpeg command:

["-loop", "1", "-i", "AlbumCover.png", "-i", "%", "-c:v", "libx264", "-tune", "stillimage", "-c:a", "aac", "-strict", "experimental", "-b:a", "192k", "-pix_fmt", "yuv420p", "-shortest", "./File 1.mp4"]

for loops are probably the single most useful flow control statement in bash, but for this kind of thing I'd steer towards find and xargs, which both support separating arguments with the \0 character rather than something that might exist in pesky filenames, such as spaces, newlines, and so on.

Assuming all the flacs are in your home directory, then:

find . -type f -iname '*.flac' -print0 | \
xargs -0 -I % bash -c \
'ffmpeg -loop 1 -i AlbumCover.png -i "%" -c:v libx264 -tune stillimage -c:a aac -strict experimental -b:a 192k -pix_fmt yuv420p -shortest "$(echo "%" | sed s/\.flac$/.mp4/)"'

We're

$ find . -type f -iname '*.flac' -print0 | xargs -0 -I % bash -c 'ffmpeg -loop 1 -i AlbumCover.png -i "%" -c:v libx264 -tune stillimage -c:a aac -strict experimental -b:a 192k -pix_fmt yuv420p -shortest "$(echo "%" | sed s/\.flac$/.mp4/)"'
["-loop", "1", "-i", "AlbumCover.png", "-i", "./File 1.flac", "-c:v", "libx264", "-tune", "stillimage", "-c:a", "aac", "-strict", "experimental", "-b:a", "192k", "-pix_fmt", "yuv420p", "-shortest", "./File 1.mp4"]
["-loop", "1", "-i", "AlbumCover.png", "-i", "./File 10.flac", "-c:v", "libx264", "-tune", "stillimage", "-c:a", "aac", "-strict", "experimental", "-b:a", "192k", "-pix_fmt", "yuv420p", "-shortest", "./File 10.mp4"]
["-loop", "1", "-i", "AlbumCover.png", "-i", "./File 2.flac", "-c:v", "libx264", "-tune", "stillimage", "-c:a", "aac", "-strict", "experimental", "-b:a", "192k", "-pix_fmt", "yuv420p", "-shortest", "./File 2.mp4"]
...

In this case, the single quotes escape the entire command nicely. Bash is invoked because we need a subshell to run after xargs has done its replacement. And the combination of find's -print0 and xarg's -0 escapes every valid filename. I do, however, assume that the filename doesn't contain any quotes.

[1]

$ cat `which ffmpeg`
#!/usr/bin/ruby
puts ARGV.inspect
erik258
  • 14,701
  • 2
  • 25
  • 31