2021-09-20 视频流实时请求实时转发

视频流

之前的写法是

  1. 直接一次性全部转发视频流
  2. 把target视频流和视频id的对应关系写到数据库中
    但是转发20多个视频流,服务器是不能够承受。
    640*480 30fps占了9G左右的内存,但是CPU使用还是太高了【跑18个是极限,10个还是没问题的】

为了稳妥起见,现在考虑的是:

  1. 把source视频流、target视频流和视频id的对应关系写到数据库中
  2. 每次请求的时候才转发
    • 考虑到后端没法判断前端什么时候不请求视频流了。现在设定的方案是
      • 用全局变量liveList保存正在转发的摄像头id和进程的pid
      • 前端每隔10秒额外发送一个信息表示还在请求视频流,此时后端更新对应摄像头id的最近使用时间戳timestamp,并检测其他的摄像头是否已经超过了最大的阈值threshold(如2分钟),若超过了的话,就杀死对应的进程。
        • 这样可以保证如果有新增的摄像头,会及时杀死没有被请求的摄像头。

代码仅供参考:

import subprocess as sp
import multiprocessing as mp
import time
class Live(object):
    '''用于推流。
        time: 上一次访问的时间
        timeThreshold: 时间阈值,超过2mins下次检测到时会关闭转发
    '''
    def __init__(self, id, sourceUrl, middleUrl, targetUrl, timeThreshold=120):
        # 自行设置
        self.id = id
        self.sourceUrl = sourceUrl # rtsp://admin:1234asdf@191.169.29.63:554
        self.middleUrl = middleUrl # rtmp://localhost:1935/live/3
        self.targetUrl = targetUrl # http://172.18.194.3/live?port=1935&app=live&stream=4
        
        self.time = time.time()
        self.timeThreshold = timeThreshold # 默认2mins,如果
        
    def run(self):
        print(type(self.id), str(self.id))
        print('---开启推流,id={}, source={}, middle={}, target={}'.format(
            self.id, self.sourceUrl, self.middleUrl, self.targetUrl))
        fps = 30
        width = 640
        height = 480
        
        # ffmpeg -rtsp_transport tcp -i rtsp://admin:1234asdf@191.169.29.63:554 -vcodec h264 -f flv -an rtmp://localhost:1935/live/1
        command = ['ffmpeg',
                       '-rtsp_transport',
                        'tcp',
                        '-i', self.sourceUrl,
                        '-vcodec', 'h264',
                        '-f', 'flv',
                        '-r', str(fps),
                        '-s', '{}x{}'.format(width, height),
                        '-preset', 'ultrafast',
                        '-an',
                        self.middleUrl]
        
        self.p = sp.Popen(command)
#         self.p = sp.run(command)
        print(type(self.p), self.id) # pid在杀死的时候并不准确
    
    def kill(self):
        '''杀死子进程
        '''
        self.p.kill()
    
    def updateTime(self):
        '''更新上次访问时间
        '''
        self.time = time.time()
        print('id={}的摄像头更新访问时间{}秒'.format(self.id, self.time))
    
    def checkTime(self, curTime):
        '''检查当前时间和上次访问时间是否超过阈值,超过就关闭,并返回false
        '''
        if curTime - self.time > self.timeThreshold:
            print('id={}的摄像头已经超过了最大的阈值{}秒'.format(self.id, self.timeThreshold))
            self.kill()
            return False
        # 仍在运行则为True
        return True


class LiveList(object):
    def __init__(self):
        self.llist = []
    
    def updateList(self, newLive: Live):
        flag = 0
        for i in range(len(self.llist)-1, -1, -1): # 倒序
            live = self.llist[i]
            if live.id == newLive.id: # 已加入,就更新最后访问时间
                flag = 1
                live.updateTime()
                print('第{}个摄像头更新time'.format(live.id))
            else: # 检查其他的摄像头是否已经超过了最大的阈值threshold
                if live.checkTime(time.time()) == False: #超过了,删除
                    print('第{}个摄像头已经超过了最大的阈值threshold'.format(live.id))
                    self.llist.pop(i)
                
        if flag == 0: # 还没有加入
            if len(newLive.sourceUrl) > 0: 
#                 newLive.run()
                self.llist.append(Live(newLive.id, newLive.sourceUrl, newLive.middleUrl, newLive.targetUrl))
                print("新加入的摄像头运行,它的id为{}".format(self.llist[-1].id))
                self.llist[-1].run()
            else:
                print('新加入的摄像头没有source和target,它的id为{}'.format(newLive.id))
            

# 全局变量liveList保存正在转发的摄像头id和进程的pid
liveList = LiveList()
######################LiveList

data_dict = {'device_id': data[0], 'source_camera_url': data[1], 'middle_camera_url': data[2], 'target_camera_url': data[3]}
live = Live(data_dict['device_id'], data_dict['source_camera_url'], data_dict['middle_camera_url'], data_dict['target_camera_url'])
liveList.updateList(live)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值