GNU make rule for multiple input files? - makefile

I have a GNU make variable with multiple audio files in it:
FILEWAV += $(wildcard $(DIRIN)/*.wav)
I need to transform wavs into f32 files using SoX:
sox -channels 1 --rate 48000 $(FILEWAV) --type raw $(FILEWAV:.wav=.f32)
How would I write a makefile target to transform all files one by one?

This works:
%.f32: %.wav
sox --channels 1 --encoding signed-integer --rate 48000 $< --type raw $#
run: $(MY_FILES_F32) $(MY_OTHER_FILES_F32)

Related

How to create random pass names in ffmpeg?

Normally, when using ffmpeg, you define a name for the "pass" information to be stored in a file when enconding videos with 2 (or more) passes, e.g.:
ffmpeg -i "INPUT_FILE" -pass 1 -passlogfile videopass.log /dev/null -y && ffmpeg -i "INPUT_FILE" -pass 2 -passlogfile videopass.log -y "OUTPUT_FILE"
I'd love to be able to create a random pass name automatically in bash in the simplest way possible, preferably a "one-liner" using the system's default tools (Linux)... something like:
$(tr -dc A-Za-z0-9 </dev/urandom | head -c 8).log | ffmpeg -i "INPUT_FILE" -pass 1 -passlogfile > /dev/null -y && ffmpeg -i "INPUT_FILE" -pass 2 -passlogfile > -y "OUTPUT_FILE"
I'm too stupid to figure out a way of doing something similar that actually makes sense.
Thank you very much in advance!
Assuming the requirement is to create a random name for the password file:
$ pwdlog=$(mktemp XXXXXXXX.log) # have mktemp create a file with 8 random characters + ".log"
$ typeset -p pwdlog
declare -- pwdlog="Em6GeMdc.log"
$ ls -l "${pwdlog}"
-rw-------+ 1 username None 0 Apr 26 15:13 Em6GeMdc.log
This file could then be referenced in the ffmpeg call like such:
ffmpeg -i "INPUT_FILE" -pass 1 -passlogfile "${pwdlog}" ...
After countless tries and googling, I found a way to do exactly what I was looking for... A one-liner, nothing too complicated or fancy and using my system's default tools:
printf $RANDOM | xargs -i sh -c 'ffmpeg -i "INPUT_VIDEO" -pass 1 -passlogfile {} -an -f mp4 /dev/null -y && ffmpeg -i "INPUT_VIDEO" -pass 2 -passlogfile {} -y "OUTPUT_VIDEO"'
This will create a very simple 5-digit random number, which will be used as the initial name for the pass files in ffmpeg, ffmpeg automatically adds the file extension(s). Of course, you can (and probably should) add video/audio parameters to your ffmpeg commands. The important elements are the "printf $RANDOM | xargs -i sh -c" at the begining and the "{}" curly brackets after the "-passlogfile" command.
There are probably even simpler or more elegant ways of doing it, but this works exactly as I wanted, so I'm happy.

Bash loop over files in directory outputting non existent files

I am making mp4 files from a series of images. The images should run about 1 hour but I cannot get a full video because FFMPEG looks for a file it should not have.
[image2 # 0x55fe14bef700] Could not open file : /mnt/run/image-005437.jpeg
What is confusing is that the list that I pass to ffmpeg should not include that file. If my script does not like the result it sends the file to a sub directory in the target folder called failed
the location of the file with that number
$ pwd
run/failed
]$ ls
failed-005437.jpeg
the command I use to launch ffmpeg is the following
image_folder=$1
singularity exec --bind $work_dir:/mnt $work_dir/longleaf2.sif ffmpeg -f concat -safe 0 -y -i <(for f in /mnt/processed_images/$image_folder/image-%06d.jpeg; do echo "file '$f'";done) -vf "crop=trunc(iw/3)*2:trunc(ih/2)*2" -movflags +faststart /mnt/run/summary_files/${image_folder}.mp4
I have checked processed images and it is not there so why is ffmpeg looking for it?
pastebin of the failed run
https://pastebin.com/pF5ZefLf
My check that the file is not in the folder reference by the for loop so that it should never cause an error
$ ls image-005437.*
ls: cannot access image-005437.*: No such file or directory
Problem
When you run:
for f in /mnt/processed_images/$image_folder/image-%06d.jpeg; do echo "file '$f'";done
It will output:
file '/mnt/processed_images/foo/image-%06d.jpeg'
So then ffmpeg will use the sequence pattern type for the image demuxer. This expects a contiguous sequence.
Solution 1: Glob
Use a glob:
for f in /mnt/processed_images/$image_folder/*.jpeg; do echo "file '$f'";done
Now it will output each file. In this example image-000003.jpeg does not exist so it does not get listed:
file '/mnt/processed_images/foo/image-000001.jpeg'
file '/mnt/processed_images/foo/image-000002.jpeg'
file '/mnt/processed_images/foo/image-000004.jpeg'
Solution 2: Simplify and skip concat
Even better is to simplify your command by using the glob pattern type for the image demuxer within ffmpeg itself, and then you can avoid the concat demuxer:
image_folder=$1
singularity exec --bind "$work_dir":/mnt "$work_dir"/longleaf2.sif ffmpeg -pattern_type glob -framerate 25 -i "/mnt/processed_images/$image_folder/*.jpeg" -vf "crop=trunc(iw/3)*2:trunc(ih/2)*2,format=yuv420p" -movflags +faststart /mnt/run/summary_files/${image_folder}.mp4
The image demuxer glob pattern is not available for Windows users.
Added the -framerate input option for the image demuxer.
Added the format filter to make YUV 4:2:0 chroma subsampling for compatibility.
The variables have been quoted. See shellcheck.net.
FFmpeg 4.1 release branch is old. Download or compile a modern version before doing anything else.

How to use Sox for all files in a directory

How do I change the sample rate for every file in the folder?
The following code converts the files, but it erases the file. After this command, every wav file is empty.
for i in wav/*.wav; do
sox -r 8000 -e unsigned -b 16 -c 1 "$i" "$i"
done
How do I run the code to every file in the directory?
Something like:
for i in wav/*.wav; do
sox -r 8000 -e unsigned -b 16 -c 1 "$i" "$i_modified"
done

GUID appended for FFMPEG output file name

Is it possible to append a GUID to the output file?
I am running:
ffmpeg -i .\Tst.mp4 -filter:v "select='gt(scene,0.5)',showinfo" -vsync 0 -s 120x68 keyframe%05d.jpg
Which produces a series of files. I need to append a GUID to every file name.
I don't believe it is possible with ffmpeg. However, you can use the MD5 muxer on the existing JPG files to provide 128-bit psuedo-UUID:
ffmpeg -v error -i "$f" -f hash -f md5 -
Result:
MD5=aa8f01566a88feb762337de3cc81f36
Bash example:
for f in *.jpg; do hash="$(ffmpeg -v error -i "$f" -f hash -f md5 -)"; mv "$f" "${f%.*}_${hash:5}.jpg"; done
Result:
keyframe_00001_aa8f01566a88feb762337de3cc81f36.jpg
keyframe_00002_49cbb3ea81acfd57edda9955b3f8ed6.jpg
keyframe_00003_31711067199dafd28a6504ec4a22e05.jpg
Not a true UUID but fine if you just need a unique identifier.

How do I generate the .ism and .ismc with FFmpeg

I'm trying to set up a service that will output .ismv files for smooth streaming.
Currently I'm using the following command to start the transcode:
ffmpeg.exe -i <infile> -movflags frag_keyframe -f ismv <outfile>
As I understand it I don't need to add isml to the movflags because I don't want to stream it but the actual output file.
According to the documentation I already should use the empty_moov and separate_moof flags because I'm using the ismv format. This however does not generate the .ism and .ismc file.
There is a part about smoothstreaming, but if I use -f smoothstreaming ffmpeg won't run.
I did find a win32 binary for ismindex which should generate the manifest files, but when I run it I don't get any useful output.
What are the correct parameters for ffmpeg so that it creates all the files at the same time?
ismindex [-split] [-ismf] [-n basename] [-path-prefix prefix] [-ismc-prefix prefix] [-output dir] file1 [file2] ...
To generate the manifest files you would do:
ismindex -n <basename> input.ismv
The smoothstreaming muxer accepts a directory as output.
ffmpeg [...] -f smoothstreaming <dir>

Resources