background

In my work, I found that many live CDN implementations of HTTPFLV pull do not use HTTP chunk encoding, but directly use the no-content-length approach. So I want to build a live CDN that supports HTTP chunk encoding.

Environment set up

Ubuntu 18.04.4 LTS software nginx-1.18.0 Nginx extension module nginx-http-flv-module

Nginx – HTTP – FLV – modulex download

git clone https://github.com/winshining/nginx-http-flv-module.git
Copy the code

Nginx configuration installation

./configure --add-module=/home/wanghao/worker/opensourcecode/nginx_module/nginx-http-flv-module
make -j 4 && make install
cd /usr/local/nginx/
Copy the code

Nginx. conf configuration file

#user nobody;
worker_processes  1;

events {
    worker_connections  1024;
}

http { ## HTTP pull configuration
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;
	
    server {
        listen       80;
        server_name  www.wawa.com;

        location /live {
            flv_live on;
        }
    }
}

rtmp {  ## RTMP push stream configurationserver { listen 1935; application myapp{ live on; record off; }}}Copy the code

In cases where the length of the file is not known (such as live streaming), nginx uses chunked_transfer_encoding by default. Therefore, you do not need to set what is displayed in the configuration file

Syntax: chunked_transfer_encoding on | off; Default: chunked_transfer_encoding on; Context: http, server, locationCopy the code

Please click the official link

Ffmepg pushes the local file to the live broadcast server

Ffmpeg - re - I q00307z84wz. 321002.1 ts-fFLV RTMP: / / 192.168.116.130:1935 / myapp / 123Copy the code

Q00307z84wz.321002.1. ts is a 5-minute file, so ffmpeg exits after about 5 minutes.

Real 5M0.382s user 0M22.750s SYS 0M8.141sCopy the code

HTTPFLV pull flow

Enter the correct IP address, port, and stream ID to pull the stream

# curl - L - v "http://192.168.116.130/live? port=1935&app=myapp&stream=123" -o 1.flv
*   Trying 192.168.116.130...
* TCP_NODELAY set% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 - : -- : -- - : -- : -- -- - : - 0 * Connected to 192.168.116.130 (192.168.116.130) port 80 (# 0)> GET /live? Port =1935&app=myapp&stream=123 HTTP/1.1 > Host: 192.168.116.130 > user-agent: curl/7.58.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.18.0 < Date: Fri, 03 Jul 2020 13:49:52 GMT < content-type: video/x-flv < Transfer-Encoding: chunked < Connection: keep-alive < Expires: -1 < { [449 bytes data] 100 1068k 0 1068k 0 0 97k 0 --:--:-- 0:00:10 --:--:-- 117kCopy the code

You can see in the response header that the HTTP chunk protocol is used and there is no content-length

< Transfer-Encoding: chunked
Copy the code

Continue to modify nginx.conf to close the HTTP chunk encoding

location /live {
    flv_live on;
    chunked_transfer_encoding off;
}
Copy the code

Use curl to pull the stream test

# curl -L -v "Http://192.168.116.130/live? port=1935&app=myapp&stream=123" -o 1.flv
*   Trying 192.168.116.130...
* TCP_NODELAY set
  %Total % Received % Xferd Average Speed Time Time Time CurrentDload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 192.168.116.130 (192.168.116.130) port 80 (# 0)>GET /live? Port = 1935 & app = myapp&stream = 123 HTTP / 1.1
> Host: 192.168.116.130
>The user-agent: curl / 7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.18.0
< Date: Fri, 03 Jul 2020 13:59:43 GMT
< Content-Type: video/x-flv
< Connection: keep-alive
< Expires: -1
* no chunk, no close, no size. Assume close to signal end
<
{ [1504 bytes data]
100  668k    0  668k    0     0    98k      0 --:--:--  0:00:06 --:--:--  112k
Copy the code

You can see that the “transfer-encoding: chunked” response header is no longer there. If you look closely, it prints a line in English

* no chunk, no close, no size. Assume close to signal end
Copy the code

No size = content-length = no chunk = transfer-encoding: If you Assume close to signal end, the live stream will end. If you Assume close to signal end, the live stream will end. If you Assume close to signal end, the live stream will end. So the no-centent-length scheme is non-standard.

“Connection: keep-alive”. In alive broadcast, the Connection is usually close. HTTP1.1 uses keep-alive by default, but clients can specify the use of HTTP short links in the header of the request.

root@PF1YTXHH-ZTB:/storage/log_live# curl - L - H "Connection: Close" - v "http://192.168.116.130/live? port=1935&app=myapp&stream=123" -o 1.flv
*   Trying 192.168.116.130...
* TCP_NODELAY set% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 - : -- : -- - : -- : -- -- - : - 0 * Connected to 192.168.116.130 (192.168.116.130) port 80 (# 0)> GET /live? Port =1935&app=myapp&stream=123 HTTP/1.1 > Host: 192.168.116.130 > user-agent: curl/7.58.0 > Accept: */* > Connection:Close# Client specify use close mode< HTTP/1.1 200 OK < Server: nginx/1.18.0 < Date: Tue, 07 Jul 2020 13:14:43 GMT < content-type: video/x-flv < Connection: closeThe server also returns close
< Expires: -1
<
{ [1637 bytes data]
100  236k    0  236k    0     0  89583      0 --:--:--  0:00:02 --:--:-- 89583^C
Copy the code

Test other live streaming apps

Using ADB Logcat to capture the logs of apps such as Fast Hand, Douyu, Huya, etc., and find the pull address. Using curl to pull the stream, I also found that many streams are no-content-length. The reason for using this non-standard no-Centengt-length is implementation simplicity.

Unfinished business

When an HTTP chunk stream is pulled, the PACKETS captured by using tcpdump and analyzed by Wireshark are not detected by the HTTP chunk protocol, which is inconsistent with other online tutorials. It needs a little more exploration.

Tcpdump -i lo host 192.168.116.130 -nnvV -w live2.pcapCopy the code

Because the nginx server is on the same machine as the stream pulling terminal, the captured packets are pulled from the local loopback interface (LO). 192.168.116.130 is the local Intranet IP address.