-
Notifications
You must be signed in to change notification settings - Fork 0
/
hlscat
executable file
·147 lines (125 loc) · 4.24 KB
/
hlscat
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
#!/bin/bash
#
# Name: hlscat
# Date: 2023-08-29
# Author: Jakub Pisarek @sgfn
# License: MIT License
DEFAULT_HLS_PREFIX="muxed"
DEFAULT_INPUT_DIR="./jellyfish_output/hls_output"
SCRIPT_NAME=$(basename "${BASH_SOURCE[0]}")
usage() {
cat <<EOF
Usage: ${SCRIPT_NAME} [-vhc] [-p <prefix>] [-i <dir>] [-o <file>] [-r [from]:[to]] [dirname prefix]
EOF
print_cat
cat <<EOF
hlscat -- Concatenate HLS headers and segments into an MP4 file
If dirname prefix is provided, it will be used to match a directory with HLS segments
inside of the parent directory passed using the \`-i\` option.
Only the first match will be processed, subsequent ones are ignored.
For instance, \`${SCRIPT_NAME} af342d\` will work on files in ${DEFAULT_INPUT_DIR}/af342d*
(if such a directory is present).
Available options:
-p <prefix> HLS file prefix. Defaults to "${DEFAULT_HLS_PREFIX}"
-i <directory> Parent of directories with HLS segments.
Defaults to "${DEFAULT_INPUT_DIR}/"
-o <file> Output filename. Defaults to "hlscat_<datetime>.mp4"
-r [from]:[to] Range of numbers of segments to concatenate (both ends inclusive).
Numbers can be omitted to signal the respective end of the range.
Defaults to all segments in directory, same as passing \`-r :\`
-v Enable verbose mode
-h Print this help and exit
-c Print the cat and exit
EOF
exit 0
}
print_cat() {
cat <<'EOF'
__ ____ ____
/ // / / / __/ _ |\_
/ _ / /___\ \ \` ..\
/_//_/____/___/ __,.-" =__Y=
." )
_ / , \/\_
((____| )_-\ \_-`
`-----'`-----` `--`
EOF
}
exit_error() {
echo "$1" >&2
exit "${2-1}"
}
parse_params() {
HLS_PREFIX="${DEFAULT_HLS_PREFIX}"
INPUT_DIR="${DEFAULT_INPUT_DIR}"
OUTPUT_FILE="hlscat_$(date '+%Y%m%d%H%M%S').mp4"
RANGE=":"
while :; do
case "${1-}" in
-h) usage ;;
-v) set -x ;;
-c) print_cat; exit 0 ;;
-p)
HLS_PREFIX="${2-}"
shift
;;
-i)
INPUT_DIR="${2-}"
shift
;;
-o)
OUTPUT_FILE="${2-}"
shift
;;
-r)
RANGE="${2-}"
shift
;;
--) break ;;
-?*) exit_error "Unknown option: $1" 2 ;;
*) break ;;
esac
shift
done
[[ -z "${HLS_PREFIX}" ]] && exit_error "Option -p requires a parameter: <prefix>" 2
[[ -z "${INPUT_DIR}" ]] && exit_error "Option -i requires a parameter: <dir>" 2
[[ -z "${OUTPUT_FILE}" ]] && exit_error "Option -o requires a parameter: <file>" 2
[[ -z "${RANGE}" ]] && exit_error "Option -r requires a parameter: [from]:[to]" 2
DIRNAME_PREFIX="${1-}"
return 0
}
main() {
parse_params "$@"
[[ ! -d "${INPUT_DIR}" ]] && exit_error "No such directory: ${INPUT_DIR}"
# pick longest dirname that matches
FILES_PATH=$(find "${INPUT_DIR}" -type d -name "${DIRNAME_PREFIX}*" | sort | tail -1)
[[ -z "${FILES_PATH}" ]] && exit_error "No directory matching ${DIRNAME_PREFIX}* found in ${INPUT_DIR}"
ORIGIN_PATH=$(pwd)
cd "${FILES_PATH}" || exit_error "Unable to open directory ${FILES_PATH}"
trap 'cd "${ORIGIN_PATH}"' EXIT
SEGMENT_NUMBERS=$(find . -name "${HLS_PREFIX}"'_segment_*.m4s' | sed -E 's/^.*'"${HLS_PREFIX}"'_segment_([0-9]+)_.*\.m4s$/\1/' | sort -n)
[[ -z "${SEGMENT_NUMBERS}" ]] && exit_error "No HLS segments prefixed '${HLS_PREFIX}_' found in ${FILES_PATH}"
# TODO: less unix runes and subshells, maybe?
MIN_SEGMENT=$(echo "${RANGE}" | sed -n -E 's/^([0-9]+):.*$/\1/p')
MAX_SEGMENT=$(echo "${RANGE}" | sed -n -E 's/^.*:([0-9]+)$/\1/p')
[[ -z "${MIN_SEGMENT}" ]] && MIN_SEGMENT=$(echo "${SEGMENT_NUMBERS}" | head -1)
[[ -z "${MAX_SEGMENT}" ]] && MAX_SEGMENT=$(echo "${SEGMENT_NUMBERS}" | tail -1)
cmd="cat"
# TODO: This probably won't work if the header is split into multiple files,
# is ugly, could be unsafe and needs to be changed
for file in ./"${HLS_PREFIX}"_header_*.mp4; do
cmd+=" ${file}"
done
for i in $(seq "${MIN_SEGMENT}" "${MAX_SEGMENT}"); do
for file in ./"${HLS_PREFIX}"_segment_"${i}"_*.m4s; do
cmd+=" ${file}"
done
done
OUTPUT_PATH="${ORIGIN_PATH}/${OUTPUT_FILE}"
${cmd} > "${OUTPUT_PATH}"
if [[ $? != 0 ]]; then
rm "${OUTPUT_PATH}"
exit_error "hlscat failed!"
fi
}
main "$@"