monochromatic

monochromatic blog: http://blog.z3bra.org
git clone git://z3bra.org/monochromatic
Log | Files | Refs

desktop-streaming.txt (5749B)


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