Skip to content

Shell script on Ubuntu to auto-stream on boot using x11grab and ffmpeg

License

Notifications You must be signed in to change notification settings

maple-underscore/x11stream

Repository files navigation

x11stream

Shell script on Ubuntu to auto-stream X11 display on boot using x11grab and ffmpeg with HLS (HTTP Live Streaming).

Features

  • Captures X11 display using ffmpeg with ultra-low-latency settings (400-600ms)
  • HLS streaming for multiple concurrent connections without crashes
  • Hardware acceleration support for Rockchip RK3588 (rkmpp), VAAPI, and Intel QSV
  • Hosts an HTTP server for direct browser/VLC/mobile access
  • Auto-starts on boot via systemd service with automatic restart on failures
  • Interactive mode for easy configuration
  • Audio streaming support with multiple quality presets
  • Auto-detect resolution with intelligent scaling (scales down if display is larger than target)
  • Configurable resolution, framerate, bitrate, and audio settings
  • Bandwidth estimation for all configurations
  • OLED display support for Orange Pi and Raspberry Pi (SH1106, SSD1306, SSD1305, SSD1309)
  • Multi-driver support - works with common I2C OLED displays

Key Improvements

  • No crash on client disconnect: HLS streaming supports multiple clients and continues running when clients disconnect
  • Ultra-low latency: Optimized to 400-600ms latency (down from 3-4 seconds)
  • Hardware acceleration: Automatic detection and use of Rockchip MPP, VAAPI, or QSV when available
  • Better quality: Improved encoding settings reduce compression artifacts
  • Stable streaming: DTS discontinuity issues resolved with proper frame timing
  • Auto-restart: Systemd service automatically restarts on any failures

Requirements

  • Ubuntu (or other Linux with X11)
  • ffmpeg with x11grab support
  • PulseAudio or ALSA (for audio streaming)
  • systemd (for auto-start on boot)

Quick Installation

The easiest way to get started is using the quickstart script:

git clone https://github.com/maple-underscore/x11stream.git
cd x11stream
./quickstart.sh

The quickstart script will:

  • Install all required dependencies (ffmpeg, i2c-tools, x11-utils, Python packages)
  • Set up OLED display support with your choice of driver (optional)
  • Install and configure systemd services
  • Guide you through the setup process interactively

Manual Installation

If you prefer to install manually or the quickstart script doesn't work for your system:

Install ffmpeg:

sudo apt update
sudo apt install ffmpeg

Install x11-utils:

sudo apt-get install x11-utils

Note

Configure ffmpeg to use x11grab and libx264:

sudo ./configure --enable-x11grab --enable-libx264

Installation

Quick Installation (Recommended)

Use the automated quickstart script:

git clone https://github.com/maple-underscore/x11stream.git
cd x11stream
./quickstart.sh

The script will guide you through the installation process and configure everything automatically.

Manual Installation

  1. Clone this repository:
git clone https://github.com/maple-underscore/x11stream.git
cd x11stream
  1. Install the script:
sudo cp x11stream.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/x11stream.sh
  1. Install and enable the systemd service:
sudo cp x11stream.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable x11stream.service
sudo systemctl start x11stream.service

Usage

Interactive Mode

Run in interactive mode to configure all settings through a menu:

./x11stream.sh --interactive
# or
./x11stream.sh -i

Non-Interactive Mode

./x11stream.sh

Access the Stream

Once the script is running, access the stream via:

  • Browser: http://<your-ip>:8080/stream.m3u8
  • VLC: Open Network Stream → http://<your-ip>:8080/stream.m3u8
  • Mobile: Most modern browsers and video players support HLS streams

Service Management

# Start the service
sudo systemctl start x11stream.service

# Stop the service
sudo systemctl stop x11stream.service

# Check status
sudo systemctl status x11stream.service

# View logs
sudo journalctl -u x11stream.service -f

OLED Display Support (Orange Pi / Raspberry Pi)

The x11stream project supports displaying the local IP address and streaming status on I2C OLED displays with multiple driver options.

Supported OLED Drivers

  • SH1106 - 128x64, common in 1.3" displays (default)
  • SSD1306 - 128x64, common in 0.96" displays
  • SSD1305 - 128x64
  • SSD1309 - 128x64

