img_20170111_205733

Streaming from Linux to a Chromecast

The Google Chromecast is an impressive little device. If you haven’t encountered one already, it’s a small HDMI dongle which, when connected to a TV screen, allows to play audio, video, or visual content of a compatible webapp from a computer or mobile device.

Google Chromecast
The first generation of the Google Chromecast (Model number H2G2-42 – Get it ?)

However, it is primarily designed to only stream content from the Web, and not from your computer itself, which follows the current trend that everything should be “in the cloud” and is infuriatingly limiting. As you can guess, that dubious ideology is not my cup of tea.

Luckily, the excellent library PyChromecast allows to control the device from a Python program. Yet the issue is that it only works for codecs the Chromecast is able to decode natively, i.e., H.264 and VP8. Besides, the Chromecast is only able to handle a few containers like MP4 and WebM. What if you want to stream other video formats ? Besides, what if you want to stream dynamically-generated content, for instance your screen or a live video from a camera ?

Introducing ffmpeg!

In this example, ffmpeg reads test.avi, recodes the video stream as VP8 and the audio stream as Vorbis, encapsulates the streams in WebM format and outputs in out.webm.

We can enhance this command for streaming to the Chromecast. In particular, ffmpeg allows video filters with -vf, and also various parameters to tune the VP8 codec. Here, we want constant-bitrate realtime encoding with a bound on 50% CPU (0 is 100% and 15 is minimum here). Here, the target bitrate is set to 4Mbps so it fits a crappy WiFi link, but you could set it higher, to 8Mbps for instance.

The video filter is a bit obscure to read but it boils down to two actions:

  1. Scale the video uniformly until either its width fits the width of the screen or its height fits the height of the screen
  2. Pad the scaled video with black so it is centered and the output size is the size of the screen

However, this creates a new problem. What about subtitles ? If a video has a subtitles track, they are now ignored and you can’t see them. The simplest solution is to just hardcode subtitles in the streamed video, whether the video uses a subtitles track or an external subtitles file.

You might have been wondering, why bother with padding ? That’s your answer: since we hardcode subtitles, we want them to take advantage of the padding so they cover the image as little as possible.

We can call ffmpeg from Python code with the subprocess module, while directing its output to the standard output (with -). It is good practice to use arrays to specify arguments rather than passing the command as a string with shell=True. The latter can be a security hazard since it allows shell injection.

The next step is to encapsulate this code in an HTTP server to stream the encoded WebM file over HTTP. In bonus, the special URL screen will allow to stream the screen content!

Let’s launch the server:
$ ./server.py 8888 &

Finally, we need a small command-line client with PyChromecast to start the video.

Now, let the magic happen:
$ ./play.py Elephants_Dream_HD.avi

One thought on “Streaming from Linux to a Chromecast”

  1. Hello Paulo,
    Could you add a “vibrate” mode on my Google Chromecast device?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">