首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从RTP包中重建图像

从RTP包中重建图像
EN

Stack Overflow用户
提问于 2014-05-26 06:38:10
回答 3查看 3.3K关注 0票数 3

我试图通过网络将用户的网络摄像头流到一个基于C的服务器上。我用过Janus网关

我创建了一个小插件,它很大程度上是基于回声测试演示示例的:我的浏览器通过WebRTC技术连接到我的janus服务器,我让它流给用户的网络摄像头。

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

我已经通过跟踪这个维基百科页面来检查头部,但是我不知道如何从UDP RTP数据包流中重建映像。理想情况下,我希望将流传递给openCV进行实时图像处理。

我听说过gstreamer,但我不明白它是什么,也不知道它如何帮助我;此外,我不知道openCV是否有内置的函数来“重建”图像?我不知道视频帧是以哪种格式编码的:PT (Payload Type)似乎是116,它被定义为“动态”,但我不知道它意味着什么。

有什么帮助吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-05-26 14:52:33

以下是处理SRTP数据包以解码它们的一些指导步骤。

  1. 确保rtp和RTCP不是多路复用的,您可以从SDP中删除该选项
  2. 将SRTP数据包解密为原始RTP,您将需要访问密钥交换(不确定是否已经这样做了,但所有媒体都已加密,密钥使用DTLS交换,必须在处理前解密)。
  3. 获取媒体有效负载类型并将其与SDP中的媒体匹配(您可以从SDP中的RTPMAP中看到什么媒体是什么有效负载)
  4. 从数据包中删除RTP有效负载(Gstreamer有用于大多数常见有效载荷的RtpDepay插件,包括VP8)并对流进行解码。使用快速示例实现命令行管道的vp8
  5. 现在,您可以显示一个原始的视频/音频包。

SDP:

  • 如果RTCP和RTP被复用,您将看到行a=rtcp-mux,您将看到a=rtcp:50111 IN IP4 <address>中的端口和候选媒体端口是相同的。
  • 如果媒体本身正在被复用,您将看到a=group:BUNDLE audio video

SRTP:

  • Janus已经处理了DTLS交换,似乎它在发送之前可能已经对rtp进行了解密,但是它看起来不像是多路复用的rtp/rtcp和媒体。
  • 这里是一个快速而肮脏的SRTP解密器,当您将在DTLS中交换的MasterKey传递给它时,它可以工作。

GStreamer:

  • 您可能需要查看GstAppSrc,它允许您将数组放入gstreamer管道中进行解码,并且可以将其推送到另一个udp端口,以便使用OpenCV获取它。
  • 下面是我编写的websocket服务器上的一些示例代码,它将抓取原始媒体并将其推送到管道中。这个例子并不是您想要做的(它不抓取RTP,而是从网页中获取原始媒体帧),但是它将向您展示如何使用AppSrc。
票数 4
EN

Stack Overflow用户

发布于 2016-07-29 14:24:13

最后,我使用Janus和GStreamer (1.9)完成了这项工作,它遵循了这个帖子中其他人的建议,包括@nschoe ( OP)和@Benjamin Trent。我想,我应该包括我的代码,以使下一个人的生活更轻松,因为我经历了这么多的尝试和错误:

首先,构建/安装GStreamer及其所有需要的插件(在我的设置中,我需要确保GST_PLUGIN_SYSTEM_PATH环境变量中有两个插件目录)。现在,当您的Janus插件初始化( GStreamer回调)时初始化init()

代码语言:javascript
复制
gst_init(NULL, NULL);

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

代码语言:javascript
复制
GstElement *pipeline, *appsrc, *multifilesink;

当创建一个Janus会话(create_session()回调)时,为该会话设置GStreamer管道(在我的例子中,我需要降低帧速率,因此需要视频/capsrate;您可能不需要这些):

代码语言:javascript
复制
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);

当传入的RTP数据包被Janus分解并准备读取(incoming_rtp()回调)时,将其输入到GStreamer管道中:

代码语言:javascript
复制
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_session()回调)时,请确保释放GStreamer资源:

代码语言:javascript
复制
if(session->pipeline) {
    gst_element_set_state(session->pipeline, GST_STATE_NULL);
    gst_object_unref(session->pipeline);
    session->pipeline = NULL;
}
票数 1
EN

Stack Overflow用户

发布于 2014-05-29 09:27:48

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

我在这里有一个twistedcv的现场演示,也有github这里的twistedcv的源代码。但流媒体并不是实时播放的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23864128

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档