gmyth-stream/server/plugins/media/mencoder.py
author morphbr
Wed Apr 04 23:30:44 2007 +0100 (2007-04-04)
branchtrunk
changeset 504 2b5355061b66
parent 499 9900800a8dd6
child 511 16312d0021cb
permissions -rw-r--r--
[svn r509] - GMyth-Streamer:
* default port changed to 50000
* increase port used for streaming when SETUP
* changed SETUP protocol
* switch command CLOSE to QUIT
     1 import os
     2 import sys
     3 import lib
     4 import time
     5 import signal
     6 import socket
     7 import ConfigParser
     8 
     9 from select import *
    10 from subprocess import *
    11 
    12 class Media(object):
    13 
    14     def __init__(self, config):
    15 
    16         self.config = config
    17         self.args = ""
    18         self.language = "en"
    19         self.socket = None
    20         self.child_pid = None
    21         self.mplayer = None
    22         self.mencoder_pid = None
    23         self.mplayer_pid = None
    24         signal.signal(signal.SIGABRT, self.kill_handler)
    25 
    26     def kill_handler(self, sig, frame):
    27         try:
    28             os.kill(self.mplayer_pid.pid + 1, signal.SIGKILL)
    29             sys.exit(0)
    30         except:
    31             lib.log("Problems closing child")
    32 
    33     def set_args(self, options):
    34 
    35         for opt in options:
    36 
    37             if opt == "local":
    38                 self.mplayer = os.popen("which mplayer").read().strip()
    39 
    40             elif opt.find("language=") >= 0:
    41                 try:
    42                     self.language = opt.split("=")[1]
    43                 except:
    44                     lib.log("Bad language option")
    45 
    46             elif opt.find("format=") >= 0:
    47                 try:
    48                     self.mux += " -mpegopts format=%s" % opt.split("=")[1]
    49                 except:
    50                     lib.log("Bad format option")
    51 
    52 
    53     def run_mplayer(self):
    54         msg = "%s 1>/dev/null 2>/dev/null" % self.filename
    55 
    56         if self.kind == "dvd":
    57             msg = "dvd://" + msg
    58 
    59         self.mplayer += " " + msg
    60         self.mplayer_pid = Popen(self.mplayer, shell=True)
    61 
    62     def setup_mencoder(self):
    63         self.path = self.config.get("Mencoder", "path")
    64         a, b = os.popen2(self.path)
    65         version = b.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]
    66 
    67         if version > "4.1.1": self.mencoder_old = False
    68         else: self.mencoder_old = True
    69 
    70         lib.log("Mencoder version: %s" % version)
    71 
    72         a.close()
    73         b.close()
    74 
    75         if self.mencoder_old:
    76             self.fifo = self.config.get("Mencoder", "fifo_path")
    77         else:
    78             self.fifo = "-"
    79 
    80     def setup_filename(self, filename):
    81         try:
    82             self.kind, self.filename = filename.split("://")
    83         except:
    84             return (False, "Wrong filename protocol")
    85 
    86         if self.acodec == "mp3lame":
    87             audio = "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
    88         else:
    89             audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
    90                     self.acodec, self.abitrate)
    91 
    92         if self.kind == "file":
    93             if not os.path.exists(self.filename):
    94                 msg = "File requested does not exist. SETUP failed."
    95                 lib.log(msg)
    96                 return (False, msg)
    97 
    98             self.args += " %s -mf fps=%s -of %s %s"\
    99                          " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s -vf scale=%s:%s"\
   100                          " -really-quiet -o %s 2>/dev/null" % (
   101                 self.filename, self.fps, self.mux, audio, self.vcodec,
   102                 self.vbitrate, self.width, self.height, self.fifo)
   103 
   104         elif self.kind == "dvd":
   105             self.args += " dvd://%s -alang %s -vf scale=%s:%s %s"\
   106                          " -of %s -ovc lavc -lavcopts vcodec=%s:vbitrate=%s"\
   107                          " -ofps %s -really-quiet -o %s 2>/dev/null" % (
   108                 self.filename, self.language, self.width, self.height, audio,
   109                 self.mux, self.vcodec, self.vbitrate, self.fps, self.fifo)
   110 
   111         return (True, "")
   112 
   113     '''
   114     MENCODER SETUP DESCRIPTION
   115     ===========================
   116 
   117     -> mux, vcodecs and acodecs
   118      |-> mencoder (-of | -ovc | -oac) help
   119 
   120     -> if used mpeg as mux:
   121      |-> to setup format: format=%s as an option at the end
   122 
   123     '''
   124 
   125     def setup(self, filename, mux, vcodec, vbitrate,\
   126               fps, acodec, abitrate, width, height, port, options):
   127 
   128         self.mux = mux
   129         self.vcodec = vcodec
   130         self.vbitrate = vbitrate
   131         self.fps = fps
   132         self.acodec = acodec
   133         self.abitrate = abitrate
   134         self.width = width
   135         self.height = height
   136         self.port = int(port)
   137 
   138         self.setup_mencoder()
   139         ret_val = self.setup_filename(filename)
   140 
   141         if not ret_val[0]:
   142             return ret_val[1]
   143 
   144         self.set_args(options)
   145 
   146         # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240 5000 file
   147         # /tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 5000 format=mpeg1 file
   148         #4 mpeg mpeg1video 400 25 mp3lame 192 400 240 5000 language=en local dvd
   149         if self.socket != None:
   150             del(self.socket)
   151 
   152         self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   153         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   154         self.socket.bind( ('', self.port) )
   155         self.socket.listen(1)
   156 
   157         return 0
   158 
   159 
   160     def play(self):
   161 
   162         if self.mencoder_old:
   163             try:
   164                 os.mkfifo(self.fifo)
   165             except:
   166                 lib.log("Fifo already exists")
   167 
   168 
   169         lib.log("Starting Mencoder: %s %s" % (self.path, self.args) )
   170         # exec Mencoder
   171         if self.mencoder_old:
   172             self.mencoder_pid = Popen(self.path + self.args, shell=True)
   173             self.pout = open(self.fifo)
   174         else:
   175             self.path += self.args
   176             pin, self.pout = os.popen2(self.path)
   177 
   178         self.child_pid = os.fork()
   179 
   180         if self.child_pid == 0:
   181             conn,addr= self.socket.accept()
   182             lib.log("Sending Data to client: %s" % addr[0])
   183 
   184             data = self.pout.read(1024)
   185 
   186             conn.settimeout(5)
   187             retry = 0
   188 
   189             while data != "" and retry < 5:
   190                 try:
   191                     conn.send(data)
   192                     r, w, x = select([conn], [], [], 0)
   193                     if conn in r:
   194                         back = conn.recv(1024)
   195                         if back == "OK" and self.mplayer and not self.mplayer_pid:
   196                             self.run_mplayer()
   197 
   198                 except socket.error:
   199                     lib.log("Socket error (maybe timeout ?)")
   200                     retry += 1
   201 
   202                 data = self.pout.read(1024)
   203 
   204             if retry < 5:
   205                 lib.log("Finished sending Data to client: %s" % addr[0])
   206             else:
   207                 lib.log("Client timed out")
   208 
   209             sys.exit(0)
   210 
   211 
   212     def stop(self):
   213         try:
   214             if self.mplayer_old:
   215                 os.kill(self.mencoder_pid.pid + 1, signal.SIGKILL)
   216             else:
   217                 self.pout.close()
   218             self.mplayer = None
   219         except:
   220             lib.log("Trying to stop before playing...")
   221 
   222         if self.socket != None:
   223             lib.log("Closing socket")
   224             self.socket.close()
   225 
   226             lib.log("Trying to stop Mencoder process")
   227             if self.child_pid != None:
   228                 os.kill(self.child_pid, signal.SIGABRT)