使用Streamlink来随时随地听Lofi Girl音乐

在休息和学习的时候,听听lofi girl的音乐是非常舒服的,只不过它要访问Youtube,然后你要开着网页才能聆听实时的音乐,所以我想,我能不能直接把直播流给转过来,这样我手机就可以不用开任何代理,而且YouTube后台播放还得开premium。刚看到有streamlink这款工具,它有这个功能,我就想着能否试着将流转到我阿里云来,这样不就可以用任意播放器播放了么。

(English version translate by GPT-3.5)

预备资源

  1. 一台境外的VPS主机(IP不能被墙),你要用它来接收流并推向境内,例如说 Bandwagon 就是一个不错的选择。
  2. 一台境内的主机,你要用它来接收流并发布流,例如 国内出名的阿里云
  3. Nginx + rtmp-flv-module,用nginx来创建流服务器
  4. ffmpeg(我试过纯推流不转码,CPU消耗微乎其微)
  5. streamlink 不是steamlink。。。

这里境外服务器要注意线路选择,尽量选择CN2,CMI的线路,这样可以保证与国内线路稳定,否则到国内拥堵可能会导致推流卡顿

境外服务器操作

建议这台服务器位于美国洛杉矶的CN2 GIA线路,或者位于香港的CMI线路,当然如果你有钱,你可以选择位于日本或香港的CN2 GIA线路,并确保你的阿里云能访问到它。

连接服务器

首先,用ssh连接到你的境外服务器,按照 streamlink的文档 进行安装,我这边是debian服务器,所以我选择使用ubuntu方式安装,如下2句命令

1
2
sudo apt upgrade
sudo apt install streamlink

现在安装好streamlink了,就可以开启推流服务了,下面的

1
2
3
4
5
streamlink "https://www.youtube.com/watch?v=jfKfPfyJRdk" best \
--player-external-http \
--player-external-http-port 30000 \
--retry-open 30 \
--ringbuffer-size 4M

对上面参数做一个解释

1
2
3
4
5
6
- "https://www.youtube.com/watch?v=jfKfPfyJRdk":这是你要下载的YouTube视频的URL。
- best:这是你选择的视频质量,"best"表示最高质量。
- --player-external-http:这个参数让streamlink启动一个HTTP服务器,允许外部设备如智能手机或流媒体盒子观看他们原本无法观看的流。这个模式下,streamlink不会启动任何播放器,服务器将监听所有可用的连接,而不仅仅是本地(环回)接口。可以用来访问流的URL将被打印到控制台,可以使用CTRL-C中断服务器。
- --player-external-http-port 30000:这个参数设置HTTP服务器的端口号为30000。如果省略或设置为0,将使用一个随机的高(>1024)端口。
- --retry-open 30:这个参数设置如果打开流失败,streamlink将尝试重新打开30次。
- --ringbuffer-size 4M:这个参数设置ringbuffer(一个用于存储下载的数据的缓冲区)的大小为4M。ringbuffer用作流和播放器之间的临时存储。这允许Streamlink比播放器更快地下载流,播放器从ringbuffer中读取数据。如果ringbuffer满了,streamlink将停止下载,直到有足够的空间存储新的数据。

运行上面的命令后,控制台会打印如下命令,表示启动成功,虽然它显示需要访问127.0.0.1,但是它实际监听0.0.0.0,因此我们可以直接打开VLC播放器,来试着访问它

1
2
3
4
5
6
[cli][info] streamlink is running as root! Be careful!
[cli][info] Found matching plugin youtube for URL https://www.youtube.com/watch?v=jfKfPfyJRdk
[cli][info] Available streams: 144p (worst), 240p, 360p, 480p, 720p, 1080p (best)
[cli][info] Starting server, access with one of:
[cli][info] http://127.0.0.1:30000/
[cli][info] http://127.0.1.1:30000/

使用VLC播放,流地址就是 http://服务器地址:30000
VLC Playing
这样,第一步就完成了

安装 ffmpeg

安装ffmpeg,还是一句命令,如果不喜欢apt安装,也可以去 Download FFmpeg - ffmpeg.org 下载静态文件,放在 /usr/bin 或者 /usr/local/bin 下面就行(当然ffmpeg也可安装在境内,来收远端的流)

1
sudo apt install ffmpeg

这样,境外服务器操作部分暂时告一段落,来到境内服务器

境内服务器操作

下面跑到境内服务器操作,境内服务器上要安装一个nginx(我也知道还有很多流服务器,但是我喜欢用nginx)

这里nginx建议使用编译安装,在编译时增加参数 --add-module=../nginx-http-flv-module-1.2.9,我的编译命令是

1
2
3
4
5
6
7
8
9
10
./configure --prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-http_sub_module \
--add-module=../nginx-http-flv-module-1.2.9 \
--with-stream

