V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V392920
V2EX  ›  程序员

关于一个摄像头的需求,求大佬指点

  •  
  •   V392920 · 57 天前 · 2181 次点击
    这是一个创建于 57 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在有这样一个需求,需要开发一个程序,写一个接口,当接口接收到请求,就需要获取摄像头当前时间-5 到+5 秒的视频

    举例说明: 比如在 10:00:00 接口接收到请求,那就需要将摄像头 9:59:55~10:00:05 这 10 秒的视频保存到指定目录并推送至指定地方,并且需要在 30 秒内完成该逻辑

    设备是海康威视摄像头

    我尝试过的方法

    1 、通过海康的 RTSP 流添加 starttime 和 endtime 来获取回放流,比如我 10:00:00 收到请求,我就拼接 rtsp 流地址 rtsp://admin:[email protected]:554/Streaming/101?starttime=20240712T095955Z,然后使用 ffmpeg 进行录制 10 秒,就能刚刚好保存出这个时间段的视频

    发现的问题: 不知道是什么原因,我只要获取当前时间的 rtsp 流,就无法访问,经过写代码尝试,发现必须获取当前时间 2 分钟前的流,才可以访问,比如 10:00:00 接到请求,只能访问到 9:58:00 左右的回放流,我猜测是因为录像没有实时落盘的原因?

    2 、集成海康 SDK 尝试,也遇到了跟 1 操作一样的问题,就是没办法实时或者说获取 10 秒内的回放,获取 1 分钟之前的回放文件可以成功,比 rtsp 稍微好一点,但是也不能满足我的需求,我在看海康文档的时候,有个刷新索引的接口,写的是设备默认 2 分钟刷新,但是我尝试了,我的摄像头提示不支持该接口

    我通过官方的 App 海康互联测试,他们 App 的回放功能好像就没这么大的差距,他们的 App 能回放 30 秒内的视频

    希望求大佬指点,或者有没有其他办法能实现这个需求,万分感谢

    第 1 条附言  ·  57 天前
    感谢各位大佬的思路,已经实现了,谢谢谢谢
    23 条回复    2024-07-17 18:05:49 +08:00
    V392920
        1
    V392920  
    OP
       57 天前
    大佬们,今天都在等下班吗?
    twosix
        2
    twosix  
       57 天前
    你要获取当前时间的 rtsp 流,不加时间戳不就是实时流了么?
    V392920
        3
    V392920  
    OP
       57 天前
    @twosix 要获取前 5 秒的,必须加时间戳了
    twosix
        4
    twosix  
       57 天前
    @V392920 哦哦,我之前处理过类似的情况,接口收到请求后,录制-2 秒,持续 8 秒的视频。因为对于-2 秒这个要求的不是很精准,所以处理方法是用 ffmpeg 持续录实时流,把每个文件保存成时长 1 秒,收到请求后等后 6 个文件录完了,拼起来上传。
    V392920
        5
    V392920  
    OP
       57 天前
    @twosix 额,主要是这个摄像头录制页面上是有时间的,实时的最少都要误差 5 秒,肯定不允许了,谢谢你的分享
    twosix
        6
    twosix  
       57 天前   ❤️ 1
    @V392920 嗯这个是按需求来的,做的比较粗糙。也做过较精准的方案,会麻烦一点,就是持续读帧放到缓存里,维持缓存队列的长度(长度由帧数×秒数决定),收到请求后再持续按需求时长往里加。
    RandomJoke
        7
    RandomJoke  
       57 天前
    这个感觉只能问问海康的人了,要是不支持,那么基本没法实现 30s 内完成这个逻辑吧
    snipking
        8
    snipking  
       57 天前
    有没有可能是你测试用的摄像头和你本地时间不同步
    rainbowmolly
        9
    rainbowmolly  
       57 天前
    delay 2 分钟再开始获取不就好了?
    V392920
        10
    V392920  
    OP
       57 天前
    @jokefaker 已经给海康发邮件了,还在等回复
    V392920
        11
    V392920  
    OP
       57 天前
    @snipking 确认过的,是同步的
    V392920
        12
    V392920  
    OP
       57 天前
    @rainbowmolly delay2 分钟,但是需求是要在接收到请求后 30 秒内完成整个逻辑,delay 就超时了
    ljl024
        13
    ljl024  
       57 天前   ❤️ 1
    有没有可能,起一个服务,一直拉取实时的流,分段每秒保存一次视频片段,保留最近 15 秒的。
    收到请求后等待 5 秒,去缓存中查找和组装需要的视频片段。
    V392920
        14
    V392920  
    OP
       57 天前
    @twosix 这个缓存方案好像还可以欸,我可以尝试一下
    V392920
        15
    V392920  
    OP
       57 天前
    @ljl024 对的对的,刚刚楼上那个兄弟提到了缓存,确实这个思路还可以,可以尝试一下
    xhatt510
        16
    xhatt510  
       57 天前
    @ljl024 保留 5 秒的不就行了?
    frayesshi1
        17
    frayesshi1  
       57 天前
    @twosix 之前也有这个需求,采用同样的方式,采集时间点前后的图片,然后用 opencv 把图片做成视频
    777yL
        18
    777yL  
       57 天前
    最后怎么实现的啊 老哥
    bxb100
        19
    bxb100  
       57 天前
    @777yL 前面有提到啊, 滚动窗口缓存呗
    ljl024
        20
    ljl024  
       57 天前
    @xhatt510 #16 按我的理解
    - 拉取流是一个异步行为,从发起请求到返回第一个关键帧,中间有个时间差
    流上有个时间戳
    - 服务拉取流,落盘保存,这个需要等一个分段完成录制才能取到
    分段会有个时间戳范围

    两个数据间拼接就涉及时间点的问题,感觉实现上不太方便,不如直接从缓存里面,取十个分段(假设一秒一个),直接拼起来

    还有一个问题,这个方式存在同时拉两个流(一个流继续做缓存,一个流接口拿来做拼接),增加了带宽消耗
    zhy321
        21
    zhy321  
       56 天前
    最后怎么实现的
    zreyu
        22
    zreyu  
       56 天前
    from flask import Flask, request
    import cv2
    import datetime
    import subprocess
    import time

    app = Flask(__name__)

    @app.route('/capture_video', methods=['POST'])
    def capture_video():
    try:
    # 获取当前时间
    current_time = datetime.datetime.now()
    start_time = (current_time - datetime.timedelta(seconds=5)).strftime('%H:%M:%S')
    end_time = (current_time + datetime.timedelta(seconds=5)).strftime('%H:%M:%S')

    # 摄像头 ID ,假设使用默认摄像头
    camera_id = 0

    # 保存视频的路径
    output_path = 'captured_video.mp4'

    # 使用 FFmpeg 捕获视频
    ffmpeg_cmd = f'ffmpeg -y -ss {start_time} -t 10 -i /dev/video{camera_id} {output_path}'
    subprocess.run(ffmpeg_cmd, shell=True, check=True)

    # 推送视频到指定地方(这里假设推送到某个 URL )
    push_url = 'http://example.com/upload'
    push_cmd = f'curl -F "file=@{output_path}" {push_url}'
    subprocess.run(push_cmd, shell=True, check=True)

    return {'status': 'success', 'message': 'Video captured and pushed successfully'}
    except Exception as e:
    return {'status': 'error', 'message': str(e)}

    if __name__ == '__main__':
    app.run(debug=True)
    liuxh7
        23
    liuxh7  
       52 天前
    老哥,我现在做的摄像头有个优化需求也是类似的问题,想找老哥聊下,方便加下小而美吗? aGFsbG9feGlhb2hlaQ==
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2392 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 00:11 · PVG 08:11 · LAX 17:11 · JFK 20:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.