0

我在 c++ 中有一个应用程序使用 gstreamer 从相机获取视频,然后通过 UDP 将视频发送到 c++ 中的另一个应用程序,该应用程序获取视频并使用 webrct 进行重新流式传输。Jetson AGX 下的一切。

如果我从 H264 中的相机获取数据并直接发送,则视频在 4k 中完美运行:

获取视频的第一个管道

pipe_source = "rtspsrc location=rtsp://192.168.1.162/z3-1.mp4 ! application/x-rtp,encoding-name=H264,profile=baseline ! ";
pipe_sink = "udpsink host=224.1.1.1 port=5000 sync=false auto-multicast=true";
launch_pipeline = pipe_source + pipe_sink;

获取视频并通过 webrtc 发送的第二个管道

pipeline = "udpsrc multicast-group=224.1.1.1 auto-multicast=true port=5000 ! application/x-rtp,encoding-name=H264,profile=baseline,media=video,clock-rate=90000,payload=96 ! webrtcbin async-handling=true name=sendrecv";

但是,如果我想在输入视频中进行一些进动,我无法在 4K 中执行此操作,因为我需要在通过 udp 发送视频之前对帧进行解码(然后编码)

pipe_source = "rtspsrc location=rtsp://192.168.1.162/z3-1.mp4 ! application/x-rtp,encoding-name=H265 !";
pipe_decode = "rtph265depay ! video/x-h265 ! nvv4l2decoder enable-max-performance=true ! ";
pipe_process = "nvvidconv output-buffers=5 name=myconv ! video/x-raw(memory:NVMM), format=RGBA ! nvvidconv output-buffers=5 ! video/x-raw(memory:NVMM), format=NV12 ! queue max-size-bytes=0 max-size-time=500 !";
pipe_encode ="nvv4l2vp9enc maxperf-enable=true ! video/x-vp9 ! rtpvp9pay !";
pipe_sink = "udpsink host=224.1.1.1 port=5000 sync=false auto-multicast=true";
launch_pipeline = pipe_source + pipe_decode + pipe_process + pipe_encode + pipe_sink;

在源代码的这个管道中,我尝试了 h264/h265。Morevoere,对于我尝试使用 h264 而不是 VP9 的编码,但看起来 H264 要慢得多。这就是我在编码部分使用 VP9 的原因。

在这种情况下,第二个管道是:

pipeline = "udpsrc multicast-group=224.1.1.1 auto-multicast=true port=5000 ! application/x-rtp,media=video,clock-rate=90000,encoding-name=VP9,payload=96, framerate=25/1 ! queue max-size-bytes=0 max-size-time=0 ! webrtcbin async-handling=true name=sendrecv";

我的问题是,使用这种配置,我无法获得高质量的 4k 视频。我得到了视频,但质量很差,我假设 VP9 正在改变比特率以拥有连续的视频而不会丢失帧。我尝试在编码部分给出比特率,这可以提高图像质量,但我会丢失一些帧。

如果我使用 1080,那么我得到的视频质量很好,因此我觉得这是硬件处理能力的问题(我使用的是 jetson AGX)进行解码/编码。

有人知道提高管道性能的方法吗?我不确定我是否在管道中做一些“无用”的事情,这会导致 4k 视频的整个过程变慢。

4

1 回答 1

1

我不确定您的真实用例是什么,但以下内容可能会帮助您进一步调查。

我没有 4K IP cam,所以在这里我将模拟使用 CSI Cam 以 1080p@30 fps 捕获并放大到 3840x2160 并以 H265 编码的 RTSP 服务器测试启动流式传输:

./test-launch "nvarguscamerasrc ! video/x-raw(memory:NVMM), width=1920, height=1080, framerate=30/1, format=NV12 ! nvvidconv ! video/x-raw(memory:NVMM), width=3840, height=2160, pixel-aspect-ratio=1/1 ! nvv4l2h265enc insert-vui=true insert-sps-pps=1 insert-aud=1 maxperf-enable=1 bitrate=30000000 ! h265parse ! video/x-h265, stream-format=byte-stream ! rtph265pay name=pay0 pt=96 "

请注意,这将编码为具有 30Mb/s 比特率的 H265 格式。您可以先检查是否可以从源中获得高质量的图像并将源比特率调整到最佳状态。假设您的显示器支持 1080p@30:

gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/test latency=500 ! application/x-rtp,encoding-name=H265 ! rtph265depay ! h265parse ! nvv4l2decoder ! nvvidconv ! video/x-raw,width=1920,height=1080 ! xvimagesink

好的,让我们走得更远。

这里解码 RTSP H265 源并重新编码为 VP9/RTP/UDP:

gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/test latency=500 ! application/x-rtp,encoding-name=H265 ! rtph265depay ! h265parse ! nvv4l2decoder enable-max-performance=1 ! queue ! nvv4l2vp9enc maxperf-enable=true bitrate=30000000 ! video/x-vp9 ! rtpvp9pay ! udpsink host=224.1.1.1 port=5000 auto-multicast=true buffer-size=32000000

请注意 VP9 30 Mb/s 比特率。您可能也需要进行调整。

为了检查,您可以显示(假设 X 正在运行):

gst-launch-1.0 udpsrc multicast-group=224.1.1.1 auto-multicast=true port=5000 buffer-size=32000000 ! application/x-rtp,encoding-name=VP9 ! rtpjitterbuffer latency=500 ! rtpvp9depay ! video/x-vp9 ! nvv4l2decoder ! nvvidconv ! video/x-raw,width=1920,height=1080 ! xvimagesink

编辑 2022 年 1 月 29 日:

您可以进一步尝试以下操作,我的 AGX Xavier 运行 L4T R32.6.1 似乎可以正常工作:

  1. 使用 H265 视频读取 RTSP 流、解码、编码到 VP9 并使用 RTP/UDP 流式传输到 localhost 的应用程序:
#include <gst/gst.h>

int main (gint argc, gchar * argv[])
{  
    gst_init (&argc, &argv);
    GMainLoop *loop = g_main_loop_new (NULL, FALSE);

    /* Create the pipeline...this will negociate unspecified caps between plugins */
    const gchar *pipeline1 = "rtspsrc location=rtsp://127.0.0.1:8554/test latency=500 ! application/x-rtp,encoding-name=H265 ! rtph265depay ! h265parse ! nvv4l2decoder enable-max-performance=1 ! queue ! nvv4l2vp9enc maxperf-enable=true bitrate=30000000 ! video/x-vp9 ! rtpvp9pay ! udpsink host=127.0.0.1 port=5000 auto-multicast=0 buffer-size=32000000 ";

    GstElement *pipeline = gst_parse_launch (pipeline1, NULL);
    if (!pipeline) {
        g_error ("Failed to create pipeline\n");
        exit(-1);
    }

    /* Ok, successfully created the pipeline, now start it */
    gst_element_set_state (pipeline, GST_STATE_READY);
    gst_element_set_state (pipeline, GST_STATE_PLAYING);

    /* wait until it's up and running or failed */
    if (gst_element_get_state (pipeline, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) {
        g_error ("Failed to go into PLAYING state");
        exit(-2);
    }

    g_print ("Running ...\n");
    g_main_loop_run (loop);

    return 0;
}

构建:gcc -Wall -o gst_testlaunch1 -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include gst_testlaunch1.cpp -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0

  1. 用于从本地主机上的 RTP/UDP 读取 VP9 编码视频的应用程序,解码和重新缩放到 1080p nvvidconv,然后在测量 fps 时显示在 X 中:
#include <gst/gst.h>

int main (gint argc, gchar * argv[])
{  
    gst_init (&argc, &argv);
    GMainLoop *loop = g_main_loop_new (NULL, FALSE);

    /* Create the pipeline...this will negociate unspecified caps between plugins */
    const gchar *pipeline2 = "udpsrc auto-multicast=0 port=5000 buffer-size=32000000 ! application/x-rtp,encoding-name=VP9 ! rtpjitterbuffer latency=500 ! rtpvp9depay ! video/x-vp9 ! nvv4l2decoder ! nvvidconv ! video/x-raw,width=1920,height=1080 ! fpsdisplaysink video-sink=xvimagesink text-overlay=0 ";

    GstElement *pipeline = gst_parse_launch (pipeline2, NULL);
    if (!pipeline) {
        g_error ("Failed to create pipeline\n");
        exit(-1);
    }

    // This will output changes and is required to display fps in terminal, you may remove it later to make it quiet.
    g_signal_connect(pipeline, "deep-notify", G_CALLBACK(gst_object_default_deep_notify), NULL);

    /* Ok, successfully created the pipeline, now start it */
    gst_element_set_state (pipeline, GST_STATE_READY);
    gst_element_set_state (pipeline, GST_STATE_PLAYING);

    /* wait until it's up and running or failed */
    if (gst_element_get_state (pipeline, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) {
        g_error ("Failed to go into PLAYING state");
        exit(-2);
    }

    g_print ("Running ...\n");
    g_main_loop_run (loop);

    return 0;
}

构建:gcc -Wall -o gst_testlaunch2 -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include gst_testlaunch2.cpp -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0

拥有可用的 4K-H265 RTSP 源,首先gst_testlaunch1在终端中运行,然后gst_testlaunch2在第二个终端中运行,以正确的质量显示图像并保持 30 fps。

于 2022-01-23T21:27:24.877 回答