WIP: Mirror Your Linux Desktop to Your TV

A while back, I wrote a script to do a live screencast of your desktop to a smart TV. I am planning to continue development on that in order to make it more user-friendly. I will update this post with my progress.

Advertisement

May 27, 2015

I tried the old scripts and verified that they can be made to work on Ubuntu 15.04 (Vivid Vervet) on a Samsung UE40H7005 TV (2014 model).

Ffmpeg is deprecated in Ubuntu, so I am using avconv instead, adapting a command line that user Avio posted in a comment here. In the file dlna_fuse.py, replace the command line in class DlnaFuse with this:


cmd = ("parec -d %(pulseaudio_monitor)s | "
       " avconv -f x11grab -s 1280x720 -r 30 -i :0.0+0,0 -ab 192k "
       " -f s16le -ac 2 -ar 44100 -i - "
       " -vcodec libx264 -crf 30 -preset ultrafast -tune animation -threads 0 "
       " -acodec libmp3lame -f matroska - "
       " | %(live_filter)s - ") % locals()

This captures a 1280×720 section of the screen at 30 frame per second and the audio that is played by Pulseaudio and encodes them as H.264 video and MP3 audio in a Matroska container.

In my test, I started the capture two minutes before starting playback on the TV, and I kept streaming for about half an hour. Worked nicely. Next I will see how far I can bring down the latency.

June 2, 2015

Currently, the scripts require several parts to work together: The screen capture is filtered and served up by a FUSE filesystem and served via UPnP by a media server like Mediatomb.

To simplify this, I want to get rid of the FUSE filesystem and package my own UPnP server. Right now I am investigating a UPnP framework written in Python that looks promising: Coherence.

The idea is to write a modified version of Coherence to serve the live stream. When the TV client requests the stream, the screen capture can be started automatically, and the necessary filtering can happen on-the-fly inside the server, circumventing the FUSE filesystem, and removing the need for installing too many additional pieces of software.

Advertisement

