思路:
opencv读取视频 —> 将视频分割为帧 —> 将每一帧进行需求加工后 —> 将此帧写入pipe管道 —> 利用ffmpeg进行推流直播
pipe管道:
啥是pipe管道? 粗略的理解就是一个放共享文件的地方(理解不是很深刻。。。)
利用这个特点, 把处理后的图片放入管道, 让ffmpeg读取处理后的图像帧并进行rtmp推流即可
代码
import subprocess as sp
rtmpUrl = ""
camera_path = ""
cap = cv.VideoCapture(camera_path)
fps = int(cap.get(cv.CAP_PROP_FPS))
width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
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)
while(cap.isOpened()):
ret, frame = cap.read()
if not ret:
print("Opening camera is failed")
break
p.stdin.write(frame.tostring())
代码说明:
- rtmpUrl就是要接收视频的服务器了, 我做实验时是在自己机子上配置了一个nginx服务器接收视频流(ubuntu 不要通过apt安装哦, 请从源码安装, 因为apt安装的版本没有rtmp协议, 需要下载nginx源码然后配合nginx-rtmp-module这个东西安装 推荐一篇nginx安装教程)
- camera_path就是要进行直播的视频地址了
- 重点的代码其实就这几句:
import subprocess as sp
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)
p.stdin.write(frame.tostring())
- 我读取的视频是rtsp网络摄像头的视频流, 但是一旦运行没多久就会出现 pipe broke 的报错(1080p视频), 不知道是什么原因, 若有大神还请指点指点
WriteN, RTMP send error 104 (129 bytes)
更新: 我改1080p为720p 暂时没出现这个问题
- 我在读取视频时候还遇到这个报错
error while decoding xxx
经过一方百度, 是“FFMPEG Lib对在rtsp协议中的H264 vidos不支持”的问题, 解决方法: 程序开启两个线程, 一个线程读取摄像头的帧, 另一个线程处理这帧图片, 这里还推荐一个大佬用队列处理视频的方法 ,大家可以套用一下啊 飞机票 多线程处理的版本:
import queue
import threading
import cv2 as cv
import subprocess as sp
class Live(object):
def __init__(self):
self.frame_queue = queue.Queue()
self.command = ""
self.rtmpUrl = ""
self.camera_path = ""
def read_frame(self):
print("开启推流")
cap = cv.VideoCapture(self.camera_path)
fps = int(cap.get(cv.CAP_PROP_FPS))
width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
self.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',
self.rtmpUrl]
while(cap.isOpened()):
ret, frame = cap.read()
if not ret:
print("Opening camera is failed")
break
self.frame_queue.put(frame)
def push_frame(self):
while True:
if len(self.command) > 0:
p = sp.Popen(self.command, stdin=sp.PIPE)
break
while True:
if self.frame_queue.empty() != True:
frame = self.frame_queue.get()
p.stdin.write(frame.tostring())
def run(self):
threads = [
threading.Thread(target=Live.read_frame, args=(self,)),
threading.Thread(target=Live.push_frame, args=(self,))
]
[thread.setDaemon(True) for thread in threads]
[thread.start() for thread in threads]
-
感谢这篇博文提供了新的知识
博主忙着做项目ing 能力也不是很高 欢迎和大家一起讨论 但是有的是真不会呀 还请见谅
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)