如果服务器已经有编译好的nginx了,那么就在nginx的源码执行make之后,停止现有的nginx服务,复制源码目录(执行make的当前目录) objs/nginx 到 $NGINX_HOME/sbin/nginx,然后重启nginx服务就行,nginx会被更新,非常方便

编辑配置

打开 nginx.conf,并写入如下配置,这个配置和 http {} 同级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
rtmp {
server {
listen 61555;
chunk_size 4096;

application lofigirl {
live on;
record off;
hls on;
hls_path /opt/lofi-stream-hls;
hls_fragment 3;
hls_playlist_length 24;
hls_continuous on;
}
}

}

///不要复制下面的,只要复制上面的
stream {......}
http {
include mime.types;
default_type application/octet-stream;
server {......}
}

然后由让GPT-4解释下上面配置的含义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
这是一个Nginx服务器的RTMP模块配置,用于设置一个流媒体服务器。RTMP是Real Time Messaging Protocol的缩写,是一种设计用来进行实时信息传输的协议。

- `server`:定义一个服务器,监听61555端口,处理RTMP请求。
- `chunk_size 4096`:设置RTMP协议的块大小为4096字节。
- `application lofigirl`:定义一个名为"lofigirl"的应用,这是流媒体的名称。
- `live on`:开启实时流功能。
- `record off`:关闭录制功能。
- `hls on`:开启HTTP Live Streaming(HLS)功能,这是一种流媒体网络传输协议。
- `hls_path /opt/lofi-stream-hls`:设置HLS的m3u8和ts文件存放路径。
- `hls_fragment 3`:设置每个HLS切片的长度为3秒。
- `hls_playlist_length 24`:设置HLS播放列表的总长度为24秒。
- `hls_continuous on`:开启HLS连续模式,这样可以在播放列表中保留过去的切片,而不是只保留最新的切片。

总的来说,这个配置文件定义了一个名为"lofigirl"的流媒体应用,它可以接收RTMP流,并将其转换为HLS流,以便在HTTP协议下进行传输和播放。

----------- by OpenAI GPT-4

配置好后,运行 nginx -s reload,流服务器就应该工作了

回到境外服务器

进行推流

上面我们安装好了nginx,ffmpeg,只不过ffmpeg还没有被使用,这里就可以使用它了。之前streamlink不是已经在不断推流了吗?现在ffmpeg就需要把这个流往阿里云推,然后由阿里云nginx的rtmp模块接收。

1
2
3
4
5
6
7
8
ffmpeg \
-re \
-rw_timeout 30000000 \
-i http://127.0.0.1:30000 \
-c copy \
-f flv \
-bsf:a aac_adtstoasc \
rtmp://阿里云服务器的IP地址,或者境内服务器IP地址:61555/lofigirl/live

上面的 【lofigirl】就是刚刚nginx配置中定义的application,参数详解:

1
2
3
4
5
6
7
8
9
10
11
这是一个使用ffmpeg进行视频流转发的命令,下面是每个参数的解释:
- `ffmpeg`:这是一个非常强大的开源视频处理工具,可以进行视频的录制、转换、流化等操作。
- `-re`:以实时速度读取数据,主要用于模拟直播的情况。
- `-rw_timeout 30000000`:设置读写超时时间,单位是微秒。
- `-i http://127.0.0.1:30000`:指定输入流的地址,这里是一个本地的地址。
- `-c copy`:指定编解码器,这里是直接复制原始的数据,不进行任何编解码。
- `-f flv`:指定输出流的格式,这里是FLV格式。
- `-bsf:a aac_adtstoasc`:指定音频比特流过滤器,这里是将AAC的ADTS封装格式转换为ASC格式。
- `rtmp://IP:61555/lofigirl/live`:指定输出流的地址,这里是一个RTMP协议的地址,用于推送到其他的服务器。
总的来说,这个命令的作用是将本地的一个视频流实时转发到其他指定的一台服务器。
----------- by OpenAI GPT-4

运行后可以看到下面的信息输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
root@us-sea02-s2n-1c1g-1:~# ffmpeg -re -rw_timeout 30000000 -i http://127.0.0.1:30000 -c copy -f flv -bsf:a aac_adtstoasc rtmp://*********:61555/lofigirl/live
ffmpeg version 4.4.2-0ubuntu0.22.04.1 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 11 (Ubuntu 11.2.0-19ubuntu1)
configuration: --pref......hared
liba.....100
Input #0, mpegts, from 'http://127.0.0.1:30000':
Duration: N/A, start: 84176.488900, bitrate: N/A
......
Stream #0:1[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 90k tbn, 60 tbc
Output #0, flv, to 'rtmp://*********:61555/lofigirl/live':
.......
Press [q] to stop, [?] for help
frame= 1 fps=0.0 q=-1.0 size= 323kB time=00:00:00.03 bitrate=67823.2kbits/s speed=0.0543x
frame= 67 fps= 30 q=-1.0 size= 405kB time=00:00:02.22 bitrate=1493.5kbits/s speed=0.998x
frame= 82 fps= 30 q=-1.0 size= 430kB time=00:00:02.73 bitrate=1288.8kbits/s speed=0.999x
frame= 112 fps= 30 q=-1.0 size= 462kB time=00:00:03.73 bitrate=1015.4kbits/s speed=0.998x
frame= 173 fps= 30 q=-1.0 size= 841kB time=00:00:05.75 bitrate=1197.6kbits/s speed=0.999x

