├── .gitignore
├── LICENSE
├── README.md
├── TODO.md
├── _config.yml
└── imgs
├── qualities.png
├── rawfile.png
└── testsrc2.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | *.mp4
2 | *.ts
3 | *.m3u8
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2020, Demétrio de Castro Menezes Neto
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | - [Meu primeiro stream](#meu-primeiro-stream)
2 | - [Ferramentas recomendadas](#ferramentas-recomendadas)
3 | - [Imagens docker necessárias](#imagens-docker-necessárias)
4 | - [Mãos a obra](#mãos-a-obra)
5 | - [Obtendo o vídeo base](#obtendo-o-vídeo-base)
6 | - [Importância do bitrate no streaming](#importância-do-bitrate-no-streaming)
7 | - [Adaptative bitrate para o resgate](#adaptative-bitrate-para-o-resgate)
8 | - [Gerando formatos de diversas qualidades a partir do vídeo base](#gerando-formatos-de-diversas-qualidades-a-partir-do-vídeo-base)
9 | - [Download Progressivo](#download-progressivo)
10 | - [Protocolos de streaming](#protocolos-de-streaming)
11 | - [Tocando o streaming](#tocando-o-streaming)
12 |
13 | # Meu primeiro stream
14 |
15 | Olá! Tudo bem? Espero que sim! :smiley:
16 |
17 | O objetivo dessa página é guiar você para entender um pouco de como funciona
18 | o mundo de entrega de vídeos.
19 |
20 | O foco é te fazer entender o fluxo básico necessário para fazer um streaming
21 | através da web.
22 |
23 | ## Ferramentas recomendadas
24 |
25 | * [VLC](https://www.videolan.org/vlc/index.pt-BR.html), FFPlay ou outro tocador de vídeos
26 | * [Docker](https://www.docker.com/get-started)
27 | * Google Chrome/Firefox ou outro navegador web de sua preferência
28 |
29 | ### Imagens docker necessárias
30 | Se você deseja seguir esse guia offline, baixe as imagens docker abaixo
31 |
32 | ```bash
33 | docker pull jrottenberg/ffmpeg:4.3-alpine
34 | docker pull webratio/nodejs-http-server:0.9.0
35 | ```
36 |
37 | ## Mãos a obra
38 |
39 | ### Obtendo o vídeo base
40 | Antes de tudo, precisamos de um vídeo base para trabalhar.
41 |
42 | Geralmente o vídeo original vem de uma captura de câmera, ou softwares de
43 | edição ou renderização 3D. Ele é salvo em um formatos comumente chamados de
44 | **RAW**, ou arquivo bruto, que contém informações muito importantes pra quem
45 | vai editar e modificar, mas não interessam para o visualizador final na
46 | maioria das vezes.
47 |
48 | 
49 |
50 | Nesse guia, iremos gerar um vídeo utilizando o **FFMPEG**, um software mais
51 | conhecido por ser o canivete suíco para se trabalhar com vídeos. Dessa
52 | maneira, você consegue seguir esse guia mesmo sem uma conexão com a internet.
53 |
54 | Caso queira utilizar arquivos de vídeo "de verdade", a Blender Foundation tem
55 | uma série de [vídeos abertos e gratuitos](https://www.blender.org/about/projects/) que possuem um licença que permite o uso livre deles.
56 |
57 | Para gerar um vídeo base utilizando o FFMPEG, basta executar o comando abaixo.
58 |
59 | ```bash
60 | docker run --rm -v $(pwd):/files "jrottenberg/ffmpeg:4.3-alpine"\
61 | -hide_banner -y \
62 | -re -f lavfi -i "testsrc2=size=1280x720:rate=30,format=yuv420p" \
63 | -f lavfi -i "sine=frequency=1000:sample_rate=48000" \
64 | -c:v libx264 -preset ultrafast -tune zerolatency -profile:v high \
65 | -t 0:20 files/mps.mp4
66 | ```
67 |
68 |
69 | Explicação do comando
70 |
71 | > * `-hide-banner`: Esconde o banner do ffmpeg
72 | > * `-re`: Lê a entrada obedecendo o framerate nativo
73 | > * `-f lavfi`: Define o formato para _lavfi_ (libavfilter). Através dele podemos usar um input virtual
74 | > * `-i "testsrc2=size=1280x720:rate=30,format=yuv420p"`:
75 | > * `testsrc2=size=1280x720`: Gerar o input virtual do tipo `testsrc2` com a resolução 1280x720
76 | > * `rate=30`: Frames por segundo (FPS)
77 | > * `format=yuv420p`: Padrão de cores utilizado
78 | > * `-i "sine=frequency=1000:sample_rate=48000"`:
79 | > * `sine=frequency=1000`: Define uma frequencia fixa de áudio no valor 1000
80 | > * `sample_rate=48000`: Define sample_rate de áudio para 48000
81 | > * `-c:v libx264`: Usa o encoder libx264 (versão opensource do H.264)
82 | > * `-preset ultrafast`: Utiliza um preset de configurações para realizar o encoding.
83 | > * `-tune zerolatency`: Realiza algumas modificações nas configurações de encoding
84 | > * `-profile:v high`: Profile do H.264, valor utilizado por padrão para dispositivos modernos
85 | > * `-t 0:20`: Duração do vídeo é igual a 20 segundos
86 | > * `files/mps.mp4`: Arquivo de saída
87 | >
88 | > Você pode ler mais sobre esses parâmetros na [documentação do FFMPEG](https://trac.ffmpeg.org/wiki/Encode/H.264)
89 |
90 |
91 | Se o comando foi executado corretamente, o resultado deve ser algo parecido
92 | com mostrado abaixo:
93 |
94 | 
95 |
96 | ### Importância do bitrate no streaming
97 |
98 | O **bitrate de um vídeo** é basicamente quantos bits existem por segundo de
99 | vídeo exibido. A unidade de medida é bem parecida com a que vemos quando
100 | realizamos um download de arquivo (`[GMK]b/s`), geralmente acaba-se omitido o
101 | `/s`, ficando por exemplo `800k`.
102 |
103 | Quanto maior o bitrate de um vídeo, mais dados são trafegados/lidos por segundo,
104 | isso significa que quanto maior o bitrate, **geralmente**, maior a
105 | qualidade. _Geralmente_ porque o fato de mais dados estarem sendo transmitidos
106 | não significa necessariamente uma qualidade maior.
107 |
108 | Para ilustrar quão importante são os bitrates para o streaming, imagine que você
109 | quer assistir um vídeo cujo bitrate seja `3.5mbps`, mas sua capacidade de
110 | banda de rede é apenas `1mbps`. Você vai precisar esperar **3 segundos e meio**
111 | pra conseguir assistir a um segundo de vídeo. Imagine o tempo necessário para
112 | assistir um vídeo que possui horas de duração, como um filme.
113 |
114 | Uma maneira atual de contornar isso é gerar cópias do mesmo vídeo com
115 | diferentes bitrates, e entregar o mais adequado para a rede do espectador.
116 | Essa técnica é chamada de **adaptative bitrate** ou bitrate adaptativo.
117 |
118 | ### Adaptative bitrate para o resgate
119 |
120 | É das mais importantes features suportadas pelos protocolos de streaming
121 | hoje. Ela permite que o player consiga trocar entre diversas qualidades
122 | disponíveis de acordo com a banda de rede disponível. Melhorando a qualidade
123 | de experiência do usuário e o consumo de banda, entre outras coisas.
124 |
125 | Para o _adaptative bitrate_ funcionar, é necessário que sejam geradas cópias
126 | do vídeo inicial com bitrates adequados para a reprodução em diferentes
127 | dispositivos e redes.
128 |
129 | #### Gerando formatos de diversas qualidades a partir do vídeo base
130 |
131 | Vamos gerar 4 vídeos com bitrates e resoluções diferentes, a partir do nosso
132 | vídeo base. As informações estão na tabela abaixo:
133 |
134 | | Resolução |Bitrate de áudio | Bitrate de Vídeo | Bitrate total |
135 | |-----------|-----------------|------------------|---------------|
136 | | 240p | 96k | 700k | 796k |
137 | | 360p | 96k | 800k | 896k |
138 | | 480p | 128k | 1400k | 1528k |
139 | | 720p | 128k | 2800k | 3928k |
140 |
141 | ```bash
142 | docker run --rm -v $(pwd):/files "jrottenberg/ffmpeg:4.3-alpine" \
143 | -hide_banner -y -i files/mps.mp4 \
144 | -s 1280x720 -c:a aac -b:a 128k -c:v libx264 -b:v 2800k files/mps_720.mp4 \
145 | -s 858x480 -c:a aac -b:a 128k -c:v libx264 -b:v 1400k files/mps_480.mp4 \
146 | -s 640x360 -c:a aac -b:a 96k -c:v libx264 -b:v 800k files/mps_360.mp4 \
147 | -s 352x240 -c:a aac -b:a 96k -c:v libx264 -b:v 700k files/mps_240.mp4
148 | ```
149 |
150 |
151 | Explicação do comando
152 |
153 | > * `-i mps.mp4`: Arquivo de entrada
154 | > * `-s 1280x720`: Redimensiona o vídeo para a resolução 1280x720
155 | > * `-c:a aac`: Utiliza `aac` como codec de áudio
156 | > * `-b:a 128k`: Utiliza 128k como bitrate de áudio
157 | > * `-c:v libx264`: Utiliza `libx264` como codec de vídeo
158 | > * `-b:v 2800k`: Utiliza 2800k como bitrate de vídeo
159 |
160 |
161 | Parece que estamos com tudo preparado para fazer nosso streaming, certo? Mais
162 | ou menos. Com esses arquivos como estão, nós conseguimos realizar um
163 | **download progressivo**.
164 |
165 | #### Download Progressivo
166 |
167 | Apesar de um nome bonito, ou talvez assustador. O download progressivo
168 | acontece quando um player de vídeo realiza uma requisição HTTP para obter um
169 | arquivo de vídeo. O servidor divide esse arquivo em partes, entregando cada
170 | parte como **partial content** (status code 206). A medida que o player
171 | recebe esses pedaços de vídeo, a reprodução acontece.
172 |
173 | Para realizar um download progressivo iremos precisar de um servidor HTTP,
174 | aqui podemos aproveitar a praticidade do Docker e subir um *nginx*
175 | rapidamente, e de um tocador de vídeos. Inicialmente usaremos o *VLC*, além
176 | de ser aberto, ele já possui a maioria dos codecs embutidos para os mais
177 | variados formatos de vídeo.
178 |
179 | Subindo o servidor web:
180 | ```bash
181 | docker run --rm \
182 | -v $(pwd):/opt/www \
183 | -p 8080:8080 webratio/nodejs-http-server:0.9.0 \
184 | http-server /opt/www -a :: -p 8080 --cors -c-1
185 | ```
186 |
187 | Rodando um vídeo no VLC
188 | ```bash
189 | vlc http://localhost:8080/mps_240.mp4
190 | ```
191 |
192 | Rodando um vídeo no ffplay
193 | ```bash
194 | ffplay http://localhost:8080/mps_240.mp4
195 | ```
196 |
197 | Infelizmente, o download progressivo não nos oferece o recurso de ABR falado
198 | anteriormente. Isso significa que, se alguma alteração acontecer na rede, a
199 | reprodução pode ser prejudicada. Para termos suporte ao ABR, precisamos
200 | realizar a entrega utilizando um **protocolo de streaming**, além de realizar
201 | alguns comandos a mais com o FFMPEG.
202 |
203 | #### Protocolos de streaming
204 |
205 | Atualmente os três protocolos mais utilizados para streaming funcionam em
206 | cima do HTTP. Eles são:
207 | * HTTP Live-streaming (**HLS**), que, apesar do nome, também é utilizado para VODs;
208 | * Dynamic Adaptative Streaming over HTTP (**DASH** ou **MPEG-DASH**); e
209 | * Microsoft Smooth Streaming (**MSS**);
210 |
211 | **Nesse guia vamos focar no HLS**, por usar um arquivo de texto com um
212 | formato de fácil entendimento. A título de curiosidade, tanto o DASH como o
213 | MSS usam um padrão XML em seus arquivos.
214 |
215 | Uma coisa em comum em todos esses protocolos é que precisamos ter todos os
216 | _chunks_ ou pedaços de vídeo já divididos anteriormente. Existem ferramentas
217 | que já fazem esse trabalho _on the fly_ (o próprio FFMPEG é capaz de fazer
218 | isso), mas para fins de aprendizado, iremos executar um comando que irá gerar
219 | cada um desses _chunks_.
220 |
221 | Além dos _chunks_, os protocolos trabalham com um arquivo principal, chamado
222 | de _playlist_ ou _master playlist_. Eles servem como um índice para o player
223 | entender como montar as URLS para baixar cada pedaço de vídeo, a url base
224 | para cada qualidade disponível, entre outras informações.
225 |
226 | No caso do **HLS** a _master playlist_ indica qual a url para as
227 | playlists individuais de cada variante("qualidade") disponível, que são
228 | chamadas de "variant playlist"
229 |
230 | No comando abaixo iremos gerar tanto os pedaços/_chunks_ de vídeo, como a
231 | _master playlist_ e as playlists variantes. Isso porque é muito mais fácil
232 | gerar todos eles de uma vez, do que em comandos separados do FFMPEG.
233 |
234 | ```bash
235 | docker run --rm -v $(pwd):/files "jrottenberg/ffmpeg:4.3-alpine"\
236 | -hide_banner -y -i files/mps_360.mp4 -i files/mps_480.mp4 -i files/mps_720.mp4 \
237 | -map 0 -map 1 -map 2 \
238 | -c:a:0 aac -ar 48000 -c:v:0 libx264 -x264opts keyint=30:min-keyint=30:scenecut=-1 -b:v:0 800k -b:a:0 96k \
239 | -c:a:1 aac -ar 48000 -c:v:1 libx264 -x264opts keyint=30:min-keyint=30:scenecut=-1 -b:v:1 1400k -b:a:1 128k \
240 | -c:a:2 aac -ar 48000 -c:v:2 libx264 -x264opts keyint=30:min-keyint=30:scenecut=-1 -b:v:2 2800k -b:a:2 128k \
241 | -var_stream_map "v:0,a:0,name:360 v:1,a:1,name:480 v:2,a:2,name:720" \
242 | -master_pl_name master.m3u8 \
243 | -f hls -hls_time 2 -hls_list_size 0 \
244 | -hls_segment_filename files/v%v_%03d.ts files/v%v.m3u8
245 | ```
246 |
247 | Explicação do comando
248 |
249 | > * `-i _nome_.mp4`: Arquivo de entrada, pode ser repetido mais de uma vez para
250 | > mútiplos arquivos de entrada
251 | > * `-map X`: Indica que irá utilizar a entrada `X`, o numero do stream é
252 | > definido pela ordem de entrada na ordem dos arquivos. 0 para o primeiro,
253 | > 1 para o segundo e assim por diante
254 | > * `-s 1280x720`: Redimensiona o vídeo para a resolução 1280x720
255 | > * `-c:a:X aac`: Utiliza `aac` como codec de áudio do stream X
256 | > * `-b:a:X 128k`: Utiliza 128k como bitrate de áudio
257 | > * `-ar 48000`: Seta samplerate de áudio para 48000
258 | > * `-c:v:X libx264`: Utiliza `libx264` como codec de vídeo
259 | > * `-b:v:X 2800k`: Utiliza 2800k como bitrate de vídeo
260 | > * `-var_stream_map`: Indica como os streams de entrada devem ser utilizados
261 | para a saída. `"v:0,a:0"` significa que o stream de vídeo 0, deve ser utilizado
262 | com o stream de áudio 0.
263 | > * `-master_pl_name`: Nome da master playlist
264 | > * `-f hls`: Utiliza o formato HLS
265 | > * `-hls_time`: Define tamanho do chunk
266 | > * `-hls_list_size 0`: Tamanho da lista do hls. 0 = infinito
267 | > * `hls_segment_filename`: Padrão de nomes do arquivo dos chunks. Ex: `files/v360_001.ts`
268 | > * `files/v%v.m3u8`: Padrão de nomeclatura das playlists variantes. Ex: `files/v360.m3u8`
269 | > * `%v`: Nome do stream
270 | > * `-x264opts keyint=30:min-keyint=30:scenecut=-1`: Define o GOP para 30 e remove detecção de cenas
271 |
272 |
273 | ### Tocando o streaming
274 |
275 | Com todos os arquivos necessários disponíveis, agora podemos subir um servidor web e tocar em um player que suporte ABR.
276 |
277 | Para subir o servidor um web:
278 | ```bash
279 | docker run --rm \
280 | -v $(pwd):/opt/www \
281 | -p 8080:8080 webratio/nodejs-http-server:0.9.0 \
282 | http-server /opt/www -a :: -p 8080 --cors -c-1
283 | ```
284 |
285 | Com o servidor de pé, iremos utilizar a página de demonstração do [hls.js](https://github.com/video-dev/hls.js/). Um player feito em javascript para suportar o protocolo HLS.
286 |
287 | > [Clique aqui para acessar](https://hls-js.netlify.app/demo/?src=http%3A%2F%2Flocalhost%3A8080%2Fmaster.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsImR1bXBmTVA0IjpmYWxzZSwibGV2ZWxDYXBwaW5nIjotMSwibGltaXRNZXRyaWNzIjotMX0=)
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dneto/meu-primeiro-stream/3a80e3ac02f113bc8361468f160e40640014af9a/TODO.md
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | remote_theme: 'johno/pixyll'
2 |
--------------------------------------------------------------------------------
/imgs/qualities.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dneto/meu-primeiro-stream/3a80e3ac02f113bc8361468f160e40640014af9a/imgs/qualities.png
--------------------------------------------------------------------------------
/imgs/rawfile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dneto/meu-primeiro-stream/3a80e3ac02f113bc8361468f160e40640014af9a/imgs/rawfile.png
--------------------------------------------------------------------------------
/imgs/testsrc2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dneto/meu-primeiro-stream/3a80e3ac02f113bc8361468f160e40640014af9a/imgs/testsrc2.gif
--------------------------------------------------------------------------------