What You Will Learn
- How to use FFmpeg’s pipe protocol (
pipe:0,pipe:1) - Reading data from standard input (
-i pipe:0or-i -) - Writing to standard output (
pipe:1or-) - Processing video from a URL directly by combining with
curl - Calling FFmpeg from Python via pipes
- Caveats and the no-seek limitation
Tested version: FFmpeg 6.1
Target OS: Windows / macOS / Linux
Why Use Pipes
With FFmpeg’s pipe feature you can:
- Process without writing files: No intermediate files, reducing disk I/O
- Stream processing: Process data in real time as it arrives
- Integrate with other programs: Combine with curl, Python, Node.js, and more
- Process in-memory data: Avoid creating temporary files on disk
Pipe Protocol Basics
| Notation | Meaning |
|---|---|
pipe:0 or - | Standard input (stdin) |
pipe:1 | Standard output (stdout) |
pipe:2 | Standard error (stderr, normally FFmpeg’s log) |
Reading from Standard Input
Read an MP4 from stdin and convert it
cat input.mp4 | ffmpeg -i pipe:0 -c:v libx264 -crf 23 -c:a aac output.mp4
Or using the shorthand -i -:
cat input.mp4 | ffmpeg -i - -c:v libx264 -crf 23 output.mp4
Writing to Standard Output
Output the converted result to stdout and pipe it onward
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -f mp4 pipe:1 | cat > output.mp4
Note: MP4 output to stdout requires -movflags frag_keyframe+empty_moov (because a normal MP4 writes the moov atom at the end of the file):
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -movflags frag_keyframe+empty_moov -f mp4 pipe:1 > output.mp4
Integration with curl
Pass video from a URL directly into FFmpeg (no temporary file):
curl -s "https://example.com/video.mp4" | ffmpeg -i pipe:0 -c:v libx264 -crf 23 output.mp4
Alternatively, specifying the URL directly with -i is more reliable:
ffmpeg -i "https://example.com/video.mp4" -c:v libx264 -crf 23 output.mp4
Outputting a Thumbnail Image to stdout
ffmpeg -i input.mp4 -ss 00:00:01 -frames:v 1 -f image2 pipe:1 > thumbnail.jpg
This is handy when returning a binary response directly from a web server.
Calling FFmpeg from Python via Pipes
python3 -c "
import subprocess, sys
proc = subprocess.run(
['ffmpeg', '-i', 'input.mp4', '-c:v', 'libx264', '-crf', '23',
'-movflags', 'frag_keyframe+empty_moov', '-f', 'mp4', 'pipe:1'],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL
)
with open('output.py.mp4', 'wb') as f:
f.write(proc.stdout)
print('Done, size:', len(proc.stdout))
"
Bidirectional stdin/stdout Pipe in Python
python3 -c "
import subprocess
with open('input.mp4', 'rb') as inp:
proc = subprocess.run(
['ffmpeg', '-i', 'pipe:0', '-c:v', 'libx264', '-crf', '23',
'-movflags', 'frag_keyframe+empty_moov', '-f', 'mp4', 'pipe:1'],
stdin=inp,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL
)
with open('output.pipe.mp4', 'wb') as out:
out.write(proc.stdout)
print('完了')
"
Pipe Limitations
Important limitations when using pipes (stdin/stdout):
| Limitation | Details |
|---|---|
| No seeking | stdin cannot seek (no random access) |
| Input format must be specified | You may need to declare the format explicitly, e.g. -f rawvideo |
| MP4 output needs care | A normal MP4 writes the moov atom at the end, so fragmented MP4 is required |
Processing rawvideo Through a Pipe (Advanced)
When passing raw video frames (raw data from a camera or your own program) into FFmpeg:
# Example of receiving a rawvideo stream through a pipe (environment-dependent)
# You must explicitly specify the format, size, and frame rate
ffmpeg -f rawvideo -vcodec rawvideo -s 1920x1080 -r 30 -pix_fmt rgb24 -i pipe:0 \
-c:v libx264 -crf 23 output.mp4
Common Problems
Invalid data found when processing input (when reading from stdin)
- Occurs when FFmpeg cannot detect the input format
- Specify the format explicitly, e.g.
-f mp4
The MP4 output to stdout is corrupted
- The normal MP4 format is incompatible with stdout
- Specify
-movflags frag_keyframe+empty_moovto produce a fragmented MP4
Common Pitfalls
-
Symptom: an MP4 sent to stdout will not play or is corrupted. Cause: a normal MP4 writes the
moovatom at the end of the file, which conflicts with non-seekable stdout. Fix: add-movflags frag_keyframe+empty_moovto produce a fragmented MP4, exactly as in the examples above. -
Symptom:
Invalid data found when processing inputwhen reading from stdin. Cause: FFmpeg cannot auto-detect the input format. Fix: declare the format explicitly before-i, e.g.-f mp4. For raw data, use-f rawvideoalong with the size, fps, and pix_fmt. -
Symptom: seeking with
-ssdoes not work or is slow. Cause: stdin has no random access, so a seek becomes a read-and-discard from the start. Fix: when seeking matters, pass the file directly with-i filenamewhere possible, or use-i "URL". -
Symptom: in Python, stderr mixes in and corrupts the data. Cause: FFmpeg’s log (stderr) is not separated from its output (stdout). Fix: as in the examples, set
stdout=subprocess.PIPEandstderr=subprocess.DEVNULLseparately.
FAQ
Q. Are pipe:0 and - the same thing?
A. Yes. For input, -i pipe:0 and -i - are equivalent. For output, pipe:1 and - both refer to standard output.
Q. Why bother using pipes at all? A. They avoid intermediate files (reducing disk I/O), let you wire FFmpeg directly to other programs like curl or Python, and let you stream in-memory data without touching disk.
Q. For a URL, should I use a pipe or -i directly?
A. When seeking or format detection matters, passing -i "URL" directly is more reliable. For a simple straight-through pass, curl ... | ffmpeg -i pipe:0 also works.
Q. Do pipes work on Windows?
A. Yes. Just substitute shell-specific notation, such as NUL instead of /dev/null. The pipe:0 and pipe:1 tokens themselves are the same everywhere.
Q. Can I pass the output straight into another FFmpeg?
A. Yes. You can chain them: ffmpeg ... -f mp4 pipe:1 | ffmpeg -i pipe:0 .... Just pick a format that stdout can handle, such as fragmented MP4.
Related Articles
- Automate FFmpeg Batch Conversion with Shell Scripts
- Causes of the moov atom Error and How to Fix It
- HLS Segment Delivery
Primary sources: ffmpeg.org/ffmpeg-protocols.html#pipe / ffmpeg.org/ffmpeg.html