Let’s watch a DVD together (remotely)

Vincent Jordan
7 min readFeb 12, 2021

Tips to share a movie over internet and watch it together with someone else.

Do you miss watching a movie with friends or family? Isn’t it great when you can pause a movie and discuss about it?

If you try to share your desktop, running a movie player, inside your favorite video meeting solution, it is probably not going to be great because of low framerate and maybe bad sound. This functionality is designed for business presentation, not video.

This article shows how to stream your desktop movie player directly. It even works directly from a DVD. You will see that DVD quality is especially adapted for streaming.

DIY streaming service

At the origin, internet was nicely designed so everyone could be a content provider. Unfortunately now most people are behind NAT, and they are not easily reachable for direct P2P streaming. Your private internet connection may also not have enough upload bandwidth to send multiple streams concurrently.
➥ A cheap cloud instance in the middle will simplify everything.

Build gstreamer’s RTSP server example

An RTSP server can serve RTP streams to clients. gstreamer has an open-source implementation.

On a newly started cloud instance, running Ubuntu 18.04 or 20.04:

apt update
apt install ninja-build
apt install libglib2.0-dev libgstreamer1.0-dev libgstrtspserver-1.0-dev libgstreamer-plugins-bad1.0-dev
git clone https://github.com/GStreamer/gst-rtsp-server
cd gst-rtsp-server/
apt install python3-pip
# Note: meson provided by apt is too old on Ubuntu 20.04, use pip
pip3 install meson
# reset to older version to be compatible with:
# - gstreamer 1.14 provided by Ubuntu 18.04
git reset --hard 1.14.5
# - gstreamer 1.16 provided by Ubuntu 20.04
git reset --hard 1.16.3
/usr/local/bin/meson ../build/
cd ../build/
ninja

Start the RTSP server example. We will stream RTP in an MPEG2 container on UDP port 5000, therefore:

cd examples/
./test-launch "( udpsrc port=5000 ! application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)MP2T ! rtpmp2tdepay ! rtpmp2tpay name=pay0 )"

Note 1: UDP port 5000 and MPEG2 are arbitrary choices. There are other (potentially better) streaming options.

Note 2: MPEG2 refers here to the container only, not the video codec. We will use the more efficient H264 for video and AAC for audio.

Note 3: Yes, rtpmp2tdepay (decode payload) followed by rtpmp2tpay (make payload) seems to be redundant, but I did not find how to get it to work without it.

Capture a window on your desktop using gstreamer

Using xwininfo, you can get the xid of any window on your X desktop.

Test if you correctly capture it, with this command (don’t forget to change the xid):

gst-launch-1.0 ximagesrc xid=0x4600005 ! video/x-raw,framerate=30/1 ! ximagesink

Capture the sound of your desktop using gstreamer

With pulseaudio, it is easy to capture the sound going to any audio device (e.g., sound card, bluetooth headset, …). Using pactl, you can list your audio sources:

pactl list | grep -A2 'Source #'

Some examples of source names (look especially for device names ending with .monitor):

# internal sound card output (on PCI)
alsa_output.pci-0000_00_1f.3.analog-stereo.monitor
# wireless headset output (on bluetooth)
bluez_sink.94_DB_56_02_C7_3B.a2dp_sink.monitor

Note: pavucontrol is a convenient way to choose where audio goes, on a per application basis.

Mixing and streaming

Captured video and audio need to be compressed and mixed in a container.

Below, an example of gstreamer command to produce an RTP stream with MPEG2 containing H264 video and AAC encoded sound:

gst-launch-1.0 ximagesrc xid=0x4a00005 ! video/x-raw,framerate=30/1 ! videoconvert ! vaapih264enc quality-level=1 ! h264parse config-interval=10 ! queue ! mux. pulsesrc device=alsa_output.pci-0000_00_1f.3.analog-stereo.monitor ! "audio/x-raw,rate=16000,channels=2,depth=16" ! audioconvert ! avenc_aac ! aacparse ! queue ! mux. mpegtsmux name=mux ! rtpmp2tpay ! udpsink host=51.13.216.45 port=5000

