[svn r724] * GMyth-Streamer version 0.3 released trunk
authormorphbr
Tue May 29 21:24:48 2007 +0100 (2007-05-29)
branchtrunk
changeset 7183fbcd3d9b2d1
parent 717 24db16480456
child 719 668ecfca1789
[svn r724] * GMyth-Streamer version 0.3 released
- Improved Log architecture;
- Creation of a history for the transcoder's actions
- Creation of an id for each transcoder instanciated
- Also wrapps default actions for python's default logger

- Created new functions to make use of this new Log architecture;
- serve_new_id
- serve_get_log
- serve_get_all_log

- _Lot_ of small bug fixes;

- Inserted header for all files;

- Splited files with too many lines (more than 1 class per file)
in more files;
gmyth-stream/server/0.3/gms.py
gmyth-stream/server/0.3/html/index.html
gmyth-stream/server/0.3/html/menu.html
gmyth-stream/server/0.3/html/shutdown.html
gmyth-stream/server/0.3/html/status.html
gmyth-stream/server/0.3/html/stop_all.html
gmyth-stream/server/0.3/html/stop_selected.html
gmyth-stream/server/0.3/lib/__init__.py
gmyth-stream/server/0.3/lib/log.py
gmyth-stream/server/0.3/lib/request_handler.py
gmyth-stream/server/0.3/lib/server.py
gmyth-stream/server/0.3/lib/transcoder.py
gmyth-stream/server/0.3/lib/utils.py
gmyth-stream/server/0.3/plugins/__init__.py
gmyth-stream/server/0.3/plugins/transcoders/__init__.py
gmyth-stream/server/0.3/plugins/transcoders/gmencoder.py
gmyth-stream/server/0.3/plugins/transcoders/mencoder.py
gmyth-stream/server/0.3/plugins/transcoders/mencoder_lib/__init__.py
gmyth-stream/server/0.3/plugins/transcoders/mencoder_lib/mythtv.py
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gmyth-stream/server/0.3/gms.py	Tue May 29 21:24:48 2007 +0100
     1.3 @@ -0,0 +1,26 @@
     1.4 +#!/usr/bin/env python
     1.5 +
     1.6 +__author__ = "Artur Duque de Souza"
     1.7 +__author_email__ = "artur.souza@indt.org.br"
     1.8 +__license__ = "GPL"
     1.9 +__version__ = "0.3"
    1.10 +__thanks__ = "Gustavo Sverzut Barbieri"
    1.11 +
    1.12 +import sys
    1.13 +import os
    1.14 +import logging as log
    1.15 +from lib.server import serve_forever, load_plugins_transcoders
    1.16 +
    1.17 +log_level = log.INFO
    1.18 +for p in sys.argv[1:]:
    1.19 +    if p == "-v" or p == "--verbose":
    1.20 +        log_level -= 10
    1.21 +
    1.22 +log.basicConfig(level=log_level,
    1.23 +                format=("### %(asctime)s %(name)-18s \t%(levelname)-8s "
    1.24 +                        "\t%(message)s"),
    1.25 +                datefmt="%Y-%m-%d %H:%M:%S")
    1.26 +
    1.27 +pd = os.path.join("plugins", "transcoders")
    1.28 +load_plugins_transcoders(pd)
    1.29 +serve_forever()
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/gmyth-stream/server/0.3/html/index.html	Tue May 29 21:24:48 2007 +0100
     2.3 @@ -0,0 +1,9 @@
     2.4 +<html>
     2.5 +   <head><title>GMyth-Streamer Server</title></head>
     2.6 +   <body>
     2.7 +<h1>Welcome to GMyth-Streamer Server</h1>
     2.8 +<ul>
     2.9 +%(menu)s
    2.10 +</ul>
    2.11 +   </body>
    2.12 +</html>
    2.13 \ No newline at end of file
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/gmyth-stream/server/0.3/html/menu.html	Tue May 29 21:24:48 2007 +0100
     3.3 @@ -0,0 +1,1 @@
     3.4 +<li><a href="%(url)s">%(name)s</a></li>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/gmyth-stream/server/0.3/html/shutdown.html	Tue May 29 21:24:48 2007 +0100
     4.3 @@ -0,0 +1,6 @@
     4.4 +<html>
     4.5 +   <head><title>GMyth-Streamer Server Exited</title></head>
     4.6 +   <body>
     4.7 +      <h1>GMyth-Streamer is not running anymore</h1>
     4.8 +   </body>
     4.9 +</html>
    4.10 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/gmyth-stream/server/0.3/html/status.html	Tue May 29 21:24:48 2007 +0100
     5.3 @@ -0,0 +1,14 @@
     5.4 +<html>
     5.5 +   <head><title>GMyth-Streamer Server Status</title></head>
     5.6 +   <body>
     5.7 +      <h1>GMyth-Streamer Status</h1>
     5.8 +      <ul>
     5.9 +            %(running)s
    5.10 +            %(stopall)s
    5.11 +            %(stopone)s
    5.12 +      </ul>
    5.13 +      <ul>
    5.14 +            %(menu)s
    5.15 +      </ul>
    5.16 +   </body>
    5.17 +</html>
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/gmyth-stream/server/0.3/html/stop_all.html	Tue May 29 21:24:48 2007 +0100
     6.3 @@ -0,0 +1,9 @@
     6.4 +<html>
     6.5 +   <head><title>GMyth-Streamer Server Stopped Transcoders</title></head>
     6.6 +   <body>
     6.7 +      <h1>GMyth-Streamer stopped running transcoders</h1>
     6.8 +      <ul>
     6.9 +      %(menu)s
    6.10 +      </ul>
    6.11 +   </body>
    6.12 +</html>
    6.13 \ No newline at end of file
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/gmyth-stream/server/0.3/html/stop_selected.html	Tue May 29 21:24:48 2007 +0100
     7.3 @@ -0,0 +1,12 @@
     7.4 +<html>
     7.5 +   <head><title>GMyth-Streamer Server Stopped Transcoders</title></head>
     7.6 +   <body>
     7.7 +      <h1>GMyth-Streamer stopped running transcoders:</h1>
     7.8 +      <ul>
     7.9 +            %(opts)s
    7.10 +      </ul>
    7.11 +      <ul>
    7.12 +            %(menu)s
    7.13 +      </ul>
    7.14 +   </body>
    7.15 +</html>
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/gmyth-stream/server/0.3/lib/log.py	Tue May 29 21:24:48 2007 +0100
     8.3 @@ -0,0 +1,109 @@
     8.4 +#!/usr/bin/env python
     8.5 +
     8.6 +__author__ = "Artur Duque de Souza"
     8.7 +__author_email__ = "artur.souza@indt.org.br"
     8.8 +__license__ = "GPL"
     8.9 +__version__ = "0.1"
    8.10 +
    8.11 +import os
    8.12 +import logging
    8.13 +
    8.14 +__all__ = ("Log", "log_structure")
    8.15 +
    8.16 +class log_structure(object):
    8.17 +    """Structure to hold log info."""
    8.18 +
    8.19 +    def __init__(self, log=None):
    8.20 +        self.log = log
    8.21 +        self.history = []
    8.22 +    # __init__()
    8.23 +
    8.24 +# log_structure()
    8.25 +
    8.26 +class Log(object):
    8.27 +    """This class implements a log where we can store status of
    8.28 +    all transcoders (even from those that are not running any more)."""
    8.29 +
    8.30 +    ## key = tid
    8.31 +    ## item = ls
    8.32 +    logs = {}
    8.33 +
    8.34 +    def insert(self, tid, name):
    8.35 +        """Insert a given tid on the log structure"""
    8.36 +        if not self.logs.has_key(tid):
    8.37 +            self.logs[tid] = log_structure(logging.getLogger(name))
    8.38 +            return True
    8.39 +        else:
    8.40 +            return False
    8.41 +    # insert()
    8.42 +
    8.43 +    def remove(self, tid=None):
    8.44 +        """Cleans up all log stored for a
    8.45 +        given tid or for all transcodes."""
    8.46 +        if not tid:
    8.47 +            self.logs = {}
    8.48 +        else:
    8.49 +            del(self.logs[tid])
    8.50 +
    8.51 +        return True
    8.52 +    # clean()
    8.53 +
    8.54 +    def get_status(self, tid=None, all=False):
    8.55 +        """Get the status of all transcoders or
    8.56 +        of just one of them if it's given an tid."""
    8.57 +        if not tid:
    8.58 +            ret = {}
    8.59 +            for tids, logs in self.logs.items():
    8.60 +                if len(logs.history) > 0:
    8.61 +                    if not all:
    8.62 +                        ret[tids] = logs.history[-1]
    8.63 +                    else:
    8.64 +                        ret[tids] = logs.history
    8.65 +            return ret
    8.66 +        elif self.logs.has_key(tid) and len(self.logs[tid].history) > 0:
    8.67 +            if not all:
    8.68 +                return self.logs[tid].history[-1]
    8.69 +            else:
    8.70 +                return self.logs[tid].history
    8.71 +
    8.72 +        return False
    8.73 +    # get_status()
    8.74 +
    8.75 +    def _update_status(self, tid=None, msg=""):
    8.76 +        """Update the status of a given tid. Private method that
    8.77 +        is only called inside error/info/debug wrappers"""
    8.78 +        if msg != "":
    8.79 +            self.logs[tid].history.append(msg)
    8.80 +            return True
    8.81 +        else:
    8.82 +            return False
    8.83 +    # update_status()
    8.84 +
    8.85 +    def error(self, tid, msg):
    8.86 +        """Python's Log.error wrapper"""
    8.87 +        if self.logs.has_key(tid):
    8.88 +            self.logs[tid].log.error("%s" % msg)
    8.89 +            return self._update_status(tid, msg)
    8.90 +        else:
    8.91 +            return False
    8.92 +    # error()
    8.93 +
    8.94 +    def info(self, tid, msg):
    8.95 +        """Python's Log.info wrapper"""
    8.96 +        if self.logs.has_key(tid):
    8.97 +            self.logs[tid].log.info("%s" % msg)
    8.98 +            self._update_status(tid, msg)
    8.99 +            return True
   8.100 +        else:
   8.101 +            return False
   8.102 +    # info()
   8.103 +
   8.104 +    def debug(self, tid, msg):
   8.105 +        """Python's Log.debug wrapper"""
   8.106 +        if self.logs.has_key(tid):
   8.107 +            self.logs[tid].log.debug("%s" % msg)
   8.108 +            self._update_status(tid, msg)
   8.109 +            return True
   8.110 +        else:
   8.111 +            return False
   8.112 +    # debug()
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/gmyth-stream/server/0.3/lib/request_handler.py	Tue May 29 21:24:48 2007 +0100
     9.3 @@ -0,0 +1,332 @@
     9.4 +#!/usr/bin/env python
     9.5 +
     9.6 +__author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
     9.7 +__author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
     9.8 +__license__ = "GPL"
     9.9 +__version__ = "0.4"
    9.10 +
    9.11 +import os
    9.12 +import threading
    9.13 +import SocketServer
    9.14 +import BaseHTTPServer
    9.15 +import socket
    9.16 +import urlparse
    9.17 +import cgi
    9.18 +import lib.utils as utils
    9.19 +import logging
    9.20 +
    9.21 +from log import Log
    9.22 +import lib.transcoder as transcoder
    9.23 +
    9.24 +__all__ = ("RequestHandler")
    9.25 +
    9.26 +class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    9.27 +    """Class that implements an HTTP request handler for our server."""
    9.28 +    log = logging.getLogger("gms.request")
    9.29 +    def_transcoder = None
    9.30 +    transcoders = utils.PluginSet(transcoder.Transcoder)
    9.31 +    transcoders_log = Log()
    9.32 +    tid_queue = []
    9.33 +
    9.34 +    menu = {
    9.35 +        "Log": "/get_log.do",
    9.36 +        "Stop": "/stop-transcoder.do",
    9.37 +        "Status": "/status.do",
    9.38 +        "All Log": "/get_all_log.do",
    9.39 +        "Version": "/version.do",
    9.40 +        "Shutdown": "/shutdown.do"
    9.41 +        }
    9.42 +
    9.43 +    @classmethod
    9.44 +    def load_plugins_transcoders(cls, directory):
    9.45 +        cls.transcoders.load_from_directory(directory)
    9.46 +
    9.47 +        if cls.def_transcoder is None and cls.transcoders:
    9.48 +            cls.def_transcoder = cls.transcoders[0].name
    9.49 +    # load_plugins_transcoders()
    9.50 +
    9.51 +
    9.52 +    def do_dispatch(self, body):
    9.53 +        self.url = self.path
    9.54 +
    9.55 +        pieces = urlparse.urlparse(self.path)
    9.56 +        self.path = pieces[2]
    9.57 +        self.query = cgi.parse_qs(pieces[4])
    9.58 +
    9.59 +        if self.path == "/":
    9.60 +            self.serve_main(body)
    9.61 +        elif self.path == "/shutdown.do":
    9.62 +            self.serve_shutdown(body)
    9.63 +        elif self.path == "/stop-transcoder.do":
    9.64 +            self.serve_stop_transcoder(body)
    9.65 +        elif self.path == "/status.do":
    9.66 +            self.serve_status(body)
    9.67 +        elif self.path == "/version.do":
    9.68 +            self.serve_version(body)
    9.69 +        elif self.path == "/new_id.do":
    9.70 +            self.serve_new_id(body)
    9.71 +        elif self.path == "/get_log.do":
    9.72 +            self.serve_get_log(body)
    9.73 +        elif self.path == "/get_all_log.do":
    9.74 +            self.serve_get_all_log(body)
    9.75 +        elif self.path == "/stream.do":
    9.76 +            self.serve_stream(body)
    9.77 +        else:
    9.78 +            action = self.query.get("action", None)
    9.79 +            if action and "stream.do" in action:
    9.80 +                self.serve_stream(body)
    9.81 +            else:
    9.82 +                self.send_error(404, "File not found")
    9.83 +    # do_dispatch()
    9.84 +
    9.85 +
    9.86 +    def do_GET(self):
    9.87 +        self.do_dispatch(True)
    9.88 +    # do_GET()
    9.89 +
    9.90 +
    9.91 +    def do_HEAD(self):
    9.92 +        self.do_dispatch(False)
    9.93 +    # do_HEAD()
    9.94 +
    9.95 +
    9.96 +    def _nav_items(self):
    9.97 +        ret = ""
    9.98 +        for name, url in self.menu.items():
    9.99 +            ret += utils.getHTML("menu", {"name": name, "url": url})
   9.100 +
   9.101 +        return ret
   9.102 +    # _nav_items()
   9.103 +
   9.104 +    def serve_main(self, body):
   9.105 +        self.send_response(200)
   9.106 +        self.send_header("Content-Type", "text/html")
   9.107 +        self.send_header('Connection', 'close')
   9.108 +        self.end_headers()
   9.109 +        if body:
   9.110 +            self.wfile.write(utils.getHTML("index", {"menu": self._nav_items()}))
   9.111 +    # serve_main()
   9.112 +
   9.113 +    def serve_version(self, body):
   9.114 +        self.send_response(200)
   9.115 +        self.send_header("Content-Type", "text/html")
   9.116 +        self.send_header('Connection', 'close')
   9.117 +        self.end_headers()
   9.118 +        if body:
   9.119 +            self.wfile.write("Version: %s" %  __version__)
   9.120 +
   9.121 +
   9.122 +    def serve_shutdown(self, body):
   9.123 +        self.send_response(200)
   9.124 +        self.send_header("Content-Type", "text/html")
   9.125 +        self.send_header('Connection', 'close')
   9.126 +        self.end_headers()
   9.127 +        if body:
   9.128 +            self.wfile.write(utils.getHTML("shutdown"))
   9.129 +        self.server.server_close()
   9.130 +    # serve_shutdown()
   9.131 +
   9.132 +
   9.133 +    def serve_stop_all_transcoders(self, body):
   9.134 +        self.send_response(200)
   9.135 +        self.send_header("Content-Type", "text/html")
   9.136 +        self.send_header('Connection', 'close')
   9.137 +        self.end_headers()
   9.138 +        if body:
   9.139 +            self.server.stop_transcoders()
   9.140 +            self.wfile.write(utils.getHTML("stop_all", {"menu": self._nav_items()}))
   9.141 +    # serve_stop_all_transcoders()
   9.142 +
   9.143 +
   9.144 +    def serve_stop_selected_transcoders(self, body, tids=[]):
   9.145 +        self.send_response(200)
   9.146 +        self.send_header("Content-Type", "text/html")
   9.147 +        self.send_header('Connection', 'close')
   9.148 +        self.end_headers()
   9.149 +        opts = ""
   9.150 +        if body:
   9.151 +            transcoders = self.server.get_transcoders()
   9.152 +
   9.153 +            for tid in tids:
   9.154 +                for t, r in transcoders:
   9.155 +                    if t.tid == int(tid):
   9.156 +                        try:
   9.157 +                            t.stop()
   9.158 +                        except Exception, e:
   9.159 +                            self.log.info("Plugin already stopped")
   9.160 +
   9.161 +                        opts += utils._create_html_item("%s" % t)
   9.162 +
   9.163 +                        break
   9.164 +
   9.165 +                self.wfile.write(utils.getHTML("stop_selected",
   9.166 +                                               {"menu": self._nav_items(),
   9.167 +                                                "opts": opts}))
   9.168 +    # serve_stop_selected_transcoders()
   9.169 +
   9.170 +
   9.171 +    def serve_stop_transcoder(self, body):
   9.172 +        req = self.query.get("request", None)
   9.173 +        tid = self.query.get("tid", None)
   9.174 +        if req and "all" in req:
   9.175 +            self.serve_stop_all_transcoders(body)
   9.176 +        elif tid:
   9.177 +            self.serve_stop_selected_transcoders(body, tid[0].split(";"))
   9.178 +        else:
   9.179 +            self.serve_status(body)
   9.180 +    # serve_stop_transcoder()
   9.181 +
   9.182 +
   9.183 +    def serve_status(self, body):
   9.184 +        self.send_response(200)
   9.185 +        self.send_header("Content-Type", "text/html")
   9.186 +        self.send_header('Connection', 'close')
   9.187 +        self.end_headers()
   9.188 +        stopone = ""
   9.189 +
   9.190 +        if body:
   9.191 +            tl = self.server.get_transcoders()
   9.192 +            if not tl:
   9.193 +                running = "<p>No running transcoder.</p>\n"
   9.194 +                stopall = ""
   9.195 +                stopone = ""
   9.196 +
   9.197 +            elif self.query.get("tid", None):
   9.198 +                req_tid = int(self.query.get("tid")[0])
   9.199 +                for transcoder, request in tl:
   9.200 +                    if transcoder.tid == req_tid:
   9.201 +                        self.wfile.write("Status: %s %%" % transcoder.status)
   9.202 +                        return True
   9.203 +
   9.204 +                return False
   9.205 +
   9.206 +            else:
   9.207 +                running = "<p>Running transcoders:</p>\n"
   9.208 +                stopall = utils._create_html_item("<a href='%s?request=all'>"
   9.209 +                                                 "[STOP ALL]</a>" %
   9.210 +                                                 self.menu["Stop"])
   9.211 +
   9.212 +                for transcoder, request in tl:
   9.213 +                    stopone += utils._create_html_item("%s;"
   9.214 +                                                       "<a href='%s?tid=%s'>"
   9.215 +                                                       " [STOP] </a>") % (
   9.216 +                        transcoder, self.menu["Stop"], transcoder.tid)
   9.217 +
   9.218 +            self.wfile.write(utils.getHTML("status",
   9.219 +                                           {"menu": self._nav_items(),
   9.220 +                                            "running": running,
   9.221 +                                            "stopall": stopall,
   9.222 +                                            "stopone": stopone}))
   9.223 +    # serve_status()
   9.224 +
   9.225 +
   9.226 +    def _get_transcoder(self):
   9.227 +        # get transcoder option: mencoder is the default
   9.228 +        request_transcoders = self.query.get("transcoder", ["mencoder"])
   9.229 +
   9.230 +        for t in request_transcoders:
   9.231 +            transcoder = self.transcoders.get(t)
   9.232 +            if transcoder:
   9.233 +                return transcoder
   9.234 +
   9.235 +        if not transcoder:
   9.236 +            return self.transcoders[self.def_transcoder]
   9.237 +    # _get_transcoder()
   9.238 +
   9.239 +
   9.240 +    def _get_new_id(self, tid):
   9.241 +        self.server.last_tid = utils.create_tid(tid)
   9.242 +        self.tid_queue.append(self.server.last_tid)
   9.243 +        return self.server.last_tid
   9.244 +    # _get_new_id()
   9.245 +
   9.246 +
   9.247 +    def serve_new_id(self, body):
   9.248 +        self.send_response(200)
   9.249 +        self.send_header("Content-Type", "text/html")
   9.250 +        self.send_header('Connection', 'close')
   9.251 +        self.end_headers()
   9.252 +
   9.253 +        if body:
   9.254 +            self.wfile.write("%s" % self._get_new_id(self.server.last_tid))
   9.255 +    # serve_new_id()
   9.256 +
   9.257 +    def serve_get_log(self, body):
   9.258 +        self.send_response(200)
   9.259 +        self.send_header("Content-Type", "text/html")
   9.260 +        self.send_header('Connection', 'close')
   9.261 +        self.end_headers()
   9.262 +
   9.263 +        if body:
   9.264 +            if self.query.get("tid", None):
   9.265 +                tid = int(self.query.get("tid")[0])
   9.266 +                stat = self.transcoders_log.get_status(tid)
   9.267 +                self.wfile.write("%s" % stat)
   9.268 +            else:
   9.269 +                stat = self.transcoders_log.get_status()
   9.270 +                for rtid, status in stat.iteritems():
   9.271 +                    self.wfile.write("<b>%s</b>: %s<br><br>" % (rtid, status))
   9.272 +    # serve_get_log()
   9.273 +
   9.274 +    def serve_get_all_log(self, body):
   9.275 +        self.send_response(200)
   9.276 +        self.send_header("Content-Type", "text/html")
   9.277 +        self.send_header('Connection', 'close')
   9.278 +        self.end_headers()
   9.279 +
   9.280 +        if body:
   9.281 +            if self.query.get("tid", None):
   9.282 +                tid = int(self.query.get("tid")[0])
   9.283 +                stat = self.transcoders_log.get_status(tid, True)
   9.284 +                for status in stat:
   9.285 +                    self.wfile.write("%s<br><br>" % status)
   9.286 +            else:
   9.287 +                stat = self.transcoders_log.get_status(None, True)
   9.288 +                for rtid, history in stat.iteritems():
   9.289 +                    for status in history:
   9.290 +                        self.wfile.write("<b>%s</b>: %s<br>" % (rtid, status))
   9.291 +                    self.wfile.write("<br><br>")
   9.292 +    # serve_get_all_log()
   9.293 +
   9.294 +    def serve_stream(self, body):
   9.295 +        transcoder = self._get_transcoder()
   9.296 +        try:
   9.297 +            obj = transcoder(self.query)
   9.298 +        except Exception, e:
   9.299 +            self.send_error(500, str(e))
   9.300 +            return
   9.301 +
   9.302 +        self.send_response(200)
   9.303 +        self.send_header("Content-Type", obj.get_mimetype())
   9.304 +        self.send_header('Connection', 'close')
   9.305 +        self.end_headers()
   9.306 +
   9.307 +        if body:
   9.308 +            test_tid = int(self.query.get("tid", "0")[0])
   9.309 +            if test_tid == 0 or test_tid not in self.tid_queue:
   9.310 +                test_tid = self._get_new_id(self.server.last_tid)
   9.311 +
   9.312 +            self.transcoders_log.insert(test_tid, "gms.%s" % obj.name)
   9.313 +            obj.tid = test_tid
   9.314 +            obj.log = self.transcoders_log
   9.315 +
   9.316 +            self.server.add_transcoders(self, obj)
   9.317 +            obj.start(self.wfile)
   9.318 +            self.server.del_transcoders(self, obj)
   9.319 +    # serve_stream()
   9.320 +
   9.321 +
   9.322 +    def log_request(self, code='-', size='-'):
   9.323 +        self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
   9.324 +    # log_request()
   9.325 +
   9.326 +
   9.327 +    def log_error(self, format, *args):
   9.328 +        self.log.error("%s: %s" % (self.address_string(), format % args))
   9.329 +    # log_error()
   9.330 +
   9.331 +
   9.332 +    def log_message(self, format, *args):
   9.333 +        self.log.info("%s: %s" % (self.address_string(), format % args))
   9.334 +    # log_message()
   9.335 +# RequestHandler
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/gmyth-stream/server/0.3/lib/server.py	Tue May 29 21:24:48 2007 +0100
    10.3 @@ -0,0 +1,117 @@
    10.4 +#!/usr/bin/env python
    10.5 +
    10.6 +__author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
    10.7 +__author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
    10.8 +__license__ = "GPL"
    10.9 +__version__ = "0.4"
   10.10 +
   10.11 +import os
   10.12 +import threading
   10.13 +import SocketServer
   10.14 +import BaseHTTPServer
   10.15 +import socket
   10.16 +import urlparse
   10.17 +import cgi
   10.18 +import lib.utils as utils
   10.19 +import logging
   10.20 +
   10.21 +from log import Log
   10.22 +from request_handler import RequestHandler
   10.23 +
   10.24 +__all__ = ("Server", "serve_forever", "load_plugins_transcoders")
   10.25 +
   10.26 +class Server(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
   10.27 +    log = logging.getLogger("gms.server")
   10.28 +    last_tid = 0
   10.29 +    run = True
   10.30 +    _transcoders = {}
   10.31 +    _lock = threading.RLock()
   10.32 +
   10.33 +    def serve_forever(self):
   10.34 +        self.log.info("GMyth-Streamer serving HTTP on %s:%s" %
   10.35 +                      self.socket.getsockname())
   10.36 +        try:
   10.37 +            while self.run:
   10.38 +                self.handle_request()
   10.39 +        except KeyboardInterrupt, e:
   10.40 +            pass
   10.41 +
   10.42 +        self.log.debug("Stopping all remaining transcoders...")
   10.43 +        self.stop_transcoders()
   10.44 +        self.log.debug("Transcoders stopped!")
   10.45 +    # serve_forever()
   10.46 +
   10.47 +
   10.48 +    def get_request(self):
   10.49 +        skt = self.socket
   10.50 +        old = skt.gettimeout()
   10.51 +        skt.settimeout(0.5)
   10.52 +        while self.run:
   10.53 +            try:
   10.54 +                r = skt.accept()
   10.55 +                skt.settimeout(old)
   10.56 +                return r
   10.57 +            except socket.timeout, e:
   10.58 +                pass
   10.59 +        raise socket.error("Not running")
   10.60 +    # get_request()
   10.61 +
   10.62 +
   10.63 +    def server_close(self):
   10.64 +        self.run = False
   10.65 +        self.stop_transcoders()
   10.66 +
   10.67 +        BaseHTTPServer.HTTPServer.server_close(self)
   10.68 +    # server_close()
   10.69 +
   10.70 +
   10.71 +    def stop_transcoders(self):
   10.72 +        self._lock.acquire()
   10.73 +        for transcoder, request in self._transcoders.iteritems():
   10.74 +            self.log.info("Stop transcoder: %s, client=%s" %
   10.75 +                          (transcoder, request.client_address))
   10.76 +            transcoder.stop()
   10.77 +        self._lock.release()
   10.78 +    # stop_transcoders()
   10.79 +
   10.80 +
   10.81 +    def get_transcoders(self):
   10.82 +        self._lock.acquire()
   10.83 +        try:
   10.84 +            return self._transcoders.items()
   10.85 +        finally:
   10.86 +            self._lock.release()
   10.87 +    # get_transcoders()
   10.88 +
   10.89 +
   10.90 +    def add_transcoders(self, request, transcoder):
   10.91 +        self._lock.acquire()
   10.92 +        try:
   10.93 +            self._transcoders[transcoder] = request
   10.94 +        finally:
   10.95 +            self._lock.release()
   10.96 +    # add_transcoders()
   10.97 +
   10.98 +
   10.99 +    def del_transcoders(self, request, transcoder):
  10.100 +        self._lock.acquire()
  10.101 +        try:
  10.102 +            del self._transcoders[transcoder]
  10.103 +        finally:
  10.104 +            self._lock.release()
  10.105 +    # del_transcoders()
  10.106 +# Server
  10.107 +
  10.108 +
  10.109 +
  10.110 +def serve_forever(host="0.0.0.0", port=40000):
  10.111 +    addr = (host, port)
  10.112 +    RequestHandler.protocol_version = "HTTP/1.0"
  10.113 +    httpd = Server(addr, RequestHandler)
  10.114 +    httpd.serve_forever()
  10.115 +# serve_forever()
  10.116 +
  10.117 +
  10.118 +def load_plugins_transcoders(directory):
  10.119 +    RequestHandler.load_plugins_transcoders(directory)
  10.120 +# load_plugins_transcoders()
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/gmyth-stream/server/0.3/lib/transcoder.py	Tue May 29 21:24:48 2007 +0100
    11.3 @@ -0,0 +1,60 @@
    11.4 +#!/usr/bin/env python
    11.5 +
    11.6 +__author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
    11.7 +__author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
    11.8 +__license__ = "GPL"
    11.9 +__version__ = "0.4"
   11.10 +
   11.11 +__all__ = ("Transcoder")
   11.12 +
   11.13 +class Transcoder(object):
   11.14 +    """Transcoder's Class: parent class to implement
   11.15 +    a plugin for transcoding data."""
   11.16 +    priority = 0   # negative values have higher priorities
   11.17 +    name = None # to be used in requests
   11.18 +    status = None
   11.19 +    log = None
   11.20 +    tid = -1
   11.21 +
   11.22 +    def __init__(self, params):
   11.23 +        self.params = params
   11.24 +    # __init__()
   11.25 +
   11.26 +
   11.27 +    def params_first(self, key, default=None):
   11.28 +        if default is None:
   11.29 +            return self.params[key][0]
   11.30 +        else:
   11.31 +            try:
   11.32 +                return self.params[key][0]
   11.33 +            except:
   11.34 +                return default
   11.35 +    # params_first()
   11.36 +
   11.37 +
   11.38 +    def get_mimetype(self):
   11.39 +        mux = self.params_first("mux", "mpg")
   11.40 +
   11.41 +        if mux == "mpeg":
   11.42 +            return "video/mpeg"
   11.43 +        elif mux == "avi":
   11.44 +            return "video/x-msvideo"
   11.45 +        else:
   11.46 +            return "application/octet-stream"
   11.47 +    # get_mimetype()
   11.48 +
   11.49 +    def start(self, outfile):
   11.50 +        return True
   11.51 +    # start()
   11.52 +
   11.53 +
   11.54 +    def stop(self):
   11.55 +        return True
   11.56 +    # stop()
   11.57 +
   11.58 +    def __str__(self):
   11.59 +        return '%s: %s( params=%s ) - Status: %s%%' % \
   11.60 +               (self.__class__.__name__, self.tid,
   11.61 +                self.params, self.status)
   11.62 +    # __str__()
   11.63 +# Transcoder
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/gmyth-stream/server/0.3/lib/utils.py	Tue May 29 21:24:48 2007 +0100
    12.3 @@ -0,0 +1,188 @@
    12.4 +#!/usr/bin/env
    12.5 +
    12.6 +__author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
    12.7 +__author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
    12.8 +__license__ = "GPL"
    12.9 +__version__ = "0.3"
   12.10 +
   12.11 +import os
   12.12 +import stat
   12.13 +import sys
   12.14 +import logging
   12.15 +import urllib
   12.16 +import gobject
   12.17 +import imp
   12.18 +
   12.19 +log = logging.getLogger("gms.utils")
   12.20 +
   12.21 +__all__ = ("which", "load_plugins", "PluginSet", "getHTML")
   12.22 +
   12.23 +def which(app):
   12.24 +    """Function to implement which(1) unix command"""
   12.25 +    pl = os.environ["PATH"].split(os.pathsep)
   12.26 +    for p in pl:
   12.27 +        path = os.path.join(p, app)
   12.28 +        if os.path.isfile(path):
   12.29 +            st = os.stat(path)
   12.30 +            if st[stat.ST_MODE] & 0111:
   12.31 +                return path
   12.32 +    return ""
   12.33 +# which()
   12.34 +
   12.35 +
   12.36 +def _load_module(pathlist, name):
   12.37 +    fp, path, desc = imp.find_module(name, pathlist)
   12.38 +    try:
   12.39 +        module = imp.load_module(name, fp, path, desc)
   12.40 +        return module
   12.41 +    finally:
   12.42 +        if fp:
   12.43 +            fp.close()
   12.44 +# _load_module()
   12.45 +
   12.46 +
   12.47 +class PluginSet(object):
   12.48 +    def __init__(self, basetype, *items):
   12.49 +        self.basetype = basetype
   12.50 +        self.map = {}
   12.51 +        self.list = []
   12.52 +
   12.53 +        for i in items:
   12.54 +            self._add(i)
   12.55 +        self._sort()
   12.56 +    # __init__()
   12.57 +
   12.58 +
   12.59 +    def _add(self, item):
   12.60 +        self.map[item.name] = item
   12.61 +        self.list.append(item)
   12.62 +    # _add()
   12.63 +
   12.64 +
   12.65 +    def add(self, item):
   12.66 +        self._add()
   12.67 +        self._sort()
   12.68 +    # add()
   12.69 +
   12.70 +
   12.71 +    def __getitem__(self, spec):
   12.72 +        if isinstance(spec, basestring):
   12.73 +            return self.map[spec]
   12.74 +        else:
   12.75 +            return self.list[spec]
   12.76 +    # __getitem__()
   12.77 +
   12.78 +
   12.79 +    def get(self, name, default=None):
   12.80 +        return self.map.get(name, default)
   12.81 +    # get()
   12.82 +
   12.83 +
   12.84 +    def __iter__(self):
   12.85 +        return self.list.__iter__()
   12.86 +    # __iter__()
   12.87 +
   12.88 +
   12.89 +    def __len__(self):
   12.90 +        return len(self.list)
   12.91 +    # __len__()
   12.92 +
   12.93 +
   12.94 +    def _sort(self):
   12.95 +        self.list.sort(lambda a, b: cmp(a.priority, b.priority))
   12.96 +    # _sort()
   12.97 +
   12.98 +
   12.99 +    def update(self, pluginset):
  12.100 +        self.map.update(pluginset.map)
  12.101 +        self.list.extend(pluginset.list)
  12.102 +        self._sort()
  12.103 +    # update()
  12.104 +
  12.105 +
  12.106 +    def load_from_directory(self, directory):
  12.107 +        for i in load_plugins(directory, self.basetype):
  12.108 +            self._add(i)
  12.109 +        self._sort()
  12.110 +    # load_from_directory()
  12.111 +
  12.112 +
  12.113 +    def __str__(self):
  12.114 +        lst = []
  12.115 +        for o in self.list:
  12.116 +            lst.append('"%s" (%s)' % (o.name, o.__name__))
  12.117 +
  12.118 +        return "%s(basetype=%s, items=[%s])" % \
  12.119 +               (self.__class__.__name__,
  12.120 +                self.basetype.__name__,
  12.121 +                ", ".join(lst))
  12.122 +    # __str__()
  12.123 +# PluginSet
  12.124 +
  12.125 +
  12.126 +def load_plugins(directory, basetype):
  12.127 +    """Function to load plugins from a given directory"""
  12.128 +    tn = basetype.__name__
  12.129 +    log.debug("Loading plugins from %s, type=%s" % (directory, tn))
  12.130 +
  12.131 +
  12.132 +    plugins = []
  12.133 +    for d in os.listdir(directory):
  12.134 +        if not d.endswith(".py"):
  12.135 +            continue
  12.136 +
  12.137 +        name = d[0: -3]
  12.138 +        if name == "__init__":
  12.139 +            continue
  12.140 +
  12.141 +        directory.replace(os.path.sep, ".")
  12.142 +        mod = _load_module([directory], name)
  12.143 +        for sym in dir(mod):
  12.144 +            cls = getattr(mod, sym)
  12.145 +            if isinstance(cls, type) and issubclass(cls, basetype) and \
  12.146 +                cls != basetype:
  12.147 +                plugins.append(cls)
  12.148 +                log.info("Loaded %s (%s) from %s" % \
  12.149 +                         (cls.__name__, tn, os.path.join(directory, d)))
  12.150 +
  12.151 +    return plugins
  12.152 +# load_plugins()
  12.153 +
  12.154 +def getHTML(html_file, params={}):
  12.155 +    """This function parses an html file with the given
  12.156 +    parameters and returns a formated web-page"""
  12.157 +    try:
  12.158 +        filename = os.path.join(sys.path[0], "html", html_file + ".html")
  12.159 +        html = open(filename).read() % params
  12.160 +        return html
  12.161 +    except Exception, e:
  12.162 +        return "HTML format error. Wrong keys: %s" % e
  12.163 +
  12.164 +# getHTML
  12.165 +
  12.166 +def _create_html_item(opt):
  12.167 +    """Create an <li> item using HTML."""
  12.168 +    return "<li>%s</li>\n" % opt
  12.169 +# _create_html_item
  12.170 +
  12.171 +def progress_bar(log, value, max, barsize):
  12.172 +    """Creates and displays a progressbar. By OSantana"""
  12.173 +    chars = int(value * barsize / float(max))
  12.174 +    percent = int((value / float(max)) * 100)
  12.175 +    sys.stdout.write("#" * chars)
  12.176 +    sys.stdout.write(" " * (barsize - chars + 2))
  12.177 +    if value >= max:
  12.178 +        sys.stdout.write("done.\n\n")
  12.179 +    else:
  12.180 +        sys.stdout.write("[%3i%%]\r" % (percent))
  12.181 +        sys.stdout.flush()
  12.182 +    return percent
  12.183 +# progress_bar() by osantana
  12.184 +
  12.185 +def create_tid(last_tid):
  12.186 +    """Function to generate TIDs (ids for transcoders).
  12.187 +    At first it just do +1 on last_tid but can be implemented
  12.188 +    to generate more sparse TIDs"""
  12.189 +    tid = last_tid + 1
  12.190 +    return tid
  12.191 +# create_id()
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/gmyth-stream/server/0.3/plugins/transcoders/gmencoder.py	Tue May 29 21:24:48 2007 +0100
    13.3 @@ -0,0 +1,99 @@
    13.4 +#!/usr/bin/env python
    13.5 +
    13.6 +__author__ = "Renato Filho"
    13.7 +__author_email__ = "renato.filho@indt.org.br"
    13.8 +__license__ = "GPL"
    13.9 +__version__ = "0.1"
   13.10 +
   13.11 +import os
   13.12 +import shlex
   13.13 +import signal
   13.14 +import subprocess
   13.15 +import time
   13.16 +
   13.17 +import select
   13.18 +
   13.19 +import lib.utils as utils
   13.20 +import lib.server as server
   13.21 +import lib.transcoder as transcoder
   13.22 +
   13.23 +__all__ = ("TranscoderGMencoder",)
   13.24 +
   13.25 +class TranscoderGMencoder(transcoder.Transcoder):
   13.26 +    gmencoder_path = utils.which("gmencoder")
   13.27 +    name = "gmencoder"
   13.28 +    priority = -1
   13.29 +    proc = None
   13.30 +
   13.31 +    def __init__(self, params):
   13.32 +        transcoder.Transcoder.__init__(self, params)
   13.33 +        self.opts = []
   13.34 +    # __init__()
   13.35 +
   13.36 +    def _insert_param (self, name, value):
   13.37 +        if (value != ""):
   13.38 +            self.opts.append(name)
   13.39 +            self.opts.append(value)
   13.40 +
   13.41 +    def _parser_params (self):
   13.42 +        self._insert_param("-i", \
   13.43 +            "%s://%s" % (self.params_first("type", "file"), self.params_first("uri", "")))
   13.44 +        self._insert_param("--video-encode", self.params_first("ve", ""))
   13.45 +        self._insert_param("--video-opts", "bitrate=200,pass=2,quantizer=5")
   13.46 +        self._insert_param("--video-fps", self.params_first("fps", ""))
   13.47 +        self._insert_param("--video-width", self.params_first("width", ""))
   13.48 +        self._insert_param("--video-height", self.params_first("height", ""))
   13.49 +        self._insert_param("--audio-rate", "32000")
   13.50 +        self._insert_param("--audio-encode", self.params_first("ae", ""))
   13.51 +    # _parse_params
   13.52 +
   13.53 +    def start(self, outfd):
   13.54 +        self.opts.append (self.gmencoder_path)
   13.55 +        self._parser_params ()
   13.56 +        self._insert_param ("-o", "fd://%d" % outfd.fileno())
   13.57 +
   13.58 +        cmd = " ".join(self.opts)
   13.59 +        self.log.info ("GMencoder: %s", cmd)
   13.60 +
   13.61 +        try:
   13.62 +            self.proc = subprocess.Popen(self.opts, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
   13.63 +        except Exception, e:
   13.64 +            self.log.error(self.tid, "Error executing GMencoder: %s" % e)
   13.65 +            return False
   13.66 +
   13.67 +        try:
   13.68 +            while (self.proc and self.proc.poll() == None):
   13.69 +                r, w, x = select.select([self.proc.stdout], [], [], 0)
   13.70 +                if self.proc.stdout in r:
   13.71 +                    progress = self.proc.stdout.readline()
   13.72 +                    self.log.info ("stdout %s" % progress)
   13.73 +                    if (progress.find ("PROGRESS") >= 0):
   13.74 +                        self.status = progress.split (":")[1]
   13.75 +                        #if (progress.find ("DONE") >= 0):
   13.76 +                        #	break
   13.77 +			self.log.info ("Process exit")
   13.78 +        except Exception, e:
   13.79 +            self.log.error(self.tid, "Problems handling data: %s" % e)
   13.80 +            return False
   13.81 +
   13.82 +        return True
   13.83 +    # start()
   13.84 +
   13.85 +
   13.86 +    def stop(self):
   13.87 +        if self.proc:
   13.88 +            self.log.info ("STOPED GMencoder plugin")
   13.89 +            try:
   13.90 +                self.proc.stdin.write ("QUIT\n")
   13.91 +            except Exception, e:
   13.92 +                pass
   13.93 +
   13.94 +            try:
   13.95 +                self.proc.wait()
   13.96 +            except Exception, e:
   13.97 +                pass
   13.98 +
   13.99 +            self.proc = None
  13.100 +    # stop()
  13.101 +
  13.102 +# TranscoderGMencoder
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/gmyth-stream/server/0.3/plugins/transcoders/mencoder.py	Tue May 29 21:24:48 2007 +0100
    14.3 @@ -0,0 +1,305 @@
    14.4 +#!/usr/bin/env python
    14.5 +
    14.6 +__author__ = "Artur Duque de Souza"
    14.7 +__author_email__ = "artur.souza@indt.org.br"
    14.8 +__license__ = "GPL"
    14.9 +__version__ = "0.1"
   14.10 +
   14.11 +import os
   14.12 +import shlex
   14.13 +import signal
   14.14 +import subprocess
   14.15 +import time
   14.16 +import fcntl
   14.17 +
   14.18 +import lib.utils as utils
   14.19 +import lib.server as server
   14.20 +import plugins.transcoders.mencoder_lib.mythtv as mythtv
   14.21 +
   14.22 +from select import select
   14.23 +import lib.transcoder as transcoder
   14.24 +
   14.25 +__all__ = ("TranscoderMencoder",)
   14.26 +
   14.27 +class TranscoderMencoder(transcoder.Transcoder):
   14.28 +    """Transcoder class that implements a transcoder using Mencoder"""
   14.29 +    mencoder_path = utils.which("mencoder")
   14.30 +    name = "mencoder"
   14.31 +    priority = -1
   14.32 +    args = {}
   14.33 +    proc = None
   14.34 +    gmyth = None
   14.35 +
   14.36 +    # only works with avi container
   14.37 +    status = 0
   14.38 +
   14.39 +    def _setup_params(self):
   14.40 +        params_first = self.params_first
   14.41 +
   14.42 +        # general_opts
   14.43 +        self.args["local"]    = params_first("local", False)
   14.44 +        self.args["language"] = params_first("language", False)
   14.45 +        self.args["subtitle"] = params_first("subtitle", False)
   14.46 +        self.args["format"]   = params_first("format", "mpeg1")
   14.47 +        self.args["outfile"]  = params_first("outfile", "-")
   14.48 +
   14.49 +        # input_opt
   14.50 +        self.args["type"]     = params_first("type", "file")
   14.51 +        self.args["input"]    = params_first("uri", "-")
   14.52 +
   14.53 +        # audio_opts
   14.54 +        self.args["acodec"]   = params_first("acodec", "mp2")
   14.55 +        self.args["abitrate"] = params_first("abitrate", 192)
   14.56 +        self.args["volume"]   = params_first("volume", 5)
   14.57 +
   14.58 +        # video_opts
   14.59 +        self.args["mux"]      = params_first("mux", "mpeg")
   14.60 +        self.args["fps"]      = params_first("fps", 25)
   14.61 +        self.args["vcodec"]   = params_first("vcodec", "mpeg1video")
   14.62 +        self.args["vbitrate"] = params_first("vbitrate", 400)
   14.63 +        self.args["width"]    = params_first("width", 320)
   14.64 +        self.args["height"]   = params_first("height", 240)
   14.65 +    # _setup_params()
   14.66 +
   14.67 +
   14.68 +    def _setup_audio(self):
   14.69 +        if self.args["acodec"] == "mp3lame":
   14.70 +            audio = "-oac mp3lame -lameopts cbr:br=%s vol=%s" % (
   14.71 +                self.args["abitrate"], self.args["volume"])
   14.72 +        else:
   14.73 +            audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (
   14.74 +                self.args["acodec"], self.args["abitrate"])
   14.75 +
   14.76 +        return audio
   14.77 +    # _setup_audio()
   14.78 +
   14.79 +
   14.80 +    def _setup_video(self):
   14.81 +        video = " -of %s" % self.args["mux"]
   14.82 +        video += " -ofps %s" % self.args["fps"]
   14.83 +
   14.84 +        vcodec = self.args["vcodec"]
   14.85 +        if vcodec == "nuv" or vcodec == "xvid"\
   14.86 +               or vcodec == "qtvideo" or vcodec == "copy":
   14.87 +            video += " -ovc %s" % vcodec
   14.88 +        else:
   14.89 +            video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
   14.90 +                vcodec, self.args["vbitrate"])
   14.91 +
   14.92 +        if self.args["mux"] == "mpeg":
   14.93 +            video += " -mpegopts format=%s" % self.args["format"]
   14.94 +        video += " -vf scale=%s:%s" % (self.args["width"], self.args["height"])
   14.95 +
   14.96 +        return video
   14.97 +    # _setup_video()
   14.98 +
   14.99 +
  14.100 +    def _arg_append(self, args, options):
  14.101 +        for arg in shlex.split(options):
  14.102 +            args.append(arg)
  14.103 +    # arg_append()
  14.104 +
  14.105 +    def _setup_mencoder_opts(self, args):
  14.106 +        args.append(self.mencoder_path)
  14.107 +
  14.108 +        if self.args["outfile"] == "-" and self.args["type"]:
  14.109 +            args.append(self.args["input"])
  14.110 +        else:
  14.111 +            args.append("-")
  14.112 +
  14.113 +        if self.args["language"]:
  14.114 +            self._arg_append(args, "-alang %s" % self.args["language"])
  14.115 +
  14.116 +        if self.args["subtitle"]:
  14.117 +            self._arg_append(args, "-slang %s" % self.args["subtitle"])
  14.118 +            self._arg_append(args, "-subfps %s" % self.args["fps"])
  14.119 +
  14.120 +        self._arg_append(args, "-idx")
  14.121 +        self._arg_append(args, "-cache 1024")
  14.122 +        self._arg_append(args, self._setup_audio())
  14.123 +        self._arg_append(args, self._setup_video())
  14.124 +
  14.125 +        self._arg_append(args, "-really-quiet")
  14.126 +        self._arg_append(args, "-o %s" % self.args["outfile"])
  14.127 +        self._arg_append(args, "2>%s" % os.devnull)
  14.128 +    # _setup_args()
  14.129 +
  14.130 +    def _setup_filename(self):
  14.131 +        """This function setups the file to encode parsing the uri.
  14.132 +        So, type can be:
  14.133 +        * file
  14.134 +        * dvd
  14.135 +        * myth
  14.136 +
  14.137 +        If the last one is detected we have to parse the uri to find args.
  14.138 +        Then we store all the args inside a dictionary: self.args['gmyth-cat']
  14.139 +        """
  14.140 +        _type = self.args["type"]
  14.141 +
  14.142 +        if _type == "file":
  14.143 +            if not os.path.exists(self.args["input"]):
  14.144 +                raise IOError,\
  14.145 +                      "File requested does not exist: %s." % self.args["input"]
  14.146 +            else:
  14.147 +                self.args["input"] = "file://%s" % self.args["input"]
  14.148 +
  14.149 +        elif _type == "dvd":
  14.150 +            self.args["input"] = "dvd://".join(self.args["input"])
  14.151 +
  14.152 +        elif _type == "myth":
  14.153 +            self.args["gmyth-cat"] = mythtv._setup_mythfilename(self)
  14.154 +    # _setup_filename()
  14.155 +
  14.156 +
  14.157 +    def __init__(self, params):
  14.158 +        transcoder.Transcoder.__init__(self, params)
  14.159 +        self.mencoder_opts = []
  14.160 +
  14.161 +        try:
  14.162 +            self._setup_params()
  14.163 +            self._setup_filename()
  14.164 +            self._setup_mencoder_opts(self.mencoder_opts)
  14.165 +        except Exception, e:
  14.166 +            self.log.error(self.tid, e)
  14.167 +    # __init__()
  14.168 +
  14.169 +
  14.170 +    def _check_opened_file(self, stdw, _stdin):
  14.171 +        loop = True
  14.172 +        while loop:
  14.173 +            try:
  14.174 +                return open(self.args["outfile"])
  14.175 +            except:
  14.176 +                os.write(stdw, _stdin.read(1024))
  14.177 +    # _check_opened_file
  14.178 +
  14.179 +
  14.180 +    def _start_outfile(self, outfd):
  14.181 +        finished = False
  14.182 +
  14.183 +        # fix this (not necessary)
  14.184 +        outfd.write("OK")
  14.185 +
  14.186 +        # Configuring stdin
  14.187 +        try:
  14.188 +            _stdin = open(self.args["input"])
  14.189 +            size = int(os.path.getsize(self.args["input"]))
  14.190 +        except Exception, e:
  14.191 +            self.log.error(self.tid, "Mencoder stdin setup error: %s" % e)
  14.192 +            return False
  14.193 +
  14.194 +        self.status = 0
  14.195 +        total_read = 0
  14.196 +
  14.197 +        # Configuring pipes
  14.198 +        stdr, stdw = os.pipe()
  14.199 +
  14.200 +        if not self._run_mencoder(input=stdr):
  14.201 +            return False
  14.202 +
  14.203 +        stdout = self._check_opened_file(stdw, _stdin)
  14.204 +
  14.205 +        try:
  14.206 +            while self.proc and self.proc.poll() == None:
  14.207 +                if not finished:
  14.208 +                    data_in = _stdin.read(4096)
  14.209 +                    if data_in != "":
  14.210 +                        os.write(stdw, data_in)
  14.211 +                        total_read += 4096
  14.212 +                        d = stdout.read(4096)
  14.213 +                        self.status = utils.progress_bar(self.log,
  14.214 +                                                         int(total_read),
  14.215 +                                                         int(size), 50)
  14.216 +                    else:
  14.217 +                        finished = True
  14.218 +                        os.close(stdw)
  14.219 +
  14.220 +                else:
  14.221 +                    d = stdout.read(4096)
  14.222 +
  14.223 +        except Exception, e:
  14.224 +            self.log.error(self.tid, "Problems handling data: %s" % e)
  14.225 +            self.stop()
  14.226 +            return False
  14.227 +
  14.228 +        self.log.info(self.tid, "%s: Finished sending data to client" % repr(self))
  14.229 +        return True
  14.230 +    # _start_outfile()
  14.231 +
  14.232 +    def _start(self, outfd):
  14.233 +        # Play a file on disk or DVD
  14.234 +        if not self._run_mencoder(output=subprocess.PIPE):
  14.235 +            return False
  14.236 +
  14.237 +        try:
  14.238 +            while self.proc and self.proc.poll() == None:
  14.239 +                d = self.proc.stdout.read(1024)
  14.240 +                outfd.write(d)
  14.241 +        except Exception, e:
  14.242 +            self.log.error(self.tid, "Problems handling data: %s" % e)
  14.243 +            return False
  14.244 +
  14.245 +        self.log.info(self.tid, "%s: Finished sending data to client" % repr(self))
  14.246 +        return True
  14.247 +    # _start()
  14.248 +
  14.249 +    def _run_mencoder(self, input=None, output=None):
  14.250 +        try:
  14.251 +            self.proc = subprocess.Popen(self.mencoder_opts, stdin=input,
  14.252 +                                         stdout=output, close_fds=True)
  14.253 +        except Exception, e:
  14.254 +            self.log.error(self.tid, "Error executing mencoder: %s" % e)
  14.255 +            return False
  14.256 +
  14.257 +        return True
  14.258 +    # _run_mencoder()
  14.259 +
  14.260 +    def start(self, outfd):
  14.261 +        cmd = " ".join(self.mencoder_opts)
  14.262 +        self.log.debug(self.tid, "Plugin's tid: %s" % self.tid)
  14.263 +        self.log.debug(self.tid, "Mencoder: %s" % cmd)
  14.264 +        #fixme
  14.265 +
  14.266 +        ret = False
  14.267 +
  14.268 +        if self.args["outfile"] == "-" and \
  14.269 +               self.args["type"] in ["file", "dvd"]:
  14.270 +            ret = self._start(outfd)
  14.271 +
  14.272 +        elif self.args["type"] == "myth":
  14.273 +            ret = mythtv.start_myth(self, outfd)
  14.274 +
  14.275 +        else:
  14.276 +            ret = self._start_outfile(outfd)
  14.277 +
  14.278 +        self.stop()
  14.279 +
  14.280 +        if not ret:
  14.281 +            self.log.error(self.tid, "Problems while starting streaming.")
  14.282 +
  14.283 +        return ret
  14.284 +    # start()
  14.285 +
  14.286 +    def _aux_stop(self, obj, next=False):
  14.287 +        if obj:
  14.288 +            try:
  14.289 +                os.kill(obj.pid, signal.SIGKILL)
  14.290 +                if next:
  14.291 +                    os.kill(obj.pid+1, signal.SIGKILL)
  14.292 +            except OSError, e:
  14.293 +                pass
  14.294 +
  14.295 +            try:
  14.296 +                obj.wait()
  14.297 +            except Exception, e:
  14.298 +                pass
  14.299 +
  14.300 +            obj = None
  14.301 +    # _aux_stop
  14.302 +
  14.303 +    def stop(self):
  14.304 +        self._aux_stop(self.proc, True)
  14.305 +        self._aux_stop(self.gmyth)
  14.306 +    # stop()
  14.307 +
  14.308 +# TranscoderMencoder
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/gmyth-stream/server/0.3/plugins/transcoders/mencoder_lib/mythtv.py	Tue May 29 21:24:48 2007 +0100
    15.3 @@ -0,0 +1,106 @@
    15.4 +import os
    15.5 +import subprocess
    15.6 +import fcntl
    15.7 +
    15.8 +import lib.utils as utils
    15.9 +import lib.server as server
   15.10 +
   15.11 +from select import select
   15.12 +
   15.13 +def _setup_mythfilename(self):
   15.14 +    # mythtv:mythtv@192.168.3.110:6543/1002_20070426230000.nuv
   15.15 +    try:
   15.16 +        _mysql = self.args["input"].split("@")[0].split(":")
   15.17 +    except IndexError, e:
   15.18 +        _mysql = ["mythtv", "mythtv"]
   15.19 +
   15.20 +    try:
   15.21 +        _args = self.args["input"].split("@")[1].split(":")
   15.22 +    except IndexError, e:
   15.23 +        _args = self.args["input"].split(":")
   15.24 +
   15.25 +    gmyth_dict = {}
   15.26 +    gmyth_dict["mysql"] = _mysql
   15.27 +    gmyth_dict["backend"] = _args[0]
   15.28 +    gmyth_dict["port"] = _args[1].split("/", 1)[0]
   15.29 +
   15.30 +    _tmp_file = _args[1].split("/", 1)[1]
   15.31 +
   15.32 +    if _tmp_file.find("channel") >= 0:
   15.33 +        gmyth_dict["kind"] = "c"
   15.34 +        gmyth_dict["cfile"] = _tmp_file.split("=")[1]
   15.35 +    else:
   15.36 +        gmyth_dict["kind"] = "f"
   15.37 +        gmyth_dict["cfile"] = _tmp_file
   15.38 +
   15.39 +    self.args["input"] = "-"
   15.40 +    return gmyth_dict
   15.41 +# _setup_mythfilename
   15.42 +
   15.43 +def _setup_mythfile(err):
   15.44 +    size = err.readline().split("Size:")[1]
   15.45 +    flags = fcntl.fcntl (err, fcntl.F_GETFL, 0) | os.O_NONBLOCK
   15.46 +    fcntl.fcntl(err, fcntl.F_SETFL, flags)
   15.47 +    return size
   15.48 +# _setup_mythfile
   15.49 +
   15.50 +def _setup_gmythcat(self):
   15.51 +    gmyth_cat = utils.which("gmyth-cat")
   15.52 +    if self.args.has_key("gmyth-cat"):
   15.53 +        return [ utils.which("gmyth-cat"),
   15.54 +                 "-h", self.args["gmyth-cat"]["backend"],
   15.55 +                 "-p", self.args["gmyth-cat"]["port"],
   15.56 +                 "-" + self.args["gmyth-cat"]["kind"],
   15.57 +                 self.args["gmyth-cat"]["cfile"]
   15.58 +                 ]
   15.59 +    else:
   15.60 +        self.log.error(self.tid, "URI error")
   15.61 +        return []
   15.62 +# _setup_gmythcat
   15.63 +
   15.64 +def start_myth(self, outfd):
   15.65 +    opts = _setup_gmythcat(self)
   15.66 +    try:
   15.67 +        self.gmyth = subprocess.Popen(opts, stdout=subprocess.PIPE,
   15.68 +                                      stderr=subprocess.PIPE,
   15.69 +                                      close_fds=True)
   15.70 +    except Exception, e:
   15.71 +        self.log.error(self.tid, "Error executing gmyth-cat: %s" % e)
   15.72 +        return False
   15.73 +
   15.74 +    if not self._run_mencoder(input=self.gmyth.stdout,
   15.75 +                              output=subprocess.PIPE):
   15.76 +        return False
   15.77 +
   15.78 +    if self.args["gmyth-cat"]["kind"] == "f":
   15.79 +        try:
   15.80 +            size = _setup_mythfile(self.gmyth.stderr)
   15.81 +            self.log.debug(self.tid, "Size of file: %s" % size)
   15.82 +        except Exception, e:
   15.83 +            self.log.error(self.tid, "Problems getting size of file: %s" % e)
   15.84 +            return False
   15.85 +
   15.86 +    try:
   15.87 +        while self.proc and self.proc.poll() == None:
   15.88 +            r, w, x = select([self.gmyth.stderr, self.proc.stdout],
   15.89 +                             [], [], 0)
   15.90 +            if self.proc.stdout in r:
   15.91 +                d = self.proc.stdout.read(4096)
   15.92 +                outfd.write(d)
   15.93 +
   15.94 +            if self.gmyth.stderr in r:
   15.95 +                partial = self.gmyth.stderr.read(50).split("\n")[-2]
   15.96 +                if partial != "":
   15.97 +                    self.status = utils.progress_bar(self.log,
   15.98 +                                                     int(partial),
   15.99 +                                                     int(size), 50)
  15.100 +
  15.101 +    except IndexError, e:
  15.102 +        pass
  15.103 +    except Exception, e:
  15.104 +        self.log.error(self.tid, "Problems handling data: %s" % e)
  15.105 +        return False
  15.106 +
  15.107 +    self.log.info(self.tid, "Finished sending data")
  15.108 +    return True
  15.109 +# _start_myth()