renatofilho@484: import os renatofilho@484: import sys renatofilho@484: import lib renatofilho@484: import time morphbr@516: import shlex renatofilho@484: import signal renatofilho@484: import socket renatofilho@484: import ConfigParser morphbr@516: import logging as log 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@516: self.path = "" morphbr@516: self.args = [] morphbr@516: self.language = None morphbr@516: self.subtitle = None morphbr@516: self.mpegopts = None 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: morphbr@514: # __init__ morphbr@514: morphbr@516: def setup_opts(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: morphbr@516: lan = opt.split("=")[1] morphbr@516: if len(lan) < 2: morphbr@516: self.language = lan morphbr@516: except Exception, e: morphbr@516: log.error("Bad language option: %s" % e) morphbr@516: morphbr@516: elif opt.find("subtitle=") >= 0: morphbr@516: try: morphbr@516: sub = opt.split("=")[1] morphbr@516: if len(sub) < 2: morphbr@516: self.language = sub morphbr@516: except Exception, e: morphbr@516: log.error("Bad subtitle option: %s" % e) renatofilho@484: morphbr@497: elif opt.find("format=") >= 0: morphbr@497: try: morphbr@516: self.mpegopts = opt.split("=")[1] morphbr@516: except Exception, e: morphbr@516: log.error("Bad format option: %s" % e) morphbr@497: morphbr@516: # setup_opts renatofilho@484: renatofilho@484: def run_mplayer(self): morphbr@514: msg = self.filename morphbr@497: morphbr@498: if self.kind == "dvd": renatofilho@484: msg = "dvd://" + msg renatofilho@484: morphbr@514: self.mplayer_pid = Popen([self.mplayer, self.filename, "1> %s" % os.devnull,\ morphbr@514: "2> %s" % os.devnull], stdout=PIPE, close_fds=True) morphbr@514: morphbr@514: # run_mplayer morphbr@514: morphbr@504: def setup_mencoder(self): morphbr@499: self.path = self.config.get("Mencoder", "path") morphbr@514: mp = Popen([self.path], stdout=PIPE, close_fds=True) morphbr@514: morphbr@514: version = mp.stdout.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@514: os.kill(mp.pid, signal.SIGKILL) morphbr@514: log.info("Mencoder version: %s" % version) morphbr@499: morphbr@499: if self.mencoder_old: morphbr@516: try: morphbr@516: self.fifo = self.config.get("Mencoder", "fifo_path") morphbr@516: os.mkfifo(self.fifo) morphbr@516: except Exception, e: morphbr@516: log.info("Fifo: %s" % e) morphbr@499: else: morphbr@499: self.fifo = "-" renatofilho@484: morphbr@514: # setup_mencoder morphbr@514: morphbr@516: def setup_audio(self): morphbr@514: morphbr@516: if self.acodec == "mp3lame": morphbr@514: return "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate morphbr@514: else: morphbr@516: return "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\ morphbr@514: self.acodec, self.abitrate) morphbr@514: morphbr@516: # setup_audio morphbr@516: morphbr@516: morphbr@516: def setup_video(self): morphbr@516: morphbr@516: video = "" morphbr@516: morphbr@516: video += " -of %s" % self.mux morphbr@516: video += " -ofps %s" % self.fps morphbr@516: morphbr@516: if self.vcodec == "nuv" or self.vcodec == "xvid"\ morphbr@516: or self.vcodec == "qtvideo" or self.vcodec == "copy": morphbr@516: video += " -ovc %s" % self.vcodec morphbr@516: else: morphbr@516: video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % ( morphbr@516: self.vcodec, self.vbitrate) morphbr@516: morphbr@516: if self.mux == "mpeg" and self.mpegopts is not None: morphbr@516: video += " -mpegopts format=%s" % self.mpegopts morphbr@516: morphbr@516: video += " -vf scale=%s:%s" % (self.width, self.height) morphbr@516: morphbr@516: return video morphbr@516: morphbr@516: # setup_video morphbr@516: morphbr@516: morphbr@516: def arg_append(self, args, options): morphbr@516: l = shlex.split(options) morphbr@516: for i in l: morphbr@516: args.append(i) morphbr@516: morphbr@516: # arg_append morphbr@516: morphbr@516: def setup_args(self, args): morphbr@516: morphbr@516: args.append(self.path) morphbr@516: args.append(self.filename) morphbr@516: morphbr@516: if self.language != None: morphbr@516: self.arg_append(args, "-alang %s" % self.language) morphbr@516: morphbr@516: if self.subtitle != None: morphbr@516: self.arg_append(args, "-slang %s" % self.subtitle) morphbr@516: self.arg_append(args, "-subfps %s" % self.fps) morphbr@516: morphbr@516: self.arg_append(args, "-idx") morphbr@516: self.arg_append(args, self.audio_opts) morphbr@516: self.arg_append(args, self.video_opts) morphbr@516: morphbr@516: self.arg_append(args, "-really-quiet") morphbr@516: self.arg_append(args, "-o %s" % self.fifo) morphbr@516: self.arg_append(args, "2> %s" % os.devnull) morphbr@516: morphbr@516: # setup_args morphbr@516: 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.kind == "file": morphbr@504: if not os.path.exists(self.filename): morphbr@504: msg = "File requested does not exist. SETUP failed." morphbr@514: log.error(msg) morphbr@504: return (False, msg) morphbr@504: morphbr@504: elif self.kind == "dvd": morphbr@516: self.filename = "dvd://" + filename morphbr@504: morphbr@504: return (True, "") morphbr@504: morphbr@514: # setup_filename morphbr@514: morphbr@516: def setup_socket(self): morphbr@516: if self.socket != None: morphbr@516: del(self.socket) morphbr@514: morphbr@516: self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) morphbr@516: self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) morphbr@514: morphbr@514: try: morphbr@516: self.socket.bind( ('', self.port) ) morphbr@516: self.socket.listen(1) morphbr@514: except Exception, e: morphbr@514: log.error("Could not create socket: %s" % e) morphbr@514: return (False, e) morphbr@514: morphbr@514: return (True, "") morphbr@514: morphbr@516: # setup_socket morphbr@516: 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@516: morphbr@516: # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240 morphbr@516: # file:///tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 format=mpeg1 morphbr@516: # dvd://4 mpeg mpeg1video 400 25 mp3lame 192 400 240 language=en local morphbr@516: # file:///tmp/mpg/bad_day.mpg avi mpeg4 400 25 mp3 192 320 240 morphbr@516: 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@516: morphbr@504: ret_val = self.setup_filename(filename) morphbr@504: if not ret_val[0]: morphbr@504: return ret_val[1] morphbr@504: morphbr@516: self.setup_opts(options) morphbr@516: self.audio_opts = self.setup_audio() morphbr@516: self.video_opts = self.setup_video() morphbr@516: self.setup_args(self.args) renatofilho@484: morphbr@516: ret_val = self.setup_socket() morphbr@514: if not ret_val[0]: morphbr@514: return ret_val[1] renatofilho@484: morphbr@514: return True renatofilho@484: morphbr@514: # setup renatofilho@484: renatofilho@484: def play(self): renatofilho@484: morphbr@516: log.info("Starting Mencoder: %s" % self.args ) morphbr@499: morphbr@516: try: morphbr@516: self.mencoder_pid = Popen(self.args, stdout=PIPE, close_fds=True) morphbr@516: except Exception, e: morphbr@516: msg = "Could not init Mencoder: %s" % e morphbr@516: log.error(msg) morphbr@516: return msg renatofilho@484: morphbr@516: if self.mencoder_old: self.pout = open(self.fifo) morphbr@516: else: self.pout = self.mencoder_pid.stdout renatofilho@484: renatofilho@484: self.child_pid = os.fork() renatofilho@484: morphbr@498: if self.child_pid == 0: morphbr@516: conn, addr = self.socket.accept() morphbr@516: log.info("Sending Data to client: %s" % addr[0]) renatofilho@484: morphbr@516: data = self.pout.read(4096) 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: morphbr@516: except socket.error, e: morphbr@516: log.error("Socket error: %s" % e) renatofilho@484: retry += 1 renatofilho@484: morphbr@516: data = self.pout.read(4096) renatofilho@484: morphbr@497: if retry < 5: morphbr@516: log.info("Finished sending Data to client: %s" % addr[0]) renatofilho@484: else: morphbr@516: log.error("Client timed out, retried more than %s times" % retry) renatofilho@484: morphbr@516: os.kill(self.mencoder_pid.pid, signal.SIGKILL) renatofilho@484: sys.exit(0) renatofilho@484: morphbr@516: return True morphbr@516: morphbr@516: # play morphbr@516: renatofilho@484: renatofilho@484: def stop(self): renatofilho@484: try: renatofilho@484: morphbr@516: if self.mencoder_pid: morphbr@516: os.kill(self.mencoder_pid.pid, signal.SIGKILL) morphbr@516: self.mencoder_pid = None renatofilho@484: morphbr@516: if self.mplayer_pid: morphbr@516: os.kill(self.mplayer_pid.pid, signal.SIGKILL) morphbr@516: self.mplayer_pid = None morphbr@516: morphbr@516: if self.socket != None: morphbr@516: self.socket.close() morphbr@516: morphbr@498: if self.child_pid != None: morphbr@516: os.kill(self.child_pid, signal.SIGKILL) morphbr@516: morphbr@516: except Exception, e: morphbr@516: log.error("Stop error: %s" % e) morphbr@516: morphbr@516: # stop