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