gmyth-stream/server/0.2/plugins/transcoders/mencoder.py
author renatofilho
Tue May 15 20:16:26 2007 +0100 (2007-05-15)
branchtrunk
changeset 654 76b9c97faada
parent 651 76a3f315ef42
child 660 ba4a948c4a55
permissions -rw-r--r--
[svn r660] implemented progress function
     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         uri = params_first("uri", "file:-").split(":", 1)
    40         self.args["type"]     = uri[0]
    41         self.args["input"]    = uri[1]
    42 
    43         # audio_opts
    44         self.args["acodec"]   = params_first("acodec", "mp2")
    45         self.args["abitrate"] = params_first("abitrate", 192)
    46         self.args["volume"]   = params_first("volume", 5)
    47 
    48         # video_opts
    49         self.args["mux"]      = params_first("mux", "mpeg")
    50         self.args["fps"]      = params_first("fps", 25)
    51         self.args["vcodec"]   = params_first("vcodec", "mpeg1video")
    52         self.args["vbitrate"] = params_first("vbitrate", 400)
    53         self.args["width"]    = params_first("width", 320)
    54         self.args["height"]   = params_first("height", 240)
    55     # _setup_params()
    56 
    57 
    58     def _setup_audio(self):
    59         if self.args["acodec"] == "mp3lame":
    60             audio = "-oac mp3lame -lameopts cbr:br=%s vol=%s" % (
    61                 self.args["abitrate"], self.args["volume"])
    62         else:
    63             audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (
    64                 self.args["acodec"], self.args["abitrate"])
    65 
    66         return audio
    67     # _setup_audio()
    68 
    69 
    70     def _setup_video(self):
    71         video = " -of %s" % self.args["mux"]
    72         video += " -ofps %s" % self.args["fps"]
    73 
    74         vcodec = self.args["vcodec"]
    75         if vcodec == "nuv" or vcodec == "xvid"\
    76                or vcodec == "qtvideo" or vcodec == "copy":
    77             video += " -ovc %s" % vcodec
    78         else:
    79             video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
    80                 vcodec, self.args["vbitrate"])
    81 
    82         if self.args["mux"] == "mpeg":
    83             video += " -mpegopts format=%s" % self.args["format"]
    84         video += " -vf scale=%s:%s" % (self.args["width"], self.args["height"])
    85 
    86         return video
    87     # _setup_video()
    88 
    89 
    90     def _arg_append(self, args, options):
    91         for arg in shlex.split(options):
    92             args.append(arg)
    93     # arg_append()
    94 
    95     def _setup_mencoder_opts(self, args):
    96         args.append(self.mencoder_path)
    97 
    98         if self.args["outfile"] == "-" and self.args["type"]:
    99             args.append(self.args["input"])
   100         else:
   101             args.append("-")
   102 
   103         if self.args["language"]:
   104             self._arg_append(args, "-alang %s" % self.args["language"])
   105 
   106         if self.args["subtitle"]:
   107             self._arg_append(args, "-slang %s" % self.args["subtitle"])
   108             self._arg_append(args, "-subfps %s" % self.args["fps"])
   109 
   110         self._arg_append(args, "-idx")
   111         self._arg_append(args, "-cache 1024")
   112         self._arg_append(args, self._setup_audio())
   113         self._arg_append(args, self._setup_video())
   114 
   115         self._arg_append(args, "-really-quiet")
   116         self._arg_append(args, "-o %s" % self.args["outfile"])
   117         self._arg_append(args, "2>%s" % os.devnull)
   118     # _setup_args()
   119 
   120 
   121     def _setup_filename(self):
   122         _type = self.args["type"]
   123 
   124         if _type == "file":
   125             if not os.path.exists(self.args["input"]):
   126                 raise IOError,\
   127                       "File requested does not exist: %s." % self.args["input"]
   128             else:
   129                 self.args["input"] = "file://%s" % self.args["input"]
   130 
   131         elif _type == "dvd":
   132             self.args["input"] = "dvd://".join(self.args["input"])
   133 
   134         elif _type == "myth":
   135             # gmyth-cat -h 192.168.1.124 -p 6543 -c 111
   136             # gmyth-cat -h 192.168.1.124 -p 6543 -f file.nuv
   137             # myth://IP:PORT:type:file
   138             self.args["gmyth-cat"] = self.args["input"].split(":")
   139             self.args["input"] = "-"
   140     # _setup_filename()
   141 
   142 
   143     def __init__(self, params):
   144         server.Transcoder.__init__(self, params)
   145         self.mencoder_opts = []
   146 
   147         try:
   148             self._setup_params()
   149             self._setup_filename()
   150             self._setup_mencoder_opts(self.mencoder_opts)
   151         except Exception, e:
   152             self.log.error(e)
   153     # __init__()
   154 
   155 
   156     def _check_opened_file(self, stdw, _stdin):
   157         loop = True
   158         while loop:
   159             try:
   160                 return open(self.args["outfile"])
   161             except:
   162                 os.write(stdw, _stdin.read(1024))
   163     # _check_opened_file
   164 
   165 
   166     def _start_outfile(self, outfd):
   167         finished = False
   168 
   169         # fix this (not necessary)
   170         outfd.write("OK")
   171 
   172         # Configuring stdin
   173         try:
   174             _stdin = open(self.args["input"])
   175             size = int(os.path.getsize(self.args["input"]))
   176         except Exception, e:
   177             self.log.error("Mencoder stdin setup error: %s" % e)
   178             return False
   179 
   180         self.status = 0
   181         total_read = 0
   182 
   183         # Configuring pipes
   184         stdr, stdw = os.pipe()
   185 
   186         if not self._run_mencoder(input=stdr):
   187             return False
   188 
   189         stdout = self._check_opened_file(stdw, _stdin)
   190 
   191         try:
   192             while self.proc and self.proc.poll() == None:
   193                 if not finished:
   194                     data_in = _stdin.read(4096)
   195                     if data_in != "":
   196                         os.write(stdw, data_in)
   197                         total_read += 4096
   198                         d = stdout.read(4096)
   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 
   207         except Exception, e:
   208             self.log.error("Problems handling data: %s" % e)
   209             self.stop()
   210             return False
   211 
   212         self.log.info("%s: Finished sending data to client" % repr(self))
   213         return True
   214     # _start_outfile()
   215 
   216     def _start(self, outfd):
   217         # Play a file on disk or DVD
   218         if not self._run_mencoder(output=subprocess.PIPE):
   219             return False
   220 
   221         try:
   222             while self.proc and self.proc.poll() == None:
   223                 d = self.proc.stdout.read(1024)
   224                 outfd.write(d)
   225         except Exception, e:
   226             self.log.error("Problems handling data: %s" % e)
   227             return False
   228 
   229         self.log.info("%s: Finished sending data to client" % repr(self))
   230         return True
   231     # _start()
   232 
   233     def _run_mencoder(self, input=None, output=None):
   234         try:
   235             self.proc = subprocess.Popen(self.mencoder_opts, stdin=input,
   236                                          stdout=output, close_fds=True)
   237         except Exception, e:
   238             self.log.error("Error executing mencoder: %s" % e)
   239             return False
   240 
   241         return True
   242     # _run_mencoder()
   243 
   244     def start(self, outfd):
   245         cmd = " ".join(self.mencoder_opts)
   246         self.log.debug("Mencoder: %s" % cmd)
   247 
   248         ret = False
   249 
   250         if self.args["outfile"] == "-" and self.args["type"] in ["file", "dvd"]:
   251             ret = self._start(outfd)
   252 
   253         elif self.args["type"] == "myth":
   254             ret = mythtv.start_myth(self, outfd)
   255 
   256         else:
   257             ret = self._start_outfile(outfd)
   258 
   259         self.stop()
   260         return ret
   261     # start()
   262 
   263 
   264     def stop(self):
   265         if self.proc:
   266             try:
   267                 os.kill(self.proc.pid, signal.SIGKILL)
   268             except OSError, e:
   269                 pass
   270 
   271             try:
   272                 self.proc.wait()
   273             except Exception, e:
   274                 pass
   275 
   276             self.proc = None
   277 
   278         if self.gmyth:
   279             try:
   280                 os.kill(self.gmyth.pid, signal.SIGKILL)
   281             except OSError, e:
   282                 pass
   283 
   284             try:
   285                 self.gmyth.wait()
   286             except Exception, e:
   287                 pass
   288 
   289             self.gmyth = None
   290 
   291     # stop()
   292 
   293 # TranscoderMencoder