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