Opencv 从RTP数据包重建图像

Opencv 从RTP数据包重建图像,opencv,udp,webrtc,janus-gateway,Opencv,Udp,Webrtc,Janus Gateway,我正在尝试通过网络将用户的网络摄像头传输到基于C的服务器。我用过 我创建了一个小插件,它主要基于echotest演示示例:我让浏览器通过WebRTC技术连接到janus服务器,并让它流式传输用户的网络摄像头 在服务器端,我有janus_incomming_rtp函数,它给我一个char*缓冲区和int长度。经检查,输入的数据缓冲区大约是MTU的长度:我的视频的每一帧都通过几个RTP数据包发送 我已经通过以下方式检查了一点头部,但我不知道如何从UDP RTP数据包流重建图像。理想情况下,我希望将流

我正在尝试通过网络将用户的网络摄像头传输到基于C的服务器。我用过

我创建了一个小插件,它主要基于echotest演示示例:我让浏览器通过WebRTC技术连接到janus服务器,并让它流式传输用户的网络摄像头

在服务器端,我有janus_incomming_rtp函数,它给我一个char*缓冲区和int长度。经检查,输入的数据缓冲区大约是MTU的长度:我的视频的每一帧都通过几个RTP数据包发送

我已经通过以下方式检查了一点头部,但我不知道如何从UDP RTP数据包流重建图像。理想情况下,我希望将流传递给openCV以进行实时图像处理

我听说过gstreamer,但我不明白它是什么,也不知道它如何帮助我;此外,我不知道openCV是否有任何内置函数来“重建”图像?我不知道视频帧的编码格式是什么:PT(有效负载类型)似乎是116,定义为“动态”,但我不知道这是什么意思


有什么帮助吗?

