zoukankan      html  css  js  c++  java
  • 基于JRTPLib的rtp编程例程

    这里演示了在linux环境下使用JRTPlib库完成rtp协议的封装,此例程可以作为流媒体传输的基本例程。

    这里只给出源码(这些在JRtplib的官方文件中都可以找到)

    发送端:

    /*
    * 发送端程序(windows,linux通用)
    * 基于IPv4的传输例程,需要提供一个端口号和目的地址
    * 参考:http://blog.csdn.net/ipromiseu/article/details/4531656
    */
    #include "rtpsession.h" //定义了rtpsession的一些实现
    #include "rtppacket.h" //定义了rtppacket数据包
    #include "rtpudpv4transmitter.h"//定义了RTPSession的第二个参数类 
    #include "rtpipv4address.h"//定义了rtpipv4address 
    #include "rtpsessionparams.h"//定义了rtpsession的第一个参数类
    #include "rtperrors.h" //定义了RTP中的错误信息 
    #ifndef WIN32
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #else
    #include <winsock2.h>
    #endif // WIN32
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include <string>

    //检查是否出现rtp错误,如果出错就打印出错信息
    void checkerror(int rtperr)
    {
    if (rtperr < 0)
    {
    std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
    exit(-1);
    }
    }

    //主循环
    int main(void)
    {
    //windows环境下我们需要首次加载套接字
    #ifdef WIN32
    WSADATA dat;
    WSAStartup(MAKEWORD(2,2),&dat);
    #endif // WIN32

    RTPSession sess;
    //RTPSession类来实例化此次的RTP会话
    uint16_t portbase,destport;
    //本机端口号,目的端口号
    uint32_t destip;
    //目的IP
    std::string ipstr;
    int status,i,num;

    //首先获得必须的信息 
    std::cout << "Enter local portbase:" << std::endl;
    std::cin >> portbase;
    std::cout << std::endl;

    std::cout << "Enter the destination IP address" << std::endl;
    std::cin >> ipstr;
    destip = inet_addr(ipstr.c_str());
    if (destip == INADDR_NONE)
    {
    std::cerr << "Bad IP address specified" << std::endl;
    return -1;
    }

    //inet_addr返回一个基于网络字节序列,我们需要的是一个基于本机字节序列的,
    //还需要使用ntohl
    destip = ntohl(destip);

    std::cout << "Enter the destination port" << std::endl;
    std::cin >> destport;

    std::cout << std::endl;
    std::cout << "Number of packets you wish to be sent:" << std::endl;
    std::cin >> num;

    //下面创建一个RTP会话,发送传入的数据包
    //这是rtpsession的第二个参数类,他的成员函数可以设定监听端口
    RTPUDPv4TransmissionParams transparams;
    //这是rtpsession的第一个参数类,他的成员函数可以设置恰当的时戳单元
    RTPSessionParams sessparams;


    //设置恰当的时戳单元,每秒我们需要发送10次,故参数为1.0/10
    sessparams.SetOwnTimestampUnit(1.0/10.0); 
    //下面设置是不是接收我们自定义的数据包,这里选是
    sessparams.SetAcceptOwnPackets(true);
    //设置本机端口
    transparams.SetPortbase(portbase);
    //初始化,创建rtp会话
    status = sess.Create(sessparams,&transparams); 
    checkerror(status);
    //组合目的地址
    RTPIPv4Address addr(destip,destport);
    //设置目的地址,增加发送的目的地址。当然可以增加很多地址完成多播的功能
    //另外还可以使用DeleteDestination()和 ClearDestinations()来删除和清楚目的地址
    //也可以写成: unsigned long addr = ntohl(inet_addr("127.0.0.1"));
    // sess.AddDestination(addr,6000);
    status = sess.AddDestination(addr);
    checkerror(status);

    for (i = 1 ; i <= num ; i++)
    {
    printf("\nSending packet %d/%d\n",i,num);

    //发送流媒体数据.第一个参数是发送的数据,二个是数据长度,往后是rtp负载类型,标识,时戳量
    //当然JRTPLIB允许将他们设置成会话的默认参数,这是调用RTPSession类的setDefaultpayloadtype(),setDefaultmark,等方法类完成的,如果那样设置之后,我们可以这样来发送数据:
    //status = sess.SendPacket((void *)"1234567890",10);
    status = sess.SendPacket((void *)"1234567890",10,0,false,10);
    checkerror(status);

    /*
    sess.BeginDataAccess();
    //收到的报文,遍历所有携带数据的源(因为一个rtp会话允许有多个参与者(源))
    if (sess.GotoFirstSourceWithData())
    {
    do
    {
    RTPPacket *pack;

    while ((pack = sess.GetNextPacket()) != NULL)
    {
    // You can examine the data here
    printf("Got packet !\n");

    // we don't longer need the packet, so
    // we'll delete it
    sess.DeletePacket(pack);
    }
    } while (sess.GotoNextSourceWithData());
    }

    sess.EndDataAccess();
    */

    #ifndef RTP_SUPPORT_THREAD
    status = sess.Poll();
    checkerror(status);
    #endif // RTP_SUPPORT_THREAD

    RTPTime::Wait(RTPTime(1,0));
    }

    sess.BYEDestroy(RTPTime(10,0),0,0);
    //windows环境下我们最后还有卸载套接字
    #ifdef WIN32
    WSACleanup();
    #endif // WIN32
    return 0;
    }
    接收端:

    /*
    * JRTPLIB接收数据例程
    * http://blog.sina.com.cn/s/blog_57e2e18901008s4h.html
    */

    #include "rtpsession.h"
    #include "rtppacket.h"
    #include "rtpudpv4transmitter.h"
    #include "rtpipv4address.h"
    #include "rtpsessionparams.h"
    #include "rtperrors.h"
    #ifndef WIN32
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #else
    #include <winsock2.h>
    #endif // WIN32
    #include "rtpsourcedata.h"
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include <string>

    //检查错误
    void checkerror(int rtperr)
    {
    if (rtperr < 0)
    {
    std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
    exit(-1);
    }
    }

    //重新封装一个类
    class MyRTPSession : public RTPSession
    {
    protected:
    void OnNewSource(RTPSourceData *dat)
    {
    if (dat->IsOwnSSRC())
    return;

    uint32_t ip;
    uint16_t port;

    if (dat->GetRTPDataAddress() != 0)
    {
    const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
    ip = addr->GetIP();
    port = addr->GetPort();
    }
    else if (dat->GetRTCPDataAddress() != 0)
    {
    const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
    ip = addr->GetIP();
    port = addr->GetPort()-1;
    }
    else
    return;

    RTPIPv4Address dest(ip,port);
    AddDestination(dest);

    struct in_addr inaddr;
    inaddr.s_addr = htonl(ip);
    std::cout << "Adding destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
    }

    void OnBYEPacket(RTPSourceData *dat)
    {
    if (dat->IsOwnSSRC())
    return;

    uint32_t ip;
    uint16_t port;

    if (dat->GetRTPDataAddress() != 0)
    {
    const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
    ip = addr->GetIP();
    port = addr->GetPort();
    }
    else if (dat->GetRTCPDataAddress() != 0)
    {
    const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
    ip = addr->GetIP();
    port = addr->GetPort()-1;
    }
    else
    return;

    RTPIPv4Address dest(ip,port);
    DeleteDestination(dest);

    struct in_addr inaddr;
    inaddr.s_addr = htonl(ip);
    std::cout << "Deleting destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
    }

    void OnRemoveSource(RTPSourceData *dat)
    {
    if (dat->IsOwnSSRC())
    return;
    if (dat->ReceivedBYE())
    return;

    uint32_t ip;
    uint16_t port;

    if (dat->GetRTPDataAddress() != 0)
    {
    const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
    ip = addr->GetIP();
    port = addr->GetPort();
    }
    else if (dat->GetRTCPDataAddress() != 0)
    {
    const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
    ip = addr->GetIP();
    port = addr->GetPort()-1;
    }
    else
    return;

    RTPIPv4Address dest(ip,port);
    DeleteDestination(dest);

    struct in_addr inaddr;
    inaddr.s_addr = htonl(ip);
    std::cout << "Deleting destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
    }
    };

    //
    // The main routine
    // 

    int main(void)
    {
    #ifdef WIN32
    WSADATA dat;
    WSAStartup(MAKEWORD(2,2),&dat);
    #endif // WIN32

    MyRTPSession sess;
    uint16_t portbase;
    std::string ipstr;
    int status,i,num;

    unsigned char *payloadpointer;
    int j,len;
    // First, we'll ask for the necessary information

    std::cout << "Enter local portbase:" << std::endl;
    std::cin >> portbase;
    std::cout << std::endl;

    std::cout << std::endl;
    std::cout << "Number of seconds you wish to wait:" << std::endl;
    std::cin >> num;


    RTPUDPv4TransmissionParams transparams;
    RTPSessionParams sessparams;

    // IMPORTANT: The local timestamp unit MUST be set, otherwise
    // RTCP Sender Report info will be calculated wrong
    // In this case, we'll be just use 8000 samples per second.
    sessparams.SetOwnTimestampUnit(1.0/8000.0); 

    sessparams.SetAcceptOwnPackets(true);
    transparams.SetPortbase(portbase);
    status = sess.Create(sessparams,&transparams); 
    checkerror(status);

    for (i = 1 ; i <= num ; i++)
    {
    sess.BeginDataAccess();

    //遍历所有的带数据的源
    if (sess.GotoFirstSourceWithData())
    {
    do
    {
    RTPPacket *pack;

    while ((pack = sess.GetNextPacket()) != NULL)
    {
    // You can examine the data here
    printf("Got packet !\n");
    payloadpointer = pack->GetPayloadData();//获得数据指针
    len = pack->GetPayloadLength();//获得数据长度

    for(j=0;j<len;j++)
    {
    printf("%c ",*(payloadpointer+j));//打印数据
    }

    printf("\n");
    //删除获得的数据
    sess.DeletePacket(pack);
    }
    } while (sess.GotoNextSourceWithData());
    }

    sess.EndDataAccess();

    #ifndef RTP_SUPPORT_THREAD
    status = sess.Poll();
    checkerror(status);
    #endif // RTP_SUPPORT_THREAD

    RTPTime::Wait(RTPTime(1,0));
    }

    sess.BYEDestroy(RTPTime(10,0),0,0);

    #ifdef WIN32
    WSACleanup();
    #endif // WIN32
    return 0;
    }

    编译:g++ -o example1 example1.cpp -I /usr/local/include/jrtplib3/ -ljrtp

  • 相关阅读:
    Mysql常用函数总结(二)
    mysql百万的数据快速创建索引
    php 中的sprintf 坑
    php5.5之后新特性整理
    mysql实践总结
    php下载远程图片到本地
    搜藏一个php文件上传类
    Attribute基本介绍
    Fiddler4抓包工具使用教程一
    HTTP传输数据压缩
  • 原文地址:https://www.cnblogs.com/tuotuteng/p/3852928.html
Copyright © 2011-2022 走看看