gmyth-stream/server/plugins/media/mencoder.py
branchtrunk
changeset 530 ad51640dd2cd
parent 514 b5352888e3c2
child 533 e55310730feb
     1.1 --- a/gmyth-stream/server/plugins/media/mencoder.py	Mon Apr 09 16:22:37 2007 +0100
     1.2 +++ b/gmyth-stream/server/plugins/media/mencoder.py	Thu Apr 12 14:58:13 2007 +0100
     1.3 @@ -2,9 +2,11 @@
     1.4  import sys
     1.5  import lib
     1.6  import time
     1.7 +import shlex
     1.8  import signal
     1.9  import socket
    1.10  import ConfigParser
    1.11 +import logging as log
    1.12  
    1.13  from select import *
    1.14  from subprocess import *
    1.15 @@ -14,28 +16,20 @@
    1.16      def __init__(self, config):
    1.17  
    1.18          self.config = config
    1.19 -        self.args = ""
    1.20 -        self.language = "en"
    1.21 +        self.path = ""
    1.22 +        self.args = []
    1.23 +        self.language = None
    1.24 +        self.subtitle = None
    1.25 +        self.mpegopts = None
    1.26          self.socket = None
    1.27          self.child_pid = None
    1.28          self.mplayer = None
    1.29          self.mencoder_pid = None
    1.30          self.mplayer_pid = None
    1.31 -        signal.signal(signal.SIGABRT, self.kill_handler)
    1.32  
    1.33      # __init__
    1.34  
    1.35 -    def kill_handler(self, sig, frame):
    1.36 -        try:
    1.37 -            os.kill(self.mplayer_pid.pid, signal.SIGKILL)
    1.38 -            log.debug("Killed Mplayer")
    1.39 -            sys.exit(0)
    1.40 -        except:
    1.41 -            log.error("Problems closing child")
    1.42 -
    1.43 -    # kill_handler
    1.44 -
    1.45 -    def set_args(self, options):
    1.46 +    def setup_opts(self, options):
    1.47  
    1.48          for opt in options:
    1.49  
    1.50 @@ -44,17 +38,27 @@
    1.51  
    1.52              elif opt.find("language=") >= 0:
    1.53                  try:
    1.54 -                    self.language = opt.split("=")[1]
    1.55 -                except:
    1.56 -                    log.error("Bad language option")
    1.57 +                    lan = opt.split("=")[1]
    1.58 +                    if len(lan) < 2:
    1.59 +                        self.language = lan
    1.60 +                except Exception, e:
    1.61 +                    log.error("Bad language option: %s" % e)
    1.62 +
    1.63 +            elif opt.find("subtitle=") >= 0:
    1.64 +                try:
    1.65 +                    sub = opt.split("=")[1]
    1.66 +                    if len(sub) < 2:
    1.67 +                        self.language = sub
    1.68 +                except Exception, e:
    1.69 +                    log.error("Bad subtitle option: %s" % e)
    1.70  
    1.71              elif opt.find("format=") >= 0:
    1.72                  try:
    1.73 -                    self.mux += " -mpegopts format=%s" % opt.split("=")[1]
    1.74 -                except:
    1.75 -                    log.error("Bad format option")
    1.76 +                    self.mpegopts = opt.split("=")[1]
    1.77 +                except Exception, e:
    1.78 +                    log.error("Bad format option: %s" % e)
    1.79  
    1.80 -    # set_args
    1.81 +    # setup_opts
    1.82  
    1.83      def run_mplayer(self):
    1.84          msg = self.filename
    1.85 @@ -67,7 +71,6 @@
    1.86  
    1.87      # run_mplayer
    1.88  
    1.89 -
    1.90      def setup_mencoder(self):
    1.91          self.path = self.config.get("Mencoder", "path")
    1.92          mp = Popen([self.path], stdout=PIPE, close_fds=True)
    1.93 @@ -81,67 +84,117 @@
    1.94          log.info("Mencoder version: %s" % version)
    1.95  
    1.96          if self.mencoder_old:
    1.97 -            self.fifo = self.config.get("Mencoder", "fifo_path")
    1.98 +            try:
    1.99 +                self.fifo = self.config.get("Mencoder", "fifo_path")
   1.100 +                os.mkfifo(self.fifo)
   1.101 +            except Exception, e:
   1.102 +                log.info("Fifo: %s" % e)
   1.103          else:
   1.104              self.fifo = "-"
   1.105  
   1.106      # setup_mencoder
   1.107  
   1.108 -    def setup_audio(self, acodec):
   1.109 +    def setup_audio(self):
   1.110  
   1.111 -        if acodec == "mp3lame":
   1.112 +        if self.acodec == "mp3lame":
   1.113              return "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
   1.114          else:
   1.115 -            return = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
   1.116 +            return "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
   1.117                  self.acodec, self.abitrate)
   1.118  
   1.119 +    # setup_audio
   1.120 +
   1.121 +
   1.122 +    def setup_video(self):
   1.123 +
   1.124 +        video = ""
   1.125 +
   1.126 +        video += " -of %s" % self.mux
   1.127 +        video += " -ofps %s" % self.fps
   1.128 +
   1.129 +        if self.vcodec == "nuv" or self.vcodec == "xvid"\
   1.130 +               or self.vcodec == "qtvideo" or self.vcodec == "copy":
   1.131 +            video += " -ovc %s" % self.vcodec
   1.132 +        else:
   1.133 +            video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
   1.134 +                self.vcodec, self.vbitrate)
   1.135 +
   1.136 +        if self.mux == "mpeg" and self.mpegopts is not None:
   1.137 +            video += " -mpegopts format=%s" % self.mpegopts
   1.138 +
   1.139 +        video += " -vf scale=%s:%s" % (self.width, self.height)
   1.140 +
   1.141 +        return video
   1.142 +
   1.143 +    # setup_video
   1.144 +
   1.145 +
   1.146 +    def arg_append(self, args, options):
   1.147 +        l = shlex.split(options)
   1.148 +        for i in l:
   1.149 +            args.append(i)
   1.150 +
   1.151 +    # arg_append
   1.152 +
   1.153 +    def setup_args(self, args):
   1.154 +
   1.155 +        args.append(self.path)
   1.156 +        args.append(self.filename)
   1.157 +
   1.158 +        if self.language != None:
   1.159 +            self.arg_append(args, "-alang %s" % self.language)
   1.160 +
   1.161 +        if self.subtitle != None:
   1.162 +            self.arg_append(args, "-slang %s" % self.subtitle)
   1.163 +            self.arg_append(args, "-subfps %s" % self.fps)
   1.164 +
   1.165 +        self.arg_append(args, "-idx")
   1.166 +        self.arg_append(args, self.audio_opts)
   1.167 +        self.arg_append(args, self.video_opts)
   1.168 +
   1.169 +        self.arg_append(args, "-really-quiet")
   1.170 +        self.arg_append(args, "-o %s" % self.fifo)
   1.171 +        self.arg_append(args, "2> %s" % os.devnull)
   1.172 +
   1.173 +    # setup_args
   1.174 +
   1.175      def setup_filename(self, filename):
   1.176          try:
   1.177              self.kind, self.filename = filename.split("://")
   1.178          except:
   1.179              return (False, "Wrong filename protocol")
   1.180  
   1.181 -        audio = setup_audio(self.acodec)
   1.182 -
   1.183          if self.kind == "file":
   1.184              if not os.path.exists(self.filename):
   1.185                  msg = "File requested does not exist. SETUP failed."
   1.186                  log.error(msg)
   1.187                  return (False, msg)
   1.188  
   1.189 -            self.args += " %s -mf fps=%s -of %s %s"\
   1.190 -                         " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s -vf scale=%s:%s"\
   1.191 -                         " -really-quiet -o %s 2>/dev/null" % (
   1.192 -                self.filename, self.fps, self.mux, audio, self.vcodec,
   1.193 -                self.vbitrate, self.width, self.height, self.fifo)
   1.194 -
   1.195          elif self.kind == "dvd":
   1.196 -            self.args += " dvd://%s -alang %s -vf scale=%s:%s %s"\
   1.197 -                         " -of %s -ovc lavc -lavcopts vcodec=%s:vbitrate=%s"\
   1.198 -                         " -ofps %s -really-quiet -o %s 2>/dev/null" % (
   1.199 -                self.filename, self.language, self.width, self.height, audio,
   1.200 -                self.mux, self.vcodec, self.vbitrate, self.fps, self.fifo)
   1.201 +            self.filename = "dvd://" + filename
   1.202  
   1.203          return (True, "")
   1.204  
   1.205      # setup_filename
   1.206  
   1.207 -    def setup_socket(self, socket):
   1.208 -        if socket != None:
   1.209 -            del(socket)
   1.210 +    def setup_socket(self):
   1.211 +        if self.socket != None:
   1.212 +            del(self.socket)
   1.213  
   1.214 -        socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   1.215 -        socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   1.216 +        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   1.217 +        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   1.218  
   1.219          try:
   1.220 -            socket.bind( ('', self.port) )
   1.221 -            socket.listen(1)
   1.222 +            self.socket.bind( ('', self.port) )
   1.223 +            self.socket.listen(1)
   1.224          except Exception, e:
   1.225              log.error("Could not create socket: %s" % e)
   1.226              return (False, e)
   1.227  
   1.228          return (True, "")
   1.229  
   1.230 +    # setup_socket
   1.231 +
   1.232      '''
   1.233      MENCODER SETUP DESCRIPTION
   1.234      ===========================
   1.235 @@ -154,6 +207,12 @@
   1.236  
   1.237      '''
   1.238  
   1.239 +
   1.240 +    # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240
   1.241 +    # file:///tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 format=mpeg1
   1.242 +    # dvd://4 mpeg mpeg1video 400 25 mp3lame 192 400 240 language=en local
   1.243 +    # file:///tmp/mpg/bad_day.mpg avi mpeg4 400 25 mp3 192 320 240
   1.244 +
   1.245      def setup(self, filename, mux, vcodec, vbitrate,\
   1.246                fps, acodec, abitrate, width, height, port, options):
   1.247  
   1.248 @@ -168,18 +227,17 @@
   1.249          self.port = int(port)
   1.250  
   1.251          self.setup_mencoder()
   1.252 +
   1.253          ret_val = self.setup_filename(filename)
   1.254 -
   1.255          if not ret_val[0]:
   1.256              return ret_val[1]
   1.257  
   1.258 -        self.set_args(options)
   1.259 +        self.setup_opts(options)
   1.260 +        self.audio_opts = self.setup_audio()
   1.261 +        self.video_opts = self.setup_video()
   1.262 +        self.setup_args(self.args)
   1.263  
   1.264 -        # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240 5000 file
   1.265 -        # /tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 5000 format=mpeg1 file
   1.266 -        #4 mpeg mpeg1video 400 25 mp3lame 192 400 240 5000 language=en local dvd
   1.267 -        ret_val = setup_socket(self.socket)
   1.268 -
   1.269 +        ret_val = self.setup_socket()
   1.270          if not ret_val[0]:
   1.271              return ret_val[1]
   1.272  
   1.273 @@ -189,30 +247,25 @@
   1.274  
   1.275      def play(self):
   1.276  
   1.277 -        if self.mencoder_old:
   1.278 -            try:
   1.279 -                os.mkfifo(self.fifo)
   1.280 -            except:
   1.281 -                lib.log("Fifo already exists")
   1.282 +        log.info("Starting Mencoder: %s" % self.args )
   1.283  
   1.284 +        try:
   1.285 +            self.mencoder_pid = Popen(self.args, stdout=PIPE, close_fds=True)
   1.286 +        except Exception, e:
   1.287 +            msg = "Could not init Mencoder: %s" % e
   1.288 +            log.error(msg)
   1.289 +            return msg
   1.290  
   1.291 -        lib.log("Starting Mencoder: %s %s" % (self.path, self.args) )
   1.292 -        # exec Mencoder
   1.293 -        if self.mencoder_old:
   1.294 -            self.mencoder_pid = Popen(self.path + self.args, shell=True,
   1.295 -                                      close_fds=True)
   1.296 -            self.pout = open(self.fifo)
   1.297 -        else:
   1.298 -            self.path += self.args
   1.299 -            pin, self.pout = os.popen2(self.path)
   1.300 +        if self.mencoder_old: self.pout = open(self.fifo)
   1.301 +        else: self.pout = self.mencoder_pid.stdout
   1.302  
   1.303          self.child_pid = os.fork()
   1.304  
   1.305          if self.child_pid == 0:
   1.306 -            conn,addr= self.socket.accept()
   1.307 -            lib.log("Sending Data to client: %s" % addr[0])
   1.308 +            conn, addr = self.socket.accept()
   1.309 +            log.info("Sending Data to client: %s" % addr[0])
   1.310  
   1.311 -            data = self.pout.read(1024)
   1.312 +            data = self.pout.read(4096)
   1.313  
   1.314              conn.settimeout(5)
   1.315              retry = 0
   1.316 @@ -226,34 +279,43 @@
   1.317                          if back == "OK" and self.mplayer and not self.mplayer_pid:
   1.318                              self.run_mplayer()
   1.319  
   1.320 -                except socket.error:
   1.321 -                    lib.log("Socket error (maybe timeout ?)")
   1.322 +                except socket.error, e:
   1.323 +                    log.error("Socket error: %s" % e)
   1.324                      retry += 1
   1.325  
   1.326 -                data = self.pout.read(1024)
   1.327 +                data = self.pout.read(4096)
   1.328  
   1.329              if retry < 5:
   1.330 -                lib.log("Finished sending Data to client: %s" % addr[0])
   1.331 +                log.info("Finished sending Data to client: %s" % addr[0])
   1.332              else:
   1.333 -                lib.log("Client timed out")
   1.334 +                log.error("Client timed out, retried more than %s times" % retry)
   1.335  
   1.336 +            os.kill(self.mencoder_pid.pid, signal.SIGKILL)
   1.337              sys.exit(0)
   1.338  
   1.339 +        return True
   1.340 +
   1.341 +        # play
   1.342 +
   1.343  
   1.344      def stop(self):
   1.345          try:
   1.346 -            if self.mplayer_old:
   1.347 -                os.kill(self.mencoder_pid.pid + 1, signal.SIGKILL)
   1.348 -            else:
   1.349 -                self.pout.close()
   1.350 -            self.mplayer = None
   1.351 -        except:
   1.352 -            lib.log("Trying to stop before playing...")
   1.353  
   1.354 -        if self.socket != None:
   1.355 -            lib.log("Closing socket")
   1.356 -            self.socket.close()
   1.357 +            if self.mencoder_pid:
   1.358 +                os.kill(self.mencoder_pid.pid, signal.SIGKILL)
   1.359 +                self.mencoder_pid = None
   1.360  
   1.361 -            lib.log("Trying to stop Mencoder process")
   1.362 +            if self.mplayer_pid:
   1.363 +                os.kill(self.mplayer_pid.pid, signal.SIGKILL)
   1.364 +                self.mplayer_pid = None
   1.365 +
   1.366 +            if self.socket != None:
   1.367 +                self.socket.close()
   1.368 +
   1.369              if self.child_pid != None:
   1.370 -                os.kill(self.child_pid, signal.SIGABRT)
   1.371 +                os.kill(self.child_pid, signal.SIGKILL)
   1.372 +
   1.373 +        except Exception, e:
   1.374 +            log.error("Stop error: %s" % e)
   1.375 +
   1.376 +    # stop