Difference between revisions of "Low Quality Transcode"

From MythTV Official Wiki
Jump to: navigation, search
(update job status to allow proper function as a transcoding task)
 
(6 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>
  
This uses mythffmpeg to do the transcoding.  On my machine it takes HD-PVR files from ~2Gb to ~400MB which works find on my wireless network and is suitable for viewing on a laptop.   
+
 
 +
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'''
 
'''NOTE: This script requires that mythffmpeg is compiled with --enable-libxvid --enable-libmp3lame'''
Line 27: Line 27:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! '''Parameter'''    
+
! '''Parameter                   '''
 
! '''Reason'''
 
! '''Reason'''
 
|-
 
|-
Line 33: Line 33:
 
| Overwrite the outputfile if it already exists
 
| Overwrite the outputfile if it already exists
 
|-
 
|-
| -i
+
| -i INFILE
 
| specify the input file
 
| specify the input file
 
|-
 
|-
Line 49: Line 49:
 
|-
 
|-
 
| -vtag XVID
 
| -vtag XVID
| Mark the file as using the  XVID codec (not sure if this is necessary
+
| Mark the file as using the  XVID codec (not sure if this is necessary)
 
|-
 
|-
 
| -qmin 3 -qmax 3
 
| -qmin 3 -qmax 3
Line 64: Line 64:
 
|-
 
|-
 
| 2> /dev/null
 
| 2> /dev/null
| mythffmpeg writes out a lot of data to STDERR.  This causes the Python System call to freeze at ~110MB.  Since we don't need the output this will dump it all to /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`.
 
|}
 
|}
  
Line 108: 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 ' % (infile, outfile) )
+
         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 114: 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 136: 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 Version24.png  Version25.png  


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`.


PythonIcon.png transcode_low.py

#!/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()