diff -r 000000000000 -r 3fbcd3d9b2d1 gmyth-stream/server/0.3/plugins/transcoders/mencoder.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth-stream/server/0.3/plugins/transcoders/mencoder.py Tue May 29 21:24:48 2007 +0100 @@ -0,0 +1,305 @@ +#!/usr/bin/env python + +__author__ = "Artur Duque de Souza" +__author_email__ = "artur.souza@indt.org.br" +__license__ = "GPL" +__version__ = "0.1" + +import os +import shlex +import signal +import subprocess +import time +import fcntl + +import lib.utils as utils +import lib.server as server +import plugins.transcoders.mencoder_lib.mythtv as mythtv + +from select import select +import lib.transcoder as transcoder + +__all__ = ("TranscoderMencoder",) + +class TranscoderMencoder(transcoder.Transcoder): + """Transcoder class that implements a transcoder using Mencoder""" + mencoder_path = utils.which("mencoder") + name = "mencoder" + priority = -1 + args = {} + proc = None + gmyth = None + + # only works with avi container + status = 0 + + def _setup_params(self): + params_first = self.params_first + + # general_opts + self.args["local"] = params_first("local", False) + self.args["language"] = params_first("language", False) + self.args["subtitle"] = params_first("subtitle", False) + self.args["format"] = params_first("format", "mpeg1") + self.args["outfile"] = params_first("outfile", "-") + + # input_opt + self.args["type"] = params_first("type", "file") + self.args["input"] = params_first("uri", "-") + + # audio_opts + self.args["acodec"] = params_first("acodec", "mp2") + self.args["abitrate"] = params_first("abitrate", 192) + self.args["volume"] = params_first("volume", 5) + + # video_opts + self.args["mux"] = params_first("mux", "mpeg") + self.args["fps"] = params_first("fps", 25) + self.args["vcodec"] = params_first("vcodec", "mpeg1video") + self.args["vbitrate"] = params_first("vbitrate", 400) + self.args["width"] = params_first("width", 320) + self.args["height"] = params_first("height", 240) + # _setup_params() + + + def _setup_audio(self): + if self.args["acodec"] == "mp3lame": + audio = "-oac mp3lame -lameopts cbr:br=%s vol=%s" % ( + self.args["abitrate"], self.args["volume"]) + else: + audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % ( + self.args["acodec"], self.args["abitrate"]) + + return audio + # _setup_audio() + + + def _setup_video(self): + video = " -of %s" % self.args["mux"] + video += " -ofps %s" % self.args["fps"] + + vcodec = self.args["vcodec"] + if vcodec == "nuv" or vcodec == "xvid"\ + or vcodec == "qtvideo" or vcodec == "copy": + video += " -ovc %s" % vcodec + else: + video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % ( + vcodec, self.args["vbitrate"]) + + if self.args["mux"] == "mpeg": + video += " -mpegopts format=%s" % self.args["format"] + video += " -vf scale=%s:%s" % (self.args["width"], self.args["height"]) + + return video + # _setup_video() + + + def _arg_append(self, args, options): + for arg in shlex.split(options): + args.append(arg) + # arg_append() + + def _setup_mencoder_opts(self, args): + args.append(self.mencoder_path) + + if self.args["outfile"] == "-" and self.args["type"]: + args.append(self.args["input"]) + else: + args.append("-") + + if self.args["language"]: + self._arg_append(args, "-alang %s" % self.args["language"]) + + if self.args["subtitle"]: + self._arg_append(args, "-slang %s" % self.args["subtitle"]) + self._arg_append(args, "-subfps %s" % self.args["fps"]) + + self._arg_append(args, "-idx") + self._arg_append(args, "-cache 1024") + self._arg_append(args, self._setup_audio()) + self._arg_append(args, self._setup_video()) + + self._arg_append(args, "-really-quiet") + self._arg_append(args, "-o %s" % self.args["outfile"]) + self._arg_append(args, "2>%s" % os.devnull) + # _setup_args() + + def _setup_filename(self): + """This function setups the file to encode parsing the uri. + So, type can be: + * file + * dvd + * myth + + If the last one is detected we have to parse the uri to find args. + Then we store all the args inside a dictionary: self.args['gmyth-cat'] + """ + _type = self.args["type"] + + if _type == "file": + if not os.path.exists(self.args["input"]): + raise IOError,\ + "File requested does not exist: %s." % self.args["input"] + else: + self.args["input"] = "file://%s" % self.args["input"] + + elif _type == "dvd": + self.args["input"] = "dvd://".join(self.args["input"]) + + elif _type == "myth": + self.args["gmyth-cat"] = mythtv._setup_mythfilename(self) + # _setup_filename() + + + def __init__(self, params): + transcoder.Transcoder.__init__(self, params) + self.mencoder_opts = [] + + try: + self._setup_params() + self._setup_filename() + self._setup_mencoder_opts(self.mencoder_opts) + except Exception, e: + self.log.error(self.tid, e) + # __init__() + + + def _check_opened_file(self, stdw, _stdin): + loop = True + while loop: + try: + return open(self.args["outfile"]) + except: + os.write(stdw, _stdin.read(1024)) + # _check_opened_file + + + def _start_outfile(self, outfd): + finished = False + + # fix this (not necessary) + outfd.write("OK") + + # Configuring stdin + try: + _stdin = open(self.args["input"]) + size = int(os.path.getsize(self.args["input"])) + except Exception, e: + self.log.error(self.tid, "Mencoder stdin setup error: %s" % e) + return False + + self.status = 0 + total_read = 0 + + # Configuring pipes + stdr, stdw = os.pipe() + + if not self._run_mencoder(input=stdr): + return False + + stdout = self._check_opened_file(stdw, _stdin) + + try: + while self.proc and self.proc.poll() == None: + if not finished: + data_in = _stdin.read(4096) + if data_in != "": + os.write(stdw, data_in) + total_read += 4096 + d = stdout.read(4096) + self.status = utils.progress_bar(self.log, + int(total_read), + int(size), 50) + else: + finished = True + os.close(stdw) + + else: + d = stdout.read(4096) + + except Exception, e: + self.log.error(self.tid, "Problems handling data: %s" % e) + self.stop() + return False + + self.log.info(self.tid, "%s: Finished sending data to client" % repr(self)) + return True + # _start_outfile() + + def _start(self, outfd): + # Play a file on disk or DVD + if not self._run_mencoder(output=subprocess.PIPE): + return False + + try: + while self.proc and self.proc.poll() == None: + d = self.proc.stdout.read(1024) + outfd.write(d) + except Exception, e: + self.log.error(self.tid, "Problems handling data: %s" % e) + return False + + self.log.info(self.tid, "%s: Finished sending data to client" % repr(self)) + return True + # _start() + + def _run_mencoder(self, input=None, output=None): + try: + self.proc = subprocess.Popen(self.mencoder_opts, stdin=input, + stdout=output, close_fds=True) + except Exception, e: + self.log.error(self.tid, "Error executing mencoder: %s" % e) + return False + + return True + # _run_mencoder() + + def start(self, outfd): + cmd = " ".join(self.mencoder_opts) + self.log.debug(self.tid, "Plugin's tid: %s" % self.tid) + self.log.debug(self.tid, "Mencoder: %s" % cmd) + #fixme + + ret = False + + if self.args["outfile"] == "-" and \ + self.args["type"] in ["file", "dvd"]: + ret = self._start(outfd) + + elif self.args["type"] == "myth": + ret = mythtv.start_myth(self, outfd) + + else: + ret = self._start_outfile(outfd) + + self.stop() + + if not ret: + self.log.error(self.tid, "Problems while starting streaming.") + + return ret + # start() + + def _aux_stop(self, obj, next=False): + if obj: + try: + os.kill(obj.pid, signal.SIGKILL) + if next: + os.kill(obj.pid+1, signal.SIGKILL) + except OSError, e: + pass + + try: + obj.wait() + except Exception, e: + pass + + obj = None + # _aux_stop + + def stop(self): + self._aux_stop(self.proc, True) + self._aux_stop(self.gmyth) + # stop() + +# TranscoderMencoder