FFmpeg / OpenCV强制使用rtsp忽略输入帧持续时间?

时间:2019-06-14 03:14:04

标签: opencv ffmpeg rtsp live-streaming

从IP摄像机播放rtsp流时,我遇到~5 sec延迟。经过一堆谷歌搜索(尤其是this question)后,我使用以下命令将延迟降低为~1 sec

ffplay -fflags nobuffer -flags low_delay -framedrop -strict experimental \
       -probesize 32 -sync ext rtsp://xxx.xxx.xxx.xxx

但是当我从同一问题尝试mplayer -benchmark命令时,我发现延迟立即消失(即几乎为0的延迟)。

mplayer的手册页中说:

  

-基准

     

在播放结束时打印一些有关CPU使用率和丢帧的统计信息。与-nosound和-vo null结合使用,仅对视频编解码器进行基准测试。

     

注意:使用此选项,MPlayer在仅播放视频时也将忽略帧持续时间(您可以将其视为无限fps)。

我认为这个“忽略帧持续时间”是问题的关键,但是经过一堆谷歌搜索之后,我在ffmpeg中没有发现与此相关的任何标志。我想知道如何在ffmpeg 中强制忽略输入帧持续时间?

另一方面,我使用ffmpeg的原因是因为我需要使用opencv进行图像处理,而我发现它似乎正在使用ffmpeg的某些部分做完这些事

cv.VideoCapture('rtsp://xxx.xxx.xxx.xxx')

直接解决opencv中问题的解决方案将受到更大的赞赏。我确实尝试过在一个单独的线程中反复读取VideoCapture,但没有帮助。


有关RTSP流的一些信息:h264、1920x1080、15fps,每4s 1个关键帧

我尝试过的其他解决方案

ffmpeg -r 99999 -i ...
# didn't work

mplayer ... -dumpstream
# it core dumped

1 个答案:

答案 0 :(得分:0)

由于I / O延迟减少,因此在单独的线程中使用VideoCapture()读取帧应提高性能。 read()操作被阻止,因此主程序被暂停,直到从相机流中读取一帧为止。通过将读取的帧放在单独的线程中,我们应该能够并行抓取和显示帧,而不是依赖单个线程按顺序抓取帧。将src替换为您的RTSP流链接。

可能会有延迟的另一个原因可能是因为您的分辨率为1920x1080。在显示框架之前,您可以调整其大小,这样可以提供更好的性能。

from threading import Thread
import cv2, time

class VideoStreamWidget(object):
    def __init__(self, src=0):
        self.capture = cv2.VideoCapture(src)
        # Start the thread to read frames from the video stream
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # Read the next frame from the stream in a different thread
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()
            time.sleep(.01)

    def show_frame(self):
        # Display frames in main program
        cv2.imshow('frame', self.frame)
        key = cv2.waitKey(1)
        if key == ord('q'):
            self.capture.release()
            cv2.destroyAllWindows()
            exit(1)

if __name__ == '__main__':
    video_stream_widget = VideoStreamWidget()
    while True:
        try:
            video_stream_widget.show_frame()
        except AttributeError:
            pass