2

currently, I run this command...

# Script designed to convert webm files to m4a for easy listening

for i in *.m4a ; do
    echo ffmpeg -i "\""$PWD/$i"\"" -c:a copy "\""$PWD/${i%.m4a}.mkv"\"" >> ~/bulk.command.txt
done

to create myself a script file that I can later run to do batch repackages of media files. Sadly this process requires me to enter each directory that needs to be repackaged and have me type the scripts name.

Sometimes these projects have quite a few directories as well as subdirectories. Also these projects when getting big, are requiring me to really be careful on the size of the projects root dir.

I am still learning how to code in bash, and this simple script took me quite some time to perfect to make sure just about every possible file name is accounted for.

What I would like to do next is modify it in such as way as I can simply go into my home folders music folder, run this command a single time AND also have it save the directory layout, but also place the files ffmpeg creates into a different directory. Do any wizards out there have some code examples, or terms, or ideas how I can accomplish this task?

3
  • Just bash? python is doing a nice job on this. Apr 5, 2017 at 6:16
  • Consider adding -map 0 if you want to stream copy all streams from the input; otherwise the ffmpeg default stream selection behavior will choose only one stream per stream type. For example, if there are two audio streams it will by default only copy one. Although, it is unlikely that M4A has more than one stream per type.
    – llogan
    Apr 5, 2017 at 18:57
  • I am not opposed to using another language to do this, I just don't know python, and learning new skills for me is difficult because of a disability...
    – Monery
    Apr 7, 2017 at 0:34

2 Answers 2

4

Enable recursive globbing to recurse into subdirectories:

shopt -s globstar

Then you could do:

for f in **/*.m4a
do
    printf 'ffmpeg -i %q -c:a copy %q\n' "$PWD/$f" "$PWD/${f%.m4a}.mkv"
done > bulk.command.txt

printf's %q quotes strings so that they can be safely used as shell input, so you don't have to mess with quotes there:

  %q    quote the argument in a way that can be reused as shell input

If you make this a script, then you can use arguments to decide whether to use a different directory for the output files:

#! /bin/bash
shopt -s globstar

for f in **/*.m4a
do
    printf 'ffmpeg -i %q -c:a copy %q\n' "$PWD/$f" "${1:-$PWD}/${f%.m4a}.mkv"
done > bulk.command.txt

${foo:-bar} uses the the value of variable foo, if it is not empty, or bar otherwise, so in this case it uses the first argument if not empty and $PWD otherwise.

You'll need to recreate the directory structure in that case, which can be done with mkdir -p:

#! /bin/bash
shopt -s globstar

for f in **/*.m4a
do
    printf 'mkdir -p %q\n' "${1:-$PWD}/${f%/*}"
    printf 'ffmpeg -i %q -c:a copy %q\n' "$PWD/$f" "${1:-$PWD}/${f%.m4a}.mkv"
done > bulk.command.txt

That's if you really need to create a script for later usage. Personally, I don't see the point - you could just run the loop directly when you actually need to run it:

#! /bin/bash
shopt -s globstar

for f in **/*.m4a
do
    mkdir -p "${1:-$PWD}/${f%/*}"
    ffmpeg -i "$PWD/$f" -c:a copy "${1:-$PWD}/${f%.m4a}.mkv"
done > bulk.command.txt
1
  • thanks for the wonderful feedback, I will try to read it again later when my mind wishes to cooperate with learning and reading. I'll let ya know if this does what I am looking to accomplish
    – Monery
    Apr 7, 2017 at 0:48
0

This is less generic and specifically targeted to those who are looking to mix HW acceleration with other filters and needing a similar setup to those outlined above.

From a given directory that contains a 4k folder, containing all the media that we want to convert, this script will find all relevant content, transcode, tone-map and scale them down to 1920whatever the original aspect ratio was, re-encode as a 20Mb/s HEVC file, convert the first embedded audio track to stereo and output each file to it's own sub directory below the 2k folder- this makes it easier to separate out native 2k content (for web content this tends to be 19201080). In addition, this uses the VAAPI interface which is hardware agnostic- so as long as the hardware supports HEVC, this will work.

For the sake of organization this also maintains the original directory structure as found in your 4k folder.

In the case where you do not maintain a 2k library, this will create an identical repository and create the needed folders to make it easy for Plex style library creation.

The previous answers were quite good for getting 95% of the way through, tho it did take a while to get everything working properly. for the sake of search engine indexing, here's what my final command ended up being:

for f in 4k/**/.mkv; do mkdir -p ./2k/transcodes/output/"${f%/}"; ffmpeg -hide_banner -loglevel warning -hwaccel 'vaapi' -hwaccel_output_format vaapi -i "$PWD/$f" -vf "scale_vaapi=w=1920:h=-1,hwdownload,format=p010le,zscale=transfer=linear,tonemap=clip,zscale=transfer=bt709,format=yuv420p,format=nv12,hwupload" -ac '2' -c:v 'hevc_vaapi' -b:v '20M' -ss 10 -t 20 ./2k/transcodes/output/"${f%}".mp4 ; done

for f in 4k/**/*.mkv; do mkdir -p ./2k/transcodes/output/"${f%/*}"; ffmpeg  -hide_banner -loglevel warning -hwaccel 'vaapi' -hwaccel_output_format vaapi -i "$PWD/$f"  -vf "scale_vaapi=w=1920:h=-1,hwdownload,format=p010le,zscale=transfer=linear,tonemap=clip,zscale=transfer=bt709,format=yuv420p,format=nv12,hwupload" -ac '2' -c:v 'hevc_vaapi' -b:v '20M' -ss 10 -t 20 ./2k/transcodes/output/"${f%}".mp4 ; done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .