File size: 11,134 Bytes
6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 b19c583 6268049 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | ---
title: Basyx FFmpeg Rendering Engine
emoji: 🎬
colorFrom: green
colorTo: yellow
sdk: docker
app_port: 7860
pinned: false
license: mit
---
# Basyx FFmpeg Rendering Engine
Basyx FFmpeg is a CPU-first rendering backend for short-form video automation. It is designed for Hugging Face Docker Spaces running on 2-8 CPU cores with 8-16 GB RAM and no GPU. The engine uses FFmpeg and FFprobe subprocess pipelines and never loads complete videos into Python memory.
## Architecture
```mermaid
flowchart TD
API["FastAPI REST API"] --> Jobs["Job Manager"]
Dashboard["Gradio Operator Dashboard"] --> Jobs
Jobs --> Engine["Render Engine"]
Engine --> Assets["Asset Probe + Metadata Cache"]
Engine --> Ingest["Remote URL + Upload Ingestion"]
Engine --> Normalize["Normalization"]
Engine --> Scenes["Scene Timeline"]
Engine --> Subtitles["SRT / ASS Subtitle Engine"]
Engine --> Transitions["Transition Filter Builder"]
Engine --> Audio["Voiceover + Ducking Mixer"]
Engine --> Exports["Export Manager"]
Ingest --> FFmpeg["FFmpeg / FFprobe"]
Normalize --> FFmpeg
Scenes --> FFmpeg
Subtitles --> FFmpeg
Transitions --> FFmpeg
Audio --> FFmpeg
```
Package layout:
```text
renderer/
core/ settings, models, ingestion, orchestration
ffmpeg/ command builder, runner, probing, normalization
subtitles/ SRT and ASS generation
transitions/ xfade graph generation
audio/ voiceover and music ducking
scenes/ timeline validation
templates/ caption templates
exports/ final deliverables
jobs/ durable job records and retries
```
## REST API
All API endpoints are served at the Space root. Asset fields may be absolute container paths or public `http`/`https` URLs. Remote assets are downloaded into a job-local temp directory with timeout and size limits before rendering.
### `POST /render`
Submit one render job.
```json
{
"template": "tiktok_classic",
"output_name": "campaign_clip.mp4",
"voiceover": "https://cdn.example.com/voiceover.wav",
"background_music": "https://cdn.example.com/music.mp3",
"subtitle_format": "ass",
"auto_subtitles": true,
"subtitle_language": "en",
"whisper_model_size": "tiny",
"preset": "tiktok_9_16_fast",
"callback_url": "https://n8n.example.com/webhook/render-complete",
"export_target": "local",
"audio_normalize": true,
"preview": false,
"normalize": true,
"scenes": [
{
"start": 0,
"duration": 5,
"media": "https://cdn.example.com/scene1.mp4",
"caption": "Launch faster with automated rendering",
"transition": "fade"
}
]
}
```
Response:
```json
{
"job_id": "job_abc123",
"status_url": "/status/job_abc123",
"download_url": "/download/job_abc123?token=..."
}
```
### `GET /presets`
Returns available render presets and caption templates. Presets let n8n submit compact requests such as `tiktok_9_16_fast`, `youtube_shorts_hd`, `podcast_square`, `reels_with_subtitles`, and `draft_preview`.
### `POST /render/ai-reels`
Submit a single-call AI Reels job using an existing voiceover and asset list. TTS is intentionally provider-pluggable in v1; the production path requires a supplied voiceover.
```json
{
"script": "Launch faster with automated rendering.",
"voiceover": "https://cdn.example.com/voiceover.wav",
"assets": ["https://cdn.example.com/scene1.jpg", "https://cdn.example.com/scene2.mp4"],
"template": "youtube_shorts",
"output_name": "ai_reel.mp4"
}
```
### `POST /render/batch`
Submit multiple render jobs. The worker pool defaults to one active render to avoid RAM exhaustion.
```json
{
"jobs": [
{
"template": "modern_minimal",
"output_name": "clip_a.mp4",
"scenes": [{"start": 0, "duration": 3, "media": "https://cdn.example.com/a.mp4"}]
}
]
}
```
### `POST /scene-builder`
Build a timeline from a script and asset list.
```json
{
"script": "One script can be split across several short scenes.",
"assets": ["https://cdn.example.com/a.mp4", "https://cdn.example.com/b.jpg"],
"duration": 8,
"transition": "fade"
}
```
### `POST /assets/upload`
Upload files from automation tools such as n8n and receive staged paths that can be used in `/render`.
Multipart form field:
- `files`: one or more images, videos, GIFs, or audio files.
Response:
```json
{
"assets": [
{
"filename": "clip.mp4",
"path": "/app/temp/uploads/abc/clip.mp4",
"reference": "upload://clip.mp4"
}
]
}
```
### `POST /render/upload`
Submit a render job and files in one multipart request.
Multipart fields:
- `request_json`: render payload JSON.
- `files`: uploaded files referenced by `upload://filename`.
Example `request_json`:
```json
{
"template": "tiktok_classic",
"output_name": "n8n_clip.mp4",
"scenes": [
{
"start": 0,
"duration": 5,
"media": "upload://clip.mp4",
"caption": "Rendered from n8n"
}
],
"voiceover": "upload://voice.wav"
}
```
### `POST /render/ai-reels/upload`
Multipart AI Reels endpoint. Use `upload://filename` inside `voiceover`, `background_music`, and `assets`.
### `POST /transcribe`
Transcribe local or remote audio/video with faster-whisper.
```json
{
"audio": "https://cdn.example.com/voiceover.wav",
"model_size": "tiny",
"language": "en",
"task": "transcribe",
"word_timestamps": true,
"vad_filter": true
}
```
Response includes `text`, detected `language`, segment timings, and optional word timings. Use this endpoint from n8n when you want subtitles before rendering.
### `POST /transcribe/upload`
Multipart faster-whisper endpoint for direct n8n file uploads.
Multipart fields:
- `file`: audio or video file.
- `model_size`: optional Whisper model, default `WHISPER_MODEL_SIZE`.
- `language`: optional ISO language code.
- `word_timestamps`: optional boolean, default `true`.
### `POST /subtitles`
Generate SRT or ASS files from timed events.
```json
{
"format": "ass",
"template": "tiktok_zoom",
"events": [
{"start": 0, "end": 1.2, "text": "Hello world"}
]
}
```
### `GET /status/{job_id}`
Returns job state, logs, FFmpeg commands, metrics, output path, and failure reason.
States: `PENDING`, `RUNNING`, `FAILED`, `COMPLETED`.
### `GET /download/{job_id}`
Returns the completed MP4 deliverable. Downloads require the signed token returned by render submission. If the job is still running, the endpoint returns `409`.
### `POST /cancel/{job_id}`
Requests job cancellation. Pending jobs are marked `CANCELLED`; running jobs are marked `CANCEL_REQUESTED` and stop before the next guarded execution point.
### `POST /admin/cleanup`
Deletes expired job records, old exports, and staged upload folders. Default retention is controlled by `JOB_RETENTION_SECONDS`.
### `POST /inspect`
Probe one local asset path and return MIME type, duration, codecs, bitrate, resolution, FPS, stream list, and cache metadata.
## n8n Workflow Integration
Recommended URL-based flow:
1. Use an HTTP Request node with `POST https://YOUR-SPACE.hf.space/render`.
2. Pass public file URLs from S3, Supabase Storage, Cloudinary, Google Drive direct-download links, or another CDN in `scenes[].media`, `voiceover`, and `background_music`.
3. Set `auto_subtitles` to `true` when you want faster-whisper captions generated from `voiceover`.
4. Add `callback_url` to receive a POST when the job completes or fails.
5. Poll `GET https://YOUR-SPACE.hf.space/status/{{$json.job_id}}` only if you do not use callbacks.
6. Download the final MP4 from the signed `download_url`.
Multipart flow:
1. Use an HTTP Request node set to multipart form-data.
2. Send `request_json` as a text field.
3. Attach files under the `files` field.
4. Reference those files in JSON as `upload://exact-filename.ext`.
Security defaults:
- Only `http` and `https` remote assets are accepted.
- Private, localhost, link-local, and multicast hosts are blocked by default.
- Set `ALLOW_PRIVATE_ASSET_URLS=true` only for trusted self-hosted deployments.
- `MAX_DOWNLOAD_BYTES` limits remote downloads and multipart upload totals.
- `WHISPER_MODEL_SIZE=tiny` and `WHISPER_COMPUTE_TYPE=int8` are the recommended CPU defaults.
- `BASYX_SIGNING_SECRET` should be set as a Space secret before public deployment.
## Operator Dashboard
The dashboard is available at `/dashboard`. It provides production operator tools for render submission, batch submission, AI Reels submission, job status, logs, downloads, and asset inspection.
## Caption Templates
Built-in templates:
- `tiktok_classic`
- `tiktok_zoom`
- `alex_hormozi`
- `modern_minimal`
- `youtube_shorts`
- `podcast_style`
- `news_style`
Templates are selected per request and do not require code changes.
## CPU And RAM Tuning
- Keep `MAX_RENDER_WORKERS=1` for 8 GB RAM deployments.
- Use `OUTPUT_PRESET=veryfast` or `ultrafast` for faster CPU rendering.
- Use `OUTPUT_CRF=23-28` to balance quality and file size.
- Keep source assets near the target duration to reduce normalization work.
- Prefer pre-trimmed voiceovers and assets for batch workloads.
- Start with `WHISPER_MODEL_SIZE=tiny` or `base` on free/CPU Spaces.
- Use `preview=true` for low-resolution draft renders.
- Use `audio_normalize=true` for voiceover or podcast-style content.
## Reliability
- FFmpeg subprocesses are killed after `FFMPEG_TIMEOUT_SECONDS`.
- Remote asset downloads are killed after `DOWNLOAD_TIMEOUT_SECONDS`.
- Remote and multipart input size is capped by `MAX_DOWNLOAD_BYTES`.
- faster-whisper models are loaded lazily and cached under `WHISPER_MODEL_DIR`.
- Webhook callbacks are best-effort and callback failures are written to job logs.
- `export_target=local` copies completed renders to `STORAGE_DIR`.
- `export_target=https://...` uploads the completed MP4 with HTTP `PUT`, which works with presigned URLs from S3, Supabase Storage, and similar providers.
- Jobs retry up to `MAX_RETRIES`.
- Intermediate files are created under `TEMP_DIR` and removed after export.
- Job records retain command history, logs, render time, output size, and failure reasons.
## Docker Deployment
Build locally:
```bash
docker build -t basyx-ffmpeg .
docker run --rm -p 7860:7860 basyx-ffmpeg
```
Open:
- API: `http://localhost:7860/health`
- Dashboard: `http://localhost:7860/dashboard`
## Hugging Face Spaces Deployment
Create a Docker Space, push this repository, and keep the README metadata above. The container listens on port `7860`, and the Space exposes the FastAPI service plus the dashboard.
## Testing
Run:
```bash
pytest --cov=renderer --cov-report=term-missing
```
Integration tests use mocked FFmpeg/FFprobe where possible and small generated media where necessary.
## Known v1 Limits
- Bundled TTS is not included. The AI Reels endpoint requires a supplied voiceover and keeps narration generation behind a provider interface for future integration.
- Advanced caption animation is implemented through ASS effects and FFmpeg-compatible filter behavior, not GPU animation layers.
- Batch rendering is intentionally sequential by default for constrained CPU/RAM Spaces.
|