Live555用作标准的RTP发送和接收库

live555很多人用来做rtsp server或者rtsp client,其实也可以单独用作通用的rtp库。笔者就是对其进行稍作封装,命名为CRtpRecevier和CRtpSender类。这样就可应付很多rtp处理。

封装后基本可以一劳永逸的移植到各个平台上使用。live555支持的payload type比较全面。各种流行的媒体rtp封装都支持,不需要自己进行分帧和特殊处理,省很多事情。
代码性能和延时都有保证。音视频可小于80毫秒。

1. 用作rtp接收,可以参考我以前的博文
发送的核心逻辑是构造媒体的sdp字符串,然后live555内部会分析这个文本创建不同的解析类实例
Live555通过SDP文本信息实现对RTP的接收

2.用作rtp发送,基本逻辑如下

a. 构建一个数据源类
我这里命名为ByteStreamQueueBufferSource
实现一个以队列为数据源的通用类, 从FramedSource派生,可供其他类使用,用作音视频直播的数据源。
注意,该类参考live555原有的类ByteStreamMemoryBufferSource和ByteStreamFileSource的实现.
注意ByteStreamMemoryBufferSource内部不可以用阻塞算法,不然多个rtp发送就不流畅了。

b.构造发送逻辑
以下以音频为例子,构造发送rtp逻辑。对于h264视频也是类似的,就是ByteStreamQueueBufferSource还要增加一个H264VideoStreamFramer分析类处理rtp分包逻辑。

bool CRtpSender::CreatePcmRtpSink(int chanNum,  int sampleRate)
{
    UsageEnvironment&  env = envir();

    frame_source_ = ByteStreamQueueBufferSource::createNew(env, 0, 0, 0);//frame_source_为FramedSource*

    if(frame_source_ == NULL)
    {
        RTP_LOGE("ByteStreamQueueBufferSource::createNew failed\n");
        return false;
    }

   


    struct in_addr dummyDestAddress;

    dummyDestAddress.s_addr = remote_ip_;//远程IPV4地址,网络字节序
    Groupsock *rtpGroupsock = new Groupsock(env, dummyDestAddress, local_port_, 0);//local_port_本地端口,主机字节序
#ifdef ENABLE_RTCP_SEND
    Groupsock *rtcpGroupsock = new Groupsock(env, dummyDestAddress, local_port_ + 1, 0);
#endif



    Port destPort(remote_port_);//remote_port_为目的rtp端口
    rtpGroupsock->changeDestinationParameters(dummyDestAddress, destPort, ~0);
#ifdef ENABLE_RTCP_SEND
    Port destRtcpPort(remote_port_ + 1);
    rtcpGroupsock->changeDestinationParameters(dummyDestAddress, destRtcpPort, ~0);
#endif
  rtp_sink_ = SimpleRTPSink::createNew(env, rtpGroupsock,
                    payload_type_, sampleRate,
                    "audio", (mime_type_ == MT_PCMU ? "PCMU" : "PCMA"), 1, False/*每个包一个rtp*/);
   
    if(rtp_sink_ == NULL)
    {
        RTP_LOGE("SimpleRTPSink::createNew failed\n");
        delete rtpGroupsock;
#ifdef ENABLE_RTCP_SEND
        delete rtcpGroupsock;
#endif
        return false;
    }

#ifdef ENABLE_RTCP_SEND
    unsigned char CNAME[32];
    sprintf((char*)CNAME, "HTTEC_RTP_%d", remote_port_ % 1000);

    const unsigned estimatedSessionBandwidthVideo = 128; // in kbps; for RTCP b/w share
    rtcp_inst_ = RTCPInstance::createNew(env, rtcpGroupsock,
        estimatedSessionBandwidthVideo, CNAME,
        rtp_sink_, NULL /* we're a server */);

    if(rtcp_inst_ == NULL)
    {
        RTP_LOGE("RTCPInstance::createNew failed\n");
        Medium::close(rtp_sink_);
        rtp_sink_ = NULL;
        delete rtpGroupsock;
        delete rtcpGroupsock;
        return false;
    }
    sock_rtcp_ = rtcpGroupsock;
#endif

    sock_rtp_ = rtpGroupsock;

    RTP_LOGD("CreatePcmRtpSink ok \n");
   

    return true;
}

回复

你的邮件地址不会被公开(Your email address will not be published.) Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>