gmyth-stream/server/0.2/plugins/transcoders/mencoder.py
author renatofilho
Thu Aug 16 14:46:11 2007 +0100 (2007-08-16)
branchtrunk
changeset 807 add4025ca678
parent 664 464d715ddb7e
permissions -rw-r--r--
[svn r813] created a timeout function for invalid channels
     1 import os
     2 import shlex
     3 import signal
     4 import subprocess
     5 import time
     6 import fcntl
     7 
     8 import lib.utils as utils
     9 import lib.server as server
    10 import plugins.transcoders.mencoder_lib.mythtv as mythtv
    11 
    12 from select import select
    13 
    14 __all__ = ("TranscoderMencoder",)
    15 
    16 class TranscoderMencoder(server.Transcoder):
    17     """Transcoder class that implements a transcoder using Mencoder"""
    18     mencoder_path = utils.which("mencoder")
    19     name = "mencoder"
    20     priority = -1
    21     args = {}
    22     proc = None
    23     gmyth = None
    24 
    25     # only works with avi container
    26     status = 0
    27 
    28     def _setup_params(self):
    29         params_first = self.params_first
    30 
    31         # general_opts
    32         self.args["local"]    = params_first("local", False)
    33         self.args["language"] = params_first("language", False)
    34         self.args["subtitle"] = params_first("subtitle", False)
    35         self.args["format"]   = params_first("format", "mpeg1")
    36         self.args["outfile"]  = params_first("outfile", "-")
    37 
    38         # input_opt
    39         self.args["type"]     = params_first("type", "file")
    40         self.args["input"]    = params_first("uri", "-")
    41 
    42         # audio_opts
    43         self.args["acodec"]   = params_first("acodec", "mp2")
    44         self.args["abitrate"] = params_first("abitrate", 192)
    45         self.args["volume"]   = params_first("volume", 5)
    46 
    47         # video_opts
    48         self.args["mux"]      = params_first("mux", "mpeg")
    49         self.args["fps"]      = params_first("fps", 25)
    50         self.args["vcodec"]   = params_first("vcodec", "mpeg1video")
    51         self.args["vbitrate"] = params_first("vbitrate", 400)
    52         self.args["width"]    = params_first("width", 320)
    53         self.args["height"]   = params_first("height", 240)
    54     # _setup_params()
    55 
    56 
    57     def _setup_audio(self):
    58         if self.args["acodec"] == "mp3lame":
    59             audio = "-oac mp3lame -lameopts cbr:br=%s vol=%s" % (
    60                 self.args["abitrate"], self.args["volume"])
    61         else:
    62             audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (
    63                 self.args["acodec"], self.args["abitrate"])
    64 
    65         return audio
    66     # _setup_audio()
    67 
    68 
    69     def _setup_video(self):
    70         video = " -of %s" % self.args["mux"]
    71         video += " -ofps %s" % self.args["fps"]
    72 
    73         vcodec = self.args["vcodec"]
    74         if vcodec == "nuv" or vcodec == "xvid"\
    75                or vcodec == "qtvideo" or vcodec == "copy":
    76             video += " -ovc %s" % vcodec
    77         else:
    78             video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
    79                 vcodec, self.args["vbitrate"])
    80 
    81         if self.args["mux"] == "mpeg":
    82             video += " -mpegopts format=%s" % self.args["format"]
    83         video += " -vf scale=%s:%s" % (self.args["width"], self.args["height"])
    84 
    85         return video
    86     # _setup_video()
    87 
    88 
    89     def _arg_append(self, args, options):
    90         for arg in shlex.split(options):
    91             args.append(arg)
    92     # arg_append()
    93 
    94     def _setup_mencoder_opts(self, args):
    95         args.append(self.mencoder_path)
    96 
    97         if self.args["outfile"] == "-" and self.args["type"]:
    98             args.append(self.args["input"])
    99         else:
   100             args.append("-")
   101 
   102         if self.args["language"]:
   103             self._arg_append(args, "-alang %s" % self.args["language"])
   104 
   105         if self.args["subtitle"]:
   106             self._arg_append(args, "-slang %s" % self.args["subtitle"])
   107             self._arg_append(args, "-subfps %s" % self.args["fps"])
   108 
   109         self._arg_append(args, "-idx")
   110         self._arg_append(args, "-cache 1024")
   111         self._arg_append(args, self._setup_audio())
   112         self._arg_append(args, self._setup_video())
   113 
   114         self._arg_append(args, "-really-quiet")
   115         self._arg_append(args, "-o %s" % self.args["outfile"])
   116         self._arg_append(args, "2>%s" % os.devnull)
   117     # _setup_args()
   118 
   119     def _setup_filename(self):
   120         """This function setups the file to encode parsing the uri.
   121         So, type can be:
   122         * file
   123         * dvd
   124         * myth
   125 
   126         If the last one is detected we have to parse the uri to find args.
   127         Then we store all the args inside a dictionary: self.args['gmyth-cat']
   128         """
   129         _type = self.args["type"]
   130 
   131         if _type == "file":
   132             if not os.path.exists(self.args["input"]):
   133                 raise IOError,\
   134                       "File requested does not exist: %s." % self.args["input"]
   135             else:
   136                 self.args["input"] = "file://%s" % self.args["input"]
   137 
   138         elif _type == "dvd":
   139             self.args["input"] = "dvd://".join(self.args["input"])
   140 
   141         elif _type == "myth":
   142             self.args["gmyth-cat"] = mythtv._setup_mythfilename(self)
   143     # _setup_filename()
   144 
   145 
   146     def __init__(self, params):
   147         server.Transcoder.__init__(self, params)
   148         self.mencoder_opts = []
   149 
   150         try:
   151             self._setup_params()
   152             self._setup_filename()
   153             self._setup_mencoder_opts(self.mencoder_opts)
   154         except Exception, e:
   155             self.log.error(e)
   156     # __init__()
   157 
   158 
   159     def _check_opened_file(self, stdw, _stdin):
   160         loop = True
   161         while loop:
   162             try:
   163                 return open(self.args["outfile"])
   164             except:
   165                 os.write(stdw, _stdin.read(1024))
   166     # _check_opened_file
   167 
   168 
   169     def _start_outfile(self, outfd):
   170         finished = False
   171 
   172         # fix this (not necessary)
   173         outfd.write("OK")
   174 
   175         # Configuring stdin
   176         try:
   177             _stdin = open(self.args["input"])
   178             size = int(os.path.getsize(self.args["input"]))
   179         except Exception, e:
   180             self.log.error("Mencoder stdin setup error: %s" % e)
   181             return False
   182 
   183         self.status = 0
   184         total_read = 0
   185 
   186         # Configuring pipes
   187         stdr, stdw = os.pipe()
   188 
   189         if not self._run_mencoder(input=stdr):
   190             return False
   191 
   192         stdout = self._check_opened_file(stdw, _stdin)
   193 
   194         try:
   195             while self.proc and self.proc.poll() == None:
   196                 if not finished:
   197                     data_in = _stdin.read(4096)
   198                     if data_in != "":
   199                         os.write(stdw, data_in)
   200                         total_read += 4096
   201                         d = stdout.read(4096)
   202                         self.status = utils.progress_bar(self.log,
   203                                                          int(total_read),
   204                                                          int(size), 50)
   205                     else:
   206                         finished = True
   207                         os.close(stdw)
   208 
   209                 else:
   210                     d = stdout.read(4096)
   211 
   212         except Exception, e:
   213             self.log.error("Problems handling data: %s" % e)
   214             self.stop()
   215             return False
   216 
   217         self.log.info("%s: Finished sending data to client" % repr(self))
   218         return True
   219     # _start_outfile()
   220 
   221     def _start(self, outfd):
   222         # Play a file on disk or DVD
   223         if not self._run_mencoder(output=subprocess.PIPE):
   224             return False
   225 
   226         try:
   227             while self.proc and self.proc.poll() == None:
   228                 d = self.proc.stdout.read(1024)
   229                 outfd.write(d)
   230         except Exception, e:
   231             self.log.error("Problems handling data: %s" % e)
   232             return False
   233 
   234         self.log.info("%s: Finished sending data to client" % repr(self))
   235         return True
   236     # _start()
   237 
   238     def _run_mencoder(self, input=None, output=None):
   239         try:
   240             self.proc = subprocess.Popen(self.mencoder_opts, stdin=input,
   241                                          stdout=output, close_fds=True)
   242         except Exception, e:
   243             self.log.error("Error executing mencoder: %s" % e)
   244             return False
   245 
   246         return True
   247     # _run_mencoder()
   248 
   249     def start(self, outfd):
   250         cmd = " ".join(self.mencoder_opts)
   251         self.log.debug("Mencoder: %s" % cmd)
   252 
   253         ret = False
   254 
   255         if self.args["outfile"] == "-" and \
   256                self.args["type"] in ["file", "dvd"]:
   257             ret = self._start(outfd)
   258 
   259         elif self.args["type"] == "myth":
   260             ret = mythtv.start_myth(self, outfd)
   261 
   262         else:
   263             ret = self._start_outfile(outfd)
   264 
   265         self.stop()
   266 
   267         if not ret:
   268             self.log.error("Problems while starting streaming.")
   269 
   270         return ret
   271     # start()
   272 
   273     def _aux_stop(self, obj):
   274         if obj:
   275             try:
   276                 os.kill(obj.pid, signal.SIGKILL)
   277             except OSError, e:
   278                 pass
   279 
   280             try:
   281                 obj.wait()
   282             except Exception, e:
   283                 pass
   284 
   285             obj = None
   286     # _aux_stop
   287 
   288     def stop(self):
   289         self._aux_stop(self.proc)
   290         self._aux_stop(self.gmyth)
   291     # stop()
   292 
   293 # TranscoderMencoder