gmyth-stream/server/plugins/media/mencoder.py
author melunko
Wed Apr 11 21:20:44 2007 +0100 (2007-04-11)
branchtrunk
changeset 526 c65fa0ad8e5a
parent 514 b5352888e3c2
child 533 e55310730feb
permissions -rw-r--r--
[svn r531] Some fixes in the scheduling
     1 import os
     2 import sys
     3 import lib
     4 import time
     5 import shlex
     6 import signal
     7 import socket
     8 import ConfigParser
     9 import logging as log
    10 
    11 from select import *
    12 from subprocess import *
    13 
    14 class Media(object):
    15 
    16     def __init__(self, config):
    17 
    18         self.config = config
    19         self.path = ""
    20         self.args = []
    21         self.language = None
    22         self.subtitle = None
    23         self.mpegopts = None
    24         self.socket = None
    25         self.child_pid = None
    26         self.mplayer = None
    27         self.mencoder_pid = None
    28         self.mplayer_pid = None
    29 
    30     # __init__
    31 
    32     def setup_opts(self, options):
    33 
    34         for opt in options:
    35 
    36             if opt == "local":
    37                 self.mplayer = lib.which("mplayer")
    38 
    39             elif opt.find("language=") >= 0:
    40                 try:
    41                     lan = opt.split("=")[1]
    42                     if len(lan) < 2:
    43                         self.language = lan
    44                 except Exception, e:
    45                     log.error("Bad language option: %s" % e)
    46 
    47             elif opt.find("subtitle=") >= 0:
    48                 try:
    49                     sub = opt.split("=")[1]
    50                     if len(sub) < 2:
    51                         self.language = sub
    52                 except Exception, e:
    53                     log.error("Bad subtitle option: %s" % e)
    54 
    55             elif opt.find("format=") >= 0:
    56                 try:
    57                     self.mpegopts = opt.split("=")[1]
    58                 except Exception, e:
    59                     log.error("Bad format option: %s" % e)
    60 
    61     # setup_opts
    62 
    63     def run_mplayer(self):
    64         msg = self.filename
    65 
    66         if self.kind == "dvd":
    67             msg = "dvd://" + msg
    68 
    69         self.mplayer_pid = Popen([self.mplayer, self.filename, "1> %s" % os.devnull,\
    70                                   "2> %s" % os.devnull], stdout=PIPE, close_fds=True)
    71 
    72     # run_mplayer
    73 
    74     def setup_mencoder(self):
    75         self.path = self.config.get("Mencoder", "path")
    76         mp = Popen([self.path], stdout=PIPE, close_fds=True)
    77 
    78         version = mp.stdout.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]
    79 
    80         if version > "4.1.1": self.mencoder_old = False
    81         else: self.mencoder_old = True
    82 
    83         os.kill(mp.pid, signal.SIGKILL)
    84         log.info("Mencoder version: %s" % version)
    85 
    86         if self.mencoder_old:
    87             try:
    88                 self.fifo = self.config.get("Mencoder", "fifo_path")
    89                 os.mkfifo(self.fifo)
    90             except Exception, e:
    91                 log.info("Fifo: %s" % e)
    92         else:
    93             self.fifo = "-"
    94 
    95     # setup_mencoder
    96 
    97     def setup_audio(self):
    98 
    99         if self.acodec == "mp3lame":
   100             return "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
   101         else:
   102             return "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
   103                 self.acodec, self.abitrate)
   104 
   105     # setup_audio
   106 
   107 
   108     def setup_video(self):
   109 
   110         video = ""
   111 
   112         video += " -of %s" % self.mux
   113         video += " -ofps %s" % self.fps
   114 
   115         if self.vcodec == "nuv" or self.vcodec == "xvid"\
   116                or self.vcodec == "qtvideo" or self.vcodec == "copy":
   117             video += " -ovc %s" % self.vcodec
   118         else:
   119             video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
   120                 self.vcodec, self.vbitrate)
   121 
   122         if self.mux == "mpeg" and self.mpegopts is not None:
   123             video += " -mpegopts format=%s" % self.mpegopts
   124 
   125         video += " -vf scale=%s:%s" % (self.width, self.height)
   126 
   127         return video
   128 
   129     # setup_video
   130 
   131 
   132     def arg_append(self, args, options):
   133         l = shlex.split(options)
   134         for i in l:
   135             args.append(i)
   136 
   137     # arg_append
   138 
   139     def setup_args(self, args):
   140 
   141         args.append(self.path)
   142         args.append(self.filename)
   143 
   144         if self.language != None:
   145             self.arg_append(args, "-alang %s" % self.language)
   146 
   147         if self.subtitle != None:
   148             self.arg_append(args, "-slang %s" % self.subtitle)
   149             self.arg_append(args, "-subfps %s" % self.fps)
   150 
   151         self.arg_append(args, "-idx")
   152         self.arg_append(args, self.audio_opts)
   153         self.arg_append(args, self.video_opts)
   154 
   155         self.arg_append(args, "-really-quiet")
   156         self.arg_append(args, "-o %s" % self.fifo)
   157         self.arg_append(args, "2> %s" % os.devnull)
   158 
   159     # setup_args
   160 
   161     def setup_filename(self, filename):
   162         try:
   163             self.kind, self.filename = filename.split("://")
   164         except:
   165             return (False, "Wrong filename protocol")
   166 
   167         if self.kind == "file":
   168             if not os.path.exists(self.filename):
   169                 msg = "File requested does not exist. SETUP failed."
   170                 log.error(msg)
   171                 return (False, msg)
   172 
   173         elif self.kind == "dvd":
   174             self.filename = "dvd://" + filename
   175 
   176         return (True, "")
   177 
   178     # setup_filename
   179 
   180     def setup_socket(self):
   181         if self.socket != None:
   182             del(self.socket)
   183 
   184         self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   185         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   186 
   187         try:
   188             self.socket.bind( ('', self.port) )
   189             self.socket.listen(1)
   190         except Exception, e:
   191             log.error("Could not create socket: %s" % e)
   192             return (False, e)
   193 
   194         return (True, "")
   195 
   196     # setup_socket
   197 
   198     '''
   199     MENCODER SETUP DESCRIPTION
   200     ===========================
   201 
   202     -> mux, vcodecs and acodecs
   203      |-> mencoder (-of | -ovc | -oac) help
   204 
   205     -> if used mpeg as mux:
   206      |-> to setup format: format=%s as an option at the end
   207 
   208     '''
   209 
   210 
   211     # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240
   212     # file:///tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 format=mpeg1
   213     # dvd://4 mpeg mpeg1video 400 25 mp3lame 192 400 240 language=en local
   214     # file:///tmp/mpg/bad_day.mpg avi mpeg4 400 25 mp3 192 320 240
   215 
   216     def setup(self, filename, mux, vcodec, vbitrate,\
   217               fps, acodec, abitrate, width, height, port, options):
   218 
   219         self.mux = mux
   220         self.vcodec = vcodec
   221         self.vbitrate = vbitrate
   222         self.fps = fps
   223         self.acodec = acodec
   224         self.abitrate = abitrate
   225         self.width = width
   226         self.height = height
   227         self.port = int(port)
   228 
   229         self.setup_mencoder()
   230 
   231         ret_val = self.setup_filename(filename)
   232         if not ret_val[0]:
   233             return ret_val[1]
   234 
   235         self.setup_opts(options)
   236         self.audio_opts = self.setup_audio()
   237         self.video_opts = self.setup_video()
   238         self.setup_args(self.args)
   239 
   240         ret_val = self.setup_socket()
   241         if not ret_val[0]:
   242             return ret_val[1]
   243 
   244         return True
   245 
   246     # setup
   247 
   248     def play(self):
   249 
   250         log.info("Starting Mencoder: %s" % self.args )
   251 
   252         try:
   253             self.mencoder_pid = Popen(self.args, stdout=PIPE, close_fds=True)
   254         except Exception, e:
   255             msg = "Could not init Mencoder: %s" % e
   256             log.error(msg)
   257             return msg
   258 
   259         if self.mencoder_old: self.pout = open(self.fifo)
   260         else: self.pout = self.mencoder_pid.stdout
   261 
   262         self.child_pid = os.fork()
   263 
   264         if self.child_pid == 0:
   265             conn, addr = self.socket.accept()
   266             log.info("Sending Data to client: %s" % addr[0])
   267 
   268             data = self.pout.read(4096)
   269 
   270             conn.settimeout(5)
   271             retry = 0
   272 
   273             while data != "" and retry < 5:
   274                 try:
   275                     conn.send(data)
   276                     r, w, x = select([conn], [], [], 0)
   277                     if conn in r:
   278                         back = conn.recv(1024)
   279                         if back == "OK" and self.mplayer and not self.mplayer_pid:
   280                             self.run_mplayer()
   281 
   282                 except socket.error, e:
   283                     log.error("Socket error: %s" % e)
   284                     retry += 1
   285 
   286                 data = self.pout.read(4096)
   287 
   288             if retry < 5:
   289                 log.info("Finished sending Data to client: %s" % addr[0])
   290             else:
   291                 log.error("Client timed out, retried more than %s times" % retry)
   292 
   293             os.kill(self.mencoder_pid.pid, signal.SIGKILL)
   294             sys.exit(0)
   295 
   296         return True
   297 
   298         # play
   299 
   300 
   301     def stop(self):
   302         try:
   303 
   304             if self.mencoder_pid:
   305                 os.kill(self.mencoder_pid.pid, signal.SIGKILL)
   306                 self.mencoder_pid = None
   307 
   308             if self.mplayer_pid:
   309                 os.kill(self.mplayer_pid.pid, signal.SIGKILL)
   310                 self.mplayer_pid = None
   311 
   312             if self.socket != None:
   313                 self.socket.close()
   314 
   315             if self.child_pid != None:
   316                 os.kill(self.child_pid, signal.SIGKILL)
   317 
   318         except Exception, e:
   319             log.error("Stop error: %s" % e)
   320 
   321     # stop