架设RTMP流媒体服务器并使用python进行推流
Published on
1、服务器架设
服务器不一定要安装在推流程序所在的机器上,也可以安装在发送、接收双方均可访问到的第三台机器上。
安装方式可以使用docker镜像或直接编译安装。
使用docker镜像
github地址:https://github.com/alfg/docker-nginx-rtmp
安装并运行:
docker pull alfg/nginx-rtmp
docker run -it -p 1935:1935 -p 8080:80 --rm alfg/nginx-rtmp
之后即可推流至:
rtmp://<server ip>:1935/stream/$STREAM_NAME
  自行编译安装
# 安装依赖库
sudo apt install -y libpcre3 libpcre3-dev openssl libssl-dev zlib1g-dev
# 下载nginx源码并解压
wget http://nginx.org/download/nginx-1.17.8.tar.gz
tar -xf nginx-1.17.8.tar.gz
# 下载nginx-rtmp-module模块源码
git clone https://github.com/arut/nginx-rtmp-module.git
# 编译并安装带nginx-rtmp-module模块的nginx
cd nginx-1.17.8
./configure --add-module=../nginx-rtmp-module
sudo make install
配置nginx,配置文件地址为:/usr/local/nginx/conf/nginx.conf。由于目前浏览器已经禁止使用Flash,不能直接播放rtmp流,因此可以选择添加hls配置。
worker_processes  1;
events {
    worker_connections  1024;
}
rtmp {          
        server {    
                listen 1935;    
                chunk_size 4096;
 
                application stream {
                        live on;   
                        record off;
                        # hls配置
                        hls on;               
                        hls_path /var/www/hls;
                        hls_fragment 3;        
                        hls_playlist_length 60;
                }
        }
}
       
http {
        server {   
                listen 80;
                # hls配置
                location /hls {
                    # Disable cache 
                    add_header Cache-Control no-cache;
                    # CORS setup 
                    add_header 'Access-Control-Allow-Origin' '*' always;
                    add_header 'Access-Control-Expose-Headers' 'Content-Length';
                    # allow CORS preflight requests 
                    if ($request_method = 'OPTIONS') {
                        add_header 'Access-Control-Allow-Origin' '*';
                        add_header 'Access-Control-Max-Age' 1728000;
                        add_header 'Content-Type' 'text/plain charset=UTF-8';
                        add_header 'Content-Length' 0;
                        return 204;
                    }
                    types {
                        application/vnd.apple.mpegurl m3u8;
                        video/mp2t ts;
                    }
                    root /var/www;
                }
        }
}
运行nginx:
sudo /usr/local/nginx/sbin/nginx
之后即可推流至:
rtmp://<server ip>:1935/stream/$STREAM_NAME
可以直接播放上面的rtmp流,也可以播放hls流:
http://<server ip>/hls/$STREAM_NAME
停止nginx:
sudo /usr/local/nginx/sbin/nginx -s stop
2、使用python推流
python可以使用ffmpeg命令进行推流,有两种方式:直接调用ffmpeg命令,或使用ffmpeg-python库。
安装ffmpeg:
sudo apt install -y ffmpeg
直接调用ffmpeg命令
使用subprocess开启ffmpeg子进程,在python中读取每一帧并进行处理,之后通过管道将图像交给子进程进行推流。
import cv2
import subprocess
# 设置视频文件与推流地址
filename = 'test.mp4'
push_url = 'rtmp://localhost:1935/stream/test'
# 读取视频属性
cap = cv2.VideoCapture(filename)
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# ffmpeg命令
command = ['ffmpeg',
           '-y',
           '-f', 'rawvideo',
           '-vcodec', 'rawvideo',
           '-pix_fmt', 'bgr24',
           '-s', "{}x{}".format(width, height),
           '-r', str(fps),
           '-i', '-',
           '-c:v', 'libx264',
           '-pix_fmt', 'yuv420p',
           '-preset', 'ultrafast',
           '-f', 'flv',
           push_url]
# 开启子进程
process = subprocess.Popen(command, stdin=subprocess.PIPE)
while True:
    # 读取每一帧
    ret, frame = cap.read()
    if not ret:
        break
    # 处理
    # frame = handle(frame)
    # 交给子进程推流
    process.stdin.write(frame.tobytes())
使用ffmpeg-python库
ffmpeg-python库将ffmpeg命令进行封装,实际仍会启动ffmpeg子进程,但是代码更加简洁。
github地址:https://github.com/kkroening/ffmpeg-python
安装
pip install ffmpeg-python
使用
import cv2
import ffmpeg
# 设置视频文件与推流地址
filename = 'test.mp4'
push_url = 'rtmp://localhost:1935/stream/test'
# 读取视频属性
cap = cv2.VideoCapture(filename)
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 开启ffmpeg子进程
process = (
    ffmpeg
    .input('pipe:', format='rawvideo', pix_fmt='bgr24', s='{}x{}'.format(width, height), r=fps)
    .output(push_url, vcodec='libx264', pix_fmt='yuv420p', preset='ultrafast', format='flv')
    .run_async(pipe_stdin=True)
)
while True:
    # 读取每一帧
    ret, frame = cap.read()
    if not ret:
        break
    # 处理
    # frame = handle(frame)
    # 交给子进程推流
    process.stdin.write(frame.tobytes())
# 关闭子进程输入并等待结束
process.stdin.close()
process.wait()