Proyecto kiradesktop - escritorio virtual CPU/GPU para captura DRM

This commit is contained in:
Joaquin
2026-07-13 17:20:02 +02:00
commit ea5b82412f
6 changed files with 1556 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
# KiraDesktop
Sistema de escritorios virtuales remotos (X11 + XFCE) pensado para **captura de
streams con protección DRM (Widevine L3) reproducidos en Firefox**. Cada
instancia levanta un escritorio Linux headless, expone acceso VNC para
control/depuración y ofrece una API REST que produce un stream de vídeo+audio
en formato MPEG-TS (vía `ffmpeg`) listo para consumir con cualquier
reproductor/pipeline aguas abajo.
La idea general: como el contenido DRM no se puede volcar "en crudo" (el
decodificador protege los frames), se renderiza en una sesión X11 real dentro
de Firefox y se captura la salida de pantalla (X11 grab) + audio (PulseAudio
null-sink), re-codificando con `ffmpeg` a H.264/AAC en MPEG-TS. El resultado es
funcionalmente equivalente a "grabar la pantalla" del escritorio remoto.
## Arquitectura: variante CPU vs variante GPU
### Variante CPU (`cpu/`)
- Contenedores LXC (Proxmox `pct`), clonados: `kiradesktop-cpu-1` ...
`kiradesktop-cpu-12`. Son **12 instancias idénticas** en el cluster, cada
una con **1 escritorio** por contenedor.
- Servidor VNC: `Xtigervnc` (framebuffer virtual, no requiere GPU).
- Captura: `ffmpeg` con `-f x11grab` + encoder software `libx264` (preset
`superfast`, escalado a 1280x720 para aliviar la carga de CPU aunque el VNC
se sirve en 1080p).
- Cada contenedor corre un único proceso (`kiradesktop-cpu.py`) que gestiona
ese único escritorio (`/desktop/0/...`).
- Incluye `kiradesktop.py`, una versión anterior/backup del mismo script. Ver
sección "Diferencias" más abajo.
### Variante GPU (`gpu/`)
- Una VM KVM (`kirastream-gpu1`, Proxmox VM id 211) con GPU NVIDIA pasada por
passthrough/vGPU.
- Servidor VNC: `x11vnc` sobre sesiones `Xorg` reales con el driver NVIDIA
(permite aceleración GLX/VDPAU y decodificación por hardware NVDEC/VA-API
dentro de Firefox: `LIBVA_DRIVER_NAME=nvidia`, `MOZ_X11_EGL=1`).
- Captura: `ffmpeg` con `-f x11grab` + encoder por hardware `h264_nvenc`.
- Un único proceso (`kiradesktop-gpu.py`) gestiona **hasta 6 escritorios en
paralelo** (`/desktop/{0..5}/...`), cada uno con su propio display
(`:1`-`:6`), puerto VNC (`5901`-`5906`) y PulseAudio aislado.
## API REST (puerto 8900 en ambas variantes)
| Método | Ruta | Descripción |
|--------|-----------------------------------------|---------------------------------------|
| GET | `/health` | Estado de escritorio(s) |
| POST | `/desktop/{id}/start` | Arranca el escritorio `id` |
| POST | `/desktop/{id}/stop` | Detiene el escritorio `id` |
| GET | `/desktop/{id}/stream` | Stream MPEG-TS (multi-cliente) |
| GET | `/sync/firefox/export[/{slot}]` | Exporta el perfil de Firefox (.tar.gz)|
| POST | `/sync/firefox/import` | Importa un perfil de Firefox |
En la variante CPU `{id}` es siempre `0` (un solo escritorio por contenedor).
En la variante GPU `{id}` va de `0` a `5` (hasta 6 escritorios por VM).
## Puertos
- **8900/tcp** — API REST (FastAPI + uvicorn, `0.0.0.0:8900`).
- **5901/tcp** (y consecutivos `5902`-`5906` en GPU) — VNC directo al
framebuffer X11 de cada escritorio.
## Despliegue (systemd)
Cada instancia corre como servicio systemd (`kiradesktop.service` en CPU,
`kiradesktop-gpu.service` en GPU) con `Restart=always` y toda la configuración
por variables de entorno — así el mismo `.py` sirve para las 12 instancias CPU
clonadas y para la VM GPU, cambiando solo el entorno:
- `MY_IP` — IP pública/interna que se anuncia en las respuestas de la API
(`vnc_addr`, `stream_url`). **Debe fijarse por instancia** al clonar el
contenedor/VM (es lo único que realmente cambia entre clones CPU).
- `RESOLUTION`, `FRAMERATE`, `VIDEO_BITRATE`, `AUDIO_BITRATE` — parámetros de
codificación.
- `VNC_PORT` / `BASE_VNC_PORT` — puerto(s) VNC.
- `WM_CMD` — gestor de ventanas a lanzar (`startxfce4` por defecto).
- Variante GPU además: `NUM_DESKTOPS` (6), `BASE_DISPLAY`, `NVENC_PRESET`,
`XORG_CONFIG` (ruta al `xorg.conf` con el driver NVIDIA).
Instalación típica en cada nodo:
```bash
cp kiradesktop-cpu.py /opt/kiradesktop-cpu.py # o kiradesktop-gpu.py
cp kiradesktop.service /etc/systemd/system/ # o kiradesktop-gpu.service
systemctl daemon-reload
systemctl enable --now kiradesktop.service # o kiradesktop-gpu.service
```
## Diferencias entre `kiradesktop.py` y `kiradesktop-cpu.py`
`cpu/kiradesktop.py` es una **versión previa/backup** del script CPU actual
(`cpu/kiradesktop-cpu.py`), tal como se encontró en `/opt` del contenedor. Se
incluye igual por trazabilidad histórica, pero **el que está desplegado y en
uso (referenciado por el `.service`) es `kiradesktop-cpu.py`**.
La diferencia real entre ambos archivos es mínima:
- Se eliminó un comentario explicativo sobre el escalado a 720p.
- Se cambió el preset del encoder `libx264` de `ultrafast` a `superfast`
(mejor relación calidad/CPU a cambio de un poco más de carga).
El resto del código (gestión de PulseAudio, Xtigervnc, ffmpeg, API FastAPI,
export/import de perfil de Firefox) es idéntico.
## Nota de seguridad (importante para un despliegue real)
Los servidores VNC de ambas variantes se levantan **sin contraseña**
(`Xtigervnc -SecurityTypes None` en CPU, `x11vnc -nopw` en GPU) y la API REST
no implementa autenticación. Esto asume que el servicio corre en una red
interna/confiable (o detrás de un firewall/VPN/reverse-proxy que añada auth).
**No exponer el puerto 8900 ni los puertos VNC directamente a Internet** sin
añadir una capa de autenticación (por ejemplo, un proxy con Basic Auth o un
túnel VPN) delante de ambos servicios.
No se encontraron contraseñas, tokens ni claves de API hardcodeadas en el
código (se auditó con `grep -iE "password|secret|token|key"` antes de subir
el repo).
## Requisitos
- Python 3 con `fastapi`, `uvicorn`.
- `ffmpeg` (con soporte `libx264` en CPU, o `h264_nvenc`/driver NVIDIA en GPU).
- `pulseaudio`, `dbus-launch`, XFCE (`startxfce4`) o el WM que se configure.
- CPU: `Xtigervnc`. GPU: `Xorg` + driver propietario NVIDIA + `x11vnc`.