Esta página explicaba cómo emitir el vídeo de la cámara de la Raspberry al navegador con la biblioteca picamera. Esa biblioteca ya no funciona en Raspberry Pi OS actual: la sustituyó Picamera2. El montaje es el mismo; cambia el código que habla con la cámara.
También te puede interesar
Qué ha cambiado
Desde Raspberry Pi OS Bookworm, la cámara funciona con libcamera, y las herramientas antiguas —raspistill, raspivid y la biblioteca picamera— están, en palabras de la documentación oficial, «obsoletas desde hace muchos años y ahora sin soporte». Además, solo funcionaban con los primeros modelos de cámara.
| Antes | Ahora |
|---|---|
import picamera | from picamera2 import Picamera2 |
raspistill, raspivid | rpicam-still, rpicam-vid |
Activar la cámara en raspi-config | se detecta sola al arrancar |
Conectar y comprobar

rpicam-hello --list-cameras
Si la lista sale vacía, apaga, revisa la orientación del cable y vuelve a probar. Picamera2 viene ya instalada en Raspberry Pi OS; si no estuviera, se instala con sudo apt install python3-picamera2, con apt y no con pip, porque depende de libcamera, que es parte del sistema.
El servidor de vídeo
La idea es la misma que antes: la cámara entrega fotogramas JPEG, un objeto guarda el último, y un servidor web se lo va enviando al navegador uno tras otro con el tipo multipart/x-mixed-replace, que hace que la imagen se vaya sustituyendo. Esto es el servidor:
import io, threading, time, urllib.request
from http import server
from threading import Condition
from PIL import Image
PAGINA = """<!doctype html><meta charset="utf-8"><title>Cámara</title>
<h1>Raspberry Pi - Cámara</h1><img src="stream.mjpg" width="640" height="480">""".encode("utf-8")
class SalidaStreaming(io.BufferedIOBase):
def __init__(self):
self.frame = None
self.condition = Condition()
def write(self, buf):
with self.condition:
self.frame = buf
self.condition.notify_all()
class Manejador(server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/":
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Content-Length", str(len(PAGINA)))
self.end_headers()
self.wfile.write(PAGINA)
elif self.path == "/stream.mjpg":
self.send_response(200)
self.send_header("Cache-Control", "no-cache, private")
self.send_header("Content-Type", "multipart/x-mixed-replace; boundary=FRAME")
self.end_headers()
try:
while True:
with salida.condition:
salida.condition.wait()
frame = salida.frame
self.wfile.write(b"--FRAME\r\n")
self.send_header("Content-Type", "image/jpeg")
self.send_header("Content-Length", str(len(frame)))
self.end_headers()
self.wfile.write(frame)
self.wfile.write(b"\r\n")
except (BrokenPipeError, ConnectionResetError):
pass
else:
self.send_error(404)
def log_message(self, *a):
pass
class Servidor(server.ThreadingHTTPServer):
allow_reuse_address = True
daemon_threads = TrueY esto es lo que conecta la cámara con él:
from picamera2 import Picamera2
from picamera2.encoders import JpegEncoder
from picamera2.outputs import FileOutput
camara = Picamera2()
camara.configure(camara.create_video_configuration(main={"size": (640, 480)}))
salida = SalidaStreaming()
camara.start_recording(JpegEncoder(), FileOutput(salida))
try:
Servidor(("", 8000), Manejador).serve_forever()
finally:
camara.stop_recording()Lo hemos probado sustituyendo la cámara por fotogramas generados:
salida/ -> 200 text/html; charset=utf-8 /stream.mjpg -> 200 multipart/x-mixed-replace; boundary=FRAME fotogramas recibidos: 3 | cada uno empieza por b'\xff\xd8'
Cada fotograma empieza por FF D8, la firma de un JPEG. Abre http://IP-de-la-raspberry:8000 desde cualquier equipo de tu red; la IP la da hostname -I.

Revisada en octubre de 2026 para Raspberry Pi OS actual. Las salidas están copiadas de ejecuciones reales; lo que no se pudo ejecutar sin el hardware se indica en el propio texto.