我们也看到了目标目录 /opt/lofi-stream-hls 有文件产生了

1
2
root@i********Z:/opt/lofi-stream-hls# ls
live-0.ts live-1.ts live.m3u8

hls直播原理

说白一点,HLS直播原理就是它会不断在指定目录下(下面称为segment-video文件夹)生成录像文件分片,这些分片是以H.264编码的后缀名为.ts文件,并根据配置 hls_fragment 来决定每一个文件存储的录像时长,可以下载这些录像文件,直接双击就能播放的。其延迟就是由这个时长决定的,例如一个直播,它开始推流,segment-video文件夹就会生成 1.ts, 2.ts, 3.ts,分别表示0-3秒的录像,3-6秒的录像,6-9秒的录像,然后里面会有一个live.m3u8,记录着当前录像的序列,它是一个不断更新的播放列表,等当前录像总时长达到设置的 hls_playlist_length,例如这里设置了24秒,意味着同一时间会存储最多8个录像,当录像9.ts也就是24-27秒录像进来时,1.ts会被自动删除,这样当前目录的录像依然是24秒,然后live.m3u8就会更新,从播放列表中去掉1.ts,增加9.ts(实际不会从1.ts开始,一般从【最新序列前几个】序列开始,从1开始,那么这个视频延迟就是24秒了,如果从【最新前几个】开始,延迟就只有不到10秒),最后播放器播放时,会先读取live.m3u8,然后根据播放列表,从头到尾播放,当播放列表快要放完时,重新读取m3u8,此时m3u8列表肯定被更新了,因此将新的内容追加到当前播放列表末尾,当然这里的播放列表不受用户控制的,也就是对于用户来说不可见的,live.m3u8不断被更新,播放列表不断获取m3u8并不断播放新的录像,从而实现直播效果。因此直播延迟就是取决于m3u8播放列表长度,以及每一个录像分片的长度,如果增加录像分片长度,会增加缓冲时间和服务器带宽压力,减少分片长度又可能因为频繁请求新文件导致连接数剧增,一般分片长度设置为2-5秒比较合适。

配置nginx,让其他程序访问到m3u8文件

在nginx.conf中,http -> server层增加如下配置

1
2
3
4
location lofi-stream-hls {
alias /opt/lofi-stream-hls;
expires -1;
}

重启nginx即可(注意权限),此时,用VLC访问 http://IP/lofi-stream-hls/live.m3u8 就能看到影像了,然后就可以随时随地后台播放了,不用受到youtube premium,也不需要任何代理了。

附:完整的nginx配置

完整nginx.conf配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
user  nginx nginx;
worker_processes 1;


events {
worker_connections 1024;
}

rtmp {
server {
listen 61555;
chunk_size 4096;

application lofigirl {
live on;
record off;
hls on;
hls_path /opt/lofi-stream-hls;
hls_fragment 3;
hls_playlist_length 24;
hls_continuous on;
}
}

}


http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;


server {
listen 80;
server_name localhost;

location / {
root html;
index index.html index.htm;
}

location lofi-stream-hls {
alias /opt/lofi-stream-hls;
expires -1;
}
}

}

附:纯音频ffmpeg命令

1
2
3
4
5
6
7
8
9
ffmpeg \
-re \
-rw_timeout 30000000 \
-i http://127.0.0.1:30000 \
-vn \
-acodec aac \
-f flv \
-bsf:a aac_adtstoasc \
rtmp://*********:61555/lofigirl/live

附:服务化

ffmpeg-stream.service

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=ffmpeg streaming Service
After=syslog.target

[Service]
Type=simple
ExecStart=/usr/bin/ffmpeg -re -rw_timeout 30000000 -i http://127.0.0.1:30000 -c copy -f flv -bsf:a aac_adtstoasc rtmp://*********:61555/lofigirl/live
Restart=always
RestartSec=3s

[Install]
WantedBy=multi-user.target
1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=streamlink Service
After=syslog.target

[Service]
Type=simple
ExecStart=/usr/bin/streamlink "https://www.youtube.com/watch?v=jfKfPfyJRdk" best --player-external-http --player-external-http-port 30000 --retry-open 30 --ringbuffer-size 4M
Restart=always
RestartSec=3s

[Install]
WantedBy=multi-user.target

附:参考资料

STLInku - 油管直播转发系统搭建教程 - github.com