morphbr@577: import os morphbr@577: import shlex morphbr@577: import signal morphbr@577: import subprocess morphbr@595: import time morphbr@577: morphbr@565: import lib.utils as utils morphbr@565: import lib.server as server morphbr@565: morphbr@595: from select import select morphbr@595: morphbr@565: __all__ = ("TranscoderMencoder",) morphbr@565: morphbr@565: class TranscoderMencoder(server.Transcoder): morphbr@585: """Transcoder class that implements a transcoder using Mencoder""" morphbr@565: mencoder_path = utils.which("mencoder") morphbr@565: name = "mencoder" morphbr@565: priority = -1 morphbr@577: args = {} morphbr@577: proc = None morphbr@605: gmyth = None morphbr@565: morphbr@595: # only works with avi container morphbr@595: status = 0 morphbr@595: morphbr@569: def _setup_params(self): morphbr@569: params_first = self.params_first morphbr@569: morphbr@569: # general_opts morphbr@569: self.args["local"] = params_first("local", False) morphbr@569: self.args["language"] = params_first("language", False) morphbr@569: self.args["subtitle"] = params_first("subtitle", False) morphbr@628: self.args["format"] = params_first("format", "mpeg1") morphbr@569: self.args["outfile"] = params_first("outfile", "-") morphbr@595: self.args["sendback"] = params_first("sendback", True) morphbr@595: morphbr@595: # handle sendback variable morphbr@595: if self.args["sendback"] == "False": morphbr@595: self.args["sendback"] = False morphbr@569: morphbr@569: # input_opt morphbr@605: uri = params_first("uri", "file:-").split(":", 1) morphbr@577: self.args["type"] = uri[0] morphbr@577: self.args["input"] = uri[1] morphbr@569: morphbr@569: # audio_opts morphbr@569: self.args["acodec"] = params_first("acodec", "mp2") morphbr@569: self.args["abitrate"] = params_first("abitrate", 192) morphbr@569: self.args["volume"] = params_first("volume", 5) morphbr@569: morphbr@569: # video_opts morphbr@569: self.args["mux"] = params_first("mux", "mpeg") morphbr@569: self.args["fps"] = params_first("fps", 25) morphbr@569: self.args["vcodec"] = params_first("vcodec", "mpeg1video") morphbr@569: self.args["vbitrate"] = params_first("vbitrate", 400) morphbr@569: self.args["width"] = params_first("width", 320) morphbr@569: self.args["height"] = params_first("height", 240) morphbr@569: # _setup_params() morphbr@569: morphbr@569: morphbr@569: def _setup_audio(self): morphbr@569: if self.args["acodec"] == "mp3lame": morphbr@569: audio = "-oac mp3lame -lameopts cbr:br=%s vol=%s" % ( morphbr@569: self.args["abitrate"], self.args["volume"]) morphbr@569: else: morphbr@569: audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % ( morphbr@569: self.args["acodec"], self.args["abitrate"]) morphbr@569: morphbr@569: return audio morphbr@569: # _setup_audio() morphbr@569: morphbr@569: morphbr@569: def _setup_video(self): morphbr@577: video = " -of %s" % self.args["mux"] morphbr@577: video += " -ofps %s" % self.args["fps"] morphbr@569: morphbr@569: vcodec = self.args["vcodec"] morphbr@569: if vcodec == "nuv" or vcodec == "xvid"\ morphbr@569: or vcodec == "qtvideo" or vcodec == "copy": morphbr@569: video += " -ovc %s" % vcodec morphbr@569: else: morphbr@569: video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % ( morphbr@569: vcodec, self.args["vbitrate"]) morphbr@569: morphbr@628: if self.args["mux"] == "mpeg": morphbr@628: video += " -mpegopts format=%s" % self.args["format"] morphbr@569: video += " -vf scale=%s:%s" % (self.args["width"], self.args["height"]) morphbr@569: morphbr@569: return video morphbr@569: # _setup_video() morphbr@569: morphbr@569: morphbr@569: def _arg_append(self, args, options): morphbr@577: for arg in shlex.split(options): morphbr@569: args.append(arg) morphbr@569: # arg_append() morphbr@569: morphbr@569: def _setup_mencoder_opts(self, args): morphbr@569: args.append(self.mencoder_path) morphbr@595: morphbr@595: if self.args["outfile"] == "-" and self.args["type"]: morphbr@595: args.append(self.args["input"]) morphbr@595: else: morphbr@595: args.append("-") morphbr@569: morphbr@569: if self.args["language"]: morphbr@569: self._arg_append(args, "-alang %s" % self.args["language"]) morphbr@569: morphbr@569: if self.args["subtitle"]: morphbr@569: self._arg_append(args, "-slang %s" % self.args["subtitle"]) morphbr@569: self._arg_append(args, "-subfps %s" % self.args["fps"]) morphbr@569: morphbr@569: self._arg_append(args, "-idx") morphbr@628: self._arg_append(args, "-cache 1024") morphbr@577: self._arg_append(args, self._setup_audio()) morphbr@577: self._arg_append(args, self._setup_video()) morphbr@569: morphbr@569: self._arg_append(args, "-really-quiet") morphbr@569: self._arg_append(args, "-o %s" % self.args["outfile"]) morphbr@595: self._arg_append(args, "2>%s" % os.devnull) morphbr@569: # _setup_args() morphbr@569: morphbr@569: morphbr@569: def _setup_filename(self): morphbr@569: _type = self.args["type"] morphbr@569: morphbr@569: if _type == "file": morphbr@569: if not os.path.exists(self.args["input"]): morphbr@577: raise IOError,\ morphbr@577: "File requested does not exist: %s." % self.args["input"] morphbr@605: else: morphbr@605: self.args["input"] = "file://%s" % self.args["input"] morphbr@569: morphbr@569: elif _type == "dvd": morphbr@569: self.args["input"] = "dvd://".join(self.args["input"]) morphbr@595: morphbr@595: elif _type == "myth": morphbr@595: # gmyth-cat -h 192.168.1.124 -p 6543 -c 111 morphbr@595: # gmyth-cat -h 192.168.1.124 -p 6543 -f file.nuv morphbr@595: # myth://IP:PORT:type:file morphbr@595: self.args["gmyth-cat"] = self.args["input"].split(":") morphbr@605: self.args["input"] = "-" morphbr@569: # _setup_filename() morphbr@569: morphbr@569: morphbr@572: def __init__(self, params): morphbr@565: server.Transcoder.__init__(self, params) morphbr@577: self.mencoder_opts = [] morphbr@565: morphbr@569: try: morphbr@569: self._setup_params() morphbr@569: self._setup_filename() morphbr@569: self._setup_mencoder_opts(self.mencoder_opts) morphbr@569: except Exception, e: morphbr@569: self.log.error(e) morphbr@565: # __init__() morphbr@565: morphbr@565: morphbr@595: def _check_opened_file(self, stdw, _stdin): morphbr@595: loop = True morphbr@595: while loop: morphbr@595: try: morphbr@595: return open(self.args["outfile"]) morphbr@595: except: morphbr@595: os.write(stdw, _stdin.read(1024)) morphbr@595: # _check_opened_file morphbr@595: morphbr@595: morphbr@595: def _start_outfile(self, outfd): morphbr@595: finished = False morphbr@595: morphbr@595: # fix this (not necessary) morphbr@595: outfd.write("OK") morphbr@595: morphbr@595: # Configuring stdin morphbr@638: try: morphbr@638: _stdin = open(self.args["input"]) morphbr@638: size = int(os.path.getsize(self.args["input"])) morphbr@638: except Exception, e: morphbr@638: self.log.error("Mencoder stdin setup error: %s" % e) morphbr@638: return False morphbr@638: morphbr@595: self.status = 0 morphbr@595: total_read = 0 morphbr@595: morphbr@595: # Configuring pipes morphbr@595: stdr, stdw = os.pipe() morphbr@569: morphbr@605: if not self._run_mencoder(input=stdr): morphbr@565: return False morphbr@565: morphbr@595: stdout = self._check_opened_file(stdw, _stdin) morphbr@595: morphbr@595: try: morphbr@595: while self.proc and self.proc.poll() == None: morphbr@595: if not finished: morphbr@595: data_in = _stdin.read(4096) morphbr@595: if data_in != "": morphbr@595: os.write(stdw, data_in) morphbr@595: total_read += 4096 morphbr@595: d = stdout.read(4096) morphbr@595: if self.args["sendback"]: morphbr@595: outfd.write(d) morphbr@595: self.status = total_read * 100 / size morphbr@595: else: morphbr@595: finished = True morphbr@595: os.close(stdw) morphbr@595: morphbr@595: else: morphbr@595: d = stdout.read(4096) morphbr@595: if self.args["sendback"] and d != "": morphbr@595: outfd.write(d) morphbr@595: morphbr@595: except Exception, e: morphbr@595: self.log.error("Problems handling data: %s" % e) morphbr@628: self.stop() morphbr@595: return False morphbr@595: morphbr@595: self.log.info("%s: Finished sending data to client" % repr(self)) morphbr@595: if not self.args["sendback"]: morphbr@595: outfd.write("DONE") morphbr@595: morphbr@595: return True morphbr@595: # _start_outfile() morphbr@595: morphbr@595: def _start(self, outfd): morphbr@605: if not self._run_mencoder(output=subprocess.PIPE): morphbr@595: return False morphbr@595: morphbr@565: try: morphbr@565: while self.proc and self.proc.poll() == None: morphbr@577: d = self.proc.stdout.read(1024) morphbr@565: outfd.write(d) morphbr@565: except Exception, e: morphbr@565: self.log.error("Problems handling data: %s" % e) morphbr@565: return False morphbr@565: morphbr@595: self.log.info("%s: Finished sending data to client" % repr(self)) morphbr@565: return True morphbr@595: # _start() morphbr@595: morphbr@605: def _start_myth(self, outfd): morphbr@605: # gmyth-cat -h 192.168.1.124 -p 6543 -c 111 morphbr@605: # gmyth-cat -h 192.168.1.124 -p 6543 -f file.nuv morphbr@605: # myth://IP:PORT:type:file morphbr@605: host = self.args["gmyth-cat"][0] morphbr@605: port = self.args["gmyth-cat"][1] morphbr@605: kind = self.args["gmyth-cat"][2] morphbr@605: fchan = self.args["gmyth-cat"][3] morphbr@605: morphbr@605: gmyth_cat = utils.which("gmyth-cat") morphbr@605: opts = [gmyth_cat, "-h", host, "-p", port, "-" + kind, fchan] morphbr@605: morphbr@605: try: morphbr@605: self.gmyth = subprocess.Popen(opts, stdout=subprocess.PIPE, close_fds=True) morphbr@605: except Exception, e: morphbr@605: self.log.error("Error executing gmyth-cat: %s" % e) morphbr@605: return False morphbr@605: morphbr@605: if not self._run_mencoder(input=self.gmyth.stdout, output=subprocess.PIPE): morphbr@605: return False morphbr@605: morphbr@628: show_loading = 0 morphbr@628: show = True morphbr@628: morphbr@628: #n800 150000 and 1000 morphbr@628: morphbr@605: try: morphbr@605: while self.proc and self.proc.poll() == None: morphbr@630: morphbr@630: r, w, x = select([self.proc.stdout], [], [], 0) morphbr@605: if self.proc.stdout in r: morphbr@605: d = self.proc.stdout.read(4096) morphbr@605: outfd.write(d) morphbr@630: # self.log.debug("Sending tv data: %d" % show_loading) morphbr@630: # if show_loading > 150000 and show: morphbr@630: # self.log.debug("Disabling loading video") morphbr@630: # show = False morphbr@628: morphbr@630: #elif show_loading % 10000 == 0 and show: morphbr@630: # show_loading += 1 morphbr@630: # d = open("loading.mpg") morphbr@630: # outfd.write(d.read()) morphbr@630: # self.log.debug("Sendind loading video: %d" % show_loading) morphbr@628: morphbr@630: #else: morphbr@630: # show_loading += 1 morphbr@628: morphbr@628: #self.log.debug("SHOW_LOADING: %d" % show_loading) morphbr@628: morphbr@605: except Exception, e: morphbr@605: self.log.error("Problems handling data: %s" % e) morphbr@605: return False morphbr@605: morphbr@605: return True morphbr@605: # _start_myth() morphbr@605: morphbr@605: def _run_mencoder(self, input=None, output=None): morphbr@605: try: morphbr@605: self.proc = subprocess.Popen(self.mencoder_opts, stdin=input, morphbr@605: stdout=output, close_fds=True) morphbr@605: except Exception, e: morphbr@605: self.log.error("Error executing mencoder: %s" % e) morphbr@605: return False morphbr@605: morphbr@605: return True morphbr@605: # _run_mencoder() morphbr@595: morphbr@595: def start(self, outfd): morphbr@595: cmd = " ".join(self.mencoder_opts) morphbr@595: self.log.debug("Mencoder: %s" % cmd) morphbr@595: morphbr@605: ret = False morphbr@605: morphbr@605: if self.args["outfile"] == "-" and self.args["type"] in ["file", "dvd"]: morphbr@605: ret = self._start(outfd) morphbr@605: morphbr@605: elif self.args["type"] == "myth": morphbr@605: ret = self._start_myth(outfd) morphbr@605: morphbr@595: else: morphbr@605: ret = self._start_outfile(outfd) morphbr@605: morphbr@605: self.stop() morphbr@605: return ret morphbr@565: # start() morphbr@565: morphbr@565: morphbr@565: def stop(self): morphbr@565: if self.proc: morphbr@565: try: morphbr@605: os.kill(self.proc.pid, signal.SIGKILL) morphbr@565: except OSError, e: morphbr@565: pass morphbr@565: morphbr@565: try: morphbr@565: self.proc.wait() morphbr@565: except Exception, e: morphbr@565: pass morphbr@565: morphbr@565: self.proc = None morphbr@605: morphbr@605: if self.gmyth: morphbr@605: try: morphbr@605: os.kill(self.gmyth.pid, signal.SIGKILL) morphbr@605: except OSError, e: morphbr@605: pass morphbr@605: morphbr@605: try: morphbr@605: self.gmyth.wait() morphbr@605: except Exception, e: morphbr@605: pass morphbr@605: morphbr@605: self.gmyth = None morphbr@605: morphbr@569: # stop() morphbr@565: morphbr@565: # TranscoderMencoder