Very Good FFmpeg
How it worksPricingDocsBlog

Published Jun 10, 2026

ffmpeg-python documentation: input, output, run explained with examples

How to use ffmpeg-python for video processing in Python, and when to offload to a hosted FFmpeg API instead

Why this article exists

Python developers who need video processing almost always find ffmpeg-python first. It is the most popular Python FFmpeg wrapper with 11,000 GitHub stars and over 83,000 dependent repositories. The core pattern -- ffmpeg.input(), .output(), .run() -- is the first thing every user learns.

But ffmpeg-python has a dirty secret. The last release was v0.2.0 in July 2019. That is seven years without an update. There are 479 open issues, 46 open pull requests, and zero maintainer responses. A question titled "Is this package being maintained?" (Issue #807) has sat unanswered since November 2023.

This article covers three things: how ffmpeg-python input, output, and run actually work, the hidden costs and pitfalls of using an unmaintained library, and when a hosted FFmpeg API like Very Good FFmpeg is the smarter choice for production.

TL;DR

  • ffmpeg-python is a pure-Python wrapper over the FFmpeg CLI. It builds command-line arguments and runs them via subprocess.
  • The FFmpeg binary must be installed separately. This is the number one source of errors.
  • The library is unmaintained since July 2019. Issue #807 asking about maintenance has no response. Issue #43 (progress tracking) has been open since 2017. Issue #200 (async support) has been open since 2019.
  • For local scripts and learning, ffmpeg-python is fine. For production, a hosted FFmpeg API removes the binary dependency and scales without infrastructure management.
  • Very Good FFmpeg offers a Python SDK (pip install very-good-ffmpeg) that replaces ffmpeg-python's .run() with an async API call to dedicated 16-core / 32 GB instances. No local FFmpeg needed.
  • Self-hosting FFmpeg on a comparable 16-core VM costs $336/month minimum on DigitalOcean (even when idle), while Very Good FFmpeg charges $0.50/GB with zero idle cost.

What is ffmpeg-python and how does it work?

ffmpeg-python is a thin Python wrapper around the FFmpeg command-line tool. It does not reimplement FFmpeg in Python. It builds an FFmpeg argument list and passes it to subprocess.Popen.

The global video streaming market was valued at $811.37 billion in 2025 and is projected to reach $3,394.56 billion by 2034 at a 17.00% CAGR (Fortune Business Insights). Streaming now commands 36% of all TV usage, surpassing cable at 27.9% and broadcast at 24.2% (Nielsen). There are approximately 1.8 billion video streaming subscriptions worldwide, and 83% of US households have at least one subscription, up from 52% in 2015. Americans spend 3 hours 6 minutes per day streaming video. With video processing demand exploding, the tools developers choose matter more than ever.

ffmpeg-python sits alongside other Python video libraries but occupies a specific niche:

LibraryApproachBest For
ffmpeg-pythonThin CLI wrapperTranslating FFmpeg commands to Python
subprocess + raw FFmpegDirect CLI callsDevelopers who know FFmpeg flags
moviepyHigh-level APISimple edits, beginners
opencvFrame-level processingComputer vision, real-time
PyAVC library bindingsPerformance-critical, low-level
Very Good FFmpeg SDKHosted API clientProduction, serverless, scale

The fundamental trade-off: ffmpeg-python is the most Pythonic way to work with FFmpeg commands, but it depends on a local FFmpeg binary and has not been maintained since 2019.

How do I use ffmpeg-python input, output, and run?

The basic pattern has three steps: create an input stream, chain output options, and execute.

python
import ffmpeg

stream = ffmpeg.input('input.mp4')
stream = ffmpeg.output(stream, 'output.mp4')
ffmpeg.run(stream)

The fluent chaining style is more common in real code:

python
import ffmpeg

ffmpeg.input('input.mp4').output('output.mp4').run()

You can pass encoding options as keyword arguments:

python
ffmpeg.input('input.mp4').output(
    'output.mp4',
    vcodec='libx264',
    acodec='aac',
    video_bitrate='2M',
    audio_bitrate='192k'
).run()

What does ffmpeg.input() accept?

ffmpeg.input() takes a filename string as its first argument. It also accepts pipe: for stdin input, plus keyword arguments that map to FFmpeg input options:

python
# Read raw video from stdin
ffmpeg.input('pipe:', format='rawvideo', pix_fmt='rgb24', s='640x480')

# Seek before reading
ffmpeg.input('input.mp4', ss=10, t=5)

Common input options you can pass as kwargs: ss (seek position), t (duration), f or format (input format), framerate, hwaccel (hardware acceleration).

What does ffmpeg.output() support?

.output() takes one or more stream specs and a filename. Keyword arguments map to FFmpeg output options:

python
ffmpeg.input('input.mp4').output(
    'output.mp4',
    vcodec='libx265',
    preset='fast',
    crf=28,
    acodec='copy'
)

Some FFmpeg flags do not translate to clean Python keywords. Use the dict-unpacking hack for these:

python
ffmpeg.input('input.mp4').output(
    'output.mp4',
    **{'c:v': 'libx264', 'qscale:v': 3, 'tag:v': 'hvc1'}
)

How does ffmpeg.run() execute the command?

.run() calls subprocess.Popen with the compiled FFmpeg arguments. It accepts several parameters:

python
out, err = ffmpeg.input('input.mp4').output('output.mp4').run(
    capture_stdout=True,
    capture_stderr=True,
    quiet=True,
    overwrite_output=True
)

For non-blocking execution, use run_async():

python
process = ffmpeg.input('input.mp4').output('output.mp4').run_async()
process.wait()

run_async() returns a subprocess.Popen object. This is useful for long-running encodes or when you pipe data through stdin/stdout.

How can I inspect the generated command?

Use compile() or get_args() to see the exact FFmpeg command:

python
args = ffmpeg.input('input.mp4').output('output.mp4').get_args()
print(args)
# ['-i', 'input.mp4', 'output.mp4']

args = ffmpeg.input('input.mp4').output(
    'output.mp4', vcodec='libx264'
).compile()
print(args)
# ['ffmpeg', '-i', 'input.mp4', '-vcodec', 'libx264', 'output.mp4']

This is essential for debugging when the generated command does not behave as expected. compile() includes the ffmpeg executable name, while get_args() returns only the arguments.

How do I handle complex FFmpeg filter graphs in ffmpeg-python?

ffmpeg-python supports complex filter graphs through method chaining and dedicated filter methods:

python
input1 = ffmpeg.input('video.mp4')
input2 = ffmpeg.input('overlay.png')

overlay = ffmpeg.overlay(input1, input2, x=10, y=10)
output = ffmpeg.output(overlay, 'output.mp4')
ffmpeg.run(output)

For concatenation:

python
input1 = ffmpeg.input('part1.mp4')
input2 = ffmpeg.input('part2.mp4')
joined = ffmpeg.concat(input1, input2, v=1, a=1)
output = ffmpeg.output(joined, 'merged.mp4')
ffmpeg.run(output)

Use .filter() for any FFmpeg filter that lacks a dedicated method:

python
stream = ffmpeg.input('input.mp4')
stream = ffmpeg.filter(stream, 'fps', fps=30)
stream = ffmpeg.filter(stream, 'scale', w=1280, h=720)
output = ffmpeg.output(stream, 'output.mp4')
ffmpeg.run(output)

How do I pass global FFmpeg flags?

Use .global_args() for flags that apply to FFmpeg globally rather than to a specific input or output:

python
ffmpeg.input('input.mp4').output('output.mp4').global_args(
    '-report', '-loglevel', 'debug'
).run()

The -report flag generates a detailed log file, which is helpful for debugging.

What are the most common ffmpeg-python pitfalls?

ffmpeg-python wraps FFmpeg but does not abstract away its complexity. Several issues trip up users.

The FFmpeg binary must be installed separately

This is the number one source of errors. The README explicitly states: "ffmpeg-python makes no attempt to download/install FFmpeg -- it is merely a pure-Python wrapper."

python
# FileNotFoundError if ffmpeg is not in PATH
import ffmpeg
ffmpeg.input('input.mp4').output('output.mp4').run()

On Windows, the common error is FileNotFoundError: [WinError 2] The system cannot find the file specified. Install FFmpeg via conda, choco, or download from ffmpeg.org and add it to PATH. The ffmpeg-downloader pip package and static-ffmpeg are portable alternatives.

Filter operations silently drop audio

Filter methods like .hflip(), .overlay(), and .drawbox() produce output with no audio. FFmpeg internally uses -map and drops unmentioned streams. Pass the audio stream explicitly:

python
input_video = ffmpeg.input('input.mp4')
video = input_video.video.hflip()
output = ffmpeg.output(video, input_video.audio, 'output.mp4')
ffmpeg.run(output)

This is a recurring theme on Stack Overflow. Users regularly lose audio during overlay or filter operations and must manually re-merge it.

The library is unmaintained

ffmpeg-python has not been updated since July 2019. The PyPI page lists only Python 3.3 through 3.6 classifiers. Three GitHub issues illustrate the problem:

  • Issue #807 (Nov 2023): "Is this package being maintained by anyone? It's a useful package and it would be a shame for it to die." No maintainer response.
  • Issue #43 (Dec 2017): Request for progress tracking during ffmpeg execution. Users want to see frame-by-frame progress during encodes. Labeled "enhancement" but never addressed. Open for over 8 years.
  • Issue #200 (May 2019): Request for run_asyncio() returning a coroutine for async/await syntax. Modern Python supports async natively. Also never addressed.

With 83,532 dependent repositories and 479 open issues, this gap between adoption and maintenance is a serious dependency risk.

Windows console window flashing

On Windows, ffmpeg-python calls subprocess.Popen without creationflags=subprocess.CREATE_NO_WINDOW. A console window flashes briefly on each .run() call. The workaround is monkey-patching ffmpeg-python's internal run function or replacing it with a direct subprocess call.

FFmpeg-to-Python flag mapping is inconsistent

Not all FFmpeg CLI flags have clean keyword aliases. Flags like -c:v, -tag:v, and -bitexact must use dict syntax. This means you constantly switch between keyword args and dict unpacking, reducing readability.

What is the real cost of self-hosting FFmpeg vs a hosted API?

When you outgrow local ffmpeg-python scripts and need to run video processing in production, you face a choice: provision your own FFmpeg server or use a hosted API. Here is the real cost breakdown.

Self-hosted VM options

ProviderInstanceSpecsHourly CostMonthly Cost (always-on)
AWS EC2c7g.large2 vCPU, 4 GB$0.0725 on-demand, $0.038 spot$52.20 on-demand
AWS EC2c6i.2xlarge8 vCPU, 16 GB$0.34 on-demand, $0.18 spot$244.80 on-demand
AWS EC2c6i.4xlarge16 vCPU, 32 GB$0.68 on-demand$489.60 on-demand
DigitalOceanc-88 vCPU, 16 GB, NVMe$0.25/hr ($168/mo cap)$168.00
DigitalOceanc-1616 vCPU, 32 GB, NVMe$0.50/hr ($336/mo cap)$336.00

Hosted API pricing

ProviderModelStarting RateVolume DiscountIdle Cost
Very Good FFmpegPer GB processed$0.50/GB$0.08/GB at 100GB+$0
AWS Elemental MediaConvertPer minute + encoding$0.01-$0.30/minReserved pricing$0
BitmovinPer encoding minuteVaries by codecEnterprise tiers$0

Real-world example: processing 100 GB of video per month

Self-hosted (DigitalOcean c-8):

  • VM: $168/month (fixed, even if idle)
  • Storage: ~$10/month (100 GB block storage)
  • Bandwidth: ~$5-15/month depending on transfer
  • Engineering time to maintain FFmpeg, handle upgrades, monitor usage
  • Total: $183+/month regardless of actual processing volume

Very Good FFmpeg:

  • First 100 GB at $0.50/GB = $50
  • Or with volume tier: 100 GB at $0.08/GB = $8
  • No idle cost. No infrastructure management.
  • Total: $8-50/month, scaled to actual usage

For a team processing 100 GB of video monthly, hosted API saves 60-95% while eliminating infrastructure overhead.

How do I migrate from ffmpeg-python to a hosted FFmpeg API?

If you have existing ffmpeg-python code, the migration is straightforward. Here is the step-by-step process.

Step 1: Identify the FFmpeg command your script runs

Use ffmpeg-python's built-in debugging tools to see the exact command:

python
# Before migration: inspect the command
args = ffmpeg.input('input.mp4').output(
    'output.mp4', vcodec='libx264', preset='fast', crf=23
).compile()
print(' '.join(args))
# ffmpeg -i input.mp4 -vcodec libx264 -preset fast -crf 23 output.mp4

Copy the FFmpeg argument list. This is the command you will send to the hosted API.

Step 2: Install the Very Good FFmpeg Python SDK

bash
pip install very-good-ffmpeg

Step 3: Get your API key and upload input files

Sign up at verygoodffmpeg.com and create an API key. Upload your input files to cloud storage (S3, GCS, or R2). The hosted API fetches inputs from URLs.

Step 4: Replace ffmpeg-python .run() with VGF SDK call

Before (ffmpeg-python):

python
import ffmpeg

ffmpeg.input('input.mp4').output(
    'output.mp4',
    vcodec='libx264',
    preset='fast',
    crf=23
).run(overwrite_output=True)

After (Very Good FFmpeg SDK):

python
from very_good_ffmpeg import VGF

vgf = VGF("your-api-key")

job = vgf.run(
    input_files={
        "input.mp4": "https://your-bucket.s3.amazonaws.com/input.mp4"
    },
    output_files=["output.mp4"],
    ffmpeg_commands=[
        "-i {{input.mp4}} -c:v libx264 -preset fast -crf 23 -c:a aac {{output.mp4}}"
    ],
    wait=True,
)

print(f"Job status: {job.status}")
print(f"Output URL: {job.output['output.mp4']}")

Step 5: Handle the results

The SDK returns presigned URLs for output files. Download them directly:

python
import requests

output_url = job.output['output.mp4']
response = requests.get(output_url)
with open('output.mp4', 'wb') as f:
    f.write(response.content)

Migration checklist

ffmpeg-python featureEquivalent in VGF SDK
.input(filename)input_files dict with URLs
.output(filename, **kwargs)ffmpeg_commands string
.run()vgf.run(wait=True)
.run_async()vgf.run(wait=False) returns job ID
capture_stdout / capture_stderrReal-time job logs in dashboard
overwrite_output=TrueSDK generates unique output paths
Filter graphsExpress as full FFmpeg command string

The key differences: the hosted SDK is async by default, requires no local binary, and processes files on dedicated infrastructure with up to 6-hour runtime and optional GPU acceleration.

When should I use ffmpeg-python vs subprocess vs a hosted API?

The choice depends on your deployment environment, scale, and how much infrastructure you want to manage.

Factorffmpeg-pythonsubprocess.run()Very Good FFmpeg SDK
FFmpeg binary neededYes, in PATHYes, in PATHNo
Setup timepip + binary installNo pip dep, binary neededpip + API key
MaintenanceUnmaintained since 2019Your own codeVendor handles infra
Async supportNo (Issue #200, open since 2019)ManualNative async
Progress trackingNo (Issue #43, open since 2017)ManualReal-time logs
ControlFull FFmpeg flags via wrapperFull FFmpeg flagsFull FFmpeg flags
ScalabilityLocal machine onlyLocal machine only16-core / 32 GB per job
ServerlessRequires bundled binaryRequires bundled binaryWorks out of the box
GPU encodingRequires local GPU + driversRequires local GPU + driversNvidia GPU support
Idle cost$0$0$0
Production costFree (software)Free (software)$0.50/GB (drops to $0.08/GB)

Stick with ffmpeg-python when

You are running local development, learning FFmpeg concepts, or writing one-off scripts on your own machine. The Pythonic API is more readable than shell strings for basic operations like format conversion and thumbnail extraction.

Use raw subprocess when

You already know FFmpeg CLI flags well and want zero abstraction overhead. subprocess.run(['ffmpeg', '-i', 'in.mp4', 'out.mp4']) is the simplest possible path. The downside is more boilerplate and the same local binary requirement.

Switch to a hosted API when

Any of these are true:

  • You deploy to serverless platforms (AWS Lambda, Vercel, Cloudflare Workers) where bundling a 30-50 MB FFmpeg binary is cumbersome
  • You need to process videos longer than serverless function timeout limits (Lambda caps at 15 minutes)
  • You manage multiple machines and do not want to install and version FFmpeg on each one
  • You want to offload compute-heavy encoding so your application server stays responsive under load
  • You need GPU-accelerated encoding without managing Nvidia drivers and CUDA versions
  • You want to avoid the dependency risk of an unmaintained library with 479 open issues and zero maintainer response
  • You process variable workloads and do not want to pay for an always-on VM that sits idle most of the time

How does ffmpeg-python compare to other Python video libraries?

ffmpeg-python is not the only option for video processing in Python. Here is how it stacks up:

  • moviepy: Higher-level library built on top of FFmpeg. Easier API for simple edits but less control. Heavier dependency footprint and also wraps FFmpeg binary.
  • opencv: Excellent for frame-level processing and computer vision. Does not handle encoding pipelines or container format conversion natively.
  • PyAV: Direct Python bindings for FFmpeg's C libraries. More performant but much steeper learning curve. Requires understanding FFmpeg internals.
  • ffmpeg-python: Best balance of simplicity and FFmpeg control for command-line-style workflows, but unmaintained.
  • Very Good FFmpeg SDK: Best for production at scale. Same FFmpeg commands but no binary dependency. Async by default. Handles infrastructure.

For most encoding and transcoding tasks, ffmpeg-python provides the right level of abstraction for local work. When you need reliability, scale, or serverless deployment, a hosted API that accepts the same FFmpeg commands is the natural evolution.

FAQ

Does ffmpeg-python install FFmpeg for me?

No. ffmpeg-python is a pure Python wrapper. You must install the FFmpeg binary separately. The README explicitly states this: "ffmpeg-python makes no attempt to download/install FFmpeg." This is the most common source of FileNotFoundError.

How do I check which FFmpeg binary ffmpeg-python is using?

ffmpeg-python uses whichever ffmpeg binary is in your system PATH. Check with subprocess.run(['which', 'ffmpeg']) on Linux/macOS or subprocess.run(['where', 'ffmpeg']) on Windows.

Can I use ffmpeg-python in AWS Lambda or other serverless platforms?

Only if you bundle the FFmpeg static binary with your deployment package. The Lambda layer size limit (250 MB unzipped) makes this feasible but adds maintenance overhead. FFmpeg static binaries are around 30-50 MB. A hosted FFmpeg API avoids this entirely and is not subject to Lambda's 15-minute execution timeout.

What is the difference between run() and run_async()?

run() blocks until the FFmpeg process finishes and returns stdout/stderr bytes. run_async() returns a subprocess.Popen object immediately, allowing you to do other work while FFmpeg runs. Call .wait() on the Popen object to block until completion. Neither supports Python async/await natively (see Issue #200).

How do I pass complex FFmpeg flags to ffmpeg-python?

Use Python dict unpacking for flags without clean keyword aliases: **{'c:v': 'h264_nvenc', 'pix_fmt': 'yuv420p'}. Use .global_args() for flags that must appear before the first input. Use .filter() for filter parameters.

What happens when ffmpeg-python breaks in production?

Since the library is unmaintained, there is no vendor to fix bugs, patch security issues, or add support for newer FFmpeg versions. If a future OS update or FFmpeg release breaks compatibility, your pipeline breaks with no fix available. This is the primary risk of depending on ffmpeg-python in production.

How does Very Good FFmpeg pricing compare to self-hosting?

For light workloads (20 GB/month), Very Good FFmpeg costs about $10 compared to $168/month minimum for a DigitalOcean droplet. For heavy workloads (500 GB/month), Very Good FFmpeg costs $40-250 depending on volume tier, compared to $336+/month for dedicated infrastructure. There is no idle cost with the hosted model. You pay only for what you process.

References

  • ffmpeg-python GitHub Repository
  • ffmpeg-python on PyPI (v0.2.0, July 2019)
  • ffmpeg-python API Reference
  • GitHub Issue #807: Is ffmpeg-python being maintained?
  • GitHub Issue #43: Progress tracking support
  • GitHub Issue #200: Async/await support
  • ffmpeg-python GitHub dependents (83,000+ repos)
  • Very Good FFmpeg Python SDK on PyPI
  • Very Good FFmpeg Hosted API
  • AWS EC2 Compute-Optimized Instance Pricing
  • DigitalOcean CPU-Optimized Droplet Pricing
  • Video Streaming Market Statistics 2025-2034
  • Stack Overflow: Combining video and audio in ffmpeg-python
  • Stack Overflow: Hiding console output in ffmpeg-python
  • Stack Overflow: Converting FFmpeg CLI to ffmpeg-python code
  • Stack Overflow: ffmpeg-python overlay dropping audio
  • Stack Overflow: ffmpeg binary not found on Windows

Related reading

  • Jun 10, 2026

    Hosted FFmpeg REST API: 2026 Pricing and Comparison Guide

    Compare the top hosted FFmpeg REST APIs for video transcoding in 2026. Transparent pricing, hidden costs, and use-case recommendations across Mux, Bitmovin, AWS, Coconut, Rendi, FetchMedia, and Very Good FFmpeg.

  • Jun 10, 2026

    FFmpeg Extract Audio From Video: Command for WAV, MP3, AAC With Codec, Channel, and Sample Rate Control

    Extract audio from video with ffmpeg using exact commands for wav mono 16khz, high-quality mp3, and aac stream copy. Covers -ac, -ar, -acodec flags and scaling with a hosted FFmpeg API.

  • Jun 10, 2026

    FFmpeg documentation: thumbnail filter, select filter, and frame extraction commands

    How to extract thumbnails from video with FFmpeg using -ss, thumbnail filter, select filter, fps filter, and contact sheets

  • Jun 10, 2026

    FFmpeg Formats Documentation: MP4, Matroska (MKV), WebM, and MOV Explained

    How to convert between video containers with FFmpeg, lose zero quality with stream copy, and when to re-encode

Very Good FFmpegChecking status...
Product
  • How it works
  • Pricing
  • Comparison
  • FAQ
  • Blog
Developers
  • Documentation
  • API Reference
  • MCP Server
  • TypeScript SDK
  • Python SDK
Company
  • Contact
  • Sign in
  • Sign up
  • Terms
  • Privacy
As Seen On
  • G2
  • Product Hunt
  • GitHub
  • PyPI
  • NPM
  • Smithery
  • MCP.so
  • AlternativeTo
  • Make
© 2026 Very Good FFmpeg