[svn r584] Added samples/gmyth-cat. Currently working only remote files (not livetv)
3 __author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
4 __author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
15 import lib.utils as utils
18 __all__ = ("Transcoder", "RequestHandler", "Server", "serve_forever",
19 "load_plugins_transcoders")
21 class Transcoder(object):
22 log = log.getLogger("gms.transcoder")
23 priority = 0 # negative values have higher priorities
24 name = None # to be used in requests
26 def __init__(self, params):
31 def params_first(self, key, default=None):
33 return self.params[key][0]
36 return self.params[key][0]
42 def get_mimetype(self):
43 mux = self.params_first("mux", "mpg")
48 return "video/x-msvideo"
50 return "application/octet-stream"
54 def start(self, outfile):
65 return '%s("%s", mux="%s", params=%s, addr=%s)' % \
66 (self.__class__.__name__,
67 self.params_first("uri", "None"),
68 self.params_first("mux", "mpg"),
76 class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
77 log = log.getLogger("gms.request")
79 transcoders = utils.PluginSet(Transcoder)
82 def load_plugins_transcoders(cls, directory):
83 cls.transcoders.load_from_directory(directory)
85 if cls.def_transcoder is None and cls.transcoders:
86 cls.def_transcoder = cls.transcoders[0].name
87 # load_plugins_transcoders()
90 def do_dispatch(self, body):
93 pieces = urlparse.urlparse(self.path)
95 self.query = cgi.parse_qs(pieces[4])
99 elif self.path == "/shutdown.do":
100 self.serve_shutdown(body)
101 elif self.path == "/stop-transcoder.do":
102 self.serve_stop_transcoder(body)
103 elif self.path == "/status.do":
104 self.serve_status(body)
105 elif self.path == "/play.do":
106 self.serve_play(body)
107 elif self.path == "/stream.do":
108 self.serve_stream(body)
110 self.send_error(404, "File not found")
115 self.do_dispatch(True)
120 self.do_dispatch(False)
124 def _nav_items(self):
125 self.wfile.write("""\
126 <li><a href="/play.do">Play</a></li>
127 <li><a href="/status.do">Status</a></li>
128 <li><a href="/stop-transcoder.do">Stop transcoders</a></li>
129 <li><a href="/shutdown.do">Shutdown Server</a></li>
134 def serve_main(self, body):
135 self.send_response(200)
136 self.send_header("Content-Type", "text/html")
137 self.send_header('Connection', 'close')
140 self.wfile.write("""\
142 <head><title>GMyth-Streamer Server</title></head>
144 <h1>Welcome to GMyth-Streamer Server</h1>
148 self.wfile.write("""\
156 def serve_play(self, body):
157 self.send_response(200)
158 self.send_header("Content-Type", "text/html")
159 self.send_header('Connection', 'close')
162 self.wfile.write("""\
164 <head><title>GMyth-Streamer Server</title></head>
167 <form action="/stream.do" method="GET">
168 <input type="text" name="type" value="file" />://<input type="text" name="location" value=""/>
169 <input type="submit" />
174 self.wfile.write("""\
182 def serve_shutdown(self, body):
183 self.send_response(200)
184 self.send_header("Content-Type", "text/html")
185 self.send_header('Connection', 'close')
188 self.wfile.write("""\
190 <head><title>GMyth-Streamer Server Exited</title></head>
192 <h1>GMyth-Streamer is not running anymore</h1>
196 self.server.server_close()
200 def serve_stop_all_transcoders(self, body):
201 self.send_response(200)
202 self.send_header("Content-Type", "text/html")
203 self.send_header('Connection', 'close')
206 self.server.stop_transcoders()
207 self.wfile.write("""\
209 <head><title>GMyth-Streamer Server Stopped Transcoders</title></head>
211 <h1>GMyth-Streamer stopped running transcoders</h1>
215 self.wfile.write("""\
220 # serve_stop_all_transcoders()
223 def serve_stop_selected_transcoders(self, body, requests):
224 self.send_response(200)
225 self.send_header("Content-Type", "text/html")
226 self.send_header('Connection', 'close')
229 self.wfile.write("""\
231 <head><title>GMyth-Streamer Server Stopped Transcoders</title></head>
233 <h1>GMyth-Streamer stopped running transcoders:</h1>
236 transcoders = self.server.get_transcoders()
240 host, port = req.split(":")
247 for t, r in transcoders:
248 if r.client_address == addr:
252 self.log.info("Plugin already stopped")
254 self.wfile.write("""\
256 """ % (t, addr[0], addr[1]))
258 self.wfile.write("""\
263 self.wfile.write("""\
268 # serve_stop_selected_transcoders()
271 def serve_stop_transcoder(self, body):
272 req = self.query.get("request", None)
273 if req and "all" in req:
274 self.serve_stop_all_transcoders(body)
276 self.serve_stop_selected_transcoders(body, req)
278 self.serve_status(body)
279 # serve_stop_transcoder()
282 def serve_status(self, body):
283 self.send_response(200)
284 self.send_header("Content-Type", "text/html")
285 self.send_header('Connection', 'close')
288 self.wfile.write("""\
290 <head><title>GMyth-Streamer Server Status</title></head>
292 <h1>GMyth-Streamer Status</h1>
294 tl = self.server.get_transcoders()
296 self.wfile.write("<p>No running transcoder.</p>\n")
298 self.wfile.write("<p>Running transcoders:</p>\n")
299 self.wfile.write("""\
301 <li><a href="/stop-transcoder.do?request=all">[STOP ALL]</a></li>
303 for transcoder, request in tl:
304 self.wfile.write("""\
305 <li>%s: %s:%s <a href="/stop-transcoder.do?request=%s:%s">[STOP]</a></li>
306 """ % (transcoder, request.client_address[0], request.client_address[1],
307 request.client_address[0], request.client_address[1]))
309 self.wfile.write("""\
314 self.wfile.write("""\
322 def _get_transcoder(self):
323 # get transcoder option: mencoder is the default
324 request_transcoders = self.query.get("transcoder", ["mencoder"])
326 for t in request_transcoders:
327 transcoder = self.transcoders.get(t)
332 return self.transcoders[self.def_transcoder]
336 def serve_stream(self, body):
337 transcoder = self._get_transcoder()
339 obj = transcoder(self.query)
341 self.send_error(500, str(e))
344 self.send_response(200)
345 self.send_header("Content-Type", obj.get_mimetype())
346 self.send_header('Connection', 'close')
350 self.server.add_transcoders(self, obj)
351 obj.start(self.wfile)
352 self.server.del_transcoders(self, obj)
356 def log_request(self, code='-', size='-'):
357 self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
361 def log_error(self, format, *args):
362 self.log.error("%s: %s" % (self.address_string(), format % args))
366 def log_message(self, format, *args):
367 self.log.info("%s: %s" % (self.address_string(), format % args))
373 class Server(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
374 log = log.getLogger("gms.server")
377 _lock = threading.RLock()
379 def serve_forever(self):
380 self.log.info("GMyth-Streamer serving HTTP on %s:%s" %
381 self.socket.getsockname())
384 self.handle_request()
385 except KeyboardInterrupt, e:
388 self.log.debug("Stopping all remaining transcoders...")
389 self.stop_transcoders()
390 self.log.debug("Transcoders stopped!")
394 def get_request(self):
396 old = skt.gettimeout()
403 except socket.timeout, e:
405 raise socket.error("Not running")
409 def server_close(self):
411 self.stop_transcoders()
413 BaseHTTPServer.HTTPServer.server_close(self)
417 def stop_transcoders(self):
419 for transcoder, request in self._transcoders.iteritems():
420 self.log.info("Stop transcoder: %s, client=%s" %
421 (transcoder, request.client_address))
427 def get_transcoders(self):
430 return self._transcoders.items()
436 def add_transcoders(self, request, transcoder):
439 self._transcoders[transcoder] = request
445 def del_transcoders(self, request, transcoder):
448 del self._transcoders[transcoder]
456 def serve_forever(host="0.0.0.0", port=40000):
459 RequestHandler.protocol_version = "HTTP/1.0"
460 httpd = Server(addr, RequestHandler)
461 httpd.serve_forever()
465 def load_plugins_transcoders(directory):
466 RequestHandler.load_plugins_transcoders(directory)
467 # load_plugins_transcoders()