Stream a Pi Camera to Oracle Cloud Part Deux
by Chris Bensen
If you prefer you can read this blog post on GitHub here.
Last time in Stream a Pi Camera to Oracle Cloud part one, I showed you how to stream to Oracle Cloud from a Raspberry Pi with a V2 Pi Camera using the new Pi Camera system. That article was simplified with step-by-step directions. I also explained a lot of the problems the Pi camera system faces, as there are many issues and I haven’t seen them outlined in one place. Lastly, when we add up all of these permutations in software, hardware, operating systems, and bugs it becomes very complicated. What I hope you come away with after this series are some examples that have been tested and verified to work so you can use them for your own projects.
Let’s look at the Legacy Pi Camera. It’s legacy, but it still works (for now). But it’s important that I explain some differences at the time of writing this:
- The Legacy Camera currently (Buster and Bullseye) works on Pi Zero, Pi 3 and Pi 4.
- I have not tested the Pi Zero (yet).
- It is not possible to initiate a stream from the Pi to an external server with the New Camera System.
- The New Camera System is not accessible from Python or OpenCV (yet).
- I have not tested every permutation or combination on all Pi.
- I have had better luck with Motion-JPEG when streaming throughout the entire stack (Pi -> Web Server -> Web Browser).
- In a future article I hope to have a full stack H264 example.
These are the best camera docs I have been able to find:
- You have an OCI account.
- You have created a Compute Instance.
- You have locked down ssh on your compute to only your computer.
- You have setup a Compute instance to be a web server.
Example Streaming a Pi Camera to Oracle Cloud and Serving that from a Web Server
One of the few examples on the internet that I could find that actually works is this example. It hosts a web server on the Pi, just go to the web server on any computer on your network and you can see what the camera sees. I took that example and teased it apart into two pieces: a Python app that runs on the Pi and streams the video from the camera to an IP address. The server receives the stream and hosts a web server. Since the web server is hosted on Oracle Cloud you have a public IP address so anywhere in the world you can see your Pi camera!
To get started you need the prerequisites above.
Note that this example is just an example. It does not handle all error cases or reconnection cases. Once the server or client is terminated both must be restarted. This is unfortunate but by not adding all of the code you get to see the core code required to get this working.
1. At this point you have a compute instance that exposes port 80 for a web server. We also need to open up port 8100 for the incoming camera stream. Follow the steps here for adding port
8100 to the security list:
2. Then run the following commands to open up port 8100:
sudo firewall-cmd — permanent — zone=public — add-port=8100/tcp
sudo firewall-cmd — permanent — zone=public — add-port=8100/udp
sudo firewall-cmd — reload
3. Copy ``vidserver.py`` to your Compute instance:
scp vidserver.py pi@<PI IP Address>:/home/pi
4. Run the video web server:
sudo python3 vidserver.py
The web server will wait until the stream is connected.
from http import server
<title>Raspberry Pi — Surveillance Camera</title>
<center><h1>Raspberry Pi — Surveillance Camera</h1></center>
<center><img src=”stream.mjpg” width=”640" height=”480"></center>
“””serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.listen()(clientConnected, clientAddress) = serverSocket.accept()
print(“Accepted a connection request from %s:%s”%(clientAddress, clientAddress))def receiveMessage(connection):
result = None
# Message: [4 byte message length][variable message]
lengthOfStruct = internalReceiveMessage(connection, 4)if lengthOfStruct:
messageLength = struct.unpack(‘>I’, lengthOfStruct)
result = internalReceiveMessage(connection, messageLength)return resultdef internalReceiveMessage(connection, length):
# Internal function to receive a specific length number of bytes.
# Returns the received data or returns None if EOF is encountered.
result = bytearray()while len(result) < length:
packet = connection.recv(length — len(result))if not packet:
result = None
breakresult.extend(packet)return resultclass StreamingHandler(server.BaseHTTPRequestHandler):
if self.path == ‘/’:
elif self.path == ‘/index.html’:
content = PAGE.encode(‘utf-8’)
elif self.path == ‘/stream.mjpg’:
self.send_header(‘Cache-Control’, ‘no-cache, private’)
self.send_header(‘Content-Type’, ‘multipart/x-mixed-replace; boundary=FRAME’)
frame = receiveMessage(clientConnected)
self.wfile.write(b’ — FRAME\r\n’)
except Exception as e:
‘Removed streaming client %s: %s’,
self.end_headers()class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
allow_reuse_address = True
daemon_threads = Truetry:
address = (‘’, 80)
server = StreamingServer(address, StreamingHandler)
Rasbperry Pi Set Up
1. Set up an SD card with your favorite OS. Here’s how you can install Oracle Linux but Raspberry Pi OS is super easy to install with the Raspberry Pi Imager. Whichever OS you decide to use, they will all work and there are reasons to use each one.
Note that there are some differences between the OS choices and the version of your Raspberry Pi, where some things work and some won’t. I’ll do my best to note where this is the case, but I don’t have an all-inclusive list. Below is a list I’ve compiled to help clear up the choices.
1. The first thing I do when I boot up a Pi is rename one audio file. When the Pi first boots up you will get an annoying “to install a screen reader press control alt space” if you have audio hooked up:
sudo mv /usr/share/piwiz/srprompt.wav /usr/share/piwiz/srprompt.wav.old
2. Update the OS:
sudo apt-get update -y && sudo apt-get upgrade -y
3. Turn on SPI, I2C and the Legacy Camera:
NOTE: Bullseye does not have this option in the GUI version of the raspi-config tool.
4. Reboot for all changes to take effect:
5. Setup the camera for Motion-MPEG. Run the command:
sudo pico /boot/config.txt
At the bottom of the file make sure any line with the name:
dtoverlay= is removed.
NOTE: I have seen examples where
dtoverlay=imx219 needs to be in the config.txt but from my experiments this is not the case. I did these tests with the V2 camera.
5. Copy sendvid.py to your Pi:
scp sendvid.py pi@<PI IP Address>:/home/pi
from threading import Condition
import structparser = argparse.ArgumentParser(description=”stream video.”)
args = parser.parse_args()address = (args.ip, args.port)
clientSocket = Nonewhile True:
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(“Connection Failed, Retrying..”)
time.sleep(1)print(“connected”)def sendMessage(connection, message):
# Message: [4 byte message length][variable message]
lmessage = struct.pack(‘>I’, len(message)) + message
self.buffer = io.BytesIO()def write(self, buf):
return self.buffer.write(buf)with picamera.PiCamera(resolution=’640x480', framerate=24) as camera:
output = StreamingOutput()
6. Once you have ``sendvid.py`` on your Pi, run it:
sudo python3 sendvid.py <IpAddress> 8100
View the Video
1. Open up a web browser, type in your public IP address and watch your camera!
If you have any questions or for interactive support and community check out Oracle’s public Slack channel for developers.