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!