Hardware Requirements

  • Orange Pi (tested on Orange Pi 5) or Raspberry Pi
  • 0.96" - 1.3" OLED Display Module (128x64 pixels, I2C)
  • I2C connection using pins:
    • I2C_SDA_M0 (SDA/Data) or GPIO2 (Raspberry Pi)
    • I2C_SCL_M0 (SCL/Clock) or GPIO3 (Raspberry Pi)
    • VCC (3.3V-5V)
    • GND

OLED Display Installation

Quick Installation (Recommended)

The easiest way is to use the quickstart script which will guide you through driver selection:

./quickstart.sh

When prompted, choose to install OLED support and select your driver type.

Manual Installation

  1. Enable I2C on Orange Pi:
# Install I2C tools and Python package manager
sudo apt-get install -y i2c-tools python3-pip

# Enable I2C using armbian-config (recommended method for Armbian-based systems)
sudo armbian-config
# Navigate to: System -> Hardware -> enable i2c0 or i2c1
# Save and reboot

# Alternative: For manual configuration, you can edit /boot/orangepiEnv.txt
# Add or uncomment the following line:
# overlays=i2c0
# Then reboot the system

For Raspberry Pi:

# Install I2C tools
sudo apt-get install -y i2c-tools python3-pip

# Enable I2C
sudo raspi-config
# Navigate to: Interface Options -> I2C -> Enable
# Reboot the system
  1. Verify I2C connection:
# Check if I2C device is detected (default address: 0x3C)
sudo i2cdetect -y 0  # Try bus 0
# or
sudo i2cdetect -y 1  # Try bus 1
  1. Install Python dependencies:

Tip

Recommended installation method: Install to user directory to avoid system package conflicts.

cd x11stream

# Install base dependencies
pip3 install --user adafruit-blinka Pillow

# Install driver for your display (choose one or install all):
pip3 install --user adafruit-circuitpython-sh1106   # For SH1106 (default)
pip3 install --user adafruit-circuitpython-ssd1306  # For SSD1306
pip3 install --user adafruit-circuitpython-ssd1305  # For SSD1305
pip3 install --user adafruit-circuitpython-ssd1309  # For SSD1309

# Or install all drivers at once:
pip3 install --user -r requirements.txt
  1. Configure OLED driver (optional):

Set the driver type and I2C address via environment variables:

# Create environment file
sudo mkdir -p /etc/default
sudo bash -c 'cat > /etc/default/oled_display << EOF
OLED_DRIVER=sh1106
I2C_ADDRESS=0x3C
EOF'

Available drivers: sh1106 (default), ssd1306, ssd1305, ssd1309

  1. Install OLED display script:
sudo cp oled_display.py /usr/local/bin/
sudo chmod +x /usr/local/bin/oled_display.py
  1. Install and enable the OLED display service:
sudo cp oled_display.service /etc/systemd/system/oled_display.service

# If you created an environment file, update the service to use it:
if ! sudo grep -q "EnvironmentFile" /etc/systemd/system/oled_display.service; then
    sudo sed -i '/^\[Service\]/a EnvironmentFile=-/etc/default/oled_display' /etc/systemd/system/oled_display.service
fi

sudo systemctl daemon-reload
sudo systemctl enable oled_display.service
sudo systemctl start oled_display.service

OLED Display Service Management

# Start the OLED display service
sudo systemctl start oled_display.service

# Stop the OLED display service
sudo systemctl stop oled_display.service

# Check status
sudo systemctl status oled_display.service

# View logs
sudo journalctl -u oled_display.service -f

OLED Display Information

The OLED display shows:

  • Header: "X11 Stream"
  • IP Address: Current local IP address (updates every 5 seconds)
  • Status: Streaming status ("Streaming", "Stopped", or "Unknown")

I2C Auto-Check Feature

Note

The script automatically performs I2C diagnostics on startup:

  • Checks for I2C device nodes: Verifies /dev/i2c-* devices exist
  • Scans I2C buses: Uses i2cdetect to find OLED display at 0x3C or 0x3D
  • Provides helpful errors: Clear guidance if I2C is not configured
  • Supports multiple drivers: Auto-detects and uses the configured driver

Example auto-check output:

Performing I2C auto-check...
âś“ Found I2C device nodes: /dev/i2c-0, /dev/i2c-1
âś“ I2C device detected on bus 0 at address 0x3C or 0x3D
Initializing SH1106 display at I2C address 0x3C...
âś“ SH1106 display initialized successfully

Driver Configuration

