Motion JPEG represents video as a continuous stream of independently encoded JPEG images. In a robot web application, a browser receives those images as a live view of the camera. section 10.4.5
A practical Motion JPEG server performs these steps:
- Watch a camera image file for changes, polling frequently enough to detect new frames. section 10.4.5
- Set the response content type to multipart Motion JPEG and define boundaries separating successive images. section 10.4.5
- Read each new JPEG, write it with its JPEG header and boundary, then flush the response to the browser. section 10.4.5
Listing 10.6 stream_web.py: Streaming video to web applications
#!/usr/bin/env python3
import os
import asyncio
import tornado.web
from watcher import FileWatcher
IMG_PATH = os.environ['XDG_RUNTIME_DIR'] + '/robo_stream.jpg'
POLL_DELAY = 1 / 60
CONTENT_TYPE = 'multipart/x-mixed-replace;boundary=image-boundary'
BOUNDARY = b'--image-boundary\r\n'
JPEG_HEADER = b'Content-Type: image/jpeg\r\n\r\n'
class MainHandler(tornado.web.RequestHandler):
async def get(self):
self.set_header('Content-Type', CONTENT_TYPE)
watcher = FileWatcher(IMG_PATH)
while True:
if watcher.has_changed():
img_bytes = open(IMG_PATH, 'rb').read()
self.write(BOUNDARY + JPEG_HEADER + img_bytes)
self.flush()
await asyncio.sleep(POLL_DELAY)
async def main():
app = tornado.web.Application([('/', MainHandler)])
app.listen(9000)
shutdown_event = asyncio.Event()
await shutdown_event.wait()
asyncio.run(main())
Use the complete Tornado listing to see the image watcher, multipart headers, asynchronous polling loop, and streaming response assembled into one server. section 10.4.5
Live robot-camera view
A robot writes successive camera frames to robo_stream.jpg. A Tornado web server detects changes and streams the JPEGs to a phone or computer on the network, allowing the viewer to see what the robot sees. section 10.0 section 10.4.5
