Media Processing
Transform your uploaded files using the full power of FFmpeg through simple HTTP requests. Whether you’re converting formats, resizing videos, extracting audio, or creating complex multi-media workflows, this guide takes you from basic to advanced processing techniques.
Input Options
Each input’s file_path can be either an uploaded file (dir_id/filename) from the File Management workflow, or a direct HTTPS URL. URLs are automatically imported before processing.
Learning Path: Simple to Advanced
🎬 Basic Operations
Format conversion, simple transformations
⚙️ Intermediate
Filters, quality settings, multi-output
🚀 Advanced
Complex filters, multi-input workflows
The Processing Request
All processing happens through POST /ffmpeg/process with a JSON task definition:
const response = await fetch('https://api.ffmpeg-api.com/ffmpeg/process', {
method: 'POST',
headers: {
'Authorization': 'Basic YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
task: {
inputs: [{ file_path: 'dir_123/input.mp4' }],
outputs: [{ file: 'output.mp4' }]
}
})
})
const result = await response.json()Task Structure Overview
inputs[] → Array of input files with their file_pathinputs[].file_path → Either dir_id/filename (uploaded file) or an HTTPS URLoutputs[] → Array of output specifications with file namesinputs[].options[] → FFmpeg options applied before inputoutputs[].options[] → FFmpeg options for outputoutputs[].maps[] → Stream mapping for complex workflowsfilter_complex → Advanced filter graphs for multi-input processingoutput_dir_id → Target directory for outputs (see below)Directory Handling
When using URL inputs, the API needs to know where to store imported files and outputs:
output_dir_id is provided, use that directorydir_id/filename format, use that directoryoutput_dir_id, a temporary directory is created automaticallyExample with mixed inputs:
const task = {
inputs: [
{ file_path: 'dir_abc123/my-logo.png' }, // Uploaded watermark
{ file_path: 'https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4' }
],
filter_complex: '[1:v][0:v]overlay=10:10[out]',
outputs: [{ file: 'watermarked.mp4', maps: ['[out]', '1:a'] }]
// Directory inferred from the uploaded file's dir_id
}Example with explicit output directory:
const task = {
inputs: [
{ file_path: 'https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4' }
],
outputs: [{ file: 'thumbnail.jpg', options: ['-vframes', '1', '-ss', '5'] }],
output_dir_id: 'dir_abc123' // Explicit target directory
}Important Constraints: For uploaded files, all must be from the same directory. Output filenames cannot conflict with input filenames. Files must not exceed your plan’s maximum size limit. URL inputs must be HTTPS and publicly accessible.
Sync vs Async Processing
FFmpeg API offers two ways to process files:
🚀 Synchronous (default)
Use POST /ffmpeg/process
- • Returns results immediately
- • Best for quick tasks (under 2 min)
- • Simple request/response flow
⏳ Asynchronous
Use POST /ffmpeg/process/async
- • Returns job_id immediately
- • Best for long-running tasks
- • Poll status or use webhooks
Async Processing Example
// 1. Submit async job
const submitRes = await fetch('https://api.ffmpeg-api.com/ffmpeg/process/async', {
method: 'POST',
headers: {
'Authorization': 'Basic YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
task: {
inputs: [{ file_path: 'dir_123/large-video.mp4' }],
outputs: [{ file: 'converted.mp4', options: ['-crf', '23'] }]
},
webhook_url: 'https://yoursite.com/webhook' // optional
})
})
const { job_id } = await submitRes.json()
console.log('Job submitted:', job_id)
// 2. Poll for status (or wait for webhook)
const statusRes = await fetch(`https://api.ffmpeg-api.com/job/${job_id}`, {
headers: { 'Authorization': 'Basic YOUR_API_KEY' }
})
const status = await statusRes.json()
// status.status: 'pending' | 'processing' | 'completed' | 'failed'Webhooks: If you provide a webhook_url, we’ll POST the results to your server when the job completes. Must be HTTPS and publicly accessible.
See the API Reference for full endpoint details.
Understanding the Response
Successful processing returns detailed results and usage information:
{
"ok": true,
"result": [
{
"file_name": "output.mp4",
"size_bytes": 1234567,
"download_url": "https://storage.example.com/result.mp4"
}
],
"usage": {
"time_sec": 12.5,
"input_size_gb": 0.098,
"output_size_gb": 0.015,
"gb_sec": 1.4125
}
}📁 Result Files
file_name → Output filenamesize_bytes → File size in bytesdownload_url → Direct download link📊 Usage Stats
time_sec → Processing timegb_sec → Billing units consumedinput_size_gb → Input file sizesoutput_size_gb → Output file sizes🎬 Level 1: Basic Operations
Start with simple, single-input transformations:
Format Conversion
Convert a GIF to MP4 (uploaded file):
const task = {
inputs: [
{ file_path: 'dir_123/animation.gif' }
],
outputs: [
{ file: 'animation.mp4' }
]
}Process from URL
Convert directly from a URL (no upload needed):
const task = {
inputs: [
{ file_path: 'https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4' }
],
outputs: [
{ file: 'compressed.mp4', options: ['-crf', '28'] }
]
}
// A temporary directory is auto-created for outputsQuality Control
Compress a video with specific quality settings:
const task = {
inputs: [
{ file_path: 'dir_123/large-video.mp4' }
],
outputs: [
{
file: 'compressed.mp4',
options: ['-crf', '28', '-preset', 'medium']
}
]
}Extract Audio
Pull audio track from a video:
const task = {
inputs: [
{ file_path: 'dir_123/movie.mp4' }
],
outputs: [
{
file: 'soundtrack.mp3',
options: ['-vn', '-acodec', 'mp3', '-ab', '192k']
}
]
}💡 Quick Reference: Common Output Options
-crf 18→ High quality-crf 23→ Good quality (default)-crf 28→ Compressed
-vn→ No video-acodec mp3→ MP3 format-ab 192k→ Audio bitrate
⚙️ Level 2: Intermediate Processing
Resize and Crop Videos
Resize to specific dimensions:
const task = {
inputs: [
{ file_path: 'dir_123/fullhd-video.mp4' }
],
outputs: [
{
file: 'mobile-video.mp4',
options: [
'-vf', 'scale=640:360',
'-crf', '25'
]
}
]
}Trim Video Segments
Extract a 30-second clip starting at 1 minute:
const task = {
inputs: [
{
file_path: 'dir_123/long-video.mp4',
options: ['-ss', '60', '-t', '30']
}
],
outputs: [
{
file: 'highlight.mp4',
options: ['-c:v', 'libx264', '-crf', '23']
}
]
}Multiple Output Files
Generate different versions from one input:
const task = {
inputs: [
{ file_path: 'dir_123/source.mp4' }
],
outputs: [
{
file: 'web-version.mp4',
options: ['-vf', 'scale=1280:720', '-crf', '25']
},
{
file: 'mobile-version.mp4',
options: ['-vf', 'scale=640:360', '-crf', '28']
},
{
file: 'audio-only.mp3',
options: ['-vn', '-acodec', 'mp3']
}
]
}🚀 Level 3: Advanced Workflows
Multi-Input Processing
Combine separate video and audio:
const task = {
inputs: [
{ file_path: 'dir_123/video.mp4' },
{ file_path: 'dir_123/audio.wav' }
],
outputs: [
{
file: 'final.mp4',
options: ['-c:v', 'copy', '-c:a', 'aac']
}
]
}Side-by-Side Video Comparison
Create split-screen view of two videos:
const task = {
inputs: [
{ file_path: 'dir_123/before.mp4' },
{ file_path: 'dir_123/after.mp4' }
],
filter_complex: '[0:v]scale=640:360[left];[1:v]scale=640:360[right];[left][right]hstack[out]',
outputs: [
{
file: 'comparison.mp4',
options: ['-c:v', 'libx264', '-crf', '23'],
maps: ['[out]']
}
]
}Picture-in-Picture Overlay
Overlay a small video on top of a larger one:
const task = {
inputs: [
{ file_path: 'dir_123/main-video.mp4' },
{ file_path: 'dir_123/overlay.mp4' }
],
filter_complex: '[1:v]scale=320:180[overlay];[0:v][overlay]overlay=W-w-10:H-h-10[out]',
outputs: [
{
file: 'picture-in-picture.mp4',
options: ['-c:v', 'libx264', '-crf', '23'],
maps: ['[out]', '0:a']
}
]
}Watermark Application
Add a logo watermark to a video:
const task = {
inputs: [
{ file_path: 'dir_123/video.mp4' },
{ file_path: 'dir_123/logo.png' }
],
filter_complex: '[0:v][1:v]overlay=W-w-10:10[out]',
outputs: [
{
file: 'branded-video.mp4',
options: ['-c:v', 'libx264', '-crf', '23'],
maps: ['[out]', '0:a']
}
]
}Understanding Filter Complex
For advanced operations, filter_complex lets you create sophisticated processing pipelines:
│ │ │
Input Filter Output Label
Input References
[0:v]→ Video from first input[1:a]→ Audio from second input[2:v:0]→ First video track from third input
Common Filters
scale=W:H→ Resize videohstack→ Side-by-side layoutoverlay=X:Y→ Position overlay
Error Handling & Troubleshooting
❌ Error 400: “Invalid task format”
Check your task structure:
- Ensure
inputsandoutputsare arrays - Verify all
file_pathvalues are strings - Options arrays should contain strings only
- Output filenames must not conflict with inputs
❌ Error 500: “FFmpeg processing failed”
FFmpeg couldn’t process your command. Common causes:
- Invalid FFmpeg options or syntax
- Incompatible input/output formats
- Complex filter syntax errors
- Insufficient processing resources for large files
❌ Error 403: “File size exceeds plan limit”
One or more files exceed your plan’s maximum file size:
- Free & Starter plans: 500 MB per file
- Pro plan: 1 GB per file
- Growth plan: 5 GB per file
- Consider compressing large files or upgrading your plan
Example error: “File ‘video.mp4’ size (750.25 MB) exceeds plan (starter) max file size limit of 500 MB. See https://ffmpeg-api.com/pricing for more details.”
❌ Error 404: “File not found”
Referenced files don’t exist:
- Verify
file_pathmatches upload response exactly - Ensure all files are in the same directory
- Check that files were successfully uploaded
- List directory contents to confirm file presence
What’s Next?
📝 Advanced Examples
See complete, production-ready code examples for complex workflows.
📊 Monitor Usage
Understand how processing complexity affects your GB-seconds consumption.
Need more FFmpeg options? Check the Advanced Usage guide for comprehensive FFmpeg command reference and edge cases.