-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathffmpeg.wrap
156 lines (136 loc) · 6.62 KB
/
ffmpeg.wrap
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
#!/bin/bash -
#title : Wrapper script for FFMPEG customizations
#description : This script is a wrapper for Jellyfin ffmpeg
FFMPEG_DIR=/usr/lib/jellyfin-ffmpeg # non-Docker server path to FFMPEG usually is /usr/bin/ffmpeg
SCRIPT_DIR=/config/ffmpeg
TRANSCODES_DIR=/config/transcodes
CLEANUP_PROG=$SCRIPT_DIR/transcode.cleanup.sh
SEMAPHORE_DIR=/config/semaphore # use RAM drive for FFMPEG transcoding PID and PAUSE files
LOG_DIR=/config/log
CLEANUP_LOG=$LOG_DIR/transcode.cleanup.log # create a single log file (easier when using OFF, WARN or INFO level logging)
#SEMAPHORE_DIR=$SCRIPT_DIR/log # use mounted directory on host machine for easier access
#LOG_DIR=$SCRIPT_DIR/log
#CLEANUP_LOG=$LOG_DIR/transcode.cleanup.$$.log # create separate log file per each cleanup wrap trigger (easier for DEBUG or TRACE level logging)
CLEANUP_PID=$SEMAPHORE_DIR/transcode.cleanup.pid
#
# Set the path/name of the configuration file
#
conf="$SCRIPT_DIR/ffmpeg.wrap.conf"
# prop - reads value of a propery from the configuration file
# use $(prop 'property.name') to read properties from a key=value lines in file
function prop {
grep "^\\s*${1}\\s*=" $conf|cut -d'=' -f2-
}
#
# $1 - Segment ID
#
# Returns FFMPEG last position from which the TS files are created (FFMPEG argument -START_NUMBER)
# Position is set in variable $FFMPEG_POS, time of the last position change in $FFMPEG_POS_TIME
# Full filepath to POS file in $POS_FILEPATH
#
function get_ffmpeg_pos {
local segment_id=$1
local POS_FILEPATH=$SEMAPHORE_DIR/${segment_id}.pos
if [ -f $POS_FILEPATH ]; then
FFMPEG_POS="$(head -1 $POS_FILEPATH)" # Sample value: 123 05-03-2023 12:20:17.655142648, where 123 is the position number
FFMPEG_POS_TIME="${FFMPEG_POS#* }" # extract the part after the first space
FFMPEG_POS=${FFMPEG_POS%% *} # extract the part before the first space
else
FFMPEG_POS=
FFMPEG_POS_TIME=
fi
}
# Log console and error output to log files in /config/ffmpeg/log
CLEANUP_ENABLED=$(prop 'transcode.cleanup')
CLEANUP_LOG_LEVEL=$(prop 'transcode.cleanup.log.level')
ARGS_LOG_ENABLED=$(prop 'ffmpeg.args.log')
DISABLE_FORCED_SUBTITLES=$(prop 'disable.forced.subtitles')
ffmpeg="$FFMPEG_DIR/ffmpeg"
#Add quotes for arguments with "spaces", "semicolon" and "parentheses")
for x in "${@}" ; do
# try to figure out if quoting was required for the $x (Arguments)
if [[ "$x" != "${x%[[:space:]]*}" ]] \
|| [[ "$x" != "${x%[;]*}" ]] \
|| [[ "$x" != "${x%(*}" ]] ; then
x="\""$x"\""
fi
_args=$_args" "$x
done
if [[ "$ARGS_LOG_ENABLED" == "true" ]]; then
echo "" >> $LOG_DIR/ffmpeg.args.log;
fi
# Execute transcode cleanup process, which will remove oldest *.ts files when space is used for more than 80%
# If parallel ffmpeg process will be launched then previous clean up process will be killed
if [[ "$CLEANUP_ENABLED" == "true" ]]; then
#
# Create <SEGMENT ID>.pid file
# Clean-up script uses PID file to monitor segment TS files individually per stream
#
# Example: _args="hls_list_size 0 -y /config/transcodes/821fe9209bd1020f178e3fdfc2241b46.m3u8"
[[ $_args =~ -y[[:space:]]+$TRANSCODES_DIR/([^\.]+)\.[^\.]+$ ]]
SEGMENT_ID=${BASH_REMATCH[1]}
if [[ "$SEGMENT_ID" != "" ]]; then
WRAP_PID=$SEMAPHORE_DIR/$SEGMENT_ID.pid
if [[ "$ARGS_LOG_ENABLED" == "true" ]]; then echo "Capturing FFMPEG WRAP process PID $$ in file: $WRAP_PID" >> $LOG_DIR/ffmpeg.args.log; fi
echo $$ > $WRAP_PID
fi
# fi
#
# Create <SEGMENT ID>.pos file
# Clean-up script uses POS file to monitor for playback position change. New position is specified with FFMPEG
# argument -start_number. Jellyfin calls FFMPEG with new -start_number even if old FFMPEG is still running.
#
# Example: _args="hls_list_size 0 -y /config/transcodes/821fe9209bd1020f178e3fdfc2241b46.m3u8"
[[ $_args =~ [[:space:]]+-start_number[[:space:]]+([0-9]+)[[:space:]]+ ]]
SEGMENT_POS=${BASH_REMATCH[1]}
WRAP_POS=$SEMAPHORE_DIR/$SEGMENT_ID.pos
if [[ "$SEGMENT_POS" == "" ]]; then
rm -f $WRAP_POS
else
get_ffmpeg_pos $SEGMENT_ID
if ([ "$FFMPEG_POS" != "" ] && [ $FFMPEG_POS -eq $SEGMENT_POS ]); then
if [[ "$ARGS_LOG_ENABLED" == "true" ]]; then echo "Earlier captured TS file ID of FFMPEG playback position $SEGMENT_POS in file has not changed: $WRAP_POS" >> $LOG_DIR/ffmpeg.args.log; fi
else
if [[ "$ARGS_LOG_ENABLED" == "true" ]]; then echo "Capturing TS file ID of FFMPEG playback position $SEGMENT_POS in file: $WRAP_POS" >> $LOG_DIR/ffmpeg.args.log; fi
# echo "$SEGMENT_POS $PAUSE_TEXT" > $WRAP_POS
echo $SEGMENT_POS $(date "+%F %T.%9N") > $WRAP_POS # "+%Y-%m-%d %H:%M:%S.%9N"
fi
fi
PRINT_LOG_TIMESTAMP=1
if [[ "$CLEANUP_LOG_LEVEL" != "" ]] && [[ $CLEANUP_LOG_LEVEL -gt 0 ]]; then
# if [[ "$_args" =~ .*(-i nullsrc|-version|-decoders|-encoders|-filters|-h filter=|-hwaccels).* ]]; then
if [[ "$_args" != *"$TRANSCODES_DIR"* ]]; then
echo "FFMPEG started without transcoding directory as argument, so will not launch clean-up process because there will be no transcoding files produced" >> $CLEANUP_LOG
else
#echo test
#sh -c 'nohup /bin/bash $CLEANUP_PROG '$CLEANUP_LOG_LEVEL' $PRINT_LOG_TIMESTAMP >> /config/ffmpeg/log/transcode.cleanup.'$$'.log 2>&1 &'
sh -c 'nohup /bin/bash '$CLEANUP_PROG' '$CLEANUP_LOG_LEVEL' '$PRINT_LOG_TIMESTAMP' >> '$CLEANUP_LOG' 2>&1 &'
fi
else
if [[ "$_args" == *"$TRANSCODES_DIR"* ]]; then
sh -c 'nohup /bin/bash '$CLEANUP_PROG' 0 '$PRINT_LOG_TIMESTAMP' 2>&1 &'
fi
fi
fi
if [[ "$DISABLE_FORCED_SUBTITLES" == "true" ]]; then
#
# Disable forced subtitles
# Forced subtitles may cause error for ffmpeg parameters specific to FireTV (for example, in a movie Avatar)
#
# Remove options such as: subtitles=f='/media/Movies/file.mkv':si=0:alpha=1:sub2video=1:fontsdir='/cache/attachments/123'
#
_args=$(echo "$_args" | sed -r "s/,subtitles=f=[^,]+//") # specifies file containing subtitles (remove prefix comma , to avoid ,, in the output)
fi
#
# Change number of threads to 1 - default 0 will spawn multiple threads based on many factors (CPU cores, encoding parameters, etc)
# NOTE: Clean-up script will work as expected with multiple threads which is the default behavior, however single thread is enough for smooth operation
_args=${_args/-threads 0/-threads 1}
if [[ "$ARGS_LOG_ENABLED" == "true" ]]; then
#
# Output modified arguments to a log file (comment this line when not debugging)
#
echo $_args >> $LOG_DIR/ffmpeg.args.log
fi
# Execute wrapper
eval $ffmpeg $_args
exit $?