Python cv2.VideoWriter和GStreamer的配置问题

Python cv2.VideoWriter和GStreamer的配置问题,python,bash,opencv,gstreamer,Python,Bash,Opencv,Gstreamer,我在设置GStreamer管道以通过OpenCV通过UDP转发视频流时遇到问题。我有一台笔记本电脑和一台连接到同一网络的AGX Xavier。我们的想法是将网络摄像头视频馈送转发给AGX,AGX将在GPU(Python)上进行一些OpenCV光流估计,在原始图像上绘制流向量,并将其发送回我的笔记本电脑。到目前为止,我可以配置两个管道。作为一个最起码的例子,我制作了两个bash脚本和一个Python脚本,理想情况下它们可以作为OpenCV的VideoCapture和VideoWriter对象的传递

我在设置GStreamer管道以通过OpenCV通过UDP转发视频流时遇到问题。我有一台笔记本电脑和一台连接到同一网络的AGX Xavier。我们的想法是将网络摄像头视频馈送转发给AGX,AGX将在GPU(Python)上进行一些OpenCV光流估计,在原始图像上绘制流向量,并将其发送回我的笔记本电脑。到目前为止,我可以配置两个管道。作为一个最起码的例子,我制作了两个bash脚本和一个Python脚本,理想情况下它们可以作为OpenCV的VideoCapture和VideoWriter对象的传递

servevideo.bash:

#!/bin/bash

gst-launch-1.0 v4l2src device=[device-fd] \
    ! video/x-raw, width=800, height=600, framerate=24/1 \
    ! jpegenc ! rtpjpegpay ! rtpstreampay \
    ! udpsink host=[destination-ip] port=12345
#!/bin/bash

gst-launch-1.0 -e udpsrc port=12344 \
    ! application/x-rtp-stream,encoding-name=JPEG \
    ! rtpstreamdepay ! rtpjpegdepay ! jpegdec \
    ! autovideosink
#!/bin/bash
gst-launch-1.0 videotestsrc device=[device-fd] \
    ! video/x-raw, width=800, height=600, framerate=20/1 \
    ! videoscale
    ! videoconvert
    ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast
    ! rtph264pay
    ! udpsink host=[destination-ip] port=12345
receivevideo.bash:

#!/bin/bash

gst-launch-1.0 v4l2src device=[device-fd] \
    ! video/x-raw, width=800, height=600, framerate=24/1 \
    ! jpegenc ! rtpjpegpay ! rtpstreampay \
    ! udpsink host=[destination-ip] port=12345
#!/bin/bash

gst-launch-1.0 -e udpsrc port=12344 \
    ! application/x-rtp-stream,encoding-name=JPEG \
    ! rtpstreamdepay ! rtpjpegdepay ! jpegdec \
    ! autovideosink
#!/bin/bash
gst-launch-1.0 videotestsrc device=[device-fd] \
    ! video/x-raw, width=800, height=600, framerate=20/1 \
    ! videoscale
    ! videoconvert
    ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast
    ! rtph264pay
    ! udpsink host=[destination-ip] port=12345
如果我在同一台计算机上或在网络上的两台不同计算机上运行这两个脚本,它可以正常工作。当我将我的Python脚本(如下所列)放入混合时,我开始遇到问题。理想情况下,在我的Jetson上运行Python脚本时,我会在笔记本电脑上运行bash脚本,并记住预期的设置。在绕捷森飞机绕道一圈后,我希望能在我的笔记本电脑上看到摄像头的视频

网络摄像头\u passthrough.py:

#!/usr/bin/python3.6

import signal, cv2
from multiprocessing import Process, Pipe

is_running = True

def signal_handler(sig, frame):
    global is_running
    print("Program was interrupted - terminating ...")
    is_running = False

def produce(pipe):
    global is_running
    video_in = cv2.VideoCapture("udpsrc port=12345 ! application/x-rtp-stream,encoding-name=JPEG ! rtpstreamdepay ! rtpjpegdepay ! jpegdec ! videoconvert ! appsink", cv2.CAP_GSTREAMER)

    while is_running:
        ret, frame = video_in.read()
        if not ret: break
        print("Receiving frame ...")

        pipe.send(frame)

    video_in.release()

