tdesktop-streaming.txt - monochromatic - monochromatic blog: http://blog.z3bra.org
 (HTM) git clone git://z3bra.org/monochromatic
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       tdesktop-streaming.txt (5732B)
       ---
            1 # Desktop streaming
            2 
            3 30 August, 2016
            4 
            5 For teaching purposes (and cool internet points!) I recently needed
            6 to share my screen and microphone online. Being the unix enthusiast
            7 that I am, I looked into how I could do it "simple" command-line
            8 tools.
            9 
           10 And here comes [`ffmpeg`](http://ffmpeg.org). `ffmpeg` is the swiss
           11 army knife for everything related to audio and video decoding/encoding.
           12 I've been using it for multiple tasks already, from converting .ogg
           13 to .mp3, to recording GIFs of my desktop.
           14 
           15 ## Server part
           16 
           17 I started looking into how I could "stream" my desktop online, and
           18 quickly found about the `ffserver` utility (which is part of the
           19 `ffmpeg` package).
           20 
           21 `ffserver` provides a service to do the following:
           22 
           23 * Receive a "Feed" sent by one user
           24 * Send a "Stream" to multiple users
           25 
           26 A "Feed", from `ffserver` point, is a URL that a user will pass to
           27 ffmpeg as the output media, to start "uploading" or "streaming" a
           28 video to.  `ffserver` will then start bufferizing this input locally,
           29 and expose this raw buffer via a "Stream". A stream will read from
           30 this buffer, and encode it in the  specified format, with a bunch
           31 of options.
           32 
           33 One can specify multiple output streams for a single feed, eg, to
           34 use different encoding formats.
           35 
           36 Enough shittalks, here is what my `/etc/ffserver.conf` looked like:
           37 
           38         # Port 80 was taken by the webserver
           39         HTTPPort 8090
           40         HTTPBindAddress 0.0.0.0
           41         MaxHTTPConnections 64
           42         MaxClients 28
           43         MaxBandwidth 10000
           44         
           45         CustomLog /var/log/ffserver.log
           46         
           47         # Where to send data.
           48         # URL will be: http://10.0.0.2:8090/0.ffm
           49         <Feed 0.ffm>
           50                 # buffer file and max size
           51                 File /tmp/ffserver/0.ffm
           52                 FileMaxSize 200K
           53         
           54                 # Only allow this IP to send streaming data ACL
           55                 allow 10.0.0.3
           56         </Feed>
           57         
           58         # How to expose the stream
           59         # URL will be: http://10.0.0.2:8090/0.flv
           60         <Stream 0.flv>
           61                 # The feed to encode data from
           62                 Feed 0.ffm
           63                 
           64                 # Video encoding options
           65                 Format flv
           66                 VideoCodec libx264
           67                 VideoFrameRate 5
           68                 VideoSize 1440x900
           69                 VideoBitRate 512
           70                 AVOptionVideo tune zerolatency
           71                 AVOptionVideo flags +global_header
           72                 
           73                 # Audio encoding options
           74                 AudioCodec aac
           75                 AVOptionAudio flags +global_header
           76         </Stream>
           77 
           78 I limited my research for the perfect stream to either
           79 [x264](https://wikipedia.org/wiki/X264) or
           80 [vp8](https://wikipedia.org/wiki/Vp8) video encoding. At first, vp8
           81 seemed appealing, being a royalty-free format. The WEBM container
           82 also seems to be pretty good for online videos. But x264 turned out
           83 to be faster, and of higher quality (especially thanks to the
           84 "zerolatency" setting).  I had to switch to x264 also because I
           85 couldn't get the libvorbis codec for audio to synchronize well with
           86 the vp8 video stream.
           87 
           88 The above configuration is the best quality/rapidity ratio I could
           89 get.
           90 
           91 When the config is ready, you just need to fire up the server with
           92 
           93         /usr/bin/ffserver -f /etc/ffserver.conf
           94 
           95 ## Watcher part
           96 
           97 In order to watch the stream, one has to use the URL defined by the
           98 `<Stream>` tag. I personally use `mplayer` to watch it, but one can
           99 use the `ffplay` command provided by `ffmpeg`:
          100 
          101         ffplay http://10.0.0.2:8090/0.flv
          102 
          103 And that's *ALL*. You can hardly do simpler to watch a stream,
          104 right?
          105 
          106 ## Feeder part
          107 
          108 In order to feed yor stream to the `ffserver`, you can use `ffmpeg`
          109 directly.  The format of the command is pretty simple. We have 2
          110 inputs: the video and the audio. We also have 1 output: the FFM
          111 feed. The simplest command we can use is thus (recording our desktop,
          112 and microphone):
          113 
          114         ffmpeg -f x11grab -i :0.0 -f alsa -i default http://10.0.0.2:8090/0.ffm
          115 
          116 Let's break it down a bit:
          117 
          118 * `-f x11grab -i :0.0`: Record the desktop, using `$DISPLAY` :0.0
          119 * `-f alsa -i default`: Record the microphone, using ALSA's default input device
          120 * `http://10.0.0.2:8090/0.ffm`: Feed location
          121 
          122 This should start recording, and sending data to the stream. If you
          123 look at it, the output will not look really great, and we need to
          124 pass a few more flags to get a nice looking output that will record
          125 the full screen in a decent way:
          126 
          127         ffmpeg -f x11grab -r 5 -s 1440x900 -thread_queue_size 1024 -i :0.0 \
          128                -f alsa -ac 1 -thread_queue_size 1024 -i default \
          129                -af 'highpass=f=200, lowpass=f=2000' \
          130                -fflags nobuffer \
          131                http://10.0.0.2:8090/0.ffm
          132 
          133 Ok, that was odd. no worries, I'm no wizard and didn't came up with
          134 all these flags out of nowhere! Let's review them:
          135 
          136         -f x11grab -r 5 -s 1440x900 -i :0.0
          137 
          138 Record our X11 desktop with a framerate (`-r`) of 5 FPS, and record
          139 the screen at size (`-s`) 1440x900 (my screen size).
          140 
          141         -f alsa -ac 1 -i default
          142 
          143 Record from the default ALSA capture device, using MONO input
          144 (`-ac`).
          145 
          146         -thread_queue_size 1024
          147 
          148 For both input, this is to increase the max number of queued packets
          149 `ffmpeg` can handle. If the thread queue is full, `ffmpeg` will
          150 start dropping packets, which can lower the stream quality.
          151 
          152         -af 'highpass=f=200, lowpass=f=2000'
          153 
          154 Add an audio filter. My microphone is utter shit, and records a lot
          155 of white noise. This filters out frequencies below 200Hz and above
          156 2000Hz (that's the typical voice range).
          157 
          158         -fflags nobuffer
          159 
          160 Avoid buffering frames when possible, so the stream is available
          161 as it is recorded.
          162 
          163 And that's pretty much it! Note that ffmpeg can have multiple
          164 outputs, so you can record to the feed AND to a local file at the
          165 same time.
          166 
          167 For instance, this is my `ffstream` script:
          168 
          169         #!/bin/sh
          170 
          171         STREAM=${1:-http://10.0.0.2:8090/0.ffm}
          172         ffmpeg -f x11grab -r 5 -s 1440x900 -thread_queue_size 1024 -i :0.0 \
          173                -f alsa -ac 1 -thread_queue_size 1024 -i default \
          174                -af 'highpass=f=200, lowpass=f=2000' \
          175                -fflags nobuffer ${STREAM} \
          176                -af 'highpass=f=200, lowpass=f=2000' \
          177                -c:v libvpx -b:v 5M -c:a libvorbis webcast-$(date +%Y%m%d%H%M%S).webm
          178 
          179 That's all folks!