-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgifv.sh
175 lines (143 loc) · 4.39 KB
/
gifv.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env bash
# Set global variables
PROGNAME=$(basename "$0")
VERSION='1.1.2'
print_help() {
cat <<EOF
Usage: $PROGNAME [options] input-file
Version: $VERSION
Convert GIFs and videos into GIF-like videos
Options: (all optional)
-c CROP The x and y crops, from the top left of the image (e.g. 640:480)
-d DIRECTION Directon (normal, reverse, alternate) [default: normal]
-l LOOP Play the video N times [default: 1]
-o OUTPUT The basename of the file to be output. The default is the
basename of the input file.
-r FPS Output at this (frame)rate.
-s SPEED Output using this speed modifier. The default is 1 (equal speed).
-t DURATION Speed or slow video to a target duration
-O OPTIMIZE Change the compression level used (1-9), with 1 being the
fastest, with less compression, and 9 being the slowest, with
optimal compression. The default compression level is 6.
-p SCALE Rescale the output (e.g. 320:240)
-x Remove the original file
Example:
gifv -c 240:80 -o gifv.mp4 -x video.mov
EOF
exit $1
}
##
# Check for a dependency
#
# @param 1 Command to check
##
dependency() {
hash "$1" &>/dev/null || error "$1 must be installed"
}
##
# Join a list with a seperator
#
# @param 1 Seperator
# @param 2+ Items to join
##
join_by() { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
################################################################################
# Check dependencies
dependency ffmpeg
# Initialize variables
levels=(ultrafast superfast veryfast faster fast medium slow slower veryslow)
level=6
OPTERR=0
while getopts "c:d:l:o:p:r:s:t:O:xh" opt; do
case $opt in
c) crop=$OPTARG;;
d) direction_opt=$OPTARG;;
h) print_help 0;;
l) loop=$OPTARG;;
o) output=$OPTARG;;
p) scale=$OPTARG;;
r) fps=$OPTARG;;
s) speed=$OPTARG;;
t) target_duration=$OPTARG;;
O) level=$OPTARG;;
x) cleanup=1;;
*) print_help 1;;
esac
done
shift $(( OPTIND - 1 ))
# Store input filename
filename="$1"
# Print help, if no input file
[ -z "$filename" ] && print_help 1
# Automatically set output filename, if not defined
if [ -z "$output" ]; then
# Strip off extension and add new extension
ext="${filename##*.}"
path=$(dirname "$filename")
output="$path/$(basename "$filename" ".$ext").mp4"
fi
# Video filters (scale, crop, speed)
if [ $crop ]; then
crop="crop=${crop}:0:0"
fi
if [ $scale ]; then
scale="scale=${scale}"
fi
if [ $target_duration ]; then
source_duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$filename")
# Can also set audio speed using atempo
# atempo=(1/(${target_duration}/${source_duration}))
speed="setpts=(${target_duration}/${source_duration})*PTS"
elif [ $speed ]; then
speed="setpts=(1/${speed})*PTS"
fi
# Convert GIFs
# A fix for gifs that may not have a perfectly sized aspect ratio
if [ "$(file -b --mime-type "$filename")" == image/gif ]; then
giffix="scale='if(eq(mod(iw,2),0),iw,iw-1)':'if(eq(mod(ih,2),0),ih,ih-1)'"
fi
# Direction
if [ "$direction_opt" == "reverse" ]; then
direction="reverse"
elif [[ "$direction_opt" == "alternate" ]]; then
filter="trim=start_frame=1,reverse,trim=start_frame=1,setpts=PTS-STARTPTS[rev];[0][rev]concat"
fi
# Concatenate options into a filter string
# Note: giffix must be applied after any scaling/cropping
if [ $scale ] || [ $crop ] || [ $speed ] || [ $giffix ] || [ $direction ]; then
filter="$(join_by "[out];[out]" $filter $(join_by , $scale $crop $speed $giffix $direction))"
fi
# Prepare filter string opt
if [ $filter ]; then
filter="-filter_complex [0]${filter}[out] -map [out]"
fi
# FPS
if [ $fps ]; then
fps="-r $fps"
fi
# Loop
if [[ $loop -gt 1 ]]; then
loop_arg="-stream_loop $(( $loop - 1 ))"
fi
# Optimization level
# 1: Fastest, worst compression
# 9: Slowest, best compression
(( $level > 9 )) && level=9 # OR err
(( $level < 1 )) && level=1 # OR err
optimize="${levels[$((level-1))]}"
# TODO: Offer further optimizations
# Constant rate factor (for better optimizations): -crf 22
# Bit rate: -b:v 1000k
# Codecs:
# libvpx: webm
# libx264: h.264
codec="-c:v libx264"
# Verbosity
verbosity="-loglevel panic"
# Create optimized GIF-like video
ffmpeg $verbosity $loop_arg -i "$filename" $codec $filter $fps \
-an -pix_fmt yuv420p -preset "$optimize" -movflags faststart "$output"
# Cleanup
if [ $cleanup ]; then
rm "$filename"
fi