RTMP、RTSP推流

在上次从萤石云摄像头读取了监控视频后,想要将读取到的视频进行处理,然后将处理后的视频进行推流。目前主要用的协议有RTMP与RTSP两种。

以下是两种协议的百度百科解释:

  1. RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议基于TCP,是一个协议族,包括RTMP基本协议及RTMPT/RTMPS/RTMPE等多种变种。RTMP是一种设计用来进行实时数据通信的网络协议,主要用来在Flash/AIR平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。支持该协议的软件包括Adobe Media Server/Ultrant Media Server/red5等。
  2. RTSP(Real Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议,由哥伦比亚大学网景和RealNetworks公司提交的IETF RFC标准。该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或UDP完成数据传输。HTTP与RTSP相比,HTTP请求由客户机发出,服务器作出响应;使用RTSP时,客户机和服务器都可以发出请求,即RTSP可以是双向的。RTSP是用来控制声音或影像的多媒体串流协议,并允许同时多个串流需求控制,传输时所用的网络通讯协定并不在其定义的范围内,服务器端可以自行选择使用TCP或UDP来传送串流内容,它的语法和运作跟HTTP 1.1类似,但并不特别强调时间同步,所以比较能容忍网络延迟。而前面提到的允许同时多个串流需求控制(Multicast),除了可以降低服务器端的网络用量,更进而支持多方视讯会议(Video Conference)。因为与HTTP1.1的运作方式相似,所以代理服务器〈Proxy〉的快取功能〈Cache〉也同样适用于RTSP,并因RTSP具有重新导向功能,可视实际负载情况来转换提供服务的服务器,以避免过大的负载集中于同一服务器而造成延迟。

那到底怎么讲本地视频或者处理过的帧进行推流呢?主要用到的还是FFMPEG。

RTMP推流

主要的命令是:

# Windows OS
ffmpeg.exe -re -i demo.wmv -vcodec copy -codec copy -f flv rtmp://127.0.0.1:1935/live/123
# Linux OS
ffmpeg -re -i demo.mp4 -vcodec copy -codec copy -f flv rtmp://127.0.0.1:1935/live/123
# 1935为默认端口,127.0.0.1即localhost

与python-opencv一起就可以用来处理本地视频或者处理好的帧的推流,此处主要参考了CSDN博客

import cv2
import subprocess as sp

rtmpUrl = 'rtmp://localhost/live/123'

# 视频来源 地址需要替换自己的可识别文件地址
filePath='C:\\Users\\angus\Videos\\'
camera = cv2.VideoCapture(filePath+"test2.mp4") # 从文件读取视频

# 视频属性
size = (int(camera.get(cv2.CAP_PROP_FRAME_WIDTH)), int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT)))
sizeStr = str(size[0]) + 'x' + str(size[1])
fps = camera.get(cv2.CAP_PROP_FPS)  # 30p/self
fps = int(fps)
hz = int(1000.0 / fps)
print('size:'+ sizeStr + ' fps:' + str(fps) + ' hz:' + str(hz))

# 视频文件输出格式
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(filePath+'res_mv.avi',fourcc, fps, size)
# 直播管道输出 
# ffmpeg推送rtmp 重点 : 通过管道 共享数据的方式
command = ['ffmpeg',
    '-y',
    '-f', 'rawvideo',
    '-vcodec','rawvideo',
    '-pix_fmt', 'bgr24',
    '-s', sizeStr,
    '-r', str(fps),
    '-i', '-',
    '-c:v', 'libx264',
    '-pix_fmt', 'yuv420p',
    '-preset', 'ultrafast',
    '-f', 'flv', 
    rtspUrl]
#管道特性配置
# pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=10**8)
pipe = sp.Popen(command, stdin=sp.PIPE) #,shell=False
# pipe.stdin.write(frame.tostring())  
while True:
    ret, frame = camera.read() # 逐帧采集视频流
    if not ret:
        break
    # 绘制推送图片帧信息
    # print(len(faces))
    # fpsshow = "Fps  :" + str(int(fps)) + "  Frame:" + str(count)  
    # nframe  = "Play :" + str(int(count / fps))
    # ntime   = "Time :" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    ############################图片输出
    # 结果帧处理 存入文件 / 推流 / ffmpeg 再处理
    pipe.stdin.write(frame.tostring())  # 存入管道用于直播
    out.write(frame)    #同时 存入视频文件 记录直播帧数据
    pass
camera.release()
# Release everything if job is finished
out.release()
print("Over!")

RTSP推流

主要

用到的命令:

# Linux OS
ffmpeg -re -i demo.mp4 -vcodec copy -codec copy -f rtsp rtsp://127.0.0.1:1935/test
# Windows OS
ffmpeg.exe -re -i demo.mp4 -vcodec copy -codec copy -f rtsp rtsp://127.0.0.1:1935/test
# 与RTMP推流的主要区别在于 -f 这个option

与python-opencv共同使用:

import cv2
import subprocess as sp

rtspUrl = 'rtsp://localhost/test'

# 视频来源 地址需要替换自己的可识别文件地址
filePath='C:\\Users\\angus\Videos\\'
camera = cv2.VideoCapture(filePath+"test2.mp4") # 从文件读取视频

# 视频属性
size = (int(camera.get(cv2.CAP_PROP_FRAME_WIDTH)), int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT)))
sizeStr = str(size[0]) + 'x' + str(size[1])
fps = camera.get(cv2.CAP_PROP_FPS)  # 30p/self
fps = int(fps)
hz = int(1000.0 / fps)
print('size:'+ sizeStr + ' fps:' + str(fps) + ' hz:' + str(hz))

# 视频文件输出
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(filePath+'res_mv.avi',fourcc, fps, size)
# 直播管道输出 
# ffmpeg推送rtmp 重点 : 通过管道 共享数据的方式
command = ['ffmpeg',
    '-y',
    '-f', 'rawvideo',
    '-vcodec','rawvideo',
    '-pix_fmt', 'bgr24',
    '-s', sizeStr,
    '-r', str(fps),
    '-i', '-',
    '-c:v', 'libx264',
    '-pix_fmt', 'yuv420p',
    '-preset', 'ultrafast',
    '-f', 'rtsp', 
    rtspUrl]
#管道特性配置
# pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=10**8)
pipe = sp.Popen(command, stdin=sp.PIPE) #,shell=False
# pipe.stdin.write(frame.tostring())  
while True:
    ret, frame = camera.read() # 逐帧采集视频流
    if not ret:
        break
    ############################图片输出
    # 结果帧处理 存入文件 / 推流 / ffmpeg 再处理
    pipe.stdin.write(frame.tostring())  # 存入管道用于直播
    out.write(frame)    #同时 存入视频文件 记录直播帧数据
    pass
camera.release()
# Release everything if job is finished
out.release()
print("Over!")

结束

这里为了测试代码,我使用的是EasyDarwin高性能开源RTSP流媒体服务器

如果是在服务器端,需要进行一些相应的配置,具体可自行百度,如此处。