rtsp是比较常用的视频流,nvr和网络摄像头基本上都支持rtsp,它是视频流中的牛鼻子,搞定了rtsp,就成功了一半。废话不多说,直接上干货。
准备条件
- 安装ffmpeg
- rtsp服务器,本地可以使用easyDarwin
正文
1.最原始的方式——使用ffmpeg命令直接推流
#简单将本地一个mp4视频无限循环推流
ffmpeg -re -stream_loop -1 -i 路径\xxx.mp4 -b:v 1000k -bufsize 1000k -maxrate 1500k -profile:v baseline -g 50 -vf -vcodec h264 -f rtsp rtsp://127.0.0.1:554/test
#光有画面不够,想加点文字
ffmpeg -re -stream_loop -1 -i 路径\xxx.mp4 -b:v 1000k -bufsize 1000k -maxrate 1500k -profile:v baseline -g 50 -vf
"drawtext=fontfile={自定义字体路径}/simsun.ttf: text='想要添加的文字 ':fontsize=40:fontcolor=yellow:x=10:y=10"
-vcodec h264 -f rtsp rtsp://127.0.0.1:554/test
#光有静态文字不够,加上动态的时间戳,只要修改一下参数
"drawtext=fontfile={自定义字体路径}/simsun.ttf: text='%{localtime:%Y-%m-%d %H-%M-%S}':fontsize=40:fontcolor=yellow:x=10:y=10"
关于命令中的那些参数,自己可以多尝试,比如码率和buffer区大小,以自己项目中效果最佳为合适。至于编码方式,鉴于通用性,我推荐使用h264。
下面是推流之后使用vlc播放的画面
2. 最灵活的一种方式——python调用ffmpeg
不管是node还是python,都可以通过子进程调用其它语言命令。这里以python为例
import cv2
import subprocess
'''拉流url地址,指定 从哪拉流'''
pull_url = 'rtsp://127.0.01:554/test' # "rtsp_address"
# 这里看需要,基本你想要的cv2基本都能帮你满足
video_capture = cv2.VideoCapture(pull_url) # 调用摄像头的rtsp协议流
# video_capture = cv2.VideoCapture("1.mp4") # 读取文件的话
# video_capture = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 如果想要自己摄像头的画面
#获取画面宽高
width = int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
'''推流url地址,指定 用opencv把各种处理后的流(视频帧) 推到 哪里'''
push_url = "rtsp://127.0.0.1:554/test2"
fps = 15
command = ['ffmpeg', # linux不用指定
'-y', '-an',
'-f', 'rawvideo',
'-vcodec','rawvideo',
'-pix_fmt', 'bgr24', #像素格式
'-s', "{}x{}".format(width, height),
'-r', str(fps), # 自己的摄像头的fps是0,若用自己的notebook摄像头,设置为15、20、25都可。
'-i', '-',
'-c:v', 'libx264', # 视频编码方式
# '-b:v', '1000k',
'-bufsize', '1000k',
'-maxrate', '1000k',
'-pix_fmt', 'yuv420p',
'-preset', 'ultrafast',
'-f', 'rtsp', # flv rtsp
'-rtsp_transport', 'udp', # 使用TCP推流,linux中一定要有这行
push_url] # rtsp rtmp
pipe = subprocess.Popen(command, shell=False, stdin=subprocess.PIPE)
while True:
ret, frame = video_capture.read()
# Hit 'q' on the keyboard to quit!
if cv2.waitKey(delay=100) & 0xFF == ord('q'): # delay=100ms为0.1s .若dealy时间太长,比如1000ms,则无法成功推流!
break
# 存入管道用于直播
pipe.stdin.write(frame.tostring())
# pipe.stdin.write(frame.tobytes())
#out.write(frame) #同时 存入视频文件 记录直播帧数据
video_capture.release()
cv2.destroyAllWindows()
pipe.terminate()
以上代码是通过管道的方式进行的rtsp推流,为什么说是最灵活的呢,因为这种方式就是针对每一帧图像,cv2负责采集每一帧画面,比如摄像头或者视频文件之类的,接下来将这一帧图像存入管道,而子进程可以通过管道源源不断获取到新的画面,这样就省去了中间文件的转储,非常实用。
3.其它现成的工具
还有很多开源工具诸如obs,vlc等都可以实现。obs默认的是推流成rtmp,只要去下载一个rtsp推流插件安装一下即可。vlc串流成rtsp即可。
以上是我学习中参考各家之长后的总结学习,便于今后参照。