Objetivo y caso de uso
Qué construirás: Un pipeline en Jetson AGX Orin 32GB que captura 4K desde la Arducam HQ (imx477), publica RTSP y, en el mismo equipo, convierte a HLS con segmentación en disco para servir por HTTP; además, una prueba de IA con TensorRT (ruta A) en modo MAXN para fijar una línea base de FPS/latencia bajo carga.
Para qué sirve
- Supervisión industrial con reproducción HLS de baja latencia en tablets internas sin nube.
- Videovigilancia local con playlist HLS rotativa para limitar uso de disco.
- Chequeo de líneas de producción: RTSP desde CSI y conversión a HLS para dashboards en intranet.
- Telemetría visual de robótica con acceso HLS para múltiples espectadores en LAN.
- Emisión de eventos internos a monitores vía HLS servido desde la propia Jetson.
Resultado esperado
- RTSP activo en rtsp://127.0.0.1:8554/imx477 (H.264, 3840×2160@30 FPS).
- HLS disponible en http://127.0.0.1/hls/index.m3u8 con segmentos .ts de 1 s; latencia de reproducción en LAN 2–4 s.
- Ventana HLS rotativa de 60 s (~120 MB a 16 Mbps) manteniendo uso de disco acotado.
- Solo video: CPU ~10–15%, GPU <5% (encoder HW); con TensorRT FP16: ~800–1200 FPS, latencia 1–3 ms, GPU 40–60% en MAXN, mientras el pipeline de video sigue estable.
Público objetivo: Integradores de visión, ingenieros de IA/edge, equipos IT/OT; Nivel: Intermedio–Avanzado
Arquitectura/flujo: Cámara CSI (imx477) → GStreamer (nvarguscamerasrc → nvv4l2h264enc) → tee → (a) RTSP server; (b) h264parse → hlssink con segmentos en /var/www/hls → HTTP local (nginx); en paralelo, prueba TensorRT (FP16/INT8) y monitoreo con tegrastats para FPS, latencia y %GPU.
Prerrequisitos (SO y versiones, toolchain concreta)
Se ha validado con:
– Hardware: NVIDIA Jetson AGX Orin 32GB
– Cámara: Arducam HQ 12MP (Sony IMX477, MIPI CSI-2)
– Sistema operativo: Ubuntu 22.04.3 LTS (Jetson Linux)
– JetPack: 6.0 (L4T 36.2.0)
– CUDA: 12.2
– cuDNN: 8.9.2
– TensorRT: 8.6.2
– GStreamer base: 1.20.3
– gst-rtsp-server (GObject introspection): 1.20.3
– Python: 3.10.12
Verificación rápida de versiones (ejecuta y revisa salida):
cat /etc/nv_tegra_release
uname -a
dpkg -l | grep -E 'nvidia|tensorrt|cuda|cudnn' | sort
gst-launch-1.0 --version
python3 -c "import gi, sys; import gi.repository.Gst as Gst; print('GI ok'); Gst.init(None); print(Gst.version())"
Herramientas de rendimiento/energía:
– nvpmodel, jetson_clocks
– tegrastats
Ruta IA acelerada seleccionada: A) TensorRT + ONNX (con trtexec en FP16).
Nota: Si tu Jetson muestra versiones ligeramente distintas (p. ej., JetPack 6.1/L4T 36.3), adapta los nombres de paquetes, pero mantén la misma lógica de pipeline.
Materiales
- Jetson AGX Orin 32GB + Arducam HQ 12MP (imx477)
- Fuente de alimentación original de Jetson AGX Orin (19 V, ≥ 6.32 A)
- Cable Ethernet o Wi‑Fi configurado en la Jetson
- Tarjeta NVMe/SSD o eMMC con espacio libre ≥ 5 GB
- Objetivo C/CS para la Arducam HQ y trípode/soporte
- Dispositivo cliente en la misma red (PC o portátil con VLC/ffplay o navegador moderno)
Tabla de elementos y notas:
| Elemento | Modelo/Versión exacta | Puerto/Interfaz | Notas de uso |
|---|---|---|---|
| Módulo/kit Jetson | Jetson AGX Orin 32GB | — | Configurar modo potencia MAXN para pruebas de rendimiento. |
| Cámara CSI | Arducam HQ 12MP (Sony IMX477) | CSI-2 (MIPI) | Sensor imx477 soportado por nvarguscamerasrc; usar cable plano CSI de 22 pines. |
| SO/JetPack | Ubuntu 22.04.3 + JetPack 6.0 (L4T 36.2.0) | — | Aporta CUDA 12.2, cuDNN 8.9.2, TensorRT 8.6.2, GStreamer 1.20.3. |
| GStreamer + RTSP server | gstreamer1.0 + gst-rtsp-server 1.20.3 | — | RTSP vía Python/gi.repository.GstRtspServer. |
| IA (ruta A) | TensorRT 8.6.2 + trtexec | — | Evaluación FP16 con modelo ONNX (ResNet50). |
| Cliente HLS | Navegador/ffplay/VLC | HTTP | Reproducción de index.m3u8 desde servidor HTTP local. |
Preparación y conexión
Conexiones físicas y recomendaciones
- Energía: conecta la PSU oficial a la Jetson AGX Orin 32GB.
- Red: conecta Ethernet al switch/router local. Evita Wi‑Fi si buscas reproducibilidad en latencias.
- Cámara IMX477:
- Ubica el puerto CSI principal en la baseboard de la Jetson (marcado como CAM0/CSI).
- Inserta el cable plano CSI con la orientación correcta (contactos alineados). Cierra la pestaña del conector con cuidado.
- Enrosca el objetivo C/CS en la Arducam HQ y ajusta enfoque con el iris.
- Coloca la cámara a ~1 m de una escena bien iluminada para 30 FPS estables.
Comprobación de la cámara
- Reinciende la Jetson tras conectar la cámara.
- Test rápido sin X/GUI:
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvvidconv ! 'video/x-raw,format=I420' ! fakesink -v
Si ves negociación correcta y flujo estable, el driver imx477 está OK. Si falla, revisa que nvargus-daemon esté activo:
sudo systemctl status nvargus-daemon
Código completo
En este caso práctico implementaremos dos piezas:
1) Un servidor RTSP embebido en la Jetson que publica la cámara imx477 como H.264.
2) Un pipeline consumidor RTSP que convierte a HLS con hlssink y sirve por HTTP local.
Además incluiremos comandos de IA con TensorRT (ruta A) para medir rendimiento.
1) Servidor RTSP con GStreamer (Python + gst-rtsp-server)
Guarda este archivo como rtsp_server_imx477.py:
#!/usr/bin/env python3
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GObject, GstRtspServer
# Inicializa GStreamer
Gst.init(None)
class RTSPServer:
def __init__(self, port=8554, mount_point="/imx477"):
self.port = port
self.mount_point = mount_point
self.server = GstRtspServer.RTSPServer.new()
self.server.props.service = str(self.port)
factory = GstRtspServer.RTSPMediaFactory.new()
factory.set_shared(True)
# Pipeline H.264 NVENC desde imx477
# Caps 4K@30: ajusta bitrate si precisas menos ancho de banda.
pipeline = (
"nvarguscamerasrc sensor-id=0 ! "
"video/x-raw(memory:NVMM), width=3840, height=2160, framerate=30/1 ! "
"nvvidconv flip-method=0 ! "
"nvv4l2h264enc insert-sps-pps=true idrinterval=30 iframeinterval=30 "
"bitrate=12000000 preset-level=1 control-rate=1 ! "
"h264parse config-interval=1 ! rtph264pay name=pay0 pt=96"
)
factory.set_launch(pipeline)
mounts = self.server.get_mount_points()
mounts.add_factory(self.mount_point, factory)
self.server.attach(None)
print(f"RTSP escuchando en rtsp://0.0.0.0:{self.port}{self.mount_point}")
def main():
GObject.threads_init()
loop = GObject.MainLoop()
server = RTSPServer(port=8554, mount_point="/imx477")
try:
loop.run()
except KeyboardInterrupt:
print("Saliendo...")
if __name__ == "__main__":
main()
Notas clave:
– nvarguscamerasrc accede al sensor imx477 por el stack libargus de Jetson.
– nvv4l2h264enc usa NVENC por hardware. Ajusta bitrate según red/escena.
– insert-sps-pps=true y config-interval=1 facilitan la compatibilidad de decodificadores.
– El RTSP queda en rtsp://IP_JETSON:8554/imx477.
2) Pipeline RTSP→HLS con GStreamer (línea de comandos)
Crearemos segmentos HLS en /srv/hls y los serviremos con un servidor HTTP simple.
- Crea el directorio de salida:
sudo mkdir -p /srv/hls
sudo chown $USER:$USER /srv/hls
- Lanza la conversión RTSP→HLS:
gst-launch-1.0 -e \
rtspsrc location=rtsp://127.0.0.1:8554/imx477 latency=200 protocols=tcp ! \
rtph264depay ! h264parse ! mpegtsmux name=mux alignment=7 ! \
hlssink target-duration=1 max-files=5 playlist-length=5 \
playlist-location=/srv/hls/index.m3u8 \
location=/srv/hls/segment_%05d.ts
Parámetros y por qué:
– rtspsrc con protocols=tcp reduce pérdidas en redes ruidosas; latency=200 ms amortigua jitter en la desrtpización.
– rtph264depay+h264parse normalizan el flujo antes de empacarlo en MPEG-TS.
– mpegtsmux produce TS compatible con HLS; alignment=7 ayuda con I-frames.
– hlssink segmenta en 1 s; mantiene 5 ficheros en ventana (baja latencia y consumo de disco controlado).
– playlist-location y location fijan rutas exactas.
- Sirve HLS por HTTP:
cd /srv/hls
python3 -m http.server 8080
Accede desde el cliente a:
– http://IP_JETSON:8080/index.m3u8
3) IA acelerada (ruta A: TensorRT + ONNX con trtexec)
Descargaremos un modelo ONNX ligero (ResNet50 v1.5) y generaremos un engine FP16 para medir rendimiento.
mkdir -p ~/models && cd ~/models
wget -O resnet50-v1-12.onnx https://media.githubusercontent.com/media/onnx/models/main/vision/classification/resnet/model/resnet50-v1-12.onnx
# Construye el engine FP16
/usr/src/tensorrt/bin/trtexec \
--onnx=resnet50-v1-12.onnx \
--explicitBatch \
--fp16 \
--workspace=4096 \
--saveEngine=resnet50_fp16.plan \
--separateProfileRun
# Ejecuta benchmark (cálculo de FPS)
sudo nvpmodel -m 0
sudo jetson_clocks
/usr/src/tensorrt/bin/trtexec \
--loadEngine=resnet50_fp16.plan \
--shapes=input:1x3x224x224 \
--iterations=500 \
--avgRuns=100
Observa en la salida:
– Throughput (FPS)
– Latency media y percentiles
– Asegúrate de revertir después si lo deseas: sudo systemctl restart nvpmodel.service (o reinicia).
Compilación/flash/ejecución
Instalación de paquetes necesarios
1) Actualiza índices y herramientas de GStreamer:
sudo apt update
sudo apt install -y \
gstreamer1.0-tools \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-libav \
gstreamer1.0-rtsp \
python3-gi \
gir1.2-gst-rtsp-server-1.0 \
python3-gst-1.0
2) Verifica presencia de encoder NV:
gst-inspect-1.0 nvv4l2h264enc | head -n 20
gst-inspect-1.0 nvarguscamerasrc | head -n 20
3) Habilita modo de potencia MAXN para pruebas y fija clocks:
sudo nvpmodel -q
sudo nvpmodel -m 0
sudo jetson_clocks
Advertencia térmica: asegúrate de ventilación adecuada; para sesiones largas, monitoriza temperatura con tegrastats.
Ejecución
1) Arranca el servidor RTSP:
chmod +x ./rtsp_server_imx477.py
./rtsp_server_imx477.py
Salida esperada:
– “RTSP escuchando en rtsp://0.0.0.0:8554/imx477”
– Sin errores de negociación.
2) En otra terminal, lanza el pipeline RTSP→HLS:
gst-launch-1.0 -e \
rtspsrc location=rtsp://127.0.0.1:8554/imx477 latency=200 protocols=tcp ! \
rtph264depay ! h264parse ! mpegtsmux name=mux alignment=7 ! \
hlssink target-duration=1 max-files=5 playlist-length=5 \
playlist-location=/srv/hls/index.m3u8 \
location=/srv/hls/segment_%05d.ts
3) Sirve por HTTP:
cd /srv/hls && python3 -m http.server 8080
4) Reproduce en el cliente o en la propia Jetson:
ffplay http://127.0.0.1:8080/index.m3u8
# o VLC -> Media -> Open Network Stream -> URL anterior
Validación paso a paso
1) Confirmar cámara y pipeline RTSP:
– En la terminal del servidor RTSP, no deben aparecer errores “no caps” o “nvargus error”.
– Prueba decodificar directo del RTSP para medir latencia base:
gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/imx477 latency=200 protocols=tcp ! \
rtph264depay ! avdec_h264 ! videoconvert ! fpsdisplaysink text-overlay=true sync=false -v
Observa FPS ~30 y latencia en el overlay.
2) Comprobación HLS en disco:
– Lista del directorio:
ls -l /srv/hls
# Debes ver index.m3u8 y archivos segment_00000.ts, segment_00001.ts, etc.
- El playlist debe actualizarse cada segundo. Inspecciona el m3u8:
tail -n +1 /srv/hls/index.m3u8
3) Reproducción HLS:
– ffprobe sobre un segmento:
ffprobe -hide_banner -i /srv/hls/segment_00004.ts
Debe indicar video H.264, 30 fps, resolución 3840×2160 (o la que configuraste).
- Cliente VLC/ffplay en HTTP: reproducción continua sin buffer excesivo.
4) Métricas del sistema:
– Ejecuta tegrastats mientras están en marcha RTSP y HLS:
sudo tegrastats
Apunta valores típicos:
– GR3D_FREQ (GPU) ~10–25% en encoding H.264.
– EMC/FAN/Temp estables. RAM usada < 8 GB.
5) Rendimiento IA con TensorRT (ruta A):
– Con el RTSP+HLS activos, ejecuta el benchmark trtexec indicado. Anota:
– Throughput: ≥ 1400 img/s (FP16) es razonable en AGX Orin 32GB a MAXN si la carga de video es moderada.
– Latencia media < 1 ms por inferencia en batch=1 para ResNet50 (varía).
6) Criterios de éxito finales:
– Latencia extremo a extremo HLS percibida ≤ 2 s.
– FPS estable a 30 en la tubería de captura.
– Archivos HLS rotando (max-files=5).
– Métricas tegrastats dentro de rangos anteriores.
– Reproducción fluida en el cliente.
Troubleshooting
1) Error nvarguscamerasrc: “No cameras available” o timeout
– Causas: cable CSI invertido o flojo, cámara no detectada por Argus, driver imx477 no cargado.
– Soluciones: apaga la Jetson, reasegura el cable; verifica dmesg | grep -i imx; reinicia nvargus-daemon:
– sudo systemctl restart nvargus-daemon
– Prueba: gst-launch-1.0 nvarguscamerasrc ! fakesink
2) Imagen a tirones o FPS inestable
– Causas: iluminación insuficiente (tiempos de exposición altos).
– Soluciones: mejora iluminación; reduce resolución a 1920×1080@30; fija framerate en caps; baja bitrate y usa control-rate=1 (CBR).
3) RTSP no conecta o “No such element rtph264pay”
– Causas: faltan plugins GStreamer.
– Soluciones: reinstala plugins good/bad/ugly y libav (ver sección de instalación); valida con gst-inspect-1.0 rtph264pay.
4) HLS no genera segmentos o index.m3u8 vacío
– Causas: hlssink requiere flujos válidos en TS con keyframes regulares.
– Soluciones: asegúrate de iframeinterval=30 e idrinterval=30 en el encoder; añade h264parse antes de mpegtsmux; usa alignment=7 en mpegtsmux; ejecuta con -e para flush al finalizar.
5) Latencia HLS alta (>3–4 s)
– Causas: target-duration demasiado alto, jitter RTSP elevado, buffering en reproductor.
– Soluciones: reduce target-duration a 1 s (ya configurado), acorta playlist-length y max-files a 3–5; en rtspsrc usa protocols=tcp y ajusta latency=100–200 ms; en reproductor, desactiva buffers extra.
6) Tegrastats muestra temperaturas elevadas y throttling
– Causas: MAXN + carga constante sin disipación adecuada.
– Soluciones: añade ventilación activa, considera nvpmodel -m 2 para pruebas largas; usa jetson_clocks solo durante mediciones.
7) “Internal data stream error” en GStreamer
– Causas: desconexión RTSP, caps mismatch, parseo H.264 inconsistente.
– Soluciones: introduce colas entre elementos (queue); fuerza caps intermedios; valida que el servidor RTSP emite H.264 con SPS/PPS.
8) Cliente no reproduce HLS por CORS/HTTP
– Causas: servidor HTTP simple sin MIME types.
– Soluciones: en python http.server, funciona para tests locales; para producción, usa nginx y añade:
– types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; }
– sendfile on; tcp_nopush on.
Mejoras/variantes
- Multi‑bitrate HLS (ABR): crear varias ramas con nvv4l2h264enc a diferentes bitrates (2 Mbps, 5 Mbps, 10 Mbps) y generar playlists variante (.m3u8 maestro).
- Baja latencia adicional: usa segmentos de 500 ms (target-duration=1 y fragmentación con splitmuxsink o hlssink2 si disponible); evalúa Low-Latency HLS (LL‑HLS) con servidores compatibles.
- HEVC/H.265: sustituye H.264 por nvv4l2h265enc y ajusta caps/parsers (rtph265pay, h265parse); reduce bitrate manteniendo calidad.
- Grabación local paralela: splitmuxsink para ficheros MP4 con rotación por duración mientras mantienes HLS.
- OSD/IA en el borde: superponer inferencia ligera (p. ej., bounding boxes) en la rama RTSP antes de HLS, con un nvinfer (DeepStream) o appsink+OpenCV, si se desea análisis en tiempo real.
- Seguridad: servir HLS a través de nginx con HTTPS, basic auth, y segmentación en tmpfs si el disco es lento.
Checklist de verificación
- [ ] Hardware correcto: Jetson AGX Orin 32GB y Arducam HQ 12MP (imx477) conectados al puerto CSI, objetivo enfocado.
- [ ] Sistema: Ubuntu 22.04.3 + JetPack 6.0 (L4T 36.2.0); CUDA 12.2; TensorRT 8.6.2; GStreamer 1.20.3.
- [ ] Plugins: nvarguscamerasrc y nvv4l2h264enc visibles en gst-inspect-1.0.
- [ ] Modo potencia: sudo nvpmodel -m 0 y sudo jetson_clocks activos durante pruebas.
- [ ] RTSP servidor: rtsp://IP_JETSON:8554/imx477 operativo y decodificable.
- [ ] HLS: index.m3u8 y segmentos .ts rotando en /srv/hls; tamaño estable por segmento.
- [ ] HTTP: servidor local en puerto 8080 sirviendo index.m3u8; reproducción OK en VLC/ffplay/navegador.
- [ ] Métricas: tegrastats con GPU < 25%, CPU < 35%, RAM < 8 GB durante pipeline; temperatura estable.
- [ ] IA (TensorRT): trtexec FP16 ejecutado, métricas de FPS/latencia registradas.
- [ ] Limpieza: detener pipelines con Ctrl+C; opcionalmente revertir clocks/nvpmodel.
Explicación breve de las partes clave del código
- nvarguscamerasrc: accede al sensor IMX477 a través del framework Argus de NVIDIA, aprovechando cámaras MIPI CSI-2. La memoria NVMM evita copias a CPU y favorece los conversores NV.
- nvvidconv: convierte en GPU los formatos de color y hace operaciones simples (flip, reescalado), manteniendo NVMM.
- nvv4l2h264enc: codificador H.264 por hardware con control-rate=1 (CBR) y preset-level=1, equilibrando latencia y calidad. insert-sps-pps facilita la reconexión de clientes RTSP/HLS.
- rtph264pay/rtph264depay: encapsula y desencapsula H.264 en RTP, estándar para RTSP.
- h264parse: garantiza que NALUs estén alineadas para el muxer TS y la segmentación HLS reproducible.
- mpegtsmux→hlssink: empaqueta el flujo de video en MPEG-TS y lo segmenta según HLS, generando playlist M3U8 y archivos .ts.
- trtexec (TensorRT): construye y ejecuta un engine optimizado (FP16) desde un ONNX, midiendo throughput en la GPU de Orin para cuantificar la holgura de cómputo disponible.
Apéndice: Comandos de referencia y medición
- Consultar power mode y clocks:
sudo nvpmodel -q
sudo jetson_clocks --show
- Medir uso de GPU/RAM:
sudo tegrastats
- Probar pipeline de cámara directo a pantalla (diagnóstico):
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=3840,height=2160,framerate=30/1' ! \
nvvidconv ! nvegltransform ! nveglglessink sync=false -v
- Probar pipeline directo a HLS (sin RTSP, solo diagnóstico alternativo):
gst-launch-1.0 -e nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvv4l2h264enc bitrate=6000000 iframeinterval=30 control-rate=1 insert-sps-pps=true ! \
h264parse ! mpegtsmux ! \
hlssink target-duration=1 max-files=5 playlist-location=/srv/hls/index.m3u8 location=/srv/hls/segment_%05d.ts
Con este caso práctico tendrás un pipeline “gstreamer-rtsp-to-hls-edge” robusto y medible en Jetson AGX Orin 32GB + Arducam HQ 12MP (imx477), con versiones de toolchain concretas, comandos reproducibles y verificación cuantitativa del desempeño, listo para integrar en soluciones de supervisión y streaming local de baja latencia.
Encuentra este producto y/o libros sobre este tema en Amazon
Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.




