Python FFmpeg查询rtsp太慢 [英] Python FFmpeg query rtsp too slow

查看:69
本文介绍了Python FFmpeg查询rtsp太慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前,我正在尝试将FFmpeg与python结合使用以查询原始格式为h264的rtsp数据.

实时流视频的信息为fps:29;分辨率:1280 * 720.

我希望我可以查询与"h264"相同格式的数据并放入python队列中,以备将来使用.

这是我的代码:

  class CCTVReader(threading.Thread):def __init __(自身,队列,URL,fps = 29):super().__ init __()self.queue =队列self.command = ["ffmpeg","-y","-hwaccel","nvdec","-c:v","h264_cuvid","-vsync","0","-max_delay","500000","-reorder_queue_size","10000","-i","rtsp://xxx.xxx.xxx.xxx:xxx/Streaming/Channels/101?transportmode = multicast","-pix_fmt","yuv420p",-预设",慢","-an",-sn","-vf","fps = 29",-"]def运行(自己):管道= sp.Popen(self.command,stdout = sp.PIPE,bufsize = 1024 ** 3,shell = True)计时器= time.time()计数器= 0而True:self.queue.put(pipe.stdout.read(int(1280 * 720 * 6//4))) 

但是,在运行该程序约10秒钟后,控制台会显示警告消息:

  [rtsp @ 0000020be0fbb9c0]已达到最大延迟.需要消耗数据包[rtsp @ 0000020be0fbb9c0] RTP:丢失了127个数据包 

似乎我的命令键入不正确.

您能给我一些有关如何解决此问题的建议吗?

非常感谢

解决方案

假设您要在不修改数据的情况下获取视频流,则需要为FFmpeg设置不同的参数集:

  • 设置-c:v","h264" 作为输入参数(在-i" 之前),以通知FFmpeg输入是 h264视频流.
  • -c:v","copy" 设置为输出参数(在-i" 之后),因此FFmpeg将输入视频流复制到输出中PIPE,无需修改(无需解码和编码).
  • -f","h264" 设置为输出参数,以将PIPE输出格式设置为 h264 .

这是一个工作代码示例(请阅读注释):

 导入ffmpeg将numpy导入为np导入子进程为sp导入线程导入队列类CCTVReader(threading.Thread):def __init __(self,q,in_stream):super().__ init __()self.q = qself.command = ["ffmpeg","-c:v","h264",#告诉ffmpeg输入流编解码器是h264"-i",in_stream,#从文件vid.264读取流"-c:v","copy",#告诉ffmpeg照原样复制视频流(不进行解码和编码)"-an","-sn",#没有声音,没有字幕"-f","h264",#定义管道格式为h264-"]#输出是管道def运行(自己):pipe = sp.Popen(self.command,stdout = sp.PIPE,bufsize = 1024 ** 3)#不要使用shell = True(不需要通过shell执行命令).#而True:对于范围在(100)中的i:#最多读取100KB用于测试data = pipe.stdout.read(1024)#从pip读取1024字节的数据块self.q.put(数据)#如果读取的字节数少于1024个字节,则中断循环(不适用于CCTV,但适用于输入文件)如果len(data)<1024:休息尝试:pipe.wait(timeout = 1)#等待子进程完成(超时为1秒).除了sp.TimeoutExpired:pipe.kill()#在超时的情况下杀死子进程(应该存在超时,因为输入流仍然存在).#制作合成视频,以开始测试:################################################宽度,高度= 1280、720#in_stream ="vid.264"#sp.Popen("ffmpeg -y -f lavfi -i testsrc = size = 1280x720:duration = 5:rate = 1 -c:v libx264 -crf 23 -pix_fmt yuv420p" + in_stream).wait()################################################in_stream ="rtsp://xxx.xxx.xxx.xxx:xxx/Streaming/Channels/101?transportmode = multicast",#使用公共RTSP流进行测试in_stream ="rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"q = queue.Queue()cctv_reader = CCTVReader(q,in_stream)cctv_reader.start()cctv_reader.join()如果q.empty():打印(有问题(队列为空)!!")别的:#将队列中的数据写入文件vid_from_queue.264(用于测试g)使用open("vid_from_queue.264","wb")作为queue_save_file:而不是q.empty():queue_save_file.write(q.get()) 

我使用

Currently, I am trying to use python with FFmpeg to query rtsp data which the original format is h264.

The information of the live stream video is, fps:29; resolution: 1280*720.

I wish that I can query the data as the same format "h264" and put into a python queue in order to the future use.

Here is my code:

class CCTVReader(threading.Thread):
def __init__(self, queue, URL, fps=29):
    super().__init__()
    self.queue = queue
    self.command = ["ffmpeg",  "-y",
                    "-hwaccel",  "nvdec",
                    "-c:v",  "h264_cuvid",
                    "-vsync", "0",
                    "-max_delay", "500000",
                    "-reorder_queue_size", "10000",
                    "-i",  "rtsp://xxx.xxx.xxx.xxx:xxx/Streaming/Channels/101?transportmode=multicast",
                    "-pix_fmt", "yuv420p",
                    "-preset", "slow",
                    "-an", "-sn",
                    "-vf", "fps=29",
                    "-"]
def run(self):
    pipe = sp.Popen(self.command, stdout = sp.PIPE, bufsize=1024**3, shell=True)
    timer = time.time()
    counter = 0
    while True:
        self.queue.put(pipe.stdout.read(int(1280*720*6//4)))

However, after I run this program about 10 second, my console shows the warning message:

[rtsp @ 0000020be0fbb9c0] max delay reached. need to consume packet
[rtsp @ 0000020be0fbb9c0] RTP: missed 127 packets

It seems like my command doesn't type appropriately.

Could you kindly give me some suggestion about how to deal with this problem?

Thank you very much

解决方案

Assuming you want to grab the video stream without modifying the data, you need to set different set of arguments to FFmpeg:

  • Set "-c:v", "h264" as input argument (before "-i"), for informing FFmpeg that the input is h264 video stream.
  • Set "-c:v", "copy" as output argument (after "-i"), so the FFmpeg copies the input video stream to the output PIPE, without modifications (without decoding and encoding).
  • Set "-f", "h264" as output argument, for setting PIPE output format to h264.

Here is a working code sample (please read the comments):

import ffmpeg
import numpy as np
import subprocess as sp
import threading
import queue

class CCTVReader(threading.Thread):
    def __init__(self, q, in_stream):
        super().__init__()
        self.q = q
        self.command = ["ffmpeg",
                        "-c:v", "h264",     # Tell ffmpeg that input stream codec is h264
                        "-i", in_stream,    # Read stream from file vid.264
                        "-c:v", "copy",     # Tell ffmpeg to copy the video stream as is (without decding and encoding)
                        "-an", "-sn",       # No audio an no subtites
                        "-f", "h264",       # Define pipe format to be h264
                        "-"]                # Output is a pipe

    def run(self):
        pipe = sp.Popen(self.command, stdout=sp.PIPE, bufsize=1024**3)  # Don't use shell=True (you don't need to execute the command through the shell).

        # while True:
        for i in range(100):  # Read up to 100KBytes for testing
            data = pipe.stdout.read(1024)  # Read data from pip in chunks of 1024 bytes
            self.q.put(data)

            # Break loop if less than 1024 bytes read (not going to work with CCTV, but works with input file)
            if len(data) < 1024:
                break

        try:
            pipe.wait(timeout=1)  # Wait for subprocess to finish (with timeout of 1 second).
        except sp.TimeoutExpired:
            pipe.kill()           # Kill subprocess in case of a timeout (there should be a timeout because input stream still lives).


# Build synthetic video, for testing begins:
################################################
# width, height = 1280, 720
# in_stream = "vid.264"
# sp.Popen("ffmpeg -y -f lavfi -i testsrc=size=1280x720:duration=5:rate=1 -c:v libx264 -crf 23 -pix_fmt yuv420p " + in_stream).wait()
################################################

#in_stream = "rtsp://xxx.xxx.xxx.xxx:xxx/Streaming/Channels/101?transportmode=multicast",

#Use public RTSP Streaming for testing
in_stream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"

q = queue.Queue()

cctv_reader = CCTVReader(q, in_stream)
cctv_reader.start()
cctv_reader.join()

if q.empty():
    print("There is a problem (queue is empty)!!!")
else:
    # Write data from queue to file vid_from_queue.264 (for testingg)
    with open("vid_from_queue.264", "wb") as queue_save_file:
        while not q.empty():
            queue_save_file.write(q.get())

I tested the code using public RTSP Streaming and using a generated synthetic video file (code for testing with file is commented).

The code stores the output to vid_from_queue.264.
The .264 file is playable - the file format is an elementary h264 video stream.


Here is the last frame of the grabbed video stream:

这篇关于Python FFmpeg查询rtsp太慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