if __name__ == "__main__":
    consumer_pipe, producer_pipe = Pipe()

    signal.signal(signal.SIGINT, signal_handler)
    producer = Process(target=produce, args=(producer_pipe,))

    video_out = cv2.VideoWriter("appsrc ! videoconvert ! jpegenc ! rtpjpegpay ! rtpstreampay ! udpsink host=[destination-ip] port=12344", cv2.CAP_GSTREAMER, 0, 24, (800, 600), True)
    producer.start()

    while is_running:
        frame = consumer_pipe.recv()
        video_out.write(frame)
        print("Sending frame ...")

    video_out.release()
    producer.join()
#!/usr/bin/python3.6

import cv2

video_in = cv2.VideoCapture("udpsrc port=12345 ! application/x-rtp-stream,encoding-name=JPEG ! rtpstreamdepay ! rtpjpegdepay ! jpegdec ! videoconvert ! appsink", cv2.CAP_GSTREAMER)
video_out = cv2.VideoWriter("appsrc ! videoconvert ! jpegenc ! rtpjpegpay ! rtpstreampay ! udpsink host=[destination-ip] port=12344", cv2.CAP_GSTREAMER, 0, 24, (800, 600), True)

while True:
    ret, frame = video_in.read()

    if not ret: break

    video_out.write(frame)
    cv2.imshow('Original', frame)

    key = cv2.waitKey(1) & 0xff
    if key == 27: break

cv2.destroyAllWindows()
video_out.release()
video_in.release()
使用下面的Python脚本,我可以通过从
servevideo.bash
脚本设置的管道接收的
cv2.imshow
来可视化帧。因此,我认为我的问题与如何在OpenCV中设置VideoWriter
video\u out
有关。当我在创建的两个管道之间中继网络摄像头视频馈送时,我已经验证了我的两个bash脚本是否正常工作,并且我已经验证了
cv2.VideoCapture
是否接收帧。我在这里不是专家,我的GStreamer知识几乎不存在,因此在我的最小示例中可能存在一些误解。如果你们中的一些人能指出我在这里遗漏了什么,我将不胜感激

如果有不清楚或遗漏的地方,我也很乐意提供更多信息

编辑: 因此,我的最低限度的例子的意图似乎没有得到明确的传达

作为一个最低示例,提供的三个脚本用于将我的网络摄像头视频从我的笔记本电脑转发给Jetson AGX Xavier,然后Jetson AGX Xavier将视频反馈转发回笔记本电脑。
servevideo.bash
在笔记本电脑上创建一个GStreamer管道,该管道使用v4l2从摄像头抓取帧并将其中继到UDP套接字。
webcam_passthrough.py
在Jetson上运行,它“连接”到笔记本电脑上运行的管道创建的UDP套接字。Python脚本提供一个passthrough,理想情况下,它将在另一个端口上打开一个新的UDP套接字,并将帧中继回笔记本电脑。
receivevideo.bash
在笔记本电脑上创建了另一条管道,用于接收在Jetson上通过Python脚本传递的帧。笔记本电脑上的第二条管道仅用于可视化目的。理想情况下,此最小示例显示连接到笔记本电脑的摄像头的“原始”视频馈送

这两个bash脚本是独立工作的,它们在笔记本电脑上本地运行,在另一台计算机上远程运行
receivevideo.bash

Python脚本中的
cv2.VideoCapture
配置似乎也可以工作,因为我可以可视化通过
servevideo.bash
脚本提供的UDP套接字接收的帧(使用
cv2.imshow
)。这是本地和远程工作以及。让我头疼的部分(我相信)是
cv2.VideoWriter
的配置;理想情况下,这应该打开一个UDP套接字,我可以通过
receivevideo.bash
脚本“连接”到该套接字。我已经在本地和远程进行了测试,但没有结果

当我运行
receivevideo.bash
连接到Python脚本提供的UDP套接字时,我得到以下输出:

Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
这对我来说似乎没有错,我尝试使用GST_DEBUG=3运行不同的脚本,这会发出一些警告,但由于bash脚本中的管道配置基本相同,对于cv2
VideoCapture
VideoWriter
来说,这些警告没有太大价值。作为一个例子,我在下面列出了一个这样的警告:

