Difference between revisions of "Low Quality Transcode"
From MythTV Official Wiki
(Created page with '{{Script info |author=Doug Haber (though Raymond Wagner did the hard work) |short=Low Quality Transcode using a slightly altered external transcode wrapper |long=This script does…') |
(update job status to allow proper function as a transcoding task) |
||
(10 intermediate revisions by 2 users not shown) | |||
Line 5: | Line 5: | ||
|category=User Job Scripts | |category=User Job Scripts | ||
|file=transcode_low.py | |file=transcode_low.py | ||
− | |S25=yes | + | |S24=yes|S25=yes |
}} | }} | ||
− | + | This script follows the transcode stub model so it can be run as: | |
− | This follows the transcode stub model so it can be run as: | ||
<pre> | <pre> | ||
transcode_low.py %JOBID% | transcode_low.py %JOBID% | ||
--- or --- | --- or --- | ||
− | transcode_low.py --chanid %CHANID% --starttime %STARTTIME% | + | transcode_low.py --chanid=%CHANID% --starttime=%STARTTIME% |
</pre> | </pre> | ||
− | + | ||
+ | The script uses mythffmpeg to do the transcoding. On my machine it takes HD-PVR files from ~2Gb to ~400MB which work fine on my wireless network and are suitable for viewing on a laptop. | ||
+ | |||
+ | '''NOTE: This script requires that mythffmpeg is compiled with --enable-libxvid --enable-libmp3lame''' | ||
+ | |||
+ | It uses the following mythffmpeg commandline: | ||
+ | |||
+ | mythffmpeg -y -i INFILE -ac 2 -vf "scale=640:360" -f avi -vcodec libxvid -vtag XVID -qmin 3 -qmax 3 -acodec libmp3lame -ab 64k OUTFILE 2> /dev/null | ||
+ | |||
+ | Here's an explanation of each parameter | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! '''Parameter ''' | ||
+ | ! '''Reason''' | ||
+ | |- | ||
+ | | -y | ||
+ | | Overwrite the outputfile if it already exists | ||
+ | |- | ||
+ | | -i INFILE | ||
+ | | specify the input file | ||
+ | |- | ||
+ | | -ac 2 | ||
+ | | Converts audio to 2 channels | ||
+ | |- | ||
+ | | -vf "scale=640:360 | ||
+ | | Converts the video from 1080i to 640 by 360 but keeps the same Aspect Ratio | ||
+ | |- | ||
+ | | -f avi | ||
+ | | Convert to avi format | ||
+ | |- | ||
+ | | -vcodec libxvid | ||
+ | | Use the XVID codec. Note that myth must have been compiled with --enable-libxvid | ||
+ | |- | ||
+ | | -vtag XVID | ||
+ | | Mark the file as using the XVID codec (not sure if this is necessary) | ||
+ | |- | ||
+ | | -qmin 3 -qmax 3 | ||
+ | | Forces the quality to be 3. The range is 1 (best) to 32 (worst). 3 seemed to be decent quality with lowish bitrates. | ||
+ | |- | ||
+ | | -acodec libmp3lame | ||
+ | | Convert to the audio to mp3. Note that myth must have been compiled with --enable-libmp3lame | ||
+ | |- | ||
+ | | -ab 64k | ||
+ | | Set the audio bit rate to 64k. | ||
+ | |- | ||
+ | | OUTFILE | ||
+ | | The file to write out to | ||
+ | |- | ||
+ | | 2> /dev/null | ||
+ | | mythffmpeg writes out a lot of data to STDERR. This causes the Python System call in 0.24 to deadlock when the 64KB pipe buffer fills. Since we don't need the output this will dump it all to /dev/null. This is not required in 0.25. Note that this syntax requires your shell be `sh` or `bash`. | ||
+ | |} | ||
{{python|transcode_low.py| | {{python|transcode_low.py| | ||
Line 58: | Line 108: | ||
############################################## | ############################################## | ||
#### probably need to adjust this one too #### | #### probably need to adjust this one too #### | ||
− | output = task('-y -i "%s" -ac 2 -vf "scale=640:360" -f avi -vcodec libxvid -vtag XVID -qmin 3 -qmax 3 -acodec libmp3lame -ab 64k "%s" 2> /dev/null ' | + | output = task('-y', |
+ | '-i "%s"' % infile, | ||
+ | '-ac 2', | ||
+ | '-vf "scale=640:360"', | ||
+ | '-f avi', | ||
+ | '-vcodec libxvid', | ||
+ | '-vtag XVID', | ||
+ | '-qmin 3', | ||
+ | '-qmax 3', | ||
+ | '-acodec libmp3lame', | ||
+ | '-ab 64k', | ||
+ | '"%s"' % outfile, | ||
+ | '2> /dev/null') | ||
############################################## | ############################################## | ||
except MythError, e: | except MythError, e: | ||
Line 64: | Line 126: | ||
sys.exit(e.returncode) | sys.exit(e.returncode) | ||
− | rec.basename = outfile | + | rec.basename = os.path.basename(outfile) |
os.remove(infile) | os.remove(infile) | ||
rec.filesize = os.path.getsize(outfile) | rec.filesize = os.path.getsize(outfile) | ||
Line 86: | Line 148: | ||
rec.update() | rec.update() | ||
+ | if jobid: | ||
+ | job.update({'status':272, 'comment':'Transcode Completed'}) | ||
def main(): | def main(): |
Latest revision as of 04:23, 8 September 2011
Author | Doug Haber (though Raymond Wagner did the hard work) |
Description | This script does a fairly low quality transcode, useful for converting an 1080i 5.1CH recording to something usable over a wireless network. I use this for my son's cartoons which he watches on a laptop. This uses as slightly altered version of Raymond Wagner's Transcode wrapper stub so it automatically handles all database operations for transcoding a file in place. |
Supports |
This script follows the transcode stub model so it can be run as:
transcode_low.py %JOBID% --- or --- transcode_low.py --chanid=%CHANID% --starttime=%STARTTIME%
The script uses mythffmpeg to do the transcoding. On my machine it takes HD-PVR files from ~2Gb to ~400MB which work fine on my wireless network and are suitable for viewing on a laptop.
NOTE: This script requires that mythffmpeg is compiled with --enable-libxvid --enable-libmp3lame
It uses the following mythffmpeg commandline:
mythffmpeg -y -i INFILE -ac 2 -vf "scale=640:360" -f avi -vcodec libxvid -vtag XVID -qmin 3 -qmax 3 -acodec libmp3lame -ab 64k OUTFILE 2> /dev/null
Here's an explanation of each parameter
Parameter | Reason |
---|---|
-y | Overwrite the outputfile if it already exists |
-i INFILE | specify the input file |
-ac 2 | Converts audio to 2 channels |
-vf "scale=640:360 | Converts the video from 1080i to 640 by 360 but keeps the same Aspect Ratio |
-f avi | Convert to avi format |
-vcodec libxvid | Use the XVID codec. Note that myth must have been compiled with --enable-libxvid |
-vtag XVID | Mark the file as using the XVID codec (not sure if this is necessary) |
-qmin 3 -qmax 3 | Forces the quality to be 3. The range is 1 (best) to 32 (worst). 3 seemed to be decent quality with lowish bitrates. |
-acodec libmp3lame | Convert to the audio to mp3. Note that myth must have been compiled with --enable-libmp3lame |
-ab 64k | Set the audio bit rate to 64k. |
OUTFILE | The file to write out to |
2> /dev/null | mythffmpeg writes out a lot of data to STDERR. This causes the Python System call in 0.24 to deadlock when the 64KB pipe buffer fills. Since we don't need the output this will dump it all to /dev/null. This is not required in 0.25. Note that this syntax requires your shell be `sh` or `bash`. |
#!/usr/bin/env python from MythTV import Job, Recorded, System, MythDB, mythproto, MythError from optparse import OptionParser import sys import os ################################ #### adjust these as needed #### transcoder = '/usr/local/bin/mythffmpeg' flush_commskip = False build_seektable = False ################################ def runjob(jobid=None, chanid=None, starttime=None): db = MythDB() if jobid: job = Job(jobid, db=db) chanid = job.chanid starttime = job.starttime rec = Recorded((chanid, starttime), db=db) sg = mythproto.findfile(rec.basename, rec.storagegroup, db=db) if sg is None: print 'Local access to recording not found.' sys.exit(1) infile = os.path.join(sg.dirname, rec.basename) outfile = '%s.t.avi' % infile.rsplit('.',1)[0] #### list of segments to be cut # rec.markup.gencutlist() #### list of segments to keep # rec.markup.genuncutlist() task = System(path=transcoder, db=db) try: ############################################## #### probably need to adjust this one too #### output = task('-y', '-i "%s"' % infile, '-ac 2', '-vf "scale=640:360"', '-f avi', '-vcodec libxvid', '-vtag XVID', '-qmin 3', '-qmax 3', '-acodec libmp3lame', '-ab 64k', '"%s"' % outfile, '2> /dev/null') ############################################## except MythError, e: print 'Command failed with output:\n%s' % e.stderr sys.exit(e.returncode) rec.basename = os.path.basename(outfile) os.remove(infile) rec.filesize = os.path.getsize(outfile) rec.transcoded = 1 rec.seek.clean() if flush_commskip: for index,mark in reversed(list(enumerate(rec.markup))): if mark.type in (rec.markup.MARK_COMM_START, rec.markup.MARK_COMM_END): del rec.markup[index] rec.bookmark = 0 rec.cutlist = 0 rec.markup.commit() if build_seektable: task = System(path='mythcommflag') task.command('--chanid %s' % chanid, '--starttime %s' % starttime, '--rebuild') rec.update() if jobid: job.update({'status':272, 'comment':'Transcode Completed'}) def main(): parser = OptionParser(usage="usage: %prog [options] [jobid]") parser.add_option('--chanid', action='store', type='int', dest='chanid', help='Use chanid for manual operation') parser.add_option('--starttime', action='store', type='int', dest='starttime', help='Use starttime for manual operation') parser.add_option('-v', '--verbose', action='store', type='string', dest='verbose', help='Verbosity level') opts, args = parser.parse_args() if opts.verbose: if opts.verbose == 'help': print MythLog.helptext sys.exit(0) MythLog._setlevel(opts.verbose) if len(args) == 1: runjob(jobid=args[0]) elif opts.chanid and opts.starttime: runjob(chanid=opts.chanid, starttime=opts.starttime) else: print 'Script must be provided jobid, or chanid and starttime.' sys.exit(1) if __name__ == '__main__': main()