gmyth-stream/server/0.2/plugins/transcoders/mencoder.py
author morphbr
Tue May 08 21:01:03 2007 +0100 (2007-05-08)
branchtrunk
changeset 638 e38953623405
parent 630 8b8efd570497
child 646 8bd1033f8bf6
permissions -rw-r--r--
[svn r644] * GMyth-Streamer:
- bug fix on mencoder plugin
- serve_version inside server.py
     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         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                         if self.args["sendback"]:
   203                             outfd.write(d)
   204                         self.status = total_read * 100 / size
   205                     else:
   206                         finished = True
   207                         os.close(stdw)
   208 
   209                 else:
   210                     d = stdout.read(4096)
   211                     if self.args["sendback"] and d != "":
   212                         outfd.write(d)
   213 
   214         except Exception, e:
   215             self.log.error("Problems handling data: %s" % e)
   216             self.stop()
   217             return False
   218 
   219         self.log.info("%s: Finished sending data to client" % repr(self))
   220         if not self.args["sendback"]:
   221             outfd.write("DONE")
   222 
   223         return True
   224     # _start_outfile()
   225 
   226     def _start(self, outfd):
   227         if not self._run_mencoder(output=subprocess.PIPE):
   228             return False
   229 
   230         try:
   231             while self.proc and self.proc.poll() == None:
   232                 d = self.proc.stdout.read(1024)
   233                 outfd.write(d)
   234         except Exception, e:
   235             self.log.error("Problems handling data: %s" % e)
   236             return False
   237 
   238         self.log.info("%s: Finished sending data to client" % repr(self))
   239         return True
   240     # _start()
   241 
   242     def _start_myth(self, outfd):
   243         # gmyth-cat -h 192.168.1.124 -p 6543 -c 111
   244         # gmyth-cat -h 192.168.1.124 -p 6543 -f file.nuv
   245         # myth://IP:PORT:type:file
   246         host = self.args["gmyth-cat"][0]
   247         port = self.args["gmyth-cat"][1]
   248         kind = self.args["gmyth-cat"][2]
   249         fchan = self.args["gmyth-cat"][3]
   250 
   251         gmyth_cat = utils.which("gmyth-cat")
   252         opts = [gmyth_cat, "-h", host, "-p", port, "-" + kind, fchan]
   253 
   254         try:
   255             self.gmyth = subprocess.Popen(opts, stdout=subprocess.PIPE, close_fds=True)
   256         except Exception, e:
   257             self.log.error("Error executing gmyth-cat: %s" % e)
   258             return False
   259 
   260         if not self._run_mencoder(input=self.gmyth.stdout, output=subprocess.PIPE):
   261             return False
   262 
   263         show_loading = 0
   264         show = True
   265 
   266         #n800 150000 and 1000
   267 
   268         try:
   269             while self.proc and self.proc.poll() == None:
   270 
   271                 r, w, x = select([self.proc.stdout], [], [], 0)
   272                 if self.proc.stdout in r:
   273                     d = self.proc.stdout.read(4096)
   274                     outfd.write(d)
   275                 #    self.log.debug("Sending tv data: %d" % show_loading)
   276                 #    if show_loading > 150000 and show:
   277                 #        self.log.debug("Disabling loading video")
   278                 #        show = False
   279 
   280                 #elif show_loading % 10000 == 0 and show:
   281                 #    show_loading += 1
   282                 #    d = open("loading.mpg")
   283                 #    outfd.write(d.read())
   284                 #    self.log.debug("Sendind loading video: %d" % show_loading)
   285 
   286                 #else:
   287                 #    show_loading += 1
   288 
   289                 #self.log.debug("SHOW_LOADING: %d" % show_loading)
   290 
   291         except Exception, e:
   292             self.log.error("Problems handling data: %s" % e)
   293             return False
   294 
   295         return True
   296     # _start_myth()
   297 
   298     def _run_mencoder(self, input=None, output=None):
   299         try:
   300             self.proc = subprocess.Popen(self.mencoder_opts, stdin=input,
   301                                          stdout=output, close_fds=True)
   302         except Exception, e:
   303             self.log.error("Error executing mencoder: %s" % e)
   304             return False
   305 
   306         return True
   307     # _run_mencoder()
   308 
   309     def start(self, outfd):
   310         cmd = " ".join(self.mencoder_opts)
   311         self.log.debug("Mencoder: %s" % cmd)
   312 
   313         ret = False
   314 
   315         if self.args["outfile"] == "-" and self.args["type"] in ["file", "dvd"]:
   316             ret = self._start(outfd)
   317 
   318         elif self.args["type"] == "myth":
   319             ret = self._start_myth(outfd)
   320 
   321         else:
   322             ret = self._start_outfile(outfd)
   323 
   324         self.stop()
   325         return ret
   326     # start()
   327 
   328 
   329     def stop(self):
   330         if self.proc:
   331             try:
   332                 os.kill(self.proc.pid, signal.SIGKILL)
   333             except OSError, e:
   334                 pass
   335 
   336             try:
   337                 self.proc.wait()
   338             except Exception, e:
   339                 pass
   340 
   341             self.proc = None
   342 
   343         if self.gmyth:
   344             try:
   345                 os.kill(self.gmyth.pid, signal.SIGKILL)
   346             except OSError, e:
   347                 pass
   348 
   349             try:
   350                 self.gmyth.wait()
   351             except Exception, e:
   352                 pass
   353 
   354             self.gmyth = None
   355 
   356     # stop()
   357 
   358 # TranscoderMencoder