gmyth-stream/server/0.2/plugins/transcoders/mencoder.py
author melunko
Tue May 08 14:54:37 2007 +0100 (2007-05-08)
branchtrunk
changeset 633 65eaca328e22
parent 628 c6af9d7a88b5
child 638 e38953623405
permissions -rw-r--r--
[svn r639] Added creation of package gmyth-utils containing gmyth-cat application
     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", "mpeg1")
    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         if self.args["mux"] == "mpeg":
    86             video += " -mpegopts format=%s" % self.args["format"]
    87         video += " -vf scale=%s:%s" % (self.args["width"], self.args["height"])
    88 
    89         return video
    90     # _setup_video()
    91 
    92 
    93     def _arg_append(self, args, options):
    94         for arg in shlex.split(options):
    95             args.append(arg)
    96     # arg_append()
    97 
    98     def _setup_mencoder_opts(self, args):
    99         args.append(self.mencoder_path)
   100 
   101         if self.args["outfile"] == "-" and self.args["type"]:
   102             args.append(self.args["input"])
   103         else:
   104             args.append("-")
   105 
   106         if self.args["language"]:
   107             self._arg_append(args, "-alang %s" % self.args["language"])
   108 
   109         if self.args["subtitle"]:
   110             self._arg_append(args, "-slang %s" % self.args["subtitle"])
   111             self._arg_append(args, "-subfps %s" % self.args["fps"])
   112 
   113         self._arg_append(args, "-idx")
   114         self._arg_append(args, "-cache 1024")
   115         self._arg_append(args, self._setup_audio())
   116         self._arg_append(args, self._setup_video())
   117 
   118         self._arg_append(args, "-really-quiet")
   119         self._arg_append(args, "-o %s" % self.args["outfile"])
   120         self._arg_append(args, "2>%s" % os.devnull)
   121     # _setup_args()
   122 
   123 
   124     def _setup_filename(self):
   125         _type = self.args["type"]
   126 
   127         if _type == "file":
   128             if not os.path.exists(self.args["input"]):
   129                 raise IOError,\
   130                       "File requested does not exist: %s." % self.args["input"]
   131             else:
   132                 self.args["input"] = "file://%s" % self.args["input"]
   133 
   134         elif _type == "dvd":
   135             self.args["input"] = "dvd://".join(self.args["input"])
   136 
   137         elif _type == "myth":
   138             # gmyth-cat -h 192.168.1.124 -p 6543 -c 111
   139             # gmyth-cat -h 192.168.1.124 -p 6543 -f file.nuv
   140             # myth://IP:PORT:type:file
   141             self.args["gmyth-cat"] = self.args["input"].split(":")
   142             self.args["input"] = "-"
   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         _stdin = open(self.args["input"])
   177         size = int(os.path.getsize(self.args["input"]))
   178         self.status = 0
   179         total_read = 0
   180 
   181         # Configuring pipes
   182         stdr, stdw = os.pipe()
   183 
   184         if not self._run_mencoder(input=stdr):
   185             return False
   186 
   187         stdout = self._check_opened_file(stdw, _stdin)
   188 
   189         try:
   190             while self.proc and self.proc.poll() == None:
   191                 if not finished:
   192                     data_in = _stdin.read(4096)
   193                     if data_in != "":
   194                         os.write(stdw, data_in)
   195                         total_read += 4096
   196                         d = stdout.read(4096)
   197                         if self.args["sendback"]:
   198                             outfd.write(d)
   199                         self.status = total_read * 100 / size
   200                     else:
   201                         finished = True
   202                         os.close(stdw)
   203 
   204                 else:
   205                     d = stdout.read(4096)
   206                     if self.args["sendback"] and d != "":
   207                         outfd.write(d)
   208 
   209         except Exception, e:
   210             self.log.error("Problems handling data: %s" % e)
   211             self.stop()
   212             return False
   213 
   214         self.log.info("%s: Finished sending data to client" % repr(self))
   215         if not self.args["sendback"]:
   216             outfd.write("DONE")
   217 
   218         return True
   219     # _start_outfile()
   220 
   221     def _start(self, outfd):
   222         if not self._run_mencoder(output=subprocess.PIPE):
   223             return False
   224 
   225         try:
   226             while self.proc and self.proc.poll() == None:
   227                 d = self.proc.stdout.read(1024)
   228                 outfd.write(d)
   229         except Exception, e:
   230             self.log.error("Problems handling data: %s" % e)
   231             return False
   232 
   233         self.log.info("%s: Finished sending data to client" % repr(self))
   234         return True
   235     # _start()
   236 
   237     def _start_myth(self, outfd):
   238         # gmyth-cat -h 192.168.1.124 -p 6543 -c 111
   239         # gmyth-cat -h 192.168.1.124 -p 6543 -f file.nuv
   240         # myth://IP:PORT:type:file
   241         host = self.args["gmyth-cat"][0]
   242         port = self.args["gmyth-cat"][1]
   243         kind = self.args["gmyth-cat"][2]
   244         fchan = self.args["gmyth-cat"][3]
   245 
   246         gmyth_cat = utils.which("gmyth-cat")
   247         opts = [gmyth_cat, "-h", host, "-p", port, "-" + kind, fchan]
   248 
   249         try:
   250             self.gmyth = subprocess.Popen(opts, stdout=subprocess.PIPE, close_fds=True)
   251         except Exception, e:
   252             self.log.error("Error executing gmyth-cat: %s" % e)
   253             return False
   254 
   255         if not self._run_mencoder(input=self.gmyth.stdout, output=subprocess.PIPE):
   256             return False
   257 
   258         show_loading = 0
   259         show = True
   260 
   261         #n800 150000 and 1000
   262 
   263         try:
   264             while self.proc and self.proc.poll() == None:
   265 
   266                 r, w, x = select([self.proc.stdout], [], [], 0)
   267                 if self.proc.stdout in r:
   268                     d = self.proc.stdout.read(4096)
   269                     outfd.write(d)
   270                 #    self.log.debug("Sending tv data: %d" % show_loading)
   271                 #    if show_loading > 150000 and show:
   272                 #        self.log.debug("Disabling loading video")
   273                 #        show = False
   274 
   275                 #elif show_loading % 10000 == 0 and show:
   276                 #    show_loading += 1
   277                 #    d = open("loading.mpg")
   278                 #    outfd.write(d.read())
   279                 #    self.log.debug("Sendind loading video: %d" % show_loading)
   280 
   281                 #else:
   282                 #    show_loading += 1
   283 
   284                 #self.log.debug("SHOW_LOADING: %d" % show_loading)
   285 
   286         except Exception, e:
   287             self.log.error("Problems handling data: %s" % e)
   288             return False
   289 
   290         return True
   291     # _start_myth()
   292 
   293     def _run_mencoder(self, input=None, output=None):
   294         try:
   295             self.proc = subprocess.Popen(self.mencoder_opts, stdin=input,
   296                                          stdout=output, close_fds=True)
   297         except Exception, e:
   298             self.log.error("Error executing mencoder: %s" % e)
   299             return False
   300 
   301         return True
   302     # _run_mencoder()
   303 
   304     def start(self, outfd):
   305         cmd = " ".join(self.mencoder_opts)
   306         self.log.debug("Mencoder: %s" % cmd)
   307 
   308         ret = False
   309 
   310         if self.args["outfile"] == "-" and self.args["type"] in ["file", "dvd"]:
   311             ret = self._start(outfd)
   312 
   313         elif self.args["type"] == "myth":
   314             ret = self._start_myth(outfd)
   315 
   316         else:
   317             ret = self._start_outfile(outfd)
   318 
   319         self.stop()
   320         return ret
   321     # start()
   322 
   323 
   324     def stop(self):
   325         if self.proc:
   326             try:
   327                 os.kill(self.proc.pid, signal.SIGKILL)
   328             except OSError, e:
   329                 pass
   330 
   331             try:
   332                 self.proc.wait()
   333             except Exception, e:
   334                 pass
   335 
   336             self.proc = None
   337 
   338         if self.gmyth:
   339             try:
   340                 os.kill(self.gmyth.pid, signal.SIGKILL)
   341             except OSError, e:
   342                 pass
   343 
   344             try:
   345                 self.gmyth.wait()
   346             except Exception, e:
   347                 pass
   348 
   349             self.gmyth = None
   350 
   351     # stop()
   352 
   353 # TranscoderMencoder