/usr/share/pyshared/pymt/modules/mjpegserver.py is in python-pymt 0.5.1-0ubuntu3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | '''
Stream the PyMT video inside MJPEG HTTP server
:Configuration:
`ip` : str, default to ''
By default, server will listen on all ips availables
`port` : int, default to 8000
TCP Port to listen
`fps` : int, default to 20
Fix a FPS to try to have the same FPS on the whole video
`size` : str, default to ''
If the image must be resized, set size to "320x240" for example
'''
#
# Developper note
#
# Double lock is needed if we don't want the sensation about laggy video
# The deal is, if we don't lock the screen, you got more FPS on OpenGL than
# streaming (and that would be good.) Except that since it's not synced,
# video look laggy.
# Double-lock was just the faster solution to do right now :)
#
import os
import pymt
import threading
import time
import StringIO
import random
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from OpenGL.GL import glReadBuffer, glReadPixels, GL_RGB, GL_UNSIGNED_BYTE, GL_FRONT
from pymt.utils import curry
if 'PYMT_DOC' not in os.environ:
from PIL import Image
lock_current = threading.Lock()
sem_current = threading.Semaphore(0)
sem_next = threading.Semaphore(1)
img_current = None
connected = False
def keep_running():
return True
class MjpegHttpRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
global connected, sem_next
try:
connected = True
self._stream_video()
finally:
connected = False
# to prevent that app hang
sem_next.release()
pymt.pymt_logger.info(
'MjpegServer: Client %s:%d disconnect' % self.client_address)
def _stream_video(self):
global img_current
lfps = []
dt = 0
frames = 0
fps_wanted = self.server.config.get('fps')
if fps_wanted == '':
fps_wanted = 0
fps_wanted = float(fps_wanted)
if fps_wanted <= 1:
fps_wanted = 0
else:
fps_wanted = 1 / fps_wanted
size = self.server.config.get('size')
if size == '':
size = None
else:
size = map(int, size.split('x'))
pymt.pymt_logger.info(
'MjpegServer: Client %s:%d connected' % self.client_address)
self.send_response(200, 'OK')
self.boundary = 'pymt-mjpegserver-boundary-%d' % (random.randint(1, 9999999))
self.send_header('Server', 'PyMT MjpegServer')
self.send_header('Content-type', 'multipart/x-mixed-replace; boundary=%s' % self.boundary)
self.end_headers()
# don't accept connection until the window is created
# XXX really needed ?
while not pymt.getWindow():
time.sleep(0.1)
win = pymt.getWindow()
dt = dt_current = dt_old = time.time()
while keep_running():
# SYNC START
sem_current.acquire()
with lock_current:
im = Image.fromstring('RGB', win.size, img_current)
img_current = None
sem_next.release()
# SYNC END
buf = StringIO.StringIO()
if size:
im = im.resize(size)
im = im.transpose(Image.FLIP_TOP_BOTTOM)
im.save(buf, format='JPEG')
jpeg = buf.getvalue()
self.wfile.write('--%s\r\n' % self.boundary)
self.wfile.write('Content-Type: image/jpeg\r\n')
self.wfile.write('Content-Length: %d\r\n\r\n' % len(jpeg))
self.wfile.write(jpeg)
dt_old = dt_current
dt_current = time.time()
d = dt_current - dt_old
if d < fps_wanted:
time.sleep(d)
frames += 1
if dt_current - dt > 2.:
fps = frames / (dt_current - dt)
lfps.append(fps)
x = sum(lfps) / len(lfps)
pymt.pymt_logger.debug('MjpegServer: current FPS is %.1f, average is %.1f' % (fps, x))
dt = dt_current
frames = 0
class MjpegServerThread(threading.Thread):
def __init__(self, config):
super(MjpegServerThread, self).__init__()
self.config = config
def run(self):
server_address = (self.config.get('ip'), int(self.config.get('port')))
httpd = HTTPServer(server_address, MjpegHttpRequestHandler)
httpd.config = self.config
pymt.pymt_logger.info('MjpegServer: Listen to %s:%d' % server_address)
while keep_running():
httpd.handle_request()
def window_flip_and_save():
global img_current
win = pymt.getWindow()
with lock_current:
if not connected:
return
sem_next.acquire()
with lock_current:
glReadBuffer(GL_FRONT)
data = glReadPixels(0, 0, win.width, win.height, GL_RGB, GL_UNSIGNED_BYTE)
img_current = str(buffer(data))
sem_current.release()
def start(win, ctx):
win.push_handlers(on_flip=window_flip_and_save)
ctx.config.setdefault('ip', '')
ctx.config.setdefault('port', '8000')
ctx.config.setdefault('fps', '')
ctx.config.setdefault('size', '')
ctx.server = MjpegServerThread(ctx.config)
ctx.server.daemon = True
ctx.server.start()
def stop(win, ctx):
win.remove_handlers(on_flip=window_flip_and_save)
|