I wrote a small bash file that reads a folder, generates a playlist, concatenates, adds a logo and encode the big video result for dash ready, i would like to implement it by checking before all videos conformance: if they have same fps, same resolution, same time base etc. Below my situation:
#!/bin/bash
# CONCAT DEMUXER
#This demuxer reads a list of #files and other directives from a text file and demuxes them one after the other, as if #all their packets had been muxed together. All files must have the same streams (same #codecs, same time base, etc.) but can be wrapped in different container formats.
times=()
for f in *.mp4; do
_t=$(ffmpeg -i "$f" 2>&1 | grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
times+=("$_t")
done
TOTALDURATION=$( echo "${times[@]}" | sed 's/ /+/g' | bc )
printf "file '%s'\n" *.mp4 > playlist.txt
ffmpeg -auto_convert 1 -f concat -safe 0 -i playlist.txt -c:a aac -b:a 384k -ar 48000 -ac 2 -async 1 -c:v libx264 -x264opts 'keyint=50:min-keyint=50:no-scenecut' -r 25 -b:v 2400k -maxrate 2400k -bufsize 1200k -vf "scale=-1:432" -vf "movie=stable.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:10 [out]" -t $TOTALDURATION out.mp4
#clear
echo “VIDEO CONCAT COMPLETED”
For example below i find this bash that calculate the total duration in second of the videos of the folder
times=()
for f in *.mp4; do
_t=$(ffmpeg -i "$f" 2>&1 | grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
times+=("$_t")
done
TOTALDURATION=$( echo "${times[@]}" | sed 's/ /+/g' | bc )
I wish to check if the videos have the same fps, and same resolution before process Thanks Massimo
Someone posted in this question an example to get the duration of a video: ffmpeg how do I get the duration onto the node.js?
His approach is:
ffmpeg -i input.mp4 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//
In my opinion you should use ffprobe instead of ffmpeg. Much better syntax:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
Good examples can be found here: https://trac.ffmpeg.org/wiki/FFprobeTips
You can save the result of the first video in a variable and compare all other videos with the first one. Can give you more examples if needed.
But I can recommend another way: nodejs
If you are familiar with JavaScript, just write a NodeJS script. Code is easier to write in my opinion.
You need to install NodeJS. In your project install fluent-ffmpeg with npm install --save fluent-ffmpeg
.
https://github.com/fluent-ffmpeg/node-fluent-ffmpeg
Write your script in a js-file of your choice and run your script from your bash script with node script.js
.
The snippet to find the needed information from your video files can look like this:
var ffmpeg = require('fluent-ffmpeg');
ffmpeg.ffprobe('./input.mp4', function(err, metadata) {
//console.dir(metadata); // all metadata
console.log(metadata.format.duration);
console.log(metadata.streams[0].width);
console.log(metadata.streams[0].height);
console.log(metadata.streams[0].r_frame_rate);
console.log(metadata.streams[0].time_base);
//... use first console.dir to get all possible informations
});
Here a complete example to convert all mp4 videos in a directory to an output directory and concatenate them after:
#!/bin/bash
SCALE="768:432"
FPS="25"
mkdir -p ./output/
for i in *.mp4;
do name=`echo $i | cut -d'.' -f1`;
echo $name;
ffmpeg -i "$i" -c:v libx264 -preset slow -crf 22 -vf scale=$SCALE -framerate $FPS -c:a aac -b:a 128k -f mp4 "output/${name}.mp4";
done
printf "file '%s'\n" ./output/*.mp4 > ./playlist.txt
ffmpeg -f concat -safe 0 -i ./playlist.txt -c copy ./output/concat.mp4