首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用Live555从记录的RTSP会话(pcap)接收多播RTP流(包含多个子会话)

使用Live555从记录的RTSP会话(pcap)接收多播RTP流(包含多个子会话)
EN

Stack Overflow用户
提问于 2020-11-26 01:33:21
回答 1查看 125关注 0票数 1

我必须实现一个RTSP客户端,它连接到现有的RTSP会话,而不能向RTSP服务器发送命令(recvonly)。

为了模拟这样的环境,我使用Wireshark录制了testH264VideoStreamer和Live555中的testRTSPClient示例之间的RTSP/RTP流,并使用tcpreplay回放,同时尝试使用修改后的testRTSPClient版本接收流数据。

我还将testH264VideoStreamer提供的SDP信息存储为SDP文件。

代码语言:javascript
运行
复制
v=0
o=- 1606317166144671 1 IN IP4 192.168.3.92
s=Session streamed by "testH264VideoStreamer"
i=test.264
t=0 0
a=tool:LIVE555 Streaming Media v2020.10.16
a=type:broadcast
a=control:*
a=source-filter: incl IN IP4 * 192.168.3.92
a=rtcp-unicast: reflection
a=range:npt=0-
a=x-qt-text-nam:Session streamed by "testH264VideoStreamer"
a=x-qt-text-inf:test.264
m=video 18888 RTP/AVP 96
c=IN IP4 232.42.39.62/255
b=AS:500
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-$
a=control:track1
^@

我已经修改了testRTSPClient示例,以便它只使用SDP File中的数据连接到RTP流。

下面是我用来初始化的两个函数。

代码语言:javascript
运行
复制
void openSDP(UsageEnvironment& env, char const* sdpFile)
{
    const char * rtspURL = "rtsp://192.168.3.92:8554/testStream/";

    RTSPClient* rtspClient = ourRTSPClient::createNew(env, rtspURL, RTSP_CLIENT_VERBOSITY_LEVEL);

    if(rtspClient == NULL)
    {
        env << "Failed to create a RTSP client for URL \"" << rtspURL << "\": " << env.getResultMsg();
        return;
    }
    else
    {
        env << "Connecting to the stream at " << rtspURL;
    }

    StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias

    std::vector<char> sdpBuffer;

    std::ifstream file(sdpFile, std::ios_base::in | std::ios_base::binary);
    file.unsetf(std::ios::skipws);

    std::streampos fileSize;
    file.seekg(0, std::ios::end);
    fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    sdpBuffer.reserve(fileSize);
    sdpBuffer.insert(sdpBuffer.begin(),
                     std::istream_iterator<unsigned char>(file),
                     std::istream_iterator<unsigned char>());

    char* const sdpDescription = sdpBuffer.data();

    // Create a media session object from this SDP description:
    scs.session = MediaSession::createNew(env, sdpDescription);

    if(scs.session == NULL)
    {
        env << *rtspClient << "Failed to create a MediaSession object from the SDP description: " << env.getResultMsg() << "\n";
    }
    else
        if(!scs.session->hasSubsessions())
        {
            env << *rtspClient << "This session has no media subsessions (i.e., no \"m=\" lines)\n";
        }

    scs.iter = new MediaSubsessionIterator(*scs.session);
    setupNextSubsession(rtspClient);
    return;
}

void setupNextSubsession(RTSPClient* rtspClient)
{
    UsageEnvironment& env = rtspClient->envir(); // alias
    StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias

    scs.subsession = scs.iter->next();
    if(scs.subsession != NULL)
    {
        if(!scs.subsession->initiate())
        {
            env << "Failed to initiate the subsession: " << env.getResultMsg();
            setupNextSubsession(rtspClient); // give up on this subsession; go to the next one
        }
        else
        {
            env << "Initiated the subsession:";

            if(scs.subsession->rtcpIsMuxed())
            {
                env << "client port " << scs.subsession->clientPortNum();
            }
            else
            {
                env << "client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1;
            }

            scs.subsession->sink = DummySink::createNew(env,
                                                       *scs.subsession,
                                                       rtspClient->url());

            // perhaps use your own custom "MediaSink" subclass instead
            if(scs.subsession->sink == NULL)
            {
                env << "Failed to create a data sink for the subsession: " << env.getResultMsg();
            }

            env << "Created a data sink for the subsession";

            scs.subsession->miscPtr = rtspClient; // a hack to let subsession handler functions get the "RTSPClient" from the subsession
            scs.subsession->sink->startPlaying(*(scs.subsession->readSource()),
                                               subsessionAfterPlaying, scs.subsession);
            // Also set a handler to be called if a RTCP "BYE" arrives for this subsession:
            if(scs.subsession->rtcpInstance() != NULL)
            {
                scs.subsession->rtcpInstance()->setByeWithReasonHandler(subsessionByeHandler, scs.subsession);
            }

            // Set up the next subsession, if any:
            setupNextSubsession(rtspClient);
        }
    }
}

一切初始化都没有错误,但是DummySink没有收到任何数据。有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-11-28 00:12:27

我发现,尽管wireshark向我显示了具有有效校验和的传入数据包,但udp端口没有收到数据包。

我试着遵循命令(像sudo一样)来避免内核丢弃包,但它们在Debian Buster上根本没有帮助。

代码语言:javascript
运行
复制
sysctl net.ipv4.conf.eth0.rp_filter=0
sysctl net.ipv4.conf.all.rp_filter=0
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter
sysctl -a | grep "\.rp_filter" | awk '{print $1 "=0"}' | xargs sysctl

基本上,我已经结束了从另一台计算机流式传输pcap文件,现在我能够接收NALU。

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

https://stackoverflow.com/questions/65009916

复制
相关文章

相似问题

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