windows下ffmpeg+nginx-rtmp环境搭建及opencv+ffmpeg+python实现拉流和rtmp直播推流

由于工作需要最近在研究rtsp拉流与直播推流的问题,目前先在我本机上进行了实验,本博客记录学习的内容,包含windows下ffmpeg、nginx-rtmp环境搭建及opencv+ffmpeg+python进行拉流、直播推流的实施代码,还有一些遇见的问题的处理。

目录

  • 一.nginx-rtmp服务器搭建及ffmpeg、VLC下载安装
    • 1.ffmpeg下载安装
    • 2.nginx-rtmp环境搭建
    • 3.本博客还涉及到使用VLC Media Player
    • 4.总结一下实际操作中常用的几个命令:
  • 二.opencv+ffmpeg+python实现拉流和rtmp直播推流
    • 1.流程
    • 2.代码

一.nginx-rtmp服务器搭建及ffmpeg、VLC下载安装

1.ffmpeg下载安装

下载地址:http://ffmpeg.org/download.html
安装教程:https://zhuanlan.zhihu.com/p/118362010
我按照这个下载安装是没有问题的,直接下载的是22M的那个。

2.nginx-rtmp环境搭建

参考教程:https://www.cnblogs.com/linuxAndMcu/p/12517787.html
我最开始找的那个教程启动nginx时报错:

D:\ProgramFile\nginx\nginx-1.20.1>nginx.exe -c conf\nginx-win.conf
nginx: [emerg] unknown directive "rtmp" in D:\ProgramFile\nginx\nginx-1.20.1/conf\nginx_win.conf:19

问题分析:经过查阅资料,问题可能是1.文件编码格式问题 2.nginx无rtmp模块或未对rtmp模块进行编译
解决办法:看网上的帖子,说是要将编码模式从utf8改为无bom。经过尝试后无效,如果是编码格式的问题,提示的应该是下面这句:

nginx: [emerg] unknown directive "锘?user" in D:\ProgramFile\nginx\nginx-1.20.1/conf\nginx_win.conf:1

所以问题应该是未编译,在git上作者提供了linux下编译步骤:
windows下ffmpeg+nginx-rtmp环境搭建及opencv+ffmpeg+python实现拉流和rtmp直播推流_第1张图片
对于我windows,教程中提到可以自行编译,但最好的方法就是安装编译好的版本,如教程中的nginx 1.7.11.3 Gryphon,下载地址详见教程,但是我打开已经404了。在查找了很多资料之后,这个下载路径是可用的:http://nginx-win.ecsds.eu/download/nginx 1.7.11.3 Gryphon.zip。
成功下载后按照原教程中的方式将下载好的东西添加到对应位置,注意如果下载的是nginx 1.7.11.3 Gryphon,修改好nginx-win.conf后,直接使用nginx.exe -c conf\nginx-win.conf启动即可,使用netstat -ano | findstr 0.0.0.0:80检查是否成功启动。

D:\ProgramFile\nginx\nginx>nginx.exe -c conf\nginx-win.conf 
C:\Users\YYL>netstat -ano | findstr 0.0.0.0:80
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       15884

提一下,windows下cmd可以使用nginx.exe -s stop -c conf\nginx-win.conf停止nginx服务,此时使用命令查看已无对应服务

D:\ProgramFile\nginx\nginx>netstat -ano | findstr 0.0.0.0:80

3.本博客还涉及到使用VLC Media Player

安装及使用教程:https://blog.csdn.net/u012130706/article/details/79508721

4.总结一下实际操作中常用的几个命令:

本地视频测试:

ffmpeg.exe -re -i .\test_video\test.mp4 -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1935/live/home

复制流 live1到live2,可以通过live2的地址进行观看:

ffmpeg -i rtmp://localhost/live1 -c copy -f flv rtmp://localhost/live2

查看启动是否成功(80端口为例):

netstat -ano | findstr 0.0.0.0:80

停止nginx服务:

nginx.exe -s stop -c conf\nginx-win.conf #快速停止
nginx.exe -s quit -c conf\nginx-win.conf #有序停止

注意:
本地视频推流测试里面的地址中,端口后的地址必须是live,可以是live或live/XXX,此处我没有深入研究,只是进行了测试,应该是协议规定的。在我们的nginx-win.conf中配置的是live,也就是直播模式。
windows下ffmpeg+nginx-rtmp环境搭建及opencv+ffmpeg+python实现拉流和rtmp直播推流_第2张图片

