Search code examples
bashvideoffmpegmpeg-dash

ffmpeg: check video folder conformance with bash file


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


Solution

  • Bash

    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

    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
    });
    

    UPDATE BASH

    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
    
    • width, height and framerate are set to a defined value to make concatenation possible
    • preset for video encode is slow, so reencode is really slow ;)
    • audio bitrate can be increased if necessary, for example to 192k