Skip to content

Commit

Permalink
Added MJPEG streamer
Browse files Browse the repository at this point in the history
  • Loading branch information
sgjava committed May 21, 2013
1 parent 0e7694f commit 16dc4d3
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
76 changes: 76 additions & 0 deletions streamer/GStreamerMjpeg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
Created on May 19, 2013
@author: sgoldsmith
Copyright (c) Steven P. Goldsmith
All rights reserved.
"""
import socket
import select
import threading
import wsgiref.simple_server
import SocketServer
import IPCameraApp

class GStreamerMjpeg(SocketServer.ThreadingMixIn, wsgiref.simple_server.WSGIServer):
"""GStreamer multipartmux MJPEG streamer.
Based on https://gist.github.com/tzicatl/2409785
Run this script and then launch the following GStreamer pipeline:
Camera produces image/jpeg (this is the most efficient since no encoding takes place):
gst-launch-1.0 v4l2src, timeout=5 ! image/jpeg, framerate=30/1, width=800, height=600 ! multipartmux boundary=cvp ! tcpclientsink port=9999
Camera produces video/x-raw:
gst-launch-1.0 v4l2src, timeout=5 ! video/x-raw, framerate=30/1, width=800, height=600 ! jpegenc ! multipartmux boundary=cvp ! tcpclientsink port=9999
If you see 'libv4l2: error dequeuing buf: Success' errors add &>/dev/null to the end of the command string.
"""
pass

def createServer(host, port, app, server_class=wsgiref.simple_server.WSGIServer, handler_class=wsgiref.simple_server.WSGIRequestHandler):
return wsgiref.simple_server.make_server(host, port, app, server_class, handler_class)

def inputLoop(app):
sock = socket.socket()
sock.bind(('', 9999))
sock.listen(1)
while True:
print "Waiting for input stream from gstreamer..."
sd, addr = sock.accept()
print "Accepted input stream from", addr
data = True
while data:
readable = select.select([sd], [], [], 0.1)[0]
for s in readable:
data = s.recv(1024)
if not data:
break
for q in app.queues:
q.put(data)
print "Lost input stream from", addr

if __name__ == "__main__":
# Launch an instance of wsgi server
app = IPCameraApp.IPCameraApp()
port = 1337
print "Launching camera server on port", port
httpd = createServer('', port, app)

print "Launch input stream thread"
t1 = threading.Thread(target=inputLoop, args=[app])
t1.setDaemon(True)
t1.start()

try:
print "Httpd serve forever"
httpd.serve_forever()
except KeyboardInterrupt:
httpd.kill()
print "Shutdown camera server"
65 changes: 65 additions & 0 deletions streamer/IPCameraApp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Created on May 20, 2013
@author: sgoldsmith
Copyright (c) Steven P. Goldsmith
All rights reserved.
"""

import Queue

INDEX_PAGE = """
<html>
<head>
<title>GStreamerMjpeg</title>
</head>
<body>
<h3>Use /mjpeg_stream to get just MJPEG stream</h3>
<img src="/mjpeg_stream"/>
<hr />
</body>
</html>
"""
ERROR_404 = """
<html>
<head>
<title>404 - Not Found</title>
</head>
<body>
<h3>404 - Not Found</h3>
</body>
</html>
"""

class IPCameraApp(object):
queues = []

def __call__(self, environ, start_response):
if environ['PATH_INFO'] == '/':
start_response("200 OK", [
("Content-Type", "text/html"),
("Content-Length", str(len(INDEX_PAGE)))
])
return iter([INDEX_PAGE])
elif environ['PATH_INFO'] == '/mjpeg_stream':
return self.stream(start_response)
else:
start_response("404 Not Found", [
("Content-Type", "text/html"),
("Content-Length", str(len(ERROR_404)))
])
return iter([ERROR_404])

def stream(self, start_response):
start_response('200 OK', [('Content-type', 'multipart/x-mixed-replace; boundary=--cvp')])
q = Queue.Queue()
self.queues.append(q)
while True:
try:
yield q.get()
except:
if q in self.queues:
self.queues.remove(q)
return
Empty file added streamer/__init__.py
Empty file.

0 comments on commit 16dc4d3

Please sign in to comment.