以下是一些处理SRTP数据包并对其进行解码的指导步骤

  • 确保rtp和RTCP没有多路复用,您可以
  • 将SRTP数据包解密为原始RTP,您将需要访问密钥交换(不确定您是否已经这样做,但所有媒体都已加密,密钥交换使用DTL,并且必须在处理之前解密)
  • 获取您的介质负载类型,并将其与SDP中的介质进行匹配(您可以从SDP中的RTPMAP中看到什么介质是什么负载)
  • 从数据包中删除RTP有效负载(Gstreamer具有用于大多数常见有效负载的RtpDepay插件,包括VP8)并解码流。使用vp8创建命令行管道
  • 现在您有了可以显示的原始视频/音频数据包
  • SDP:

    • 如果RTCP和RTP被多路复用,您将看到该行
      a=rtcp mux
      您将看到IP4中
      a=rtcp:50111中的端口
      是一个快速而肮脏的SRTP解密程序,当您将DTL中交换的主密钥传递给它时,它就会工作
    GStreamer:

    • 你可能想调查一下 它允许您将数组字符化到gstreamer管道中,以便 解码后,您可以将其推送到另一个udp端口以使用 OpenCV
    • 这里有一些 从我编写的websocket服务器上,可以抓取原始媒体并推送它 连接到管道。这个例子并不完全是你想要做的(它) 不获取RTP,而是从网页获取原始媒体帧) 但它将向您展示如何使用AppSrc

    以下是处理SRTP数据包以对其进行解码的一些指导步骤

  • 确保rtp和RTCP没有多路复用,您可以
  • 将SRTP数据包解密为原始RTP,您将需要访问密钥交换(不确定您是否已经这样做,但所有媒体都已加密,密钥交换使用DTL,并且必须在处理之前解密)
  • 获取您的介质负载类型,并将其与SDP中的介质进行匹配(您可以从SDP中的RTPMAP中看到什么介质是什么负载)
  • 从数据包中删除RTP有效负载(Gstreamer具有用于大多数常见有效负载的RtpDepay插件,包括VP8)并解码流。使用vp8创建命令行管道
  • 现在您有了可以显示的原始视频/音频数据包
  • SDP:

    • 如果RTCP和RTP被多路复用,您将看到该行
      a=rtcp mux
      您将看到IP4中
      a=rtcp:50111中的端口
      是一个快速而肮脏的SRTP解密程序,当您将DTL中交换的主密钥传递给它时,它就会工作
    GStreamer:

    • 你可能想调查一下 它允许您将数组字符化到gstreamer管道中,以便 解码后,您可以将其推送到另一个udp端口以使用 OpenCV
    • 这里有一些 从我编写的websocket服务器上,可以抓取原始媒体并推送它 连接到管道。这个例子并不完全是你想要做的(它) 不获取RTP,而是从网页获取原始媒体帧) 但它将向您展示如何使用AppSrc

    我们对WebRTC的流媒体传输也有同样的担忧。我所做的是将视频帧发送到WebSocket服务器,然后使用imdecode()对图像缓冲区进行解码

    我在这里有一个现场演示,也在github中托管了源代码。
    但是流媒体不是实时的。

    我们对WebRTC的流媒体也有同样的担忧。我所做的是将视频帧发送到WebSocket服务器,然后使用imdecode()对图像缓冲区进行解码

    我在这里有一个现场演示,也在github中托管了源代码。
    但是流媒体不是实时的。

    我最终使用Janus和GStreamer(1.9)按照其他人的建议完成了这项工作,包括@nschoe(OP)和@Benjamin Trent。我想我会加入我的代码,让下一个出现的人的生活更轻松,因为我经历了这么多的尝试和错误:

    首先构建/安装GStreamer及其所有需要的插件(对于我的设置,我需要确保GST\u plugin\u SYSTEM\u PATH环境变量中有两个插件目录)。现在在Janus插件初始化时初始化GStreamer(
    init()
    callback):

    对于每个WebRTC会话,您需要保留一些GStreamer句柄,因此将以下内容添加到Janus plugin会话结构中:

    GstElement *pipeline, *appsrc, *multifilesink;
    
    创建Janus插件会话时(
    create_session()
    callback),为该会话设置GStreamer管道(在我的情况下,我需要降低帧速率,从而降低视频速率/capsrate;您可能不需要这些):

    当传入RTP数据包被Janus解复用并准备好读取时,(
    incoming_RTP()
    callback),将其馈送到GStreamer管道:

    if(video && session->video_active) {
        // Send to GStreamer
        guchar* temp = NULL;
        temp = (guchar*)malloc(len);
        memcpy(temp, buf, len);
    
        GstBuffer*  buffer = gst_buffer_new_wrapped_full(0, temp, len, 0, len, temp, g_free);
        gst_app_src_push_buffer(GST_APP_SRC(session->appsrc), buffer);
    }
    
    最后,当Janus插件会话结束时(
    destroy_
    
    GstElement *conv, *vp8depay, *vp8dec, *videorate, *capsrate, *pngenc;
    
    session->pipeline = gst_pipeline_new("pipeline");
    
    session->appsrc         = gst_element_factory_make("appsrc", "source");
    vp8depay                = gst_element_factory_make("rtpvp8depay", NULL);
    vp8dec                  = gst_element_factory_make("vp8dec", NULL);
    videorate               = gst_element_factory_make("videorate", NULL);
    capsrate                = gst_element_factory_make("capsfilter", NULL);
    conv                    = gst_element_factory_make("videoconvert", "conv");
    pngenc                  = gst_element_factory_make("pngenc", NULL);
    session->multifilesink  = gst_element_factory_make("multifilesink", NULL);
    
    GstCaps* capsRate = gst_caps_new_simple("video/x-raw", "framerate", GST_TYPE_FRACTION, 15, 1, NULL);
    g_object_set(capsrate, "caps", capsRate, NULL);
    gst_caps_unref(capsRate);
    
    GstCaps* caps = gst_caps_new_simple ("application/x-rtp",
                     "media", G_TYPE_STRING, "video",
                     "encoding-name", G_TYPE_STRING, "VP8-DRAFT-IETF-01",
                     "payload", G_TYPE_INT, 96,
                     "clock-rate", G_TYPE_INT, 90000,
                     NULL);
    g_object_set(G_OBJECT (session->appsrc), "caps", caps, NULL);
    gst_caps_unref(caps);
    
    gst_bin_add_many(GST_BIN(session->pipeline), session->appsrc, vp8depay, vp8dec, conv, videorate, capsrate, pngenc, session->multifilesink, NULL);
    gst_element_link_many(session->appsrc, vp8depay, vp8dec, conv, videorate, capsrate, pngenc, session->multifilesink, NULL);
    
    // Setup appsrc
    g_object_set(G_OBJECT (session->appsrc), "stream-type", 0, NULL);
    g_object_set(G_OBJECT (session->appsrc), "format", GST_FORMAT_TIME, NULL);
    g_object_set(G_OBJECT (session->appsrc), "is-live", TRUE, NULL);
    g_object_set(G_OBJECT (session->appsrc), "do-timestamp", TRUE, NULL);
    
    g_object_set(session->multifilesink, "location", "/blah/some/dir/output-%d.png", NULL);
    gst_element_set_state(session->pipeline, GST_STATE_PLAYING);
    
    if(video && session->video_active) {
        // Send to GStreamer
        guchar* temp = NULL;
        temp = (guchar*)malloc(len);
        memcpy(temp, buf, len);
    
        GstBuffer*  buffer = gst_buffer_new_wrapped_full(0, temp, len, 0, len, temp, g_free);
        gst_app_src_push_buffer(GST_APP_SRC(session->appsrc), buffer);
    }
    
    if(session->pipeline) {
        gst_element_set_state(session->pipeline, GST_STATE_NULL);
        gst_object_unref(session->pipeline);
        session->pipeline = NULL;
    }