You can configure the OLED driver in several ways:

  1. Environment variable (recommended for systemd):
export OLED_DRIVER=sh1106  # or ssd1306, ssd1305, ssd1309
export I2C_ADDRESS=0x3C    # or 0x3D
  1. System-wide configuration file:
# Create /etc/default/oled_display
OLED_DRIVER=sh1106
I2C_ADDRESS=0x3C
  1. Edit the Python script directly (not recommended): Edit /usr/local/bin/oled_display.py and change the default values.

Troubleshooting OLED Display

Display not working:

Tip

Troubleshooting checklist:

  • Verify I2C is enabled: sudo i2cdetect -y 0 or sudo i2cdetect -y 1
  • Check if device appears at address 0x3C or 0x3D
  • Verify wiring connections (SDA, SCL, VCC, GND)
  • Check service logs: sudo journalctl -u oled_display.service -f
  • Verify correct driver is selected (check logs for driver name)
  • Try different driver if display shows garbled output

Wrong driver selected:

Tip

If the display shows garbled output or doesn't work:

  • Check which driver your display uses (consult display documentation)
  • Common 0.96" displays use SSD1306
  • Common 1.3" displays use SH1106
  • Update driver: sudo nano /etc/default/oled_display and change OLED_DRIVER
  • Restart service: sudo systemctl restart oled_display.service

Wrong I2C bus:

Important

The script uses board.SCL and board.SDA, which are the default I2C pins defined by the board library. They do not auto-detect alternate buses or pins.

  • If you're using a different I2C bus, you may need to modify the Python script
  • For manual configuration, check which I2C bus your display is on with i2cdetect
  • You may need to modify the script to use a different I2C bus if your hardware differs from the default configuration

Maintenance and Testing

Updating the Repository

The update.sh script allows you to easily update your x11stream installation to the latest version:

./update.sh

The update script will:

  • Check for uncommitted changes and offer to stash them
  • Fetch the latest changes from the remote repository
  • Pull and merge updates to your current branch
  • Notify you if requirements.txt or service files were updated
  • Provide instructions for updating dependencies or reloading services if needed

Testing OLED Drivers

The drivertest.py script allows you to test OLED displays with custom configurations without modifying the main display service.

Configuration

Edit the configuration section at the top of drivertest.py:

# OLED Driver Selection
DRIVER_NAME = "sh1106"  # sh1106, ssd1306, ssd1305, or ssd1309

# Text to display
DISPLAY_TEXT = "Hello World!"

# I2C Interface Selection
I2C_SDA_PIN = "I2C2_SDA_M0"  # Orange Pi: I2C2_SDA_M0, I2C0_SDA
I2C_SCL_PIN = "I2C2_SCL_M0"  # Raspberry Pi: GPIO2 (SDA), GPIO3 (SCL), or SDA/SCL

# I2C Address
I2C_ADDRESS = 0x3C  # Most displays use 0x3C or 0x3D

Usage

# Run the driver test
python3 drivertest.py

The script will:

  • Display configuration information (driver, text, I2C pins)
  • Initialize the selected OLED driver
  • Clear the display
  • Show your custom text
  • Keep the display on until you press Ctrl+C

Use Cases

  • Test different drivers: Quickly test which driver works with your display
  • Test different I2C interfaces: Verify correct pin configuration
  • Custom messages: Display any text on your OLED for testing
  • Troubleshooting: Isolate display issues from the main service

Example Configurations

Orange Pi 5 with 1.3" SH1106 display:

DRIVER_NAME = "sh1106"
I2C_SDA_PIN = "I2C2_SDA_M0"
I2C_SCL_PIN = "I2C2_SCL_M0"

Raspberry Pi with 0.96" SSD1306 display:

DRIVER_NAME = "ssd1306"
I2C_SDA_PIN = "SDA"  # or "GPIO2"
I2C_SCL_PIN = "SCL"  # or "GPIO3"

Custom I2C bus:

DRIVER_NAME = "ssd1309"
I2C_SDA_PIN = "I2C0_SDA"
I2C_SCL_PIN = "I2C0_SCL"

Configuration

Environment Variables

The following environment variables can be set to customize the stream:

