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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
#!/bin/bash
# convert recording to avi compatable with San Disk Sansa Fuze
# Based on and/or inspired by myth2xvid, the video4fuze project:
# http://code.google.com/p/video4fuze
# and the fuzemux project:
# http://code.google.com/p/fuzemux
#
# version 0.1
#
# usage:
# first parameter must be %DIR%/%FILE% of the recording
# second parameter must be the desired base name of the output
# third parameter must be %CHANID% if you set USECUTLIST=Y
# fourth parameter must be %STARTTIME% if you set USECUTLIST=Y
# fifth parameter must be %JOBID% for the User Job status to be updated in MythTV
# in the mythtv setup screen invoke this script like this:
# MYTHTV User Job Command:
# /usr/bin/myth2fuze "%DIR%/%FILE%" "%TITLE% - %SUBTITLE%" "%CHANID%" "%STARTTIME%" "%JOBID%"
# options:
USECUTLIST=Y # Y or N
# check prerequesites
for APP in {fuzemux,mencoder,ffmpeg,mythcommflag,mythtranscode,mysql}; do
/usr/bin/which $APP &>/dev/null
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "$APP not found in your PATH! Aborting! ERROR: $ERROR" >> $LOGFILE
update_status 304
update_comment "$APP not found in your PATH! Aborting! Exit status: $ERROR"
exit 1
fi
done
# where the converted video is stored
OUT_DIR=/myth/md0/video/fuze
# Ensure output directory exists
if [ ! -d $OUT_DIR ] ; then
mkdir -p -m777 $OUT_DIR
fi
# database settings
BACKEND_HOSTNAME=${BACKEND_HOSTNAME:-"localhost"}
DBUSERNAME=${DBUSERNAME:-"mythtv"}
DBPASSWORD=${DBPASSWORD:-"mythtv"}
SQLCMD="mysql -u $DBUSERNAME --password=$DBPASSWORD -h $BACKEND_HOSTNAME mythconverg -e"
#------FUNCTIONS---------------
update_comment()
# Arg_1 = COMMENT
{
if [ $NO_JOBID = 0 ]; then
`$SQLCMD "update jobqueue set comment=\"$1\" where id=\"$JOBID\";"`
fi
}
update_status()
# Arg_1 = status code
{
if [ $NO_JOBID = 0 ]; then
`$SQLCMD "update jobqueue set status=\"$1\" where id=\"$JOBID\";"`
fi
}
check_background_progress()
# check mencoder progress in background
# Arg_1 = PROGRESS CALCULATION
{
while [ `tail -1 $STATUSFILE | grep -cE "^Audio stream:|^Video stream:"` = 0 ]
do
sleep 10
check_myth_jobcmds
current_status=`tail -1 $STATUSFILE | grep "([ 0-9]\{1,\}%)"`
prog_percent=`echo "$current_status" | sed 's_.*(\([ 0-9][ 0-9]\)%).*_\1_'`
current_FPS=`echo "$current_status" | sed 's_.*\([ 0-9][ 0-9].[ 0-9][ 0-9]\)fps.*_\1_'`
if [ -n "$prog_percent" ]; then
prog_percent=`expr $prog_percent / $1`
echo "$prog_percent% Completed @ $current_FPS fps"
update_comment "$prog_percent% Completed @ $current_FPS fps"
fi
sleep 10
done
}
check_myth_jobcmds()
# check the myth database for stop pause or resume commands
{
if [ $NO_JOBID = 0 ]; then
CURRENT_CMD=`$SQLCMD "select cmds from jobqueue where id=\"$JOBID\";" | sed '/[0-9]/!d'`
case "$CURRENT_CMD" in
# JOB_RUN
0) ;;
# JOB_PAUSE
1) update_status 6
kill -s STOP $mencoder_pid ;;
# JOB_RESUME
2) update_status 4
`$SQLCMD "update jobqueue set cmds=\"0\" where id=\"$JOBID\";"`
kill -s CONT $mencoder_pid ;;
# JOB_STOP
4) update_status 5
`$SQLCMD "update jobqueue set cmds=\"0\" where id=\"$JOBID\";"`
kill -9 $mencoder_pid $command_pid
clean_up_files
echo "Encode Cancelled" >> $LOGFILE
update_status 320
exit ;;
esac
fi
}
get_mencoder_pid()
{
process_name=""
i1=1
while [ "$process_name" != "found" ]; do
if [ "`ps $mencoder_pid | grep mencoder | sed 's_.*\(mencoder\).*_\1_'`" = "mencoder" ]; then
process_name="found"
else
mencoder_pid=`expr $mencoder_pid + 1`
fi
i1=`expr $i1 + 1`
if [ $i1 -gt 20 ]; then
break
fi
done
}
run_fuzemux()
# Remux avi to fuze compatable avi
{
/usr/bin/fuzemux ${TMPFILE} ${OUTPUTFILE} >> $LOGFILE || return 1
}
create_thumbnail()
# Create a thumbnail image for the fuze
{
/usr/bin/ffmpeg -y -v -1 -i ${OUTPUTFILE} -t 1 -ss 3 -s 224x176 -f image2 ${OUTPUTFILE%.*}.thm >> $LOGFILE
}
clean_up_files()
# clean up left over files
{
unlink $TMPFILE 2> /dev/null
unlink $TMPCUTFILE 2> /dev/null
unlink $TMPCUTFILE.map 2> /dev/null
unlink $TWOPASSFILE 2> /dev/null
unlink $TWOPASSFILE.tmp 2> /dev/null
unlink $STATUSFILE 2> /dev/null
unlink $MENCODER_RETURN_CODE 2> /dev/null
unlink $MENCODER_RETURN_CODE_2 2> /dev/null
}
#-------MAIN SCRIPT------------
# check if %JOBID% is passed from command line
JOBID=$5
if [ -z "$JOBID" ]; then
NO_JOBID=1
else
NO_JOBID=0
fi
# create temp filename so multiple instances won't conflict
TMPNAME=toFUZE-$$
TMPFILE=/myth/md0/tmp/$TMPNAME.avi
TMPCUTFILE=/myth/md0/tmp/$TMPNAME.mpg
MENINPUTFILE=$1
TWOPASSFILE=/tmp/$TMPNAME-2pass.log
STATUSFILE=/tmp/$TMPNAME-status.log
MENCODER_RETURN_CODE=/tmp/$TMPNAME-mencoder_return_code
MENCODER_RETURN_CODE_2=/tmp/$TMPNAME-mencoder_return_code_2
# log file location
LOGFILE=/var/log/mythtv/myth2fuze.log
CDate="`date`"
echo "" >> $LOGFILE
echo $CDate >> $LOGFILE
echo "File to encode: $MENINPUTFILE Name: $2" >> $LOGFILE
# start timer
beforetime="$(date +%s)"
check_myth_jobcmds
# check if using cutlist
if [ $USECUTLIST = Y ]; then
MYTHCOMMFRAMES=`mythcommflag --getcutlist -f $MENINPUTFILE | grep 'Cutlist:' | cut -d \ -f 2`
if [ -n "$MYTHCOMMFRAMES" ]; then
echo "Extracting Cutlist..." >> $LOGFILE
update_comment "Extracting Cutlist"
/usr/bin/nice -n19 /usr/bin/mythtranscode --chanid "$3" --starttime "$4" --outfile "$TMPCUTFILE" --mpeg2 --honorcutlist
MENINPUTFILE=$TMPCUTFILE
fi
fi
# run mencoder in background to do 1st pass conversion
echo "Encoding 1st Pass for the Fuze..." >> $LOGFILE
( /usr/bin/nice -n19 /usr/bin/mencoder $MENINPUTFILE -passlogfile $TWOPASSFILE \
-ffourcc DX50 -ofps 20 -vf pp=li,expand=:::::224/176,scale=224:176,harddup \
-ovc lavc -lavcopts vcodec=mpeg4:vbitrate=683:vmax_b_frames=0:keyint=15:turbo:vpass=1 \
-nosound -o /dev/null > $STATUSFILE 2>&1 ; echo $? > $MENCODER_RETURN_CODE ) &
mencoder_pid=$!
command_pid=$mencoder_pid
get_mencoder_pid
check_background_progress "2"
if [ `cat $MENCODER_RETURN_CODE` -ne 0 ]; then
echo "Mencoder pass #1 exited with error $MENCODER_RETURN_CODE. Encoding fa$
update_status 304
update_comment "ERROR: Mencoder pass #1 exited with error $MENCODER_RETURN_C$
clean_up_files
exit 1
fi
# run mencoder in background to do 2nd pass conversion
echo "Encoding 2nd Pass for the Fuze..." >> $LOGFILE
( /usr/bin/nice -n19 /usr/bin/mencoder $MENINPUTFILE -passlogfile $TWOPASSFILE \
-ffourcc DX50 -ofps 20 -vf pp=li,expand=:::::224/176,scale=224:176,harddup \
-ovc lavc -lavcopts vcodec=mpeg4:vbitrate=683:vmax_b_frames=0:keyint=15:vpass=2 \
-srate 44100 -af resample=44100:0:1,format=s16le -oac mp3lame \
-lameopts cbr:br=128 -o "$TMPFILE" > $STATUSFILE 2>&1 ; echo $? \
> $MENCODER_RETURN_CODE_2 ) &
mencoder_pid=$!
command_pid=$mencoder_pid
get_mencoder_pid
check_background_progress "2"
if [ `cat $MENCODER_RETURN_CODE_2` -ne 0 ]; then
echo "Mencoder pass #1 exited with error $MENCODER_RETURN_CODE. Encoding fa$
update_status 304
update_comment "ERROR: Mencoder pass #1 exited with error $MENCODER_RETURN_C$
clean_up_files
exit 1
fi
# make output filename unique, remove punctuation and "special" characters,
# replace spaces with underscores and force lowercase names
FILENAME=$( echo ${2} | tr -d '[:punct:]' | tr -d "\"" | tr -d "\!" \
| tr -d "\`" | tr -s '[:blank:]' '[_]' \
| tr '[:upper:]' '[:lower:]' )_fuze.avi | tr -s '[_]'
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Creating unique file name exited with error $ERROR" >> $LOGFILE
update_status 304
update_comment "ERROR: Creating unique file name exited with error $ERROR Job Failed!"
clean_up_files
exit 1
fi
OUTPUTFILE=${OUT_DIR}/${FILENAME}
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Setting output file name exited with error $ERROR" >> $LOGFILE
update_status 304
update_comment "ERROR: Setting output file name exited with error $ERROR Job failed!"
clean_up_files
exit 1
fi
i=1
while [ -e "$OUTPUTFILE" ]
do
FILENAME=$( echo ${2} | tr -d '[:punct:]' | tr -d "\"" | tr -d "\!" \
| tr -d "\`" | tr -s '[:blank:]' '[_]' \
| tr '[:upper:]' '[:lower:]' )_fuze-$i.avi
OUTPUTFILE=${OUT_DIR}/${FILENAME}
i=`expr $i + 1`
done
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Setting output file name exited with error $ERROR" >> $LOGFILE
update_status 304
update_comment "ERROR: Setting output file name exited with error $ERROR Job failed!"
clean_up_files
exit 1
fi
run_fuzemux
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Fuzemux exited with error $ERROR" >> $LOGFILE
update_status 304
update_comment "ERROR: Fuzemux exited with error $ERROR Job Failed!"
clean_up_files
exit 1
fi
# ensure mythtv owns the final avi
chown mythtv ${OUTPUTFILE}
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Changing ownership of avi to mythtv exited with error $ERROR"
update_status 304
update_comment "ERROR: Changing ownership of avi to mythtv exited with error $ERROR Job failed!"
clean_up_files
exit 1
fi
create_thumbnail
# ensure mythtv owns the thumbnail
chown mythtv ${OUTPUTFILE%.*}.thm
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Changing ownership of thumbnail to mythtv exited with error $ERROR"
update_status 304
update_comment "ERROR: Changing ownership of thumbnail to mythtv exited with error $ERROR Job failed!"
clean_up_files
exit 1
fi
# stop timer
aftertime="$(date +%s)"
seconds="$(expr $aftertime - $beforetime)"
echo "File Encoded Successfully: $OUTPUTFILE" >> $LOGFILE
hours=$((seconds / 3600))
seconds=$((seconds % 3600))
minutes=$((seconds / 60))
seconds=$((seconds % 60))
echo "Encoding took $hours hour(s) $minutes minute(s) $seconds second(s) @ $current_FPS fps." >> $LOGFILE
update_status 272
update_comment "Encode Successful. Encoding Time: $hours hour(s) $minutes minute(s) $seconds second(s)"
clean_up_files
|