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