0:00:06.595120595  8962      0x25b8cf0 WARN              rtpjpegpay gstrtpjpegpay.c:596:gst_rtp_jpeg_pay_read_sof:<rtpjpegpay0> warning: Invalid component
我希望我的意图现在更清楚了,正如我已经指出的,我相信Python脚本中的
cv2.VideoWriter
有问题,但我不是专家,GStreamer远非我每天都使用的东西。因此,我可能误解了一些东西

编辑2: 因此,现在我尝试将这两条管道分成@Abyslover建议的两个单独的流程。我仍然看到同样的结果,我仍然不知道为什么会这样。下面列出了我当前的Python脚本实现

网络摄像头\u passthrough.py:

#!/usr/bin/python3.6

import signal, cv2
from multiprocessing import Process, Pipe

is_running = True

def signal_handler(sig, frame):
    global is_running
    print("Program was interrupted - terminating ...")
    is_running = False

def produce(pipe):
    global is_running
    video_in = cv2.VideoCapture("udpsrc port=12345 ! application/x-rtp-stream,encoding-name=JPEG ! rtpstreamdepay ! rtpjpegdepay ! jpegdec ! videoconvert ! appsink", cv2.CAP_GSTREAMER)

    while is_running:
        ret, frame = video_in.read()
        if not ret: break
        print("Receiving frame ...")

        pipe.send(frame)

    video_in.release()

if __name__ == "__main__":
    consumer_pipe, producer_pipe = Pipe()

    signal.signal(signal.SIGINT, signal_handler)
    producer = Process(target=produce, args=(producer_pipe,))

    video_out = cv2.VideoWriter("appsrc ! videoconvert ! jpegenc ! rtpjpegpay ! rtpstreampay ! udpsink host=[destination-ip] port=12344", cv2.CAP_GSTREAMER, 0, 24, (800, 600), True)
    producer.start()

    while is_running:
        frame = consumer_pipe.recv()
        video_out.write(frame)
        print("Sending frame ...")

    video_out.release()
    producer.join()

我在两个进程之间创建的管道提供了一个新的框架。当我尝试使用
netcat
收听UDP端口12344时,我没有收到任何与以前相同的内容。我也很难理解管道的差异是如何变化的,因为我希望它们已经在不同的环境中运行。尽管如此,关于这个假设,我可能是错的。

注意:由于声誉不高,我无法发表评论

根据你的问题描述,很难理解你的问题是什么

简单地说,您将在笔记本电脑上运行两个bash脚本(
servevideo.bash
receivevideo.bash
),它们可以从笔记本电脑接收和发送网络摄像头帧(?),而Python脚本(
webcam\u passthrough.py
)在Jetson AGX Xavier上运行

您的bash脚本工作正常,因此我猜您在Python脚本中遇到了一些问题。根据您的解释,您已经在bash脚本中获得了gst启动的框架,并可视化了这些框架

那么,你真正的问题是什么?你想干什么
#!/usr/bin/python3

import signal, cv2
from multiprocessing import Process, Pipe

is_running = True

def signal_handler(sig, frame):
    global is_running
    print("Program was interrupted - terminating ...")
    is_running = False

def produce(pipe):
    global is_running
    video_in = cv2.VideoCapture("udpsrc port=12345 ! application/x-rtp-stream,encoding-name=JPEG ! rtpstreamdepay ! rtpjpegdepay ! jpegdec ! videoconvert ! appsink", cv2.CAP_GSTREAMER)

    while is_running:
        ret, frame = video_in.read()
        if not ret: break
        print("Receiving frame ...")

        pipe.send(frame)

    video_in.release()

if __name__ == "__main__":
    consumer_pipe, producer_pipe = Pipe()

    signal.signal(signal.SIGINT, signal_handler)
    producer = Process(target=produce, args=(producer_pipe,))

    # the only edit is here, added video/x-raw capsfilter:     <-------
    video_out = cv2.VideoWriter("appsrc ! videoconvert ! video/x-raw,format=I420 ! jpegenc ! rtpjpegpay ! rtpstreampay ! udpsink host=[receiver ip] port=12344", cv2.CAP_GSTREAMER, 0, 24, (800, 600), True)
    producer.start()

    while is_running:
        frame = consumer_pipe.recv()
        rr = video_out.write(frame)
        print("Sending frame ...")
        print(rr)

    video_out.release()
    producer.join()