GUID appended for FFMPEG output file name - ffmpeg

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.

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 variable changes in loop with ffmpeg

I wrote a skript to quickly create short preview clips from vides I recorded on timestamps that I found worth checking out later for cutting.
My file with the timestamps is written like this
FILE_NAME1#MM:SS MM:SS
FILE_NAME2#MM:SS MM:SS MM:SS MM:SS
example:
MAH01728#02:47 03:34 03:44 05:00 06:08 06:55
The script looks like this:
#!/bin/bash
while read f
do
file=$(echo $f | cut -d"#" -f1)
filename=${file}".MP4"
timestamps=$(echo $f | cut -d"#" -f2)
for time in $timestamps
do
ffmpeg -ss 00:${time}.0 -i "orig/${filename}" -c copy -t 10 "preview/${file}_${time}.MP4"
done
done < $1
The script gets half of the previews that I want and on the other the filename is messed up and ffmpeg complains that the file is not found:
orig/714.MP4: No such file or directory
orig/00:58 01:25.MP4: No such file or directory
So I modified the script for trouble shooting and just put an echo in front of the ffmpeg command - now all file names are correct. What am I missing?
ffmpeg -ss 00:01:47.0 -i orig/MAH01714.MP4 -c copy -t 10 preview/MAH01714_01:47.MP4
ffmpeg -ss 00:02:00.0 -i orig/MAH01713.MP4 -c copy -t 10 preview/MAH01713_02:00.MP4
ffmpeg -ss 00:00:58.0 -i orig/MAH01712.MP4 -c copy -t 10 preview/MAH01712_00:58.MP4
ffmpeg -ss 00:01:25.0 -i orig/MAH01712.MP4 -c copy -t 10 preview/MAH01712_01:25.MP4
ffmpeg reads from standard input, consuming data from $1 that was intended for the read command at the top of the loop. Redirect its standard input from /dev/null:
while IFS="#" read file timestamps; do
filename="$file.MP4"
for time in $timestamps; do
ffmpeg -ss 00:${time}.0 -i "orig/${filename}" \
-c copy -t 10 "preview/${file}_${time}.MP4" < /dev/null
done
done < "$1"
echo does not read from standard input, which is why your modification made it appear to be working correctly.

FFMPEG Batch convert, then create folder

Using this code is it possible for it run this code then create a folder with file name if folder already exits move same name to same folder?
for i in *.mkv;
do name=`echo "${i%.*}.mkv"`;
ass="ass='$name'.ass";
echo "$ass"; ffmpeg -i "$i" -vf "$ass" anime2/"${i%.mkv}.mp4";
done
You can just use mkdir -p and avoid having to use if/then:
for i in *.mkv; do mkdir -p "${i%.*}" && ffmpeg -i "$i" -vf ass="${i%.*}.ass" "${i%.*}/${i%.*}.mp4"; done

Bash loop thru files not working as expected

Why is my code below not working as expected?
shopt -s extglob || {
echo "Unable to enable exglob."
exit 1
}
TARGETEXT='.jpg'
TARGETPREFIX='./' ## Make sure it ends with /.
while IFS= read -r FILE; do
BASE=${FILE##*/}
NOEXT=${BASE%.*}
TARGETFILEPATH=${TARGETPREFIX}${NOEXT}${TARGETEXT}
duration=$(ffprobe -i "$FILE" -show_format -v quiet | sed -n 's/duration=//p'| sed 's/\.[^\.]*$//')
space=$(awk '{print $1/$2}' <<<"$duration 5")
echo ffmpeg -ss "$space" -i "$FILE" -vf "select='isnan(prev_selected_t)+gte(t-prev_selected_t,"$space")',sca
le='if(gt(a,4/3),206,-1):if(gt(a,4/3),-1,154)',pad=w=206:h=155:x=(ow-iw)/2:y=(oh-ih)/2:color=black,tile=4x1" -aspect
4:3 -frames:v 1 -vsync vfr "$TARGETFILEPATH" -y
done < <(exec find -type f -name '*.mp4')
I have 2 mp4 files in the directory. If I run this code it work fine with 'echo' in front of the ffmpeg command. It'll output 2 lines of ffmpeg, one line for each file. Filenames are correct and all looks perfect.
When I run the same, removing 'echo', the first ffmpeg command will run successfully and my script will give an error for the 2nd file name. I can see in the ffmpeg output that there is one character missing at the beginning of the filename(should be uscenes.mp4).
scenes.mp4: No such file or directory
I've started over with a for loop and without find. All working now!
IEXT='.jpg'
for fname in ./*.mp4; do
[ -e "$fname" ] || continue
NOEXT=${fname::-4}
OUPUT=${NOEXT}${IEXT}
duration=$(ffprobe -i "$fname" -show_format -v quiet | sed -n 's/duration=//p'| sed 's/\.[^\.]*$//')
space=$(awk '{print $1/$2}' <<<"$duration 5")
ffmpeg -ss "$space" -i "$fname" -vf "select='isnan(prev_selected_t)+gte(t-prev_selected_t,"$space")',scale='
if(gt(a,4/3),206,-1):if(gt(a,4/3),-1,154)',pad=w=206:h=155:x=(ow-iw)/2:y=(oh-ih)/2:color=black,tile=4x1" -aspect 4:3
-frames:v 1 -vsync vfr "$OUPUT" -y
done

ffmpeg with shell: oncat listed movies

I'm new to shell script, trying to concat listed movies in a folder like:
filename="list.txt"
cat ${filename} | while read line;
do
ffmpeg -y -i sum.mov -i $line -filter_complex concat tmp.mov
cp tmp.mov sum.mov
done
However, this loop runs only one time.
What is the best practice?
Thanks
SOLVED:
#list.txt
file 'movie1.mov'
file 'movie2.mov'
file 'movie3.mov'
Don't need to write a shell script. Just
ffmpeg -f concat -i list.txt -c copy output.mov

Resources