|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# requires ffmpeg, ffprobe, imagemagick's convert and vidstab python module , python3 |
| 4 | + |
| 5 | +# print usage if no params |
| 6 | +if [ -z $1 ]; then |
| 7 | + echo "usage: $0 -f <video file> -F <convert evaluate filter > -r <factor to reduce fps captures> -s <start mm:sec.fraction> -S <stabilize video first 0/1>" |
| 8 | + echo "for a list of all convert filters, run convert -list evaluate " |
| 9 | + exit |
| 10 | +fi |
| 11 | +# do the base software checks, only check python and vidstab if using -S |
| 12 | +for i in ffmpeg ffprobe convert; do |
| 13 | + which $i 2>&1 > /dev/null |
| 14 | + if [ "$?" != "0" ]; then |
| 15 | + echo "Required program $i not found, exiting"; |
| 16 | + exit; |
| 17 | + fi |
| 18 | +done |
| 19 | + |
| 20 | +until [[ -z $1 ]]; do |
| 21 | + case $1 in |
| 22 | + -f) filename="$2"; shift ;; # quote this in case video contains spaces |
| 23 | + -F) filter=$2; shift ;; |
| 24 | + -r) reduce_factor=$2; shift ;; |
| 25 | + -s) start_time=$2; shift ;; |
| 26 | + -S) stabilize=$2; shift ;; |
| 27 | + esac |
| 28 | + shift |
| 29 | +done |
| 30 | + |
| 31 | +# need to check the basic requires params of $filename and $filter are all there |
| 32 | + |
| 33 | +newvid=new.mp4 |
| 34 | +if [ -z $stabilize ] || [ $stabilize == 0 ]; then |
| 35 | + echo "skipping stabilizing video" |
| 36 | + # just copy $filename to $newvid |
| 37 | + cp "$filename" $newvid |
| 38 | +else |
| 39 | + which python3 2>&1 > /dev/null |
| 40 | + if [ "$?" != "0" ]; then |
| 41 | + echo "video stabilization requires python3 not found, exiting"; |
| 42 | + exit; |
| 43 | + fi |
| 44 | + pip3 show vidstab 2>&1 > /dev/null |
| 45 | + if [ "$?" != "0" ]; then |
| 46 | + echo "video stabilization requires pip3 vidstab not found, exiting"; |
| 47 | + exit; |
| 48 | + fi |
| 49 | + echo "stabilizing video" |
| 50 | + # first pass $filename through vidstab to stabilize it - use the $newvid from here out to leave the source video the same |
| 51 | + python3 -m vidstab -i "$filename" -o $newvid |
| 52 | +fi |
| 53 | + |
| 54 | +TMPDIR="tmp_$$" |
| 55 | + |
| 56 | +if [ -e $TMPDIR ]; then |
| 57 | + rm -rf $TMPDIR |
| 58 | + mkdir $TMPDIR |
| 59 | +else |
| 60 | + mkdir $TMPDIR |
| 61 | +fi |
| 62 | + |
| 63 | +# use ffprobe to determine length and fps from these 2 output lines |
| 64 | +# Duration: 00:00:21.77, start: 0.000000, bitrate: 25404 kb/s |
| 65 | +# Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 2400x1080, 25151 kb/s, SAR 1:1 DAR 20:9, 30 fps, 30 tbr, 90k tbn, 180k tbc (default) |
| 66 | + |
| 67 | +ffprobe "$newvid" > $TMPDIR/ff_output 2>&1 |
| 68 | +duration_string=$(grep Duration: $TMPDIR/ff_output); |
| 69 | +fps_string=$(grep Stream $TMPDIR/ff_output); |
| 70 | + |
| 71 | +# probably won't have a hour or minute long video for this, so we just strip out the last digits |
| 72 | +duration=$(echo $duration_string| sed 's/.*Duration.*[0-9][0-9]:[0-9][0-9]:\([0-9][0-9]\.[0-9][0-9]\),.*/\1/'); |
| 73 | +fps=$(echo $fps_string |sed 's/.*\([0-9][0-9]\) fps.*/\1/'); |
| 74 | + |
| 75 | +# optional $reduce_factor - to decrease the number of slices - e.g. for 30 fps and 2 $reduce_factor, will capture 15 slices per second |
| 76 | +if [ ! -z $reduce_factor ]; then |
| 77 | + images_per_sec=$(echo "$fps / $reduce_factor" | bc); |
| 78 | + else |
| 79 | + images_per_sec=$fps |
| 80 | +fi |
| 81 | + |
| 82 | +# optional -s option to start slicing at a certain point in the video - e.g. instable video for the first 10 seconds, pass 11 to start slicing at 11 seconds in. |
| 83 | +if [ -z $start_time ]; then |
| 84 | + start_time="-ss 0" |
| 85 | +else |
| 86 | + start_time="-ss $start_time" |
| 87 | +fi |
| 88 | + |
| 89 | +frames=$(echo "scale=2;$duration * $images_per_sec" | bc); |
| 90 | +echo "Video is $duration seconds long at $fps fps - - will capture $images_per_sec images per second - which should generate $frames images - start at $start_time" |
| 91 | +# note that the -r $fps option placement is important. If places BEFORE the -i it affects the input file rate |
| 92 | +ffmpeg $start_time -loglevel quiet -stats -hide_banner -i "$newvid" -q:v 1 -r $images_per_sec $TMPDIR/slice_%04d.png |
| 93 | + |
| 94 | +# cd into $TMPDIR so all the output is generated in the $TMPDIR |
| 95 | +cd $TMPDIR |
| 96 | + |
| 97 | +newname="${filename%.*}_stacked.png" |
| 98 | +#nice convert -monitor -flatten slice* -evaluate-sequence $i output_$i.png |
| 99 | +time convert slice* -evaluate-sequence $filter ../$newname |
| 100 | +exit; |
| 101 | +if [ "$?" == "0" ]; then |
| 102 | + cd .. |
| 103 | + rm -r $TMPDIR |
| 104 | + rm $newvid |
| 105 | +fi |
| 106 | +ls -la $newname |
0 commit comments