Streaming video using pyzmq
<p>I am using the Python bindings for zmq to send messages both between processes and across a network.  So far, no problem.  I now have an application where I want to stream data recovered from a small camera on a Raspberry Pi.  I have no issues actually recording the data but now I want to be able to stream that data.  I have an example on how to do this using the low level <code>sockets</code> api but would really like to use <code>zmq</code> for this application.</p>

<p>The <code>picamera</code> <a href="https://picamera.readthedocs.io/en/release-1.10/recipes1.html#recording-to-a-network-stream" rel="nofollow">documentation</a> has the example below on how to use a network stream to send data:</p>

<pre><code>import socket
import time
import picamera

# Connect a client socket to my_server:8000 (change my_server to the
# hostname of your server)
client_socket = socket.socket()
client_socket.connect(('my_server', 8000))

# Make a file-like object out of the connection
connection = client_socket.makefile('wb')
try:
    with picamera.PiCamera() as camera:
        camera.resolution = (640, 480)
        camera.framerate = 24
        # Start a preview and let the camera warm up for 2 seconds
        camera.start_preview()
        time.sleep(2)
        # Start recording, sending the output to the connection for 60
        # seconds, then stop
        camera.start_recording(connection, format='h264')
        camera.wait_recording(60)
        camera.stop_recording()
finally:
    connection.close()
    client_socket.close()
</code></pre>

<p><code>zmq</code> does not implement a <code>buffer</code> interface, so you can not simply change the <code>socket</code> object for a <code>zmq.Context()</code> object.  I feel like this should be relatively simple, but have been unable to find any information on this.  Does anyone have any suggestions on how to use the <code>zmq</code> api in this case?</p>

<h2>RPi side: <code>picamera.PiCamera()</code> API rulez:</h2>

<p>Besides the file-based output, RPi has another alternative for the <strong><code>output</code></strong> attribute, worth a try.</p>

<blockquote>
  <p><a href="https://picamera.readthedocs.io/en/release-1.12/api_camera.html" rel="nofollow">If output is not a <strong><code>string</code></strong>, but is an object with a <strong><code>write()</code></strong> method, it is assumed to be a file-like object and the video data is appended to it (the implementation only assumes the object has a <code>write()</code> method - no other methods are required but <strong><code>flush()</code></strong> will be called at the end of recording if it is present).<br><br>If output is not a <code>string</code>, and has no <code>write()</code> method it is assumed to be a writeable object implementing the buffer protocol. In this case, the video frames will be written sequentially to the underlying buffer (which must be large enough to accept all frame data).</a></p>
</blockquote>

<h2>So?</h2>

<p>The most straight forward way is to create a Class for interfacing objects, equipped with both the <strong><code>.write()</code></strong> and <strong><code>.flush()</code></strong> methods, that would transfer the relevant video-data towards the messaging zmq-sockets ( may have more than just the one trivial <strong><code>PUB/SUB</code></strong> archetype, so as to have Out-of-Band signalling and similar nice features coming from ZeroMQ Scaleable Formal Communications Framework ) that were instantiated under the central <code>zmq.Context()</code>.</p>

<h2>Performance?</h2>

<p>If running into doubts about IO-performance, there are steps that could be done on the ZeroMQ side -- instantiate the central I/O-pumping <code>Context</code> with more than just a single I/O-thread by <code>zmq.Context( numOfIOthreads )</code> and perhaps decide on using sort of balancing steps with different <strong><code>AFFINITY</code></strong> settings in instantiated <code>aSocketINSTANCE.setsockopt()</code> so as to "reserve" some relative I/O-priorities among the respective instances, pre-reserving the shared-resources in respective manner to protect some minimum levels of access to I/O-threads as needed in your design's performance requirements ( until hardware can support and benefit from those levels of concurrency ).</p>

python sockets raspberry-pi zeromq pyzmq