12 thoughts on “WIP: Mirror Your Linux Desktop to Your TV”

  1. Hi Mike,

    Just yesterday I googled on how to stream my laptop’s screen to my Samsung TV and I found your old article. And I was surprised and happy to see that you were following up on that post of long time ago at the exact time I needed to get this to work! Talk about coincidences !! 😀

    Anyhow, I tried using the scripts and I didn’t get any success. I’m fairly competent in Linux, but not that experienced in video codecs and files, etc. On a side note, my device is a relatively unsupported one, (Asus Eeebook X205TA) and there is little driver support (audio doesn’t work, trackpad doesn’t have multitouch etc.). I’m eagerly awaiting a newer update to your script!

    Thanks for the effort! I always think of why linux doesn’t magically have some of these small things built in 😀

    Kenny.

  2. @Kenny: Does the video not work (i.e., TV refuses to play it) or does it not show up at all on the TV?

    There are few things I would try:

    1. Does the capture work? Run these two commands:

    export CAPTURE_AUDIO_DEVICE=`pactl list | grep -A2 '^Source #' | grep 'Name: .*\.monitor$' | awk '{print $NF}' | tail -n1`
    echo $CAPTURE_AUDIO_DEVICE

    This prints the device name for capturing audio. On my machine, it’s “alsa_output.pci-0000_00_1b.0.analog-stereo.monitor”.

    Then run:

    parec -d $CAPTURE_AUDIO_DEVICE | avconv -f x11grab -s 1280x720 -r 30 -i :0.0+86,0 -ab 192k -f s16le -ac 2 -ar 44100 -i - -vcodec libx264 -crf 30 -preset ultrafast -tune animation -threads 0 -acodec libmp3lame -f matroska name-of-output-file.mkv

    Let it record for a while, then press Ctrl+C to stop recording. Was the file “name-of-output-file.mkv” produced? Can you play this on the computer? When you copy the file to the TV (on a USB stick or via Mediatomb), can the TV play this?

    This tests the capturing and whether the TV has support for the codecs. If this fails, you either don’t have the necessary codecs installed (might be enough to “sudo apt-get install libavcodec-extra”), or you need to find another combination of audio/video codecs that your TV understands.

    2. Does the filter and the FUSE mount work?

    After you started the script, check whether you can see the file “fuse_mnt/a/fuse_live.mkv” show up in your mount point and try playing it on your computer first. If the file doesn’t show up or it contains garbage, there might be something wrong in one of the commands. This would happen, for example, if the “avconv” command crashes, so the subsequent filter and FUSE mount don’t have anything to stream. Check the log output for errors.

  3. I got the audio device as auto_null.monitor.
    The parec command produced the mkv file, and it played perfectly on the computer as well as the tv when I used a usb stick

    The FUSE gets mounted and I can see the three folders a,b and c. I tried playing a/fuse_live.mkv on vlc but it wouldn’t play.

    I’m pasting all the main logs, if that’s helpful.

    Thanks! 🙂

    Audio Device:
    ————-


    $ echo $CAPTURE_AUDIO_DEVICE
    auto_null.monitor

    Running the Fuse Server:
    ————————


    $ ./dlna_fuse.py -s -f fuse_mnt/
    Using PulseAudio monitor auto_null.monitor
    Running capture command: parec -d auto_null.monitor | ffmpeg -f s16le -ac 2 -ar 44100 -i - -f x11grab -r 20 -s 1024x576 -i :0.0+128,224 -acodec ac3 -ac 1 -vcodec libx264 -vpre fast -threads 0 -f matroska - | /home/kenny/stream/matroska_live_filter.py -
    read 1048576 0
    need to wait for file size 1048576 have 0
    Process has exited with code 0
    Process has exited with code 0
    Capture thread has exited
    getattr /.Trash
    getattr /.Trash-1000
    getattr /.xdg-volume-info
    getattr /autorun.inf
    readdir / 0
    getattr /a
    getattr /b
    getattr /c
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    readdir / 0
    getattr /autorun.inf
    getattr /
    getattr /
    readdir / 0
    getattr /a
    getattr /b
    getattr /c
    readdir / 0
    readdir / 0
    readdir / 0
    getattr /a
    getattr /
    readdir /a 0
    getattr /a/fuse_live.mkv
    readdir /a 0
    readdir /a 0
    readdir /a 0
    getattr /a/fuse_live.mkv
    readdir /a 0
    getattr /
    getattr /a
    read /a/fuse_live.mkv 4096 0
    Capture thread has exited
    read /a/fuse_live.mkv 16384 4096
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 32768 20480
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 65536 12288
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 4096 32768
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 4096 0
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 16384 0
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 65536 12288
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 65536 12288
    Capture thread has exited
    getattr /a/fuse_live.mkv
    read /a/fuse_live.mkv 65536 12288
    Capture thread has exited
    getattr /a/Folder.jpg
    getattr /a/AlbumArtSmall.jpg
    getattr /a/AlbumArt.jpg
    getattr /a/Album.jpg
    getattr /a/.folder.png
    getattr /a/cover.jpg
    getattr /a/thumb.jpg
    getattr /a/Folder.jpg
    getattr /a/AlbumArtSmall.jpg
    getattr /a/AlbumArt.jpg
    getattr /a/Album.jpg
    getattr /a/.folder.png
    getattr /a/cover.jpg
    getattr /a/thumb.jpg
    getattr /a
    getattr /a/fuse_live.mkv
    getattr /a/Folder.jpg
    getattr /a/AlbumArtSmall.jpg
    getattr /a/AlbumArt.jpg
    getattr /a/Album.jpg
    getattr /a/.folder.png
    getattr /a/cover.jpg
    getattr /a/thumb.jpg
    getattr /a/Folder.jpg
    getattr /a/AlbumArtSmall.jpg
    getattr /a/AlbumArt.jpg
    getattr /a/Album.jpg
    getattr /a/.folder.png
    getattr /a/cover.jpg
    getattr /a/thumb.jpg

    Playing a/fuse_live.mkv on vlc
    ——————————


    $ vlc fuse_live.mkv
    VLC media player 2.2.0 Weatherwax (revision 2.2.0-0-g1349ef2)
    [0000000001e99118] core libvlc: Running vlc with the default interface. Use 'cvlc' to use vlc without interface.
    [matroska,webm @ 0x7f38b4c7aea0] Read error at pos. 1 (0x1)
    [matroska,webm @ 0x7f38b4c7aea0] EBML header using unsupported features
    (EBML version 0, doctype (null), doc version 0)
    "sni-qt/2917" WARN 16:08:51.642 void StatusNotifierItemFactory::connectToSnw() Invalid interface to SNW_SERVICE
    [00007f38940011d8] core stream error: cannot pre fill buffer

  4. @Kenny: Good to hear that the mkv works, this means you’re really close. I can see in the output (thanks for posting!) that the dlna_fuse.py script still contains a call to “ffmpeg” in the parec command. Please go into dlna_fuse.py and replace that line with the one that I posted on May 27 above. (Sorry, I didn’t update the dlna_fuse.py download on the other page. I thought I’d fix a few other things before I do.)

  5. Hi Mike,

    I found your site while searching for WiDi support for linux, no luck yet, but your scripts for DNLA/Upnp look promising.
    I’ll give them a go when I get back from vacation.

    May I propose two bad alternatives to your original problem streaming ustream.tv to Samsung
    1. Use android, and TV Miracast
    2. Install SS IPTV or Smart IPTV for Samsung/LG and
    add your casters as channel sources. You’ll need a clever way to get to the m3u8 resource but LiveHttp does the trick (this is the best quality+fps I’ve ever encoutered)
    3. Livestream is a python script that does some magic parsing http sites for streaming resources and routing that through VLC, maybe it’s out/pipe can be manipulated into a dnla compatible file.
    4. Use the browser off your TV. I was surprised of how well my LG manages twitch.tv (really shitty quality though).

    Thanks for your work, it has so many applications.

  6. Hi Mike,

    cool stuff, really. I’m amazed how well it worked out of the box. However, just quickl tried it with a video and the sound seems to be lagging behind. I tried correcting it with the vsync or itsoffset command but it seemed to make things worse. I will try to have a more thorough look at it, but have you encountered the same problem once?

    Cheers

  7. Hey Mike! Thank You very much for this work. It is awesome!

    When I run the command:
    python dlna_fuse.py -s -f fuse_mnt/

    I’ve got the following output:

    Using PulseAudio monitor
    Running capture command: parec -d | avconv -f x11grab -s 1280×720 -r 30 -i :0.0+0,0 -ab 192k -f s16le -ac 2 -ar 44100 -i – -vcodec libx264 -crf 30 -preset ultrafast -tune animation -threads 0 -acodec libmp3lame -f matroska – | /home/john/bin/dlna_live_streaming/matroska_live_filter.py –
    read 1048576 0
    need to wait for file size 1048576 have 0

    This still on this message forever. I’ve tested my scrren capture and my TV codecs and everything worked.

    When I ran the comman my fuse_mnt folder still empty. Can you help me to get this working?

    Thank you in advance.

    John

  8. what good happen if you can make this as standalone application and package it to .deb and .rpm
    there is lake of miracast and … in linux
    so there is single way to share desktop over wifi

  9. Hello Mike,

    thank you for your efforts, I’m really happy that you are still on these scripts.

    I have a problem with the matroska_live_filter.py. If I change the cmd variable in dlna_fuse.py and remove the filter, then the script is running and it captures the first several seconds. If I use the dlna_fuse.py as it is downloaded, I receive this error:

    Using PulseAudio monitor alsa_output.pci-0000_00_1b.0.analog-stereo.monitor
    Running capture command: parec -d alsa_output.pci-0000_00_1b.0.analog-stereo.monitor | avconv -f x11grab -s 1280×720 -r 30 -i :0.0+0,0 -ab 192k -f s16le -ac 2 -ar 44100 -i – -vcodec libx264 -crf 30 -preset ultrafast -tune animation -threads 0 -acodec libmp3lame -f matroska – | /usersdata/home/akos/tmp/desktop_stream/matroska_live_filter.py –
    read 1048576 0
    need to wait for file size 1048576 have 0
    Process has exited with code 1
    Process has exited with code 1
    Capture thread has exited

    The filter file is a bit too high for me, I couldn’t overcome this problem. Would be a big issue to support also the wmv/asf/avi files (they are same AFAIK).

    Thank you for your reply in advance.

    Br,
    Ákos

  10. Hi Mike,
    done all as you described in articles on ubuntu 15 but stuck on:
    :~/fuse_mnt/a$ vlc fuse_live.mkv
    VLC media player 2.2.1 Terry Pratchett (Weatherwax) (revision 2.2.1-0-ga425c42)
    [000000000132d088] core libvlc: Running vlc with the default interface. Use ‘cvlc’ to use vlc without interface.
    [00007fc3440011a8] core stream error: cannot pre fill buffer

    so, obviously, my tv samsung via mediatomb say “file format unsupportable”.

    $ python dlna_fuse.py -s -f fuse_mnt
    creates subfolders and file fuse_live.mkv but something goes wrong.

    Please help!

  11. I should add to my previous comment that Ubuntu and OSMC devices are both running Kodi 16.1. The mkv is playable via Kodi on the Ubuntu device, but the video stream is black on the OSMC device.

Leave a Reply

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