I wanted to just comment on an answer to a question very similar to this but I don't have enough rep. I'm looking for a way to change this line of code:
for i in *.mkv; do ffmpeg -i "$i" "${i%.*}.mp4"; done
So that it includes .avi files and so that it can search through nested folders. I want to be able to target /Videos and have the script automatically traverse through the folder tree into /Videos/2016/January, convert all of the video files contained within that folder, then do the same for /Videos/2016/February and so on.
Thanks in advance.
(credit for above line of code goes to LordNeckBeard, from this post.)
Using LordNeckBeard's reference to find, I came up with the following solution:
find ./ -iname '*.avi' -o -iname '*.mkv' -exec bash -c 'ffmpeg -i "{}" -c:v libx265 -preset medium -crf 28 -c:a aac "{}".mp4' \;
Tested and worked exactly how I expected, so it is currently running through the entire library.
If you want to give your converted files a different name to the original, see Parameter Expansion.
If you wish to destructively convert all files, be extremely careful with this command:
find ./ -iname '*.avi' -o -iname '*.mkv' -exec bash -c 'ffmpeg -i "{}" -c:v libx265 -preset medium -crf 28 -c:a aac "{}".mp4 && rm "{}"' \;
NOTE: The command above isn't bulletproof and was removing some files BEFORE the conversion process had finished, meaning I have now lost those files (thank God for backups). I tested with disposable files and have made sure I have a fully functional back up of my data before starting this procedure.
Related
I'm trying to batch convert thousands of wav files into 96k m4a files on Mac OS Mojave using ffmpeg in the terminal.
I'm trying to use the following code:
for f in *.wav; do ffmpeg -i "$f" -c:a libfdk_aac -b:a 96k “${f%.wav}.m4a”; done
I'm being given the following error:
Unable to find a suitable output format for '“file.m4a”'
“file.m4a”: Invalid argument
Can anyone help?
Smartquotes are treated as part of the filename.
Use plain quotes instead:
for f in *.wav; do ffmpeg -i "$f" -c:a libfdk_aac -b:a 96k "${f%.wav}.m4a"; done
If you have lots of files to convert, you might want to do that in parallel:
find . -name '*. wav' -type f -print0 | parallel -0 ffmpeg -i {} -c:a libfdk_aac -b:a 96k {.}.m4a
Check this doc for how to work with parallel. If you don't have the tool, install it with brew install parallel.
Scott's answer is perfectly fine too. I like parallel as it also allows me to easily e.g. modify the name of the output file.
Hi I've got a script that i want to scan all sub directories 1/2/3/4/ etc deep but when i've placed an mkv sample file here for example;
/home/storage/movies/folder1/folder2/folder3/sample.mkv
but it doesnt find the .mkv
and it get the error
**/*.mkv: No such file or directory
shopt -s globstar
while true; do
for f in **/*.mkv; do
ffmpeg -i "$f" -c:v libx264 -preset ultrafast -minrate 4.5M -maxrate 4.5M -bufsize 9M -c:a ac3 "${f%mkv}mp4";
rm "$f";
done
sleep 60
done
Can anyone see what is wrong or have any other suggestions
Daniel, it has been 2 months, and I hope you found the solution. If you did not you may try this as quick workaround,
for f in `find . -name *.mkv`; do
You can have a look find's exec option as well
I have a code that using ffmpeg to conver *.avi to *.mp4 on all files in the folder. I want it to run on all folders and sub folders; and to save the result in this subfolder.
I tried already with find but no success
#!/bin/bash
for i in *.avi;
do
ffmpeg -i /location/"$i" -c:v libx264 -preset ultrafast \
-strict -2 -n /location/"$(basename "$i" .avi)".mp4
done
You can use find to find matching files in all sub-directories:
find <top-dir> -iname "*.avi" | while read filename; do ffmpeg -i "$filename" ... "${filename%avi}mp4"; done
Replace ... with your ffmpeg options.
You can also use GNU parallel utility to parallelize processing of found files over multiple CPUs:
find <top-dir> -iname "*.avi" | parallel -i -- ffmpeg -i "{}" ... "{.}.mp4"
I have hundreds of folders containing video, audio, images.. which I need to create video thumbs foreach 10 seconds of video of every video file found (mp4/avi/mov/3gp) and placed in one location /thumbs/.
I have this, which I've been trying to figure out for days.
find . -exec ffmpeg -i {} -vf fps=1/8 {}.png \;
or
find /Users/media/Desktop/videoframes/input/ -regex ".*\.\(mp4\)" -print0 | while read -d $'\0' file; do ffmpeg -i $file -vf fps=1/8 ${file}%d.png done
I know little about the syntax but want to learn more but Im stumped.
Thanks!
I am trying to convert a directory full of mp3's (with spaces in file names) to m4a.
To convert a single file (this works):
ffmpeg -i Traffic.mp3 -c:a libfaac -vn Traffic.m4a
The command that is failing (on OS X Mavericks):
find . -name \*.mp3 -print0 | xargs -0 ffmpeg -i {} -c:a libfaac -vn {}.m4a
find . -name '*.mp3' -type f -exec bash -c 'ffmpeg -i "$0" -c:a libfaac -vn "${0%.mp3}.m4a"' {} \;
Why do you use xargs? find -exec is enough:
find . -name \*.mp3 -exec ffmpeg -i {} -c:a libfaac -vn {}.m4a \;
The problem is that xargs is more similar to find -exec … + than find -exec … \;. It launches preferably just one instance of the command, replacing a single {} by sequence of space separated items read from input (more or less). If you want xargs to behave like find -exec … \;, you need to specify -I{} (xargs -0 -I{} ffmpeg …).
This converts Traffic.mp3 to Traffic.mp3.m4a. If you want to save the conversion result to Traffic.m4a, you can
rename the files after the conversion (not a very clean solution),
execute shell in the -exec action and remove the .mp3 before appending .m4a or
use xargs after sedding the .mp3 extension away from find result.
I vote for the last option as it executes less processes (and shell is quite a big one, though ffmpeg would be difinitely so large that the difference in performance is negligible).
find . -name \*.mp3 | sed 's/\.mp3$//' | xargs -I{} ffmpeg -i {}.mp3 -c:a libfaac -vn {}.m4a