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
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:
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.
{
"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:
{
"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.
{
"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.
{
"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.
{
"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:
{
"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 byupload://filename.
Example request_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.
{
"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, defaultWHISPER_MODEL_SIZE.language: optional ISO language code.word_timestamps: optional boolean, defaulttrue.
POST /subtitles
Generate SRT or ASS files from timed events.
{
"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 automation endpoints
POST /media/inspectsafely downloads a local or remote asset and returns FFprobe metadata as an asynchronous JSON artifact.POST /render/templatesubstitutes validated JSON variables into a named or inline render template.POST /render/variantscreates up to 12 platform outputs and returns a render group ID.GET /render/groups/{group_id}returns aggregate and per-variant status.POST /toolkitsupportsloudness_analyze,silence_detect,black_detect,scene_detect,contact_sheet, andhlstasks.
n8n Workflow Integration
Recommended URL-based flow:
- Use an HTTP Request node with
POST https://YOUR-SPACE.hf.space/render. - Pass public file URLs from S3, Supabase Storage, Cloudinary, Google Drive direct-download links, or another CDN in
scenes[].media,voiceover, andbackground_music. - Set
auto_subtitlestotruewhen you want faster-whisper captions generated fromvoiceover. - Add
callback_urlto receiverender.completed,render.failed, orrender.cancelledevents. Toolkit and analysis jobs use the correspondingtask.*event names. - Poll
GET https://YOUR-SPACE.hf.space/status/{{$json.job_id}}only if you do not use callbacks. - Download the final MP4 from the signed
download_url.
Multipart flow:
- Use an HTTP Request node set to multipart form-data.
- Send
request_jsonas a text field. - Attach files under the
filesfield. - Reference those files in JSON as
upload://exact-filename.ext.
Security defaults:
- Only
httpandhttpsremote assets are accepted. - Private, localhost, link-local, and multicast hosts are blocked by default.
- Set
ALLOW_PRIVATE_ASSET_URLS=trueonly for trusted self-hosted deployments. MAX_DOWNLOAD_BYTESlimits remote downloads and multipart upload totals.WHISPER_MODEL_SIZE=tinyandWHISPER_COMPUTE_TYPE=int8are the recommended CPU defaults.BASYX_SIGNING_SECRETshould 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_classictiktok_zoomalex_hormozimodern_minimalyoutube_shortspodcast_stylenews_style
Templates are selected per request and do not require code changes.
CPU And RAM Tuning
- Keep
MAX_RENDER_WORKERS=1for 8 GB RAM deployments. - Use
OUTPUT_PRESET=veryfastorultrafastfor faster CPU rendering. - Use
OUTPUT_CRF=23-28to 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=tinyorbaseon free/CPU Spaces. - Use
preview=truefor low-resolution draft renders. - Use
audio_normalize=truefor 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 retry with exponential backoff.
CALLBACK_MAX_RETRIESandCALLBACK_RETRY_SECONDScontrol delivery. - Webhooks include
X-Ava2lon-Eventand an HMACX-Ava2lon-Signaturecomputed with the signing secret. - Set
PUBLIC_BASE_URLso submissions, status payloads, and callbacks contain absolute URLs. export_target=localcopies completed renders toSTORAGE_DIR.export_target=https://...uploads the completed MP4 with HTTPPUT, which works with presigned URLs from S3, Supabase Storage, and similar providers.- Jobs retry up to
MAX_RETRIES. - Intermediate files are created under
TEMP_DIRand removed after export. - Job records retain command history, logs, render time, output size, SHA-256 artifact checksums, callback delivery state, and failure reasons.
Docker Deployment
Build locally:
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:
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.