forked from NapoleonWils0n/ffmpeg-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtile-thumbnails
executable file
·136 lines (118 loc) · 4.05 KB
/
tile-thumbnails
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
#!/bin/sh
# tile thumbnails from a video
# script usage
usage()
{
echo "\
# tile thumbnails from a video into an image
$(basename "$0") -i infile.(mp4|mkv|mov|m4v|webm) -s 00:00:00.000 -w 000 -t 0x0 -p 00 -m 00 -c color -o outfile.png
-i infile.(mp4|mkv|mov|m4v|webm)
-s seek into the video file : default 00:00:05
-w thumbnail width : 160
-t tile layout format width x height : 4x3 : default 4x3
-p padding between images : default 7
-m margin : default 2
-c color = https://ffmpeg.org/ffmpeg-utils.html#color-syntax : default black
-o outfile.png :optional agument
# if option not provided defaults to infile-name-tile-date-time.png"
exit 2
}
# error messages
NOTFILE_ERR='not a file'
INVALID_OPT_ERR='Invalid option:'
REQ_ARG_ERR='requires an argument'
WRONG_ARGS_ERR='wrong number of arguments passed to script'
NOT_MEDIA_FILE_ERR='is not a media file'
# if script is run arguments pass and check the options with getopts,
# else display script usage and exit
[ $# -gt 0 ] || usage "${WRONG_ARGS_ERR}"
# timecode - match 00:00:00
timecode='^[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}([.]\{1\}[0-9]\{1,3\})?$'
scale_regex='^[0-9]\{3\}$'
tile_regex='^[0-9]\{1,2\}[x]\{1\}[0-9]\{1,2\}$'
padding_regex='^[0-9]\{1,2\}$'
margin_regex='^[0-9]\{1,2\}$'
# getopts check and validate options
while getopts ':i:s:w:t:p:m:c:o:h' opt
do
case ${opt} in
i) infile="${OPTARG}"
[ -f "${infile}" ] || usage "${infile} ${NOTFILE_ERR}";;
s) seek="${OPTARG}"
expr "${seek}" : "${timecode}" 1>/dev/null;;
w) scale="${OPTARG}"
expr "${scale}" : "${scale_regex}" 1>/dev/null || usage;;
t) tile="${OPTARG}"
expr "${tile}" : "${tile_regex}" 1>/dev/null || usage;;
p) padding="${OPTARG}"
expr "${padding}" : "${padding_regex}" 1>/dev/null || usage;;
m) margin="${OPTARG}"
expr "${margin}" : "${margin_regex}" 1>/dev/null || usage;;
c) color="${OPTARG}";;
o) outfile="${OPTARG}";;
h) usage;;
\?) usage "${INVALID_OPT_ERR} ${OPTARG}" 1>&2;;
:) usage "${INVALID_OPT_ERR} ${OPTARG} ${REQ_ARG_ERR}" 1>&2;;
esac
done
shift $((OPTIND-1))
# infile, infile name
infile_nopath="${infile##*/}"
infile_name="${infile_nopath%.*}"
# file command check input file mime type
filetype="$(file --mime-type -b "${infile}")"
# audio and video mimetypes
mov_mime='video/quicktime'
mkv_mime='video/x-matroska'
mp4_mime='video/mp4'
m4v_mime='video/x-m4v'
webm_mime='video/webm'
avi_mime='video/x-msvideo'
# ffprobe get fps and duration
videostats=$(ffprobe \
-v error \
-select_streams v:0 \
-show_entries stream=r_frame_rate:format=duration \
-of default=noprint_wrappers=1 \
"${infile}")
# fps
fps=$(echo "${videostats}" | awk -F'[=//]' '/r_frame_rate/{print $2}')
# duration
duration=$(echo "${videostats}" | awk -F'[=/.]' '/duration/{print $2}')
# check if tile is null
if [ -z "${tile}" ]; then
: # tile variable not set : = pass
else
# tile variable set
# tile layout
tile_w=$(echo "${tile}" | awk -F'x' '{print $1}')
tile_h=$(echo "${tile}" | awk -F'x' '{print $2}')
# title sum
tile_sum=$(echo "${tile_w} * ${tile_h}" | bc)
fi
# defaults
seek_default='00:00:05'
scale_default='160'
tile_layout_default='4x3'
tile_default='12'
padding_default='7'
margin_default='2'
color_default='black'
outfile_default="${infile_name}-tile-$(date +"%Y-%m-%d-%H-%M-%S").png"
# duration * fps / number of tiles
frames=$(echo "${duration} * ${fps} / ${tile_sum:=${tile_default}}" | bc)
# tile function
tilevideo () {
ffmpeg \
-hide_banner \
-stats -v panic \
-ss "${seek:=${seek_default}}" \
-i "${infile}" \
-frames 1 -vf "select=not(mod(n\,${frames})),scale=${scale:=${scale_default}}:-1,tile=${tile:=${tile_layout_default}}:padding=${padding:=${padding_default}}:margin=${margin:=${margin_default}}:color=${color:=${color_default}}" \
"${outfile:=${outfile_default}}"
}
# check the files mime type
case "${filetype}" in
${mov_mime}|${mkv_mime}|${mp4_mime}|${m4v_mime}|${webm_mime}|${avi_mime})tilevideo "${infile}";;
*) usage "${infile} ${NOT_MEDIA_FILE_ERR}";;
esac