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
|
#!/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.2
#
# usage:
# first parameter must be %DIR%/%FILE% of the recording
# second parameter must be the %TITLE% for the output filename
# third parameter must be the %SUBTITLE% for the output filename
# fourth parameter must be %CHANID% if you set USECUTLIST=Y
# fifth parameter must be %STARTTIME% for USECUTLIST=Y and output filename
# sixth 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/LH/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/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"
# create temp filename so multiple instances won't conflict
TMPNAME=toFUZE-$$
TMPDIR=/myth/tmp
TMPFILE=${TMPDIR}/${TMPNAME}.avi
TMPCUTFILE=${TMPDIR}/${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
# Ensure temp directory exists
if [ ! -d ${TMPDIR} ] ; then
mkdir -p -m777 ${TMPDIR}
fi
#------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/nice -n19 /usr/bin/fuzemux ${TMPFILE} ${OUTPUTFILE} >> ${LOGFILE} || return 1
}
create_thumbnail()
# Create a thumbnail image for the fuze
{
/usr/bin/nice -n19 /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=${6}
if [ -z ${JOBID} ]; then
NO_JOBID=1
else
NO_JOBID=0
fi
# log file location
LOGFILE=/var/log/mythtv/myth2fuze.log
CDate="`date`"
echo "" >> ${LOGFILE}
echo ${CDate} >> ${LOGFILE}
echo "File to encode: ${MENINPUTFILE} Name: ${2} - ${3}" >> ${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 ${4} --starttime ${5} --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 failed!"
update_status 304
update_comment "ERROR: Mencoder pass #1 exited with error ${MENCODER_RETURN_CODE}"
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 + 50"
if [ `cat ${MENCODER_RETURN_CODE_2}` -ne 0 ]; then
echo "Mencoder pass #1 exited with error ${MENCODER_RETURN_CODE}. Encoding failed!"
update_status 304
update_comment "ERROR: Mencoder pass #1 exited with error ${MENCODER_RETURN_CODE_2}"
clean_up_files
exit 1
fi
# make output filename unique, remove punctuation and "special" characters,
# replace spaces with underscores and force lowercase names
OAD=$( echo ${5} | cut -b 1-8 )
FILENAME=$( echo "${2} ${OAD} ${3}" | tr -d '[:punct:]' \
| tr -s '[:blank:]' '[_]' | tr '[:upper:]' '[:lower:]' )_fuze.avi
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
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
|