Stream Video Between Two Computers Using FFmpeg (Linux & macOS).
Stream video across your network in real time with FFmpeg and FFplay. This guide covers point-to-point streaming over UDP, TCP, or SSH for Linux and macOS without media servers. Note: The receiver requires an active graphical display (X11/Wayland). For full options, run ffmpeg -h.
To stream video directly from the command line, we’ll use two powerful open-source multimedia utilities included in the FFmpeg project: FFmpeg and FFplay.
FFmpeg is a command-line multimedia framework capable of recording, transcoding, converting, processing, and streaming virtually any audio or video format. In this tutorial, it serves as the streaming server (sender) by reading a video file, encoding it if necessary, packaging it into a transport stream, and transmitting it across the network in real time.
FFplay is a lightweight media player bundled with FFmpeg. Designed primarily for testing and debugging media streams, it acts as the streaming client (receiver) by listening for the incoming network stream and immediately decoding and displaying the video with minimal latency.
Together, these two tools create a complete point-to-point live streaming pipeline, allowing one computer to stream video directly to another without requiring a graphical interface, dedicated streaming software, or a media server.
This approach is:
- Fast
- Lightweight
- Cross-platform
- Ideal for LAN environments
- Entirely CLI-based
No SMB shares, NFS mounts, Plex, Jellyfin, or VLC server are required.
Requirements
Both systems should have:
- FFmpeg
- ffplay (included with most FFmpeg builds)
- Network connectivity
Verify your installation:
$ ffmpeg -version
$ ffplay -versionIf ffplay is not found:
$ which ffplayor
$ command -v ffplay
If Commands not found
You need to install:
on macOS
$ brew install ffmpegor
on Linux
$ sudo apt install ffmpegHow It Works
Local Network
Linux A / macOS A
(contains the video file)
SNUBMONKEY_3080.MOV
│
▼
ffmpeg
│
MPEG-TS over TCP/UDP
│
═══════════════════════════════════════
│
▼
ffplay
Linux B / macOS B
Video plays instantlyNotice that Machine B never stores the video. It simply receives the stream and displays it as it arrives.
Step 1 — Start the Receiver
On Machine B, open a terminal and run:
$ ffplay "tcp://0.0.0.0:5000?listen"
or
$ ffplay "udp://0.0.0.0:5000?listen"Here is the quick breakdown:
tcp://– Uses the Transmission Control Protocol, guaranteeing stable, error-corrected video delivery.udp://– Uses the User Datagram Protocol, prioritizing ultra-low latency and real-time speed over data verification.0.0.0.0– Tells FFplay to listen on all active network interfaces (Wi-Fi, Ethernet, and localhost) simultaneously. Alternatively, you can restrict this to a specific IP by replacing0.0.0.0with the exact local IP address of the receiver's specific network card (e.g., your wired Ethernet IP192.168.1.50). FFplay will then strictly listen for data on that single network interface and completely ignore traffic coming from Wi-Fi or other networks.:5000– Opens port 5000 to catch the incoming video data.?listen– Crucial flag that turns FFplay into a passive server. It will sit and wait silently until an FFmpeg sender connects and starts pushing the stream.
Why the "quotes'?
If you're using zsh, the ? character is interpreted as a wildcard.
These are all equivalent:
$ ffplay "tcp://0.0.0.0:5000?listen"$ ffplay 'tcp://0.0.0.0:5000?listen'or
$ ffplay tcp://0.0.0.0:5000\?listen
output:
$ ffplay version 8.1.2 Copyright (c) 2003-2026 the FFmpeg developers
built with Apple clang version 21.0.0 (clang-2100.0.123.102)
configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/8.1.2_1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gpl --enable-libsvtav1 --enable-libopus --enable-libx264 --enable-libmp3lame --enable-libdav1d --enable-libvmaf --enable-libvpx --enable-libx265 --enable-openssl --enable-videotoolbox --enable-audiotoolbox --enable-neon
libavutil 60. 26.102 / 60. 26.102
libavcodec 62. 28.102 / 62. 28.102
libavformat 62. 12.102 / 62. 12.102
libavdevice 62. 3.102 / 62. 3.102
libavfilter 11. 14.102 / 11. 14.102
libswscale 9. 5.102 / 9. 5.102
libswresample 6. 3.102 / 6. 3.102
nan : 0.000 fd= 0 aq= 0KB vq= 0KB sq= 0B Machine B is now waiting for an incoming connection.
Step 2 — Start Streaming
On Machine A:
Using TCP (Transmission Control Protocol)
$ ffmpeg \
-re \
-i movie.mov \
-c copy \
-f mpegts \
tcp://192.168.1.xxx:5000Replace the IP address with the address of your receiving machine (B).
As soon as the connection is established, playback begins automatically.
- How it works: It establishes a strict, handshake-based connection between the sender and receiver.
- The Pros: Guaranteed delivery. If a packet is lost on the network, TCP pauses the stream and resends it. This prevents visual corruption and blocky artifacts.
- The Cons: Higher latency. If your network hiccups, the video will freeze and lag behind real-time while it waits for missing data to arrive.
- Best for: Unreliable connections (like Wi-Fi) where video quality and completeness matter more than instant delivery.
Using UDP (User Datagram Protocol)
$ ffmpeg \
-re \
-i movie.mov \
-c copy \
-f mpegts \
udp://192.168.1.xxx:5000Replace the IP address with the address of your receiving machine (B).
As soon as the connection is established, playback begins automatically.
- How it works: It opens the port and catches data packets as they are thrown at it, without any connection verification.
- The Pros: Ultra-low latency. It streams in absolute real-time because there is zero overhead or waiting for lost data.
- The Cons: Potential visual glitches. If a packet drops, FFplay ignores it and keeps going, which causes momentary blocky distortion or green screen streaks on the video.
- Best for: Local wired networks (Ethernet) where speed is the priority and packet loss is highly unlikely.
Understanding the Command
-re
- Reads the file at its native playback speed.
Without it, FFmpeg transmits as fast as possible.
-i movie.mov
- Specifies the input video.
-c copy
- Copies the existing video stream without re-encoding.
Advantages:
- No quality loss
- Extremely low CPU usage
- Maximum throughput
-f mpegts
- Uses the MPEG Transport Stream container.
This format was specifically designed for streaming and tolerates packet loss far better than MP4 or MOV.
tcp://192.168.1.xxx:5000||udp://192.168.1.xxx:5000
- Defines the transmission protocol, the receiver's local IP address, and the target port.
:5000
- The destination port where FFplay is listening. This must be a port above 1024 (e.g., 5000 or 8080), as ports 1–1023 are restricted privileges reserved for system services and require root access.
Streaming Without Saving
Unlike SCP or rsync:
movie.mov
│
▼
ffmpeg
│
Network
│
▼
ffplayNo temporary file is created.
No storage is required on the receiving computer.
Playback happens directly from the incoming network stream.
Streaming Over SSH
If you prefer an encrypted connection:
$ ffmpeg \
-re \
-i movie.mov \
-c copy \
-f mpegts - \
| ssh user@host \
'ffplay -i -'This pipes (|) the stream through SSH before handing it to ffplay.
Although convenient, encryption introduces additional CPU overhead compared to direct TCP streaming on a trusted LAN.
Playback Controls (Keyboard Shortcuts)
Because FFplay is a bare-bones, lightweight player, it does not have a visual control menu or clickable buttons. Instead, you must use keyboard shortcuts to control the stream while clicking inside the FFplay window:
Spacebar– Pause / Resume playback.Left / Right Arrows– Seek backward / forward by 10 seconds.Down / Up Arrows– Seek backward / forward by 1 minute.S– Step to the next frame (useful when paused).F– Toggle full-screen mode.QorEsc
Connection Refused
Verify:
- The receiver is already running.
- Both machines are on the same network.
- Firewalls permit TCP port
xxxxx.
⚠️ Critical Requirement: Graphical Display
Remember, ffplay opens a GUI window to render video, it cannot run on headless systems. Whether you are using a raw console, virtual machine, Docker container, or SSH session, the receiver host must have an active graphical session (X11 or Wayland) running.
Without an active display server or a valid display variable, the command will instantly crash with this error:Could not initialize SDL - No available video device
How to fix it:
- Locally: Run the command inside a desktop terminal app (like GNOME Terminal or iTerm2), never from a text-only bare console.
- Remotely (SSH): Use X11 forwarding flags (like
ssh -X) or explicitly export your display environment variable so the system knows where to render the window.
Note: This streaming workflow applies to almost any video format (including .mp4, .mkv, .mov, .avi, and .webm). Both FFmpeg and FFplay include tons of powerful features and configurations.
For a full list of available flags, run ffmpeg -h or ffplay -h in your terminal.
FFmpeg provides an elegant, lightweight way to stream media between Linux and macOS systems with just a few commands. Streaming directly over TCP using -c copy skips slow file transfers and unnecessary transcoding, making it highly efficient. Whether you are previewing footage on a remote workstation, testing media pipelines, or playing a video stored on a different machine, this method offers a reliable, low-overhead solution.
That's it.
We hope this has been helpful!