diff -r 2061bf4c30c7 -r ae56c46c7b71 gmyth-stream/server/plugins/transcoders/mencoder.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth-stream/server/plugins/transcoders/mencoder.py Mon Oct 08 19:23:42 2007 +0100 @@ -0,0 +1,334 @@ +#!/usr/bin/env python + +__author__ = "Artur Duque de Souza" +__author_email__ = "artur.souza@indt.org.br" +__license__ = "GPL" +__version__ = "0.3" + +import os +import time +import fcntl +import shlex +import socket +import struct +import signal +import subprocess + +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["type"] and self.args["type"] == "tv": + self._arg_append(args, self.args["tv"]) + elif 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") + + if self.args["outfile"] != "-": + self.args["outfile"] = ".transcoded/%s" % ( + os.path.basename(self.args["outfile"])) + + 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://%s" % self.args["input"] + + elif _type == "myth": + self.args["gmyth-cat"] = mythtv._setup_mythfilename(self) + + elif _type == "tv": + driver = self.params_first("driver", "v4l2") + norm = self.params_first("norm", "pal-m") + channel = self.params_first("channel", "13") + chanlist = self.params_first("chanlist", "us-bcast") + outfmt = self.params_first("outfmt", "yuy2") + vdev = self.params_first("vdev", "/dev/video0") + adev = self.params_first("adev", "/dev/dsp") + self.args["tv"] = "tv:// -v -tv driver=%s:norm=%s:channel=%s:" \ + "chanlist=%s:width=%s:height=%s:outfmt=%s:" \ + "device=%s:adevice=%s" % (driver, norm, + channel, chanlist, + self.args["width"], + self.args["height"], + outfmt, vdev, adev) + # _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: + if self.log: + self.log.error(self.tid, "Error: %s" % e) + else: + raise + # __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 + + # Configuring stdin + try: + filename = self.args["input"].split("://")[1] + _stdin = open(filename) + size = int(os.path.getsize(filename)) + except Exception, e: + self.log.error(self.tid, "Error: Mencoder stdin"\ + " setup error: %s" % e) + outfd.write("Error: 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) + outfd.write("OK ") + + 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(total_read, + size, 50) + else: + finished = True + os.close(stdw) + + else: + d = stdout.read(4096) + + except Exception, e: + self.log.error(self.tid, "Error: %s" % e) + self.stop() + return False + + self.log.info(self.tid, "OK: Done") + 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, "Error: %s" % e) + return False + + self.log.info(self.tid, "OK: Done") + 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: 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) + + ret = False + + if self.args["outfile"] == "-" and \ + self.args["type"] in ["file", "dvd", "tv"]: + 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, "Error: 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