Values which need to be updated to your environment in the command above:

  • ximagesrc xid=0x4a00005 with the xid of your window
  • pulsesrc device=... with the device name of your audio source
  • udpsink host=51.13.216.45 with the IP address of your RTSP server

Notice the use of vaapih264enc for hardware-accelerated video encoding using VAAPI. Different graphic card manufacturers use different API. VAAPI, originally designed by Intel, is adapted for Intel integrated GPU and some others.
The quality-level parameter decides quality, as well as latency. 1 is high quality and high latency, higher values means lower quality and lower latency.

CPU encoding is also possible, see x264enc and maybe add tune=zerolatency if low latency important to you.

Stream playback on client side

The VLC media player runs pretty much everywhere (even Android) and can open an RTSP link in the “Open Network Stream” menu:

This is the link:

rtsp://rtsp_server_ip:8554/test

Note: the same link can be opened multiple times. The RTSP server will copy the input stream accordingly.

Intended use

Now you can share your video player. In order to discuss about the movie simultaneously, you can use any video meeting solution (e.g., jitsi).

Whenever someone wants to pause playback, he asks the one controlling the video player.
That person is now like the one holding the remote from the older time when people used DVD players.

Real life test

What you you will need

A cheap cloud instance.
You do not need many CPU cores, since the stream will not be processed on the cloud instance. Only network bandwidth is needed. A quick test shows that the stream consumes a few hundreds of Kilobytes per second.

Can you guess the cloud provider? (see End Credits)

A movie and a headset.
The headset is required to prevent audio loopback with the video meeting.

Note: it might also work if the movie is not French nor famous

A friend to watch the movie with.

Result

It works! No problem occurred, despite the long distance.

RTSP server CPU/memory load is very low while streaming
DVD upload bandwidth

DVD upload bandwidth depends on the action in the movie.
It can be as low as 100KB/s when nothing much happens in the movie, and it can be above 1MB/s when there is a complex traveling or much details in the scene.

Advantages/drawbacks of this solution

Advantages

  • You choose the streaming quality and framerate, not your video meeting solution.
  • Sound is captured directly at the source.
  • You keep control on the video playback: you can pause, fast forward or replay on the stream server and all clients will see the same. You can even navigate the DVD menus.
  • The mouse pointer is still visible if you need, you can point at something in the movie.

Disadvantages

  • Stream quality does not adapt to network speed. The RTSP server is just a relay. It does not re-encode the stream to a lower quality if the network is too slow.
  • There is some delay. Not as low latency as a professional solution or WebRTC.

Note: lower latency can be achieve with less buffering on the client side. VLC does not seem to allow for no buffering at all.

Try setting 0 to “RTSP frame buffer size”…

Using ffmpeg (but less user friendly compared to VLC):

ffplay -fflags nobuffer rtsp://rtsp_server_ip:8554/test

Other ideas

VLC has a web interface. If you manage to give access to the clients, anyone can control video playback (i.e., everyone can fight for the remote).

H265 is also possible if hardware allows it:

$ vainfo | grep HEVC
VAProfileHEVCMain : VAEntrypointVLD
VAProfileHEVCMain : VAEntrypointEncSlice

Replace h264 with h265 in the gstreamer command (everything else remaining the same):

[...] vaapih265enc quality-level=1 ! h265parse [...]

At quality-level=1, network bandwidth usage is the same but quality is supposedly better (not really visible from a DVD though):

Bandwidth usage is similar, but quality is higher

TODO: Increase the quality-levelvalue.

The End

Troubleshooting

Problem: vaapih264enc not found despite having installed the gstreamer1.0-vaapi package:

WARNING: erroneous pipeline: no element "vaapih264enc"

Solution: try adding GST_VAAPI_ALL_DRIVERS=1 in front of the command.

You can also clear gstreamer local cache:

rm ~/.cache/gstreamer-1.0/*

Explanation: gst-vaapi has a whitelisting for driver support.

--

--