Variable Default Description
DISPLAY :0.0 X11 display to capture
RESOLUTION 1920x1080 Target resolution (auto-detects and adjusts)
FRAMERATE 60 Frames per second
BITRATE 6M Video bitrate
HTTP_PORT 8080 HTTP server port
HTTP_BIND 0.0.0.0 HTTP server bind address (0.0.0.0 or 127.0.0.1)
USE_HARDWARE_ACCEL auto Hardware acceleration (auto, rkmpp, vaapi, qsv, none)
HLS_TIME 1 HLS segment duration in seconds
HLS_LIST_SIZE 3 Number of segments to keep in playlist
AUDIO_ENABLED false Enable audio streaming
AUDIO_BITRATE 128 Audio bitrate (kbps)
AUDIO_CODEC aac Audio codec (aac, mp3, pcm)
AUDIO_SAMPLE_RATE 44100 Sample rate for PCM audio
AUDIO_BIT_DEPTH 16 Bit depth for PCM audio

Hardware Acceleration

The script automatically detects available hardware acceleration:

  • Rockchip RK3588/MPP: Best for Orange Pi 5/5 Plus - uses h264_rkmpp encoder
  • VAAPI: For AMD and Intel GPUs on Linux - uses h264_vaapi encoder
  • Intel QSV: For Intel CPUs with Quick Sync - uses h264_qsv encoder
  • Software: Falls back to libx264 if no hardware acceleration is available

To force a specific encoder:

export USE_HARDWARE_ACCEL=rkmpp  # or vaapi, qsv, none

Security Considerations

The HTTP server binds to 0.0.0.0 by default, making the stream accessible from all network interfaces. For enhanced security:

# Restrict to localhost only
export HTTP_BIND=127.0.0.1

# Or restrict to specific interface
export HTTP_BIND=192.168.1.100

For production use with sensitive data, consider:

  • Using a reverse proxy (nginx) with authentication
  • Setting up a VPN for remote access
  • Using firewall rules to restrict access

Resolution Auto-Detection

Note

The script automatically detects your display resolution using xdpyinfo:

  • If detected resolution is higher than the target: captures full screen and scales down to target
  • If detected resolution is lower than the target: uses the native (lower) resolution
  • If resolution cannot be detected: uses the configured target resolution

Audio Quality Presets

When using interactive mode, you can choose from these audio presets:

Lossy Compression (AAC/MP3)

Preset Bitrate Quality Bandwidth
1 64 kbps Voice/Low ~8 KB/s
2 128 kbps Standard ~16 KB/s
3 192 kbps Good ~24 KB/s
4 256 kbps High ~32 KB/s
5 320 kbps Maximum ~40 KB/s

Lossless PCM (16-bit)

Preset Sample Rate Quality Bandwidth
6 44.1 kHz CD quality ~172 KB/s
7 48 kHz DVD quality ~188 KB/s
8 96 kHz Hi-Res ~375 KB/s
9 192 kHz Ultra Hi-Res ~750 KB/s

Lossless PCM (24-bit)

Preset Sample Rate Quality Bandwidth
10 44.1 kHz Studio ~258 KB/s
11 48 kHz Professional ~281 KB/s
12 96 kHz Hi-Res Studio ~563 KB/s
13 192 kHz Ultra Hi-Res Studio ~1125 KB/s

Video Quality Presets

Bitrate Quality Bandwidth
2M Low bandwidth ~250 KB/s
4M Medium quality ~500 KB/s
6M Good quality ~750 KB/s
10M High quality ~1.25 MB/s
15M Very high ~1.9 MB/s
20M Excellent ~2.5 MB/s

To modify these settings permanently, edit the service file:

sudo systemctl edit x11stream.service

Or edit /etc/systemd/system/x11stream.service directly.

Troubleshooting

"Display not found" error

Warning

Ensure X11 is running and the DISPLAY variable is set correctly. On systems with multiple displays, try :1.0 or :0.1.

"Permission denied" error

Warning

The user running the script needs access to the X11 display. Run with appropriate permissions or add the user to the video group.

Stream not accessible

Tip

Common solutions:

  • Check if ffmpeg is running: ps aux | grep ffmpeg
  • Ensure the port is not blocked by firewall: sudo ufw allow 8080/tcp
  • Verify the IP address and port in the startup output

Audio not working

Tip

Troubleshooting steps:

  • Ensure PulseAudio or ALSA is running
  • Check audio source: pactl list short sources (PulseAudio)
  • Try different audio source in interactive mode

License

MIT License

About

Shell script on Ubuntu to auto-stream on boot using x11grab and ffmpeg

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •