-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.