Author: duncan
Date: Thu Oct 19 16:49:39 2006
New Revision: 8423
Added:
branches/rel-1/freevo/src/encodingcore.py
- copied, changed from r8410,
/branches/rel-1/freevo/src/helpers/encodingcore.py
branches/rel-1/freevo/src/video/encodingclient.py (contents, props changed)
- copied, changed from r8414, /branches/rel-1/freevo/src/encodingclient.py
branches/rel-1/freevo/src/video/plugins/reencode.py
Removed:
branches/rel-1/freevo/src/encodingclient.py
branches/rel-1/freevo/src/helpers/encodingcore.py
Modified:
branches/rel-1/freevo/src/helpers/encodingserver.py
branches/rel-1/freevo/src/video/plugins/dvdbackup.py
Log:
[ 1580642 ] Use the encoding server to re-encode recorded programmes
Updated for an experimental version of re-encoding tv programmes
Copied: branches/rel-1/freevo/src/encodingcore.py (from r8410,
/branches/rel-1/freevo/src/helpers/encodingcore.py)
==============================================================================
--- /branches/rel-1/freevo/src/helpers/encodingcore.py (original)
+++ branches/rel-1/freevo/src/encodingcore.py Thu Oct 19 16:49:39 2006
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------
-# EncodingCore.py, part of EncodingServer - for use with or without Freevo
+# EncodingCore.py, part of EncodingServer - for use with Freevo
# -----------------------------------------------------------------------
# $Id: rc.py 8278 2006-09-30 07:22:11Z duncan $
#
@@ -32,7 +32,7 @@
import threading
from time import sleep
import sys, os, re, popen2 #, ConfigParser, copy
-#import config # QuickRip global configuration.
+import config
import mmpython
from copy import copy
from string import split, join
@@ -48,10 +48,15 @@
__copyright__ = "Copyright (C) 2004 den_RDC"
__license__ = "GPL"
-DEBUG=False
+def _debug_(text, level=1):
+ if DEBUG >= level:
+ try:
+ self.log.debug(String(text))
+ except:
+ print(String(text))
#"hardcoded capabilities" .. these might change or become dynamic in the
future, when more capabilities are supported
-#the "container format" will remain hardcoded
+#the "container format" will remain hardcoded
ContainerCapList = [ 'Avi' ]
VideoCodecList = [ 'MPEG 4 (lavc)', 'XViD']
@@ -70,7 +75,7 @@
'Normal denoise' : "denoise3d",
'HQ denoise' : "hqdn3d"
}
-
+
MencoderMapping = {
'MPEG 4 (lavc)' :
["lavc",["-lavcopts","vcodec=mpeg4:vhq:vqmin=2:v4mv:trell:autoaspect:vbitrate=%s%s"]],
#to hard 'MPEG 4 (lavc)' :
["lavc",["-lavcopts","vcodec=mpeg4:vhq:vqmin=2:v4mv:vlelim=-4:vcelim=9:lumi_mask=0.05:dark_mask=0.01:autoaspect:vbitrate=%s%s"]],
@@ -79,7 +84,7 @@
'MPEG 1 Layer 3 (mp3)' : ["mp3lame",["-lameopts", "cbr:br=%s"]]
}
-
+
#from pytvgrab enum.py, see http://pytvgrab.sourceforge.net
class Enum(dict):
"""Enum
@@ -90,102 +95,103 @@
for i in range(x, x+len(names)):
self.__dict__[names[i-x]]=i
self[i]=names[i-x]
- # __init__()
-
-
-status = Enum(["notset","apass","vpass1","vpassfinal","postmerge"])
+ # __init__()
+
+
+status = Enum(["notset","apass","vpass1","vpassfinal","postmerge"])
class EncodingJob:
"""Class for creation & configuration of EncodingJobs. This generates the
mencoder commands"""
-
+
def __init__(self, source, output, friendlyname, idnr, chapter=None):
"""Initialize class instance"""
+ _debug_('__init__(self, %s, %s, %s, %s, %s)' % (source, output,
friendlyname, idnr, chapter), 2)
#currently only MEncoder can be used, but who knows what will happen
in the future :)
self._generateCL = self._GenerateCLMencoder
-
+
self.source = source
self.output = output
self.name = friendlyname
self.idnr = idnr
self.chapter = chapter
-
+
self.sourcetype = None
-
+
self.container = "Avi"
-
+
self.tgtsize = None
self.length = None
-
+
self.vcodec = None
self.vbrate = None
self.multipass = False
self.vfilters = []
self.crop = None
-
-
+
+
self.acodec = AudioCodecList[0]
self.abrate = 128
self.afilters = {} # Not used atm, might be used in the future
-
+
self.cls = []
-
+
self.percentage = 0
self.trem = 0
-
+
self.status = status.notset
self.pid = 0
-
+
self.pal = False
self.ntsc = False
self.ntscprog = False
self.ana = False
-
+
#Analyze our source
self.finishedanalyze = False
self._AnalyzeSource()
-
-
+
+
def setContainer(self, container):
"""Set a container to hold the audio & video streams"""
#safety checks
if container not in ContainerCapList:
return "Unknown container format"
-
+
self.container = container
-
+
def getContainerList(self):
return ContainerCapList
-
-
+
+
def getVideoCodecList(self):
"""Return a possible video codec list"""
return VideoCodecList
-
+
def setVideoCodec(self, vcodec, tgtsize, multipass=False):
"""Set video codec and target filesize (in MB)"""
#safety checks first
if vcodec not in self.getVideoCodecList():
return "Unknown video codec"
-
+
self.vcodec = vcodec
self.tgtsize = (int(tgtsize) * 1024) #filesize is internally stored in
kb
self.multipass = multipass
-
-
+
+
def getAudioCodecList(self):
"""Return a possible audio codec list"""
return AudioCodecList
-
-
+
+
def setAudioCodec(self, acodec, abrate=128):
"""Set audio codec & bitrate"""
#safety first
if acodec not in self.getAudioCodecList():
return "Unknown audio codec"
-
+
self.acodec = acodec
self.abrate = abrate
-
+
def getVideoFiltersList(self):
"""Return a list of possible video filters"""
if self.ntsc:
@@ -194,41 +200,49 @@
non_ivtcdict = VFDict.copy()
del non_ivtcdict['Inverse Telecine']
return non_ivtcdict
-
+
def setVideoFilters(self, videofilters):
"""Set video filters"""
for vfilter, option in videofilters.items():
if MencoderFilters.has_key(option):
self.vfilters += [ MencoderFilters[option] ]
-
+
def _CalcVideoBR(self):
"""Calculates the video bitrate"""
-
+
self.vbrate = int((((int(self.tgtsize)*8) / int(self.length)) -
int(self.abrate)) / 0.98)
if self.vbrate > 12000: #we got a very short file, very high bitrates
are interpreted as bit/s instead of kbit/s, shitty qual
self.vbrate = 6000
-
-
+
+
def _AnalyzeSource(self):
"""Find out some basic information about the source
-
+
ATM we will blindly assume it's a dvdrom device or a disk dvd image,
if a chapter is given"""
-
+ _debug_('_AnalyzeSource(self)', 2)
+
if self.chapter:
self.sourcetype = "dvd"
-
#check some things, like length
mmpython.disc.ifoparser.open(self.source)
data = mmpython.disc.ifoparser.title(self.chapter)
self.length = data[2]
- if DEBUG: print "Video length: %s" % self.length
+ _debug_("Video length: %s" % self.length)
#NI : maybe implement procedure to get resolution, handy for
scaling/manual cropping
self._CropDetect()
-
-
+ else:
+ data = mmpython.parse(self.source)
+ self.sourcetype = data['type'].encode('latin1')
+ for f in dir(data):
+ print '%s: %s' % (f, eval('data["%s"]' % f))
+ self.length = data.get_length()
+ _debug_("Video length: %s" % self.length)
+ self._CropDetect()
+
+
def _CropDetect(self): #contains pieces of QuickRip
"""Detect cropping
-
+
Function is always called because cropping is a good thing, and we can
pass our ideal values
back to the client wich can verify them visually if needed.""" #not
true atm
#build mplayer parameters
@@ -243,53 +257,57 @@
arguments += [ '-dvd-device', self.source, 'dvd://%s' %
self.chapter ]
else:
arguments += [ self.source ]
-
+
+ _debug_('arguments=%s' % arguments)
+ _debug_('_run(mplayer, arguments, self._CropDetectParse, None, 0,
None)', 2)
self._run(mplayer, arguments, self._CropDetectParse, None, 0, None)
-
+
def _GenerateCLMencoder(self):
"""Generate the command line(s) to be executed, using MEncoder for
encoding"""
#calculate the videobitrate
self._CalcVideoBR()
-
+
#generate the audio pass
audiopass = []
-
-
+
+
audiopass += self._GCLMAudiopass()
audiopass += self._GCLMSource()
-
+
#for single passes
if not self.multipass:
- videopass = []
+ videopass = []
videopass += self._GCLMVideopass(0)
videopass += self._GCLMSource()
-
+
self.cls = [ audiopass, videopass ]
-
+
else:
videopass1 = []
videopass2 = []
-
+
videopass1 += self._GCLMVideopass(1)
- videopass1 += self._GCLMSource()
-
+ videopass1 += self._GCLMSource()
+
videopass2 += self._GCLMVideopass(2)
- videopass2 += self._GCLMSource()
-
- self.cls = [ audiopass, videopass1, videopass2 ]
-
+ videopass2 += self._GCLMSource()
+
+ self.cls = [ audiopass, videopass1, videopass2 ]
+
def _GCLMSource(self):
"""Returns source part of mencoder"""
if self.sourcetype == "dvd":
#return [ "-endpos", "10","-dvd-device", self.source , "dvd://%s"
% self.chapter]
return [ "-dvd-device", self.source , "dvd://%s" % self.chapter]
-
+ else:
+ return [ self.source ]
+
def _GCLMAudiopass(self):
"""Returns audio pass specefic part of mencoder cl"""
- return ["-ovc", "frameno", "-oac", MencoderMapping[self.acodec][0],
MencoderMapping[self.acodec][1][0],
+ return ["-ovc", "frameno", "-oac", MencoderMapping[self.acodec][0],
MencoderMapping[self.acodec][1][0],
MencoderMapping[self.acodec][1][1] % self.abrate,
"-o", "frameno.avi"]
-
+
def _GCLMVideopass(self, passnr):
"""Returns video pass specefic part of mencoder cl"""
vf = copy(self.vfilters)
@@ -303,13 +321,13 @@
passname = ":pass=%s"
else:
passname = ":vpass=%s"
-
+
vpass = passname % passnr
- #generate videofilters first, NI completly yet
+ #generate videofilters first, NI completly yet
if self.crop != None:
vf += [ "crop=%s" % self.crop ]
-
+
#in case of xvid and anamorphic dvd, add scaling to compensate AR.. if
we didn't find cropping we have no res, so no tricks
if self.vcodec == "XViD" and (self.crop != None):
if self.ana:
@@ -319,59 +337,59 @@
yscaled -= rounded
if rounded > 7.5:
yscaled += 16
- if DEBUG: print "Rescaled, corrected for AR res is %sx%s" %
(self.cropres[0], int(yscaled))
+ _debug_("Rescaled, corrected for AR res is %sx%s" %
(self.cropres[0], int(yscaled)))
else: # no scaling, w ehave a 4/3
yscaled = self.cropres[1]
#new, calculate ideal res based on BPP
idealres = self._OptimalRes(self.cropres[0], int(yscaled))
- if DEBUG: print "Rescaled, rounded yres is %sx%s" % (idealres[0],
idealres[1])
+ _debug_("Rescaled, rounded yres is %sx%s" % (idealres[0],
idealres[1]))
vf += [ "scale=%s:%s" % (idealres[0], idealres[1])]
-
- if DEBUG: print "Video filters: %s" % vf
-
+
+ _debug_("Video filters: %s" % vf)
+
#join vf options
if len(vf)> 1:
for vfopt in vf[0:-1]:
vfilter = vfilter + vfopt + ","
if len(vf) >= 1:
vfilter = vfilter + vf[-1]
-
- #if we have a dualpass, for the first pass, dump the output to
/dev/null
+
+ #if we have a dualpass, for the first pass, dump the output to
/dev/null
if passnr == 1:
output="/dev/null"
else:
output=self.output
-
+
args = ["-oac", "copy", "-ovc",MencoderMapping[self.vcodec][0],
MencoderMapping[self.vcodec][1][0],
- MencoderMapping[self.vcodec][1][1] % (self.vbrate, vpass),
+ MencoderMapping[self.vcodec][1][1] % (self.vbrate, vpass),
"-vf", vfilter, "-o", output]
-
+
#if we have a progressive ntsc file, lock the output fps (do this with
ivtc too)
if ("ivtc=1" in vf) or self.ntscprog:
args = ["-ofps","23.976"].append(args)
-
+
#if we scale, use the bilinear algorithm
if yscaled:
args += ["-sws","1"]
-
+
return args
-
+
#from QuickRip, heavily adapted, new algo
#TODO give this another name, it does more then crop detection only
- def _CropDetectParse(self, lines, data): #seek to remove data
- """Parses Mplayer output to obtain ideal cropping parameters, and do
PAL/NTSC detection"""
-
+ def _CropDetectParse(self, lines, data): #seek to remove data
+ """Parses Mplayer output to obtain ideal cropping parameters, and do
PAL/NTSC detection"""
+
re_crop = re.compile('.*-vf crop=(\d*:\d*:\d*:\d*).*')
re_ntscprog = re.compile('24fps progressive NTSC content detected')
re_pal = re.compile('25.000 fps')
re_ana = re.compile('(aspect 3)')
-
+
crop_options = {}
##~ common_crop = ""
##~ cc_hits = 2
-
+
foundtype = False
-
+
for line in lines:
if re_crop.search(line):
crop = re_crop.search(line).group(1)
@@ -381,7 +399,7 @@
##~ common_crop = crop
except:
crop_options[crop] = 1
-
+
#try to see if this is a PAL DVD, an NTSC Progressive DVD, ar an
NTSC DVD
if not foundtype and self.sourcetype == "dvd":
if re_pal.search(line):
@@ -391,25 +409,25 @@
if re_ntscprog.search(line):
self.ntscprog = True
foundtype = True
-
+
if re_ana.search(line):
self.ana = True
if not foundtype: self.ntsc = True
-
- if DEBUG:
+
+ if DEBUG:
print "All collected cropopts: %s" % crop_options
if self.pal: print "This is a PAL dvd"
if self.ntsc: print "This is an NTSC dvd"
- if self.ntscprog: print "This is a progressive NTSC dvd"
-
+ if self.ntscprog: print "This is a progressive NTSC dvd"
+
#if we didn't find cropping options (seems to happen sometimes on VERY
short dvd chapters)
if crop_options == {}:
#end analyzing
self.finishedanalyze = True
return
-
-
+
+
#some homegrown sleezy alghorythm to pick the best crop options
hcounter = 0
possible_crop = []
@@ -419,16 +437,16 @@
if counter > hcounter:
hcounter = counter
possible_crop = [crop]
-
+
self.crop = possible_crop[0]
-
+
if len(possible_crop) > 1:
for crop in possible_crop:
if crop < self.crop:
self.crop = crop
-
-
-
+
+
+
#make the final crop outputs a resolution wich is a multiple of 16 , v
and h ....
crop = split(self.crop, ":")
adjustedcrop = []
@@ -438,26 +456,26 @@
adjustedcrop += crop[2:]
#save cropped resolution for later
self.cropres = ( int(adjustedcrop[0]), int(adjustedcrop[1]) )
-
+
self.crop = join(adjustedcrop, ":")
-
- if DEBUG: print "Selected crop option: %s" % self.crop
-
+
+ _debug_("Selected crop option: %s" % self.crop)
+
#end analyzing
self.finishedanalyze = True
-
+
def _CalcBPP(self, x, y):
"""Perform a BPP (Bits per Pixel calculation)"""
if self.pal: fps = 25.000
if self.ntscprog: fps = 23.976
if self.ntsc: fps = 29.970
return (self.vbrate * 1000)/(x * y * fps)
-
+
def _OptimalRes(self, x, y):
"""Using BPP calculations, try to find out the ideal resolution for
this movie"""
nonoptimal = True
optx = x
-
+
#scale down until or ideal size is met
while nonoptimal:
#scale down x with 16 pix, calc y with the same AR as original x &
y
@@ -470,11 +488,11 @@
opty += 16
if self._CalcBPP( optx, opty ) >= 0.22:
nonoptimal = False
-
+
return ( int(optx), int (opty) )
-
+
#from Quickrip, adapted
- def _MencoderParse(self, line, data): #seek to remove data
+ def _MencoderParse(self, line, data): #seek to remove data
"""Parses mencoder stdout to get progress and trem"""
#(passtype, title) = data
@@ -483,22 +501,22 @@
self.percentage = re_progress.search(line).group(1)
self.trem = re_progress.search(line).group(2)
#self.ui_updateProgress(perc, trem, passtype)
-
+
#from QuickRip, adapted
def _run(self, program, arguments, finalfunc, updatefunc=None,
flushbuffer=0, data=None, lock=None): # seek to remove data
andor crop (not really used)
"""Runs a program; supply program name (string) and arguments (list)"""
- command = [program]
+ command = [program]
command += arguments
self.thread = CommandThread(self, command, updatefunc, finalfunc,
flushbuffer, data, None) #self.lock)
- self.thread.start()
-
-
+ self.thread.start()
+
+
+
+
-
-
#command executing class - Taken from Quickrip & adapted.
class CommandThread(threading.Thread): # seek to remove data andor crop (not
really used)
"""Handle threading of external commands"""
@@ -518,16 +536,16 @@
pid = self.pipe.pid
self.parent.pid = copy(pid)
totallines = []
-
- if DEBUG: print "Mencoder running at PID %s" % self.pipe.pid
-
+
+ _debug_("Mencoder running at PID %s" % self.pipe.pid)
+
while 1:
if self.flushbuffer:
line = self.pipe.fromchild.read(1000)
else:
line = self.pipe.fromchild.readline()
- if DEBUG: print line
+ _debug_(line)
if not line:
break
else:
@@ -540,7 +558,7 @@
# Clean up process table--you already handle exceptions in the function
#self.kill_pipe()
-
+
#give mplayer/mencoder some time to die before we try & kill it, or
zombies will raise from their grave :)
sleep(0.5)
@@ -548,14 +566,14 @@
os.waitpid(pid, os.WNOHANG)
except:
pass
-
+
self.kill_pipe()
-
+
if self.finalFunc != None:
self.finalFunc(totallines, self.data)
#self.lock.release()
-
+
sys.exit(2)
@@ -566,28 +584,30 @@
os.waitpid(self.pipe.pid, os.WNOHANG)
except:
pass
-
-
-
+
+
+
class EncodingQueue:
"""Class for generating an encoding queue"""
-
- def __init__(self, logger):
+
+ def __init__(self, logger, debug=0):
#we keep a list and a dict because a dict doesn't store an order
+ global DEBUG
+ DEBUG = debug
self.qlist = []
self.qdict = {}
self.running = False
self.log = logger
-
+
#remove old files
self._removeTmp()
-
+
def addEncodingJob(self, encjob):
"""Adds an encodingjob to the queue"""
-
+
self.qlist += [encjob]
self.qdict[encjob.idnr] = encjob
-
+
def getProgress(self):
"""Gets progress on the current job"""
if hasattr(self,"currentjob"):
@@ -595,14 +615,14 @@
int(self.currentjob.percentage), self.currentjob.trem)
else:
return "No job currently running"
-
+
def startQueue(self):
"""Start the queue"""
if not self.running:
self.running = True
- self.log.info("queue started")
+ _debug_("queue started", 0)
self._runQueue()
-
+
def listJobs(self):
"""Returns a list of queue'ed jobs"""
if self.qdict == {}:
@@ -612,15 +632,15 @@
for idnr, job in self.qdict.items():
jlist += [ (idnr, job.name, job.status) ]
return jlist
-
+
def _removeTmp(self):
"""Removes possible temporary files created during encoding"""
tmpfiles = ['frameno.avi', 'divx2pass.log', 'xvid-twopass.stats' ]
-
+
for tmpfile in tmpfiles:
if os.path.exists(tmpfile):
os.remove(tmpfile)
-
+
def _runQueue(self, line="", data=""):
"""Executes the jobs in the queue, and gets called after every
mencoder run is completed"""
if self.qlist == []:
@@ -628,32 +648,32 @@
self.running = False
if hasattr(self,"currentjob"):
del self.currentjob
- self.log.info("queue empty, stopping processing...")
+ _debug_("queue empty, stopping processing...", 0)
return
-
- if DEBUG: print "runQueue callback data : %s" % line
+
+ _debug_("runQueue callback data : %s" % line)
#get the first queued object
self.currentjob = self.qlist[0]
-
- if DEBUG: print "PID %s" % self.currentjob.pid
-
+
+ _debug_("PID %s" % self.currentjob.pid)
+
if self.currentjob.status == status.vpassfinal:
- self.log.info("Job %s finished" % self.currentjob.idnr)
+ _debug_("Job %s finished" % self.currentjob.idnr, 0)
#we are done with this job, remove it
del self.qlist[0]
del self.qdict[self.currentjob.idnr]
#currently, keep running until the queue is empty
self._runQueue()
return
-
+
if self.currentjob.status == status.vpass1:
#start final video encoding pass
self.currentjob.cls.pop(0)
self.currentjob.status = status.vpassfinal
#start video encoding
- self.currentjob._run(mencoder, self.currentjob.cls[0],
self._runQueue,
+ self.currentjob._run(mencoder, self.currentjob.cls[0],
self._runQueue,
self.currentjob._MencoderParse, 1, None)
-
+
if self.currentjob.status == status.apass:
#in case audio encoding started before auto-crop detection
returned, we are gonna
#rebuild the clis... audio encoding doesn't need cropping
@@ -665,37 +685,38 @@
self.currentjob.status = status.vpassfinal
else:
self.currentjob.status = status.vpass1
- self.currentjob._run(mencoder, self.currentjob.cls[0],
self._runQueue,
+ self.currentjob._run(mencoder, self.currentjob.cls[0],
self._runQueue,
self.currentjob._MencoderParse, 1, None)
-
+
if self.currentjob.status == status.notset:
#generate cli's
self.currentjob._generateCL()
- if DEBUG: print "CLIs : %s" % self.currentjob.cls
-
+ _debug_("CLIs : %s" % self.currentjob.cls)
+
#clean out temporary files
self._removeTmp()
-
+
#start audio encoding
self.currentjob.status = status.apass
- self.currentjob._run(mencoder, self.currentjob.cls[0],
self._runQueue,
+ self.currentjob._run(mencoder, self.currentjob.cls[0],
self._runQueue,
self.currentjob._MencoderParse, 1, None)
-
- self.log.info("Started job %s, %s on PID %s" % (self.currentjob.idnr,
status[self.currentjob.status], self.currentjob.pid))
- self.log.info("Encoder Command is %s" % self.currentjob.cls[0])
-
-
-
+
+ _debug_("Started job %s, %s on PID %s" % (self.currentjob.idnr, \
+ status[self.currentjob.status], self.currentjob.pid), 0)
+ _debug_("Encoder Command is %s" % self.currentjob.cls[0], 0)
+
+
+
# -----DEBUGGING STUFF BELOW---USE ONLY WHEN WEARING A BULLETPROOF VEST ;)
-
-
+
+
##~ def conc(list):
##~ str = ""
##~ for el in list:
##~ str = str + el + " "
-##~ return str
-
+##~ return str
+
#FOR TESTING ONLY
if __name__ == '__main__':
encjob = EncodingJob('/storage/video/dvd/BRUCE_ALMIGHTY/',
'test.avi','lala', 456789, 17)
@@ -716,10 +737,7 @@
import logging
log = logging.getLogger("EncodingCore")
log.setLevel(logging.DEBUG)
-
- queue = encodingqueue(log)
+
+ queue = encodingqueue(log, 2)
queue.addEncodingJob(encjob)
queue.startqueue()
-
-
-
Modified: branches/rel-1/freevo/src/helpers/encodingserver.py
==============================================================================
--- branches/rel-1/freevo/src/helpers/encodingserver.py (original)
+++ branches/rel-1/freevo/src/helpers/encodingserver.py Thu Oct 19 16:49:39 2006
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------
-# EncodingServer.py, part of EncodingServer - for use with or without Freevo
+# EncodingServer.py, part of EncodingServer - for use with Freevo
# -----------------------------------------------------------------------
# $Id: rc.py 8278 2006-09-30 07:22:11Z duncan $
#
@@ -27,14 +27,34 @@
#
# -----------------------------------------------------------------------
-#Import statements
+import sys, string, random, time, os, re, pwd, stat
+import config
+from util import vfs
+
+appname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
+appconf = appname.upper()
+
+# change uid
+if __name__ == '__main__':
+ uid='config.'+appconf+'_UID'
+ gid='config.'+appconf+'_GID'
+ try:
+ if eval(uid) and os.getuid() == 0:
+ os.setgid(eval(gid))
+ os.setuid(eval(uid))
+ os.environ['USER'] = pwd.getpwuid(os.getuid())[0]
+ os.environ['HOME'] = pwd.getpwuid(os.getuid())[5]
+ except Exception, e:
+ print e
+
from twisted.web import xmlrpc, server
from twisted.internet.app import Application
from twisted.internet import reactor
from twisted.python import log
from util.marmalade import jellyToXML, unjellyFromXML
-import logging
import time, random, sys, os
+import logging
+import config
from encodingcore import EncodingJob, EncodingQueue
@@ -44,9 +64,19 @@
__copyright__ = "Copyright (C) 2004 den_RDC"
__license__ = "GPL"
-tmppath = '/tmp/encodingserver'
+DEBUG = hasattr(config, appconf+'_DEBUG') and eval('config.'+appconf+'_DEBUG')
or config.DEBUG
-DEBUG=False
+logfile = '%s/%s-%s.log' % (config.LOGDIR, appname, os.getuid())
+log.startLogging(open(logfile, 'a'))
+
+def _debug_(text, level=1):
+ if DEBUG >= level:
+ try:
+ log.debug(String(text))
+ except:
+ print String(text)
+
+tmppath = '/tmp/encodingserver'
jam = jellyToXML
unjam = unjellyFromXML
@@ -57,23 +87,25 @@
self.jobs = {}
#setup a logger
- if debug: #when debugging, output everything to stdout using the root
logging class
- self.log = logging
- else: #normally, write nice formatted messages to a logfile)
- self.log = logging.getLogger("EncodingServer")
- self.log.setLevel(logging.INFO)
- FHandler = logging.FileHandler("encodingserver.log")
- FHandler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s
%(message)s"))
- self.log.addHandler(FHandler)
+ #if debug: #when debugging, output everything to stdout using the root
logging class
+ # self.log = logging
+ #else: #normally, write nice formatted messages to a logfile)
+ # self.log = logging.getLogger("EncodingServer")
+ # self.log.setLevel(logging.INFO)
+ # FHandler = logging.FileHandler("encodingserver.log")
+ #
FHandler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s
%(message)s"))
+ # self.log.addHandler(FHandler)
- self.queue = EncodingQueue(self.log)
+ self.queue = EncodingQueue(log, DEBUG)
- self.log.info("EncodingServer started...")
+ _debug_("EncodingServer started...", 0)
def xmlrpc_echotest(self, blah):
+ _debug_("xmlrpc_echotest(self, blah)", 2)
return (True, 'EncodingServer::echotest: %s' % blah)
def xmlrpc_initEncodeJob(self, source, output, friendlyname="",
chapter=None):
+ _debug_("xmlrpc_initEncodeJob(self, %s, %s, %s, %s)" % (source,
output, friendlyname, chapter), 2)
#safety checks
if not (source or output):
return (False, 'EncodingServer::initEncodeJob: no source or
output given')
@@ -81,20 +113,23 @@
#in p2.3 , int() can return long int's, wich is fine, except it makes
XMLRPC fail somwhere along the way
# so we devide or random number by 100 :)
idnr = int((time.time() / random.random()) / 100)
+ _debug_("idnr=%s" % (idnr), 2)
self.jobs[idnr] = EncodingJob(source, output, friendlyname, idnr,
chapter)
#wait for the analyzing to end
while not self.jobs[idnr].finishedanalyze:
time.sleep(0.1)
- self.log.info("Initialized job %s (idnr : %s)" % (friendlyname,idnr))
+ _debug_("Initialized job %s (idnr : %s)" % (friendlyname,idnr), 0)
return (True, idnr)
def xmlrpc_getContainerCAP(self, idnr):
+ _debug_("xmlrpc_getContainerCAP(self, idnr)", 2)
return (True, jam(self.jobs[idnr].getContainerList()))
def xmlrpc_setContainer(self, idnr, container):
+ _debug_("xmlrpc_setContainer(self, idnr, container)", 2)
status = self.jobs[idnr].setContainer(container)
if not status:
@@ -103,9 +138,11 @@
return (False, "EncodingServer::setContainer: %s" % status)
def xmlrpc_getVideoCodecCAP(self, idnr):
+ _debug_("xmlrpc_getVideoCodecCAP(self, idnr)", 2)
return (True, jam(self.jobs[idnr].getVideoCodecList()))
def xmlrpc_setVideoCodec(self, idnr, vcodec, tgtsize, multipass=False):
+ _debug_("xmlrpc_setVideoCodec(self, idnr, vcodec, tgtsize,
multipass=False)", 2)
#safety checks
if not (vcodec or tgtsize):
return (False, 'EncodingServer::setVideoCodec: no codec or target
size given')
@@ -118,9 +155,11 @@
return (False, "EncodingServer::setVideoCodec: %s" % status)
def xmlrpc_getAudioCodecCAP(self, idnr):
+ _debug_("xmlrpc_getAudioCodecCAP(self, idnr)", 2)
return (True, jam(self.jobs[idnr].getAudioCodecList()))
def xmlrpc_setAudioCodec(self, idnr, acodec, abrate):
+ _debug_("xmlrpc_setAudioCodec(self, idnr, acodec, abrate)", 2)
#safety checks
if not (acodec or abrate):
return (False, 'EncodingServer::setAudioCodec: no codec or
bitrate given')
@@ -133,10 +172,12 @@
return (False, "EncodingServer::setAudioCodec: %s" % status)
def xmlrpc_getVideoFiltersCAP(self, idnr):
+ _debug_("xmlrpc_getVideoFiltersCAP(self, idnr)", 2)
return (True, jam(self.jobs[idnr].getVideoFiltersList()))
def xmlrpc_setVideoFilters(self, idnr, filters):
+ _debug_("xmlrpc_setVideoFilters(self, idnr, filters)", 2)
#safety checks
if not filters:
return (False, 'EncodingServer::setAudioCodec: no codec or
bitrate given')
@@ -149,33 +190,34 @@
return (False, "EncodingServer::setVideoFilters: %s" % status)
def xmlrpc_queueIt(self, idnr, now=False):
+ _debug_("xmlrpc_queueIt(self, idnr, now=False)", 2)
self.queue.addEncodingJob(self.jobs[idnr])
del self.jobs[idnr]
- self.log.info("Added job %s to the queue" % idnr)
+ _debug_("Added job %s to the queue" % idnr, 0)
if now:
self.queue.startQueue()
return (True, "EncodingServer::queueIt: OK")
def xmlrpc_getProgress(self):
+ _debug_("xmlrpc_getProgress(self)", 2)
prog = self.queue.getProgress()
if type(prog) is str:
return (False, "EncodingServer::getProgress: %s" % prog)
return (True, jam(prog))
def xmlrpc_startQueue(self):
+ _debug_("xmlrpc_startQueue(self)", 2)
self.queue.startQueue()
-
return (True, "EncodingServer::startqueue: OK")
def xmlrpc_listJobs(self):
+ _debug_("xmlrpc_listJobs(self)", 2)
jlist = self.queue.listJobs()
-
return (True, jam(jlist))
-
-
def main():
+ global DEBUG
#check for /tmp/encodingserver and if it doesn't exist make it
if not (os.path.exists(tmppath) and os.path.isdir(tmppath)):
os.mkdir(tmppath)
@@ -185,12 +227,15 @@
app = Application("EncodingServer")
if len(sys.argv) >= 2 and sys.argv[1] == "debug":
es = EncodingServer(True)
- DEBUG=True
import encodingcore
encodingcore.DEBUG=True
else:
es = EncodingServer()
- app.listenTCP(6666, server.Site(es))
+ _debug_('main: DEBUG=%s' % DEBUG, 0)
+ if (DEBUG == 0):
+ app.listenTCP(config.ENCODINGSERVER_PORT, server.Site(es,
logPath='/dev/null'))
+ else:
+ app.listenTCP(config.ENCODINGSERVER_PORT, server.Site(es))
app.run(save=0)
@@ -204,5 +249,5 @@
except:
traceback.print_exc()
if start + 10 > time.time():
- print 'server problem, sleeping 1 min'
+ _debug_('server problem, sleeping 1 min', 0)
time.sleep(60)
Copied: branches/rel-1/freevo/src/video/encodingclient.py (from r8414,
/branches/rel-1/freevo/src/encodingclient.py)
==============================================================================
--- /branches/rel-1/freevo/src/encodingclient.py (original)
+++ branches/rel-1/freevo/src/video/encodingclient.py Thu Oct 19 16:49:39 2006
@@ -27,17 +27,18 @@
# -----------------------------------------------------------------------
import xmlrpclib, sys
-from twisted.persisted import marmalade
+from util.marmalade import jellyToXML, unjellyFromXML
+import config
server_string = 'http://%s:%s/' % \
- ("localhost", 6666)
+ (config.ENCODINGSERVER_IP, config.ENCODINGSERVER_PORT)
-server = xmlrpclib.Server(server_string)
+server = xmlrpclib.Server(server_string, allow_none=1)
#server = object() - uncomment this and comment the previous line to enable
pychecker testing
-jam = marmalade.jellyToXML
-unjam = marmalade.unjellyFromXML
+jam = jellyToXML
+unjam = unjellyFromXML
#some data
__author__ = "den_RDC ([EMAIL PROTECTED])"
@@ -115,14 +116,15 @@
This call can take some time (10 seconds on average) before returning,
because the
encodingserver analyzes the video during this call."""
+ _debug_('initEncodeJob(%s, %s, %s, %s)' % (source, output, friendlyname,
title), 0)
if not (source or output):
return (False, "EncodingClient: no source and/or output")
try:
(status, response) = server.initEncodeJob(source, output,
friendlyname, title)
except:
-##~ print "Unexpected eroor:", sys.exc_info()[0]
-##~ raise
+ print "Unexpected error:", sys.exc_info()[0]
+ raise
return (False, 'EncodingClient: connection error')
return (status, response)
Modified: branches/rel-1/freevo/src/video/plugins/dvdbackup.py
==============================================================================
--- branches/rel-1/freevo/src/video/plugins/dvdbackup.py (original)
+++ branches/rel-1/freevo/src/video/plugins/dvdbackup.py Thu Oct 19
16:49:39 2006
@@ -30,7 +30,7 @@
from os.path import join, split
import plugin, config, menu
#import config
-from encodingclient import *
+from video.encodingclient import *
from gui.AlertBox import AlertBox
from gui.PopupBox import PopupBox
@@ -84,6 +84,8 @@
menuw.pushmenu(encoding_menu)
def create_job(self, menuw=None, arg=None):
+ '''
+ '''
#create a filename for the to-be-encoded dvd title
#title = int(self.item.url[6:])
fname = join(config.VIDEO_ITEMS[0][1], "%s_%s.avi" %
(self.item.parent.name, self.title))
Added: branches/rel-1/freevo/src/video/plugins/reencode.py
==============================================================================
--- (empty file)
+++ branches/rel-1/freevo/src/video/plugins/reencode.py Thu Oct 19 16:49:39 2006
@@ -0,0 +1,204 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------
+# re-encode recorded TV programmes
+# -----------------------------------------------------------------------
+# $Id: encode.py $
+#
+# Notes:
+# To activate, put the following line in local_conf.py:
+# plugin.activate('tv.encode')
+# ToDo:
+#
+# -----------------------------------------------------------------------
+# Freevo - A Home Theater PC framework
+# Copyright (C) 2002 Krister Lagerstrom, et al.
+# Please see the file freevo/Docs/CREDITS for a complete list of authors.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# -----------------------------------------------------------------------
+
+
+from os.path import join, split
+import plugin
+import menu
+import config
+from video.encodingclient import *
+from gui.AlertBox import AlertBox
+from gui.PopupBox import PopupBox
+
+DEBUG = config.DEBUG
+DEBUG = 9
+
+print "DJW: reencode DEBUG=%s" % DEBUG
+
+class PluginInterface(plugin.ItemPlugin):
+ """
+ Plug-in to archive recorded TV programmes using EncodingServer
+
+ This plugin NEEDS a running encodingserver to work properly.
+ You can start an encodingserver with "freevo encodingserver start".
+ """
+
+class PluginInterface(plugin.ItemPlugin):
+ def __init__(self):
+ _debug_('__init__')
+ plugin.ItemPlugin.__init__(self)
+
+
+ def actions(self, item):
+ #testing stuff
+ for d in dir(item):
+ print '%s: %s' % (d, eval('item.%s' % d))
+ for d in dir(item.info):
+ print '%s: %s' % (d, eval('item.info.%s' % d))
+ print 'type:', item.type
+ print 'mode:', item.mode
+ print 'name:', type(item.name)
+ print 'name:', item.name.encode('utf-8')
+ print 'filename:', item.filename
+ if hasattr(item, 'parentname'):
+ print item.parentname
+ if hasattr(item, 'media'):
+ print 'media:', item.media
+ if hasattr(item.media, 'devicename'):
+ print item.media.devicename
+
+ if item.type == 'video' and item.mode == 'file':
+ #for dvd on disc
+ self.dvdsource = item.filename
+
+ self.title = item.name
+ self.source = item.filename
+ self.filename =
item.filename[0:item.filename.rfind('.')]+'.divx'
+
+ self.item = item
+ return [ (self.encoding_profile_menu, _('Re-encode this
program...')) ]
+ return []
+
+ def encoding_profile_menu(self, menuw=None, arg=None):
+ #create a menu with a few encoding options (1cd, 2cd, xvid, mpeg4)
+ #args : tuple, (videocodec, size, multipass
+ menu_items = [ menu.MenuItem("XViD, 700mb", self.create_job,
(1,700,False)) ]
+ menu_items.append( menu.MenuItem("XViD, 700mb, High Quality",
self.create_job, (1,700,True)) )
+ menu_items.append( menu.MenuItem("XViD, 1400mb", self.create_job,
(1,1400,False)) )
+ menu_items.append( menu.MenuItem("XViD, 1400mb, High Quality",
self.create_job, (1,1400,True)) )
+ menu_items.append( menu.MenuItem("DivX, 700mb", self.create_job,
(0,700,False)) )
+ menu_items.append( menu.MenuItem("DivX, 700mb, High Quality",
self.create_job, (0,700,True)) )
+ menu_items.append( menu.MenuItem("DivX, 1400mb", self.create_job,
(0,1400,False)) )
+ menu_items.append( menu.MenuItem("DivX, 1400mb, High Quality",
self.create_job, (0,1400,True)) )
+
+ encoding_menu = menu.Menu(_('Choose your encoding profile'),
menu_items)
+ menuw.pushmenu(encoding_menu)
+
+ def create_job(self, menuw=None, arg=None):
+ print 'arg:', arg
+ #unwrap settings tupple
+ vcodecnr, tgtsize, mpass = arg
+
+ #we are going to create a job and send it to the encoding server, this
can take some time while analyzing
+
+ box = PopupBox(text=_('Please wait, analyzing video...'))
+ box.show()
+
+ (status, resp) = initEncodeJob(self.source, self.filename, self.title)
+ print 'initEncodeJob:status:', status, ' resp:', resp
+
+ box.destroy()
+
+ if not status:
+ self.error(resp)
+ return
+
+ idnr = resp
+
+ #ask for possible containers and set the first one (should be avi), we
will get a list
+ (status, resp) = getContainerCAP(idnr)
+ print 'getContainerCAP:status:', status, ' resp:', resp
+
+ if not status:
+ self.error(resp)
+ return
+
+ container = resp[0]
+
+ (status, resp) = setContainer(idnr, container)
+ print 'setContainer:status:', status, ' resp:', resp
+
+ if not status:
+ self.error(resp)
+ return
+
+ #ask for possible videocodec and set the first one (should be mpeg4),
we will get a list
+ (status, resp) = getVideoCodecCAP(idnr)
+ print 'getVideoCodecCAP:status:', status, ' resp:', resp
+
+ if not status:
+ self.error(resp)
+ return
+
+ vcodec = resp[vcodecnr]
+
+ (status, resp) = setVideoCodec(idnr, vcodec, tgtsize, mpass)
+ print 'setVideoCodec:status:', status, ' resp:', resp
+
+ if not status:
+ self.error(resp)
+ return
+
+ #ask for possible audiocodec and set the first one (should be mp3), we
will get a list
+ #Audiocodec call isn't necessary atm, it defaults to 128 kbit mp3, but
this might change in the future
+ #so we play safe
+ (status, resp) = getAudioCodecCAP(idnr)
+ print 'getAudioCodecCAP:status:', status, ' resp:', resp
+
+ if not status:
+ self.error(resp)
+ return
+
+ acodec = resp[0]
+
+ (status, resp) = setAudioCodec(idnr, acodec, 128)
+ print 'setAudioCodec:status:', status, ' resp:', resp
+
+ if not status:
+ self.error(resp)
+ return
+
+ #And finally, qeue and start the job
+ (status, resp) = queueIt(idnr, True)
+ print 'queueIt:status:', status, ' resp:', resp
+
+ if not status:
+ self.error(resp)
+ return
+
+ self.menuw = menuw
+ AlertBox(width=400, height=200, text=_("Encoding started"),
handler=self.mopup).show()
+
+ print "boe"
+ #menuw.delete_menu()
+ #menuw.delete_menu()
+
+
+
+ def error(self, text=""):
+ AlertBox(width=400, height=200, text="ERROR: %s" % text).show()
+
+
+ def mopup(self):
+ self.menuw.delete_menu()
+ self.menuw.back_one_menu()
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog