renatofilho@484: import os
renatofilho@484: import sys
renatofilho@484: import lib
renatofilho@484: import time
renatofilho@484: import signal
renatofilho@484: import socket
renatofilho@484: import ConfigParser
renatofilho@484: 
renatofilho@484: from select import *
renatofilho@484: from subprocess import *
renatofilho@484: 
morphbr@497: class Media(object):
renatofilho@484: 
renatofilho@484:     def __init__(self, config):
renatofilho@484: 
renatofilho@484:         self.config = config
morphbr@504:         self.args = ""
renatofilho@484:         self.language = "en"
renatofilho@484:         self.socket = None
renatofilho@484:         self.child_pid = None
renatofilho@484:         self.mplayer = None
renatofilho@484:         self.mencoder_pid = None
renatofilho@484:         self.mplayer_pid = None
renatofilho@484:         signal.signal(signal.SIGABRT, self.kill_handler)
renatofilho@484: 
renatofilho@484:     def kill_handler(self, sig, frame):
renatofilho@484:         try:
renatofilho@484:             os.kill(self.mplayer_pid.pid + 1, signal.SIGKILL)
renatofilho@484:             sys.exit(0)
renatofilho@484:         except:
renatofilho@484:             lib.log("Problems closing child")
renatofilho@484: 
renatofilho@484:     def set_args(self, options):
renatofilho@484: 
renatofilho@484:         for opt in options:
renatofilho@484: 
morphbr@504:             if opt == "local":
morphbr@511:                 self.mplayer = lib.which("mplayer")
renatofilho@484: 
morphbr@497:             elif opt.find("language=") >= 0:
renatofilho@484:                 try:
renatofilho@484:                     self.language = opt.split("=")[1]
renatofilho@484:                 except:
renatofilho@484:                     lib.log("Bad language option")
renatofilho@484: 
morphbr@497:             elif opt.find("format=") >= 0:
morphbr@497:                 try:
morphbr@497:                     self.mux += " -mpegopts format=%s" % opt.split("=")[1]
morphbr@497:                 except:
morphbr@497:                     lib.log("Bad format option")
morphbr@497: 
renatofilho@484: 
renatofilho@484:     def run_mplayer(self):
renatofilho@484:         msg = "%s 1>/dev/null 2>/dev/null" % self.filename
morphbr@497: 
morphbr@498:         if self.kind == "dvd":
renatofilho@484:             msg = "dvd://" + msg
renatofilho@484: 
renatofilho@484:         self.mplayer += " " + msg
morphbr@511:         self.mplayer_pid = Popen(self.mplayer, shell=True, close_fds=True)
renatofilho@484: 
morphbr@504:     def setup_mencoder(self):
morphbr@499:         self.path = self.config.get("Mencoder", "path")
morphbr@499:         a, b = os.popen2(self.path)
morphbr@499:         version = b.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]
morphbr@499: 
morphbr@499:         if version > "4.1.1": self.mencoder_old = False
morphbr@499:         else: self.mencoder_old = True
morphbr@499: 
morphbr@504:         lib.log("Mencoder version: %s" % version)
morphbr@504: 
morphbr@499:         a.close()
morphbr@499:         b.close()
morphbr@499: 
morphbr@499:         if self.mencoder_old:
morphbr@499:             self.fifo = self.config.get("Mencoder", "fifo_path")
morphbr@499:         else:
morphbr@499:             self.fifo = "-"
renatofilho@484: 
morphbr@504:     def setup_filename(self, filename):
morphbr@504:         try:
morphbr@504:             self.kind, self.filename = filename.split("://")
morphbr@504:         except:
morphbr@504:             return (False, "Wrong filename protocol")
morphbr@504: 
morphbr@504:         if self.acodec == "mp3lame":
morphbr@504:             audio = "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
morphbr@504:         else:
morphbr@504:             audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
morphbr@504:                     self.acodec, self.abitrate)
morphbr@504: 
morphbr@504:         if self.kind == "file":
morphbr@504:             if not os.path.exists(self.filename):
morphbr@504:                 msg = "File requested does not exist. SETUP failed."
morphbr@504:                 lib.log(msg)
morphbr@504:                 return (False, msg)
morphbr@504: 
morphbr@504:             self.args += " %s -mf fps=%s -of %s %s"\
morphbr@504:                          " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s -vf scale=%s:%s"\
morphbr@504:                          " -really-quiet -o %s 2>/dev/null" % (
morphbr@504:                 self.filename, self.fps, self.mux, audio, self.vcodec,
morphbr@504:                 self.vbitrate, self.width, self.height, self.fifo)
morphbr@504: 
morphbr@504:         elif self.kind == "dvd":
morphbr@504:             self.args += " dvd://%s -alang %s -vf scale=%s:%s %s"\
morphbr@504:                          " -of %s -ovc lavc -lavcopts vcodec=%s:vbitrate=%s"\
morphbr@504:                          " -ofps %s -really-quiet -o %s 2>/dev/null" % (
morphbr@504:                 self.filename, self.language, self.width, self.height, audio,
morphbr@504:                 self.mux, self.vcodec, self.vbitrate, self.fps, self.fifo)
morphbr@504: 
morphbr@504:         return (True, "")
morphbr@504: 
morphbr@504:     '''
morphbr@504:     MENCODER SETUP DESCRIPTION
morphbr@504:     ===========================
morphbr@504: 
morphbr@504:     -> mux, vcodecs and acodecs
morphbr@504:      |-> mencoder (-of | -ovc | -oac) help
morphbr@504: 
morphbr@504:     -> if used mpeg as mux:
morphbr@504:      |-> to setup format: format=%s as an option at the end
morphbr@504: 
morphbr@504:     '''
morphbr@504: 
morphbr@504:     def setup(self, filename, mux, vcodec, vbitrate,\
morphbr@504:               fps, acodec, abitrate, width, height, port, options):
morphbr@504: 
morphbr@504:         self.mux = mux
morphbr@504:         self.vcodec = vcodec
morphbr@504:         self.vbitrate = vbitrate
morphbr@504:         self.fps = fps
morphbr@504:         self.acodec = acodec
morphbr@504:         self.abitrate = abitrate
morphbr@504:         self.width = width
morphbr@504:         self.height = height
morphbr@504:         self.port = int(port)
morphbr@504: 
morphbr@504:         self.setup_mencoder()
morphbr@504:         ret_val = self.setup_filename(filename)
morphbr@504: 
morphbr@504:         if not ret_val[0]:
morphbr@504:             return ret_val[1]
morphbr@504: 
renatofilho@484:         self.set_args(options)
renatofilho@484: 
morphbr@498:         # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240 5000 file
morphbr@504:         # /tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 5000 format=mpeg1 file
morphbr@497:         #4 mpeg mpeg1video 400 25 mp3lame 192 400 240 5000 language=en local dvd
morphbr@498:         if self.socket != None:
renatofilho@484:             del(self.socket)
renatofilho@484: 
renatofilho@484:         self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
renatofilho@484:         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
renatofilho@484:         self.socket.bind( ('', self.port) )
renatofilho@484:         self.socket.listen(1)
renatofilho@484: 
renatofilho@484:         return 0
renatofilho@484: 
renatofilho@484: 
renatofilho@484:     def play(self):
renatofilho@484: 
morphbr@499:         if self.mencoder_old:
morphbr@499:             try:
morphbr@499:                 os.mkfifo(self.fifo)
morphbr@499:             except:
morphbr@499:                 lib.log("Fifo already exists")
morphbr@499: 
renatofilho@484: 
renatofilho@484:         lib.log("Starting Mencoder: %s %s" % (self.path, self.args) )
renatofilho@484:         # exec Mencoder
morphbr@499:         if self.mencoder_old:
morphbr@511:             self.mencoder_pid = Popen(self.path + self.args, shell=True,
morphbr@511:                                       close_fds=True)
morphbr@504:             self.pout = open(self.fifo)
morphbr@499:         else:
morphbr@499:             self.path += self.args
morphbr@499:             pin, self.pout = os.popen2(self.path)
renatofilho@484: 
renatofilho@484:         self.child_pid = os.fork()
renatofilho@484: 
morphbr@498:         if self.child_pid == 0:
renatofilho@484:             conn,addr= self.socket.accept()
renatofilho@484:             lib.log("Sending Data to client: %s" % addr[0])
renatofilho@484: 
morphbr@499:             data = self.pout.read(1024)
morphbr@499: 
renatofilho@484:             conn.settimeout(5)
renatofilho@484:             retry = 0
renatofilho@484: 
morphbr@498:             while data != "" and retry < 5:
renatofilho@484:                 try:
renatofilho@484:                     conn.send(data)
renatofilho@484:                     r, w, x = select([conn], [], [], 0)
renatofilho@484:                     if conn in r:
renatofilho@484:                         back = conn.recv(1024)
morphbr@498:                         if back == "OK" and self.mplayer and not self.mplayer_pid:
renatofilho@484:                             self.run_mplayer()
renatofilho@484: 
renatofilho@484:                 except socket.error:
renatofilho@484:                     lib.log("Socket error (maybe timeout ?)")
renatofilho@484:                     retry += 1
renatofilho@484: 
morphbr@499:                 data = self.pout.read(1024)
renatofilho@484: 
morphbr@497:             if retry < 5:
renatofilho@484:                 lib.log("Finished sending Data to client: %s" % addr[0])
renatofilho@484:             else:
renatofilho@484:                 lib.log("Client timed out")
renatofilho@484: 
renatofilho@484:             sys.exit(0)
renatofilho@484: 
renatofilho@484: 
renatofilho@484:     def stop(self):
renatofilho@484:         try:
morphbr@499:             if self.mplayer_old:
morphbr@499:                 os.kill(self.mencoder_pid.pid + 1, signal.SIGKILL)
morphbr@499:             else:
morphbr@499:                 self.pout.close()
renatofilho@484:             self.mplayer = None
renatofilho@484:         except:
renatofilho@484:             lib.log("Trying to stop before playing...")
renatofilho@484: 
morphbr@498:         if self.socket != None:
renatofilho@484:             lib.log("Closing socket")
renatofilho@484:             self.socket.close()
renatofilho@484: 
renatofilho@484:             lib.log("Trying to stop Mencoder process")
morphbr@498:             if self.child_pid != None:
renatofilho@484:                 os.kill(self.child_pid, signal.SIGABRT)