Why Use Pipes

A pipe (|) sends one program’s output straight into another program. With pipes, FFmpeg can:

  • skip intermediate files, so there is less disk I/O
  • process data as it arrives
  • work with other programs such as curl, Python and Node.js
  • take data your program holds in memory, with no temporary file on disk

Pipe Protocol Basics

Standard input (stdin) is the data a program receives, for example through |. Standard output (stdout) is what it writes out, which > can save to a file. FFmpeg names them like this:

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

-i - is short for -i pipe:0:

cat input.mp4 | ffmpeg -i - -c:v libx264 -crf 23 output.mp4

This works only if the MP4’s moov atom (the index needed for playback) is at the start of the file. FFmpeg puts moov at the end by default. With such a file, FFmpeg stops with partial file and Invalid data found when processing input. Move moov to the front first with ffmpeg -i input.mp4 -c copy -movflags +faststart faststart.mp4 and pipe that file. Or skip the pipe and pass the file with -i input.mp4. TS and MKV files can be piped as they are.

Writing to Standard Output

Output the converted result to stdout and pipe it onward

ffmpeg -i input.mp4 -c:v libx264 -crf 23 -movflags frag_keyframe+empty_moov -f mp4 pipe:1 > output.mp4

To write MP4 to stdout, add -movflags frag_keyframe+empty_moov. A normal MP4 goes back to the start of the file to finish its header. A pipe cannot go back, so FFmpeg stops with muxer does not support non seekable output. With these flags, FFmpeg writes a fragmented MP4 (an MP4 written in small pieces, one after another) with the moov atom at the front.

Integration with curl

Send a video from a URL straight into FFmpeg, with no temporary file:

curl -s "https://example.com/video.mp4" | ffmpeg -i pipe:0 -c:v libx264 -crf 23 output.mp4

This fails the same way if the MP4 has moov at the end. Passing the URL to -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 image2pipe pipe:1 > thumbnail.jpg

This is useful when a web server sends the image straight back as its response.

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

The input MP4 must have moov at the start, for example a file written with -movflags +faststart. If moov is at the end, FFmpeg stops with an error and the output is empty.

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('Done')
"

Pipe Limitations

Pipes have these limits:

Limitation Details
No seeking stdin can only be read from start to end (no random access)
Input format may be needed Some inputs need their format declared, e.g. -f rawvideo
MP4 output needs care A normal MP4 writes the moov atom at the end, so use fragmented MP4

Processing rawvideo Through a Pipe (Advanced)

To feed raw video frames into FFmpeg (for example, straight from a camera or from your own program):

# 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)

  • Happens when FFmpeg cannot detect the input format, or when the input is an MP4 with moov at the end
  • For such an MP4, -f mp4 does not help. Pipe a copy made with -movflags +faststart, or pass the file with -i input.mp4
  • For raw data, declare -f rawvideo with the size, fps and pix_fmt before -i

MP4 output to stdout stops with muxer does not support non seekable output

  • A normal MP4 cannot be written to stdout, because stdout cannot seek. FFmpeg does not write the header, and the output is 0 bytes
  • Add -movflags frag_keyframe+empty_moov to write a fragmented MP4

Common Pitfalls

  • Symptom: seeking with -ss does not work, or is slow. Cause: stdin has no random access, so FFmpeg must read and throw away everything before the seek point. Fix: when seeking matters, pass the file with -i filename, or the URL with -i "URL".

  • Symptom: in Python, the log gets mixed into the video data. Cause: FFmpeg’s log (stderr) is not kept apart from its output (stdout). Fix: pass stdout=subprocess.PIPE and stderr=subprocess.DEVNULL as separate arguments.

FAQ

Q. Are pipe:0 and - the same thing? A. Yes. For input, -i pipe:0 and -i - do the same thing. For output, pipe:1 and - both mean standard output.

Q. Why bother using pipes at all? A. You skip intermediate files, so there is less disk I/O. You can also connect FFmpeg directly to other programs such as curl or Python, or feed it data your program holds in memory.

Q. For a URL, should I use a pipe or -i directly? A. Passing the URL with -i "URL" is more reliable, especially when seeking or format detection matters. curl ... | ffmpeg -i pipe:0 also works for a straight pass through a TS or MKV file, or an MP4 with moov at the start.

Q. Do pipes work on Windows? A. Yes. pipe:0 and pipe:1 work the same everywhere. Only the shell syntax changes, for example NUL instead of /dev/null. In Windows PowerShell 5.1, > and | treat binary data such as video as text and corrupt it. Run these commands in Command Prompt (cmd.exe) or PowerShell 7.4 or later.

Q. Can I pass the output straight into another FFmpeg? A. Yes: ffmpeg ... -f mp4 pipe:1 | ffmpeg -i pipe:0 .... Use a format that can be written to a pipe, such as fragmented MP4.