二.opencv+ffmpeg+python实现拉流和rtmp直播推流

首先列出我的参考文章:
基于python2.7的opencv3.3-ffmpeg-nginx-rtmp视频处理并推送流直播
python利用ffmpeg进行rtmp推流直播
opencv读取rtsp图像处理后推流rtmp
Python实现直播推流效果
python利用ffmpeg进行rtmp推流直播

1.流程

结合我自己的理解总结一下,流程要点有以下:
1.要完成整个流程,你需要配置pipe管道并创建两个线程,其中一个用于向加工队列压入图片,另一个用于从队列抽出图片进行加工,并写入pipe管道。(如果不是多线程处理的话,图像加工速度赶不上抽帧速度,将造成很大延时切卡顿明显;并且加工队列中应时刻保持被抽出的是最新帧)
2.线程1opencv读取视频并抽帧——向加工队列中压入图片——线程2从队列中抽出图片根据需求进行图像加工——向pipe中写入图片——使用ffmpeg工具推流

2.代码

核心代码:

#ffmpeg 命令 其中rtmpUrl为推送地址
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',
        rtmpUrl]
# 管道配置
p = sp.Popen(command, stdin=sp.PIPE)
#多线程处理
threadList = [threading.Thread(target=image_sample, args=(q,)),
              threading.Thread(target=image_push, args=(q,))]
for t in threadList:
    t.start()
#压入帧,注意保持最新帧
while True:
    q.put(cap.read()[1])
    if q.qsize() > max_size:
        q.get() #尽量确保实时性,仅保留最新的一帧

完整代码:

import cv2
import queue
import subprocess as sp
import threading
import os
path = 'http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8'
max_size = 1

fps = 25
width = 100
height = 100
# 采集cctv6直播流
cap = cv2.VideoCapture(path)
if cap.isOpened():
    print('success')
    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))
    print(fps,'\t',width,'\t',height)
    width = int(0.25*width)
    height = int(0.25*height)
else:
    print('faild')

rtmpUrl = 'rtmp://127.0.0.1:1935/live/test'

q = queue.Queue()

#保存
# save_path = 'save_folder'
# if not os.path.exists(save_path):
#     os.mkdir(save_path)
# ffmpeg command
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',
        rtmpUrl]
# 管道配置
p = sp.Popen(command, stdin=sp.PIPE)


def image_sample(q):
    #抽帧压入q队列
    while True:
        q.put(cap.read()[1])
        if q.qsize() > max_size:
            q.get() #尽量确保实时性,仅保留最新的一帧


def image_push(q):
    # i=0
    while True:
        # 管道配置
        # p = sp.Popen(command, stdin=sp.PIPE)  # 初始化
        if not q.empty():
            frame = q.get()
            #图像处理
            frame = cv2.putText(frame, 'sent rtmp frame', (500, 500), cv2.FONT_HERSHEY_SIMPLEX, 3.0, (255, 255, 255), 5)
            frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25, interpolation=cv2.INTER_NEAREST)
            p.stdin.write(frame.tostring())

            # cv2.imshow("frame", frame)

            # save = os.path.join(save_path,'%s.jpg'%str(i))
            # cv2.imwrite(save,frame)
            # print('saved')
            # i+=1
def main():
    threadList = [threading.Thread(target=image_sample, args=(q,)),
                  threading.Thread(target=image_push, args=(q,))]
    for t in threadList:
        t.start()

if __name__ == '__main__':
    main()

在代码实施的过程中发现了一些点需要注意:
1.如果帧分辨率过大,会直接报错 Broken pipe,我拉的cctv6的1920x1080,本地电脑上有一段2560x1440的视频,测试的时候报错了。不过也有可能是本地流视频过大:参考https://blog.csdn.net/achang21/article/details/77870066
2.管道设置的宽高要和推送的图片保持一致。
3.分辨率越高拉取的视频效果越卡,甚至可能失败。所以我直接缩小到原来帧的1/4。

青古の每篇一歌
《有何不可》
天空好想下雨
我好想住你隔壁

你可能感兴趣的:(python,python,opencv,ffmpeg,vlc,nginx)