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.

Stream Video Between Two Computers Using FFmpeg (Linux & macOS).
Image credit: Unknown. Please contact us if you are the owner.

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 -version

If ffplay is not found:

$ which ffplay

or

$ command -v ffplay


If Commands not found

You need to install:

on macOS

$ brew install ffmpeg

or

on Linux

$ sudo apt install ffmpeg

How 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 instantly

Notice 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 replacing 0.0.0.0 with the exact local IP address of the receiver's specific network card (e.g., your wired Ethernet IP 192.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:5000

Replace 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:5000

Replace 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

  1. -re
  • Reads the file at its native playback speed.
    Without it, FFmpeg transmits as fast as possible.
  1. -i movie.mov
  • Specifies the input video.
  1. -c copy
  • Copies the existing video stream without re-encoding.

Advantages:

  • No quality loss
  • Extremely low CPU usage
  • Maximum throughput
  1. -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.

  1. 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.
  1. :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
     │
     ▼
 ffplay

No 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.
  • Q or Esc

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!

Keep Us Caffeinated  ⦿ ⦿
Icon Join our 36K+ readers Spotify Logo