使用jrtplib打包发送h264数据,关使用vlc|mplayer播放

http://blog.csdn.net/xyyangkun/article/details/20453051?utm_source=tuicool&utm_medium=referral

前段时间写了个测试程序,使用jrtplib,把h264打成标准的rtp数据包,并能通过vlc,mpalyer等播放器播放出来。这中间主要的难点是解析h264数据中的nal单元,并把nal单元打成rtp包,之后的事情都是jrtplib库做了。然后就可以通过播放器播放出来了。

使用播放器播放时使用以下命令:

mplayer player.sdp

或者

用vlc打开player.sdp

对于rtp打包不懂的同学,可以仔细看下这个包里面的文档和一个rtp打包的代码,这是我上传的资源。

http://download.csdn.net/detail/xyyangkun/6990313

主要的代码贴出来:

[cpp]  view plain  copy
 
  1. /* 
  2.  * test_jrtp.cpp 
  3.  * 
  4.  *  Created on: 2014-2-19 
  5.  *      Author: xy 
  6.  */  
  7.   
  8. #include "rtpsession.h"  
  9. #include "rtpsessionparams.h"  
  10. #include "rtpudpv4transmitter.h"  
  11. #include "rtpipv4address.h"  
  12. #include "rtptimeutilities.h"  
  13. #include "rtppacket.h"  
  14. #include   
  15. #include   
  16. #include "h264.h"  
  17. #define SSRC           100  
  18.   
  19. #define DEST_IP_STR   "127.0.0.1"  
  20. #define DEST_PORT     9000  
  21. #define BASE_PORT     2222  
  22.   
  23. using namespace jrtplib;  
  24.   
  25. int main(int argc, char** argv)  
  26. {  
  27.     RTPSession session;  
  28.   
  29.     RTPSessionParams sessionparams;  
  30.     sessionparams.SetOwnTimestampUnit(1.0/90000.0);  
  31.   
  32.     RTPUDPv4TransmissionParams transparams;  
  33.     transparams.SetPortbase(8000);  
  34.   
  35.     int status = session.Create(sessionparams,&transparams);  
  36.     if (status < 0)  
  37.     {  
  38.         std::cerr << RTPGetErrorString(status) << std::endl;  
  39.         exit(-1);  
  40.     }  
  41.   
  42.     uint8_t localip[]={127,0,0,1};  
  43.     RTPIPv4Address addr(localip,9000);  
  44.   
  45.     status = session.AddDestination(addr);  
  46.     if (status < 0)  
  47.     {  
  48.         std::cerr << RTPGetErrorString(status) << std::endl;  
  49.         exit(-1);  
  50.     }  
  51.   
  52.     session.SetDefaultPayloadType(96);  
  53.     session.SetDefaultMark(false);  
  54.     session.SetDefaultTimestampIncrement(90000.0 /25.0);  
  55.   
  56.   
  57.   
  58.   
  59.     RTPTime delay(0.040);  
  60.     RTPTime starttime = RTPTime::CurrentTime();  
  61.   
  62.   
  63.   
  64.     NALU_HEADER     *nalu_hdr;  
  65.     FU_INDICATOR    *fu_ind;  
  66.     FU_HEADER       *fu_hdr;  
  67.     char sendbuf[1500];  
  68.     char* nalu_payload;  
  69.     unsigned int timestamp_increse=0,ts_current=0;  
  70.   
  71. #define ddd  
  72.     //OpenBitstreamFile("agnt.264");//打开264文件,并将文件指针赋给bits,在此修改文件名实现打开别的264文件。  
  73.     OpenBitstreamFile("1.264");//打开264文件,并将文件指针赋给bits,在此修改文件名实现打开别的264文件。  
  74.     //OpenBitstreamFile("test.264");//打开264文件,并将文件指针赋给bits,在此修改文件名实现打开别的264文件。  
  75.     //OpenBitstreamFile("slamtv60.264");//打开264文件,并将文件指针赋给bits,在此修改文件名实现打开别的264文件。  
  76.     //OpenBitstreamFile("avc.h264");//打开264文件,并将文件指针赋给bits,在此修改文件名实现打开别的264文件。  
  77.     NALU_t *n;  
  78.     n = AllocNALU(8000000);//为结构体nalu_t及其成员buf分配空间。返回值为指向nalu_t存储空间的指针  
  79.     bool start=false;  
  80.     while(!feof(bits))  
  81.     {  
  82.         int size=GetAnnexbNALU(n);//每执行一次,文件的指针指向本次找到的NALU的末尾,下一个位置即为下个NALU的起始码0x000001  
  83.         if(size<4)  
  84.         {  
  85.             printf("get nul error!\n");  
  86.             continue;  
  87.         }  
  88.         dump(n);//输出NALU长度和TYPE  
  89.         if(!start)  
  90.         {  
  91.             if(n->nal_unit_type==5||n->nal_unit_type==6||  
  92.                     n->nal_unit_type==7||n->nal_unit_type==7)  
  93.             {  
  94.                 printf("begin\n");  
  95.                 start=true;  
  96.             }  
  97.         }  
  98.         //将编码数据写入文件t  
  99.         //fwrite(pNals[i].p_payload, 1, pNals[i].i_payload, pFile);  
  100.         //发送编码文件  
  101. #if 1  
  102.         //  当一个NALU小于MAX_RTP_PKT_LENGTH字节的时候,采用一个单RTP包发送  
  103.             if(n->len<=MAX_RTP_PKT_LENGTH)  
  104.             {  
  105.                 //printf("ddd0\n");  
  106.                 //session.SetDefaultMark(false);  
  107.                 //设置NALU HEADER,并将这个HEADER填入sendbuf[12]  
  108.                 nalu_hdr =(NALU_HEADER*)&sendbuf[0]; //将sendbuf[12]的地址赋给nalu_hdr,之后对nalu_hdr的写入就将写入sendbuf中;  
  109.                 nalu_hdr->F=n->forbidden_bit;  
  110.                 nalu_hdr->NRI=n->nal_reference_idc>>5;//有效数据在n->nal_reference_idc的第6,7位,需要右移5位才能将其值赋给nalu_hdr->NRI。  
  111.                 nalu_hdr->TYPE=n->nal_unit_type;  
  112.   
  113.                 nalu_payload=&sendbuf[1];//同理将sendbuf[13]赋给nalu_payload  
  114.                 memcpy(nalu_payload,n->buf+1,n->len-1);//去掉nalu头的nalu剩余内容写入sendbuf[13]开始的字符串。  
  115.                 ts_current=ts_current+timestamp_increse;  
  116.   
  117.                 //status = session.SendPacket((void *)sendbuf,n->len);  
  118.                 if(n->nal_unit_type==1 || n->nal_unit_type==5)  
  119.                 {  
  120.                     status = session.SendPacket((void *)sendbuf,n->len,96,true,3600);  
  121.                 }  
  122.                 else  
  123.                 {  
  124.                         status = session.SendPacket((void *)sendbuf,n->len,96,true,0);\  
  125.                         //如果是6,7类型的包,不应该延时;之前有停顿,原因这在这  
  126.                         continue;  
  127.                 }  
  128.                 //发送RTP格式数据包并指定负载类型为96  
  129.                 if (status < 0)  
  130.                 {  
  131.                     std::cerr << RTPGetErrorString(status) << std::endl;  
  132.                     exit(-1);  
  133.                 }  
  134.   
  135.             }  
  136.             else if(n->len>MAX_RTP_PKT_LENGTH)  
  137.             {  
  138.                 //得到该nalu需要用多少长度为MAX_RTP_PKT_LENGTH字节的RTP包来发送  
  139.                 int k=0,l=0;  
  140.                 k=n->len/MAX_RTP_PKT_LENGTH;//需要k个MAX_RTP_PKT_LENGTH字节的RTP包  
  141.                 l=n->len%MAX_RTP_PKT_LENGTH;//最后一个RTP包的需要装载的字节数  
  142.                 int t=0;//用于指示当前发送的是第几个分片RTP包  
  143.                 ts_current=ts_current+timestamp_increse;  
  144.                 while(t<=k)  
  145.                 {  
  146.   
  147.                     if(!t)//发送一个需要分片的NALU的第一个分片,置FU HEADER的S位  
  148.                     {  
  149.                         //printf("dddd1");  
  150.                         memset(sendbuf,0,1500);  
  151.                         //session.SetDefaultMark(false);  
  152.                         //设置FU INDICATOR,并将这个HEADER填入sendbuf[12]  
  153.                         fu_ind =(FU_INDICATOR*)&sendbuf[0]; //将sendbuf[12]的地址赋给fu_ind,之后对fu_ind的写入就将写入sendbuf中;  
  154.                         fu_ind->F=n->forbidden_bit;  
  155.                         fu_ind->NRI=n->nal_reference_idc>>5;  
  156.                         fu_ind->TYPE=28;  
  157.   
  158.                         //设置FU HEADER,并将这个HEADER填入sendbuf[13]  
  159.                         fu_hdr =(FU_HEADER*)&sendbuf[1];  
  160.                         fu_hdr->E=0;  
  161.                         fu_hdr->R=0;  
  162.                         fu_hdr->S=1;  
  163.                         fu_hdr->TYPE=n->nal_unit_type;  
  164.   
  165.   
  166.                         nalu_payload=&sendbuf[2];//同理将sendbuf[14]赋给nalu_payload  
  167.                         memcpy(nalu_payload,n->buf+1,MAX_RTP_PKT_LENGTH);//去掉NALU头  
  168.   
  169.                         //status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2);  
  170.                         status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2,96,false,0);  
  171.                         if (status < 0)  
  172.                         {  
  173.                             std::cerr << RTPGetErrorString(status) << std::endl;  
  174.                             exit(-1);  
  175.                         }  
  176.                         t++;  
  177.                     }  
  178.                     //发送一个需要分片的NALU的非第一个分片,清零FU HEADER的S位,如果该分片是该NALU的最后一个分片,置FU HEADER的E位  
  179.                     else if(k==t)//发送的是最后一个分片,注意最后一个分片的长度可能超过MAX_RTP_PKT_LENGTH字节(当l>1386时)。  
  180.                     {  
  181.                         //printf("dddd3\n");  
  182.                         memset(sendbuf,0,1500);  
  183.                         //session.SetDefaultMark(true);  
  184.                         //设置FU INDICATOR,并将这个HEADER填入sendbuf[12]  
  185.                         fu_ind =(FU_INDICATOR*)&sendbuf[0]; //将sendbuf[12]的地址赋给fu_ind,之后对fu_ind的写入就将写入sendbuf中;  
  186.                         fu_ind->F=n->forbidden_bit;  
  187.                         fu_ind->NRI=n->nal_reference_idc>>5;  
  188.                         fu_ind->TYPE=28;  
  189.   
  190.                         //设置FU HEADER,并将这个HEADER填入sendbuf[13]  
  191.                         fu_hdr =(FU_HEADER*)&sendbuf[1];  
  192.                         fu_hdr->R=0;  
  193.                         fu_hdr->S=0;  
  194.                         fu_hdr->TYPE=n->nal_unit_type;  
  195.                         fu_hdr->E=1;  
  196.                         nalu_payload=&sendbuf[2];//同理将sendbuf[14]赋给nalu_payload  
  197.                         memcpy(nalu_payload,n->buf+t*MAX_RTP_PKT_LENGTH+1,l-1);//将nalu最后剩余的l-1(去掉了一个字节的NALU头)字节内容写入sendbuf[14]开始的字符串。  
  198.   
  199.                         //status = session.SendPacket((void *)sendbuf,l+1);  
  200.                         status = session.SendPacket((void *)sendbuf,l+1,96,true,3600);  
  201.                         if (status < 0)  
  202.                         {  
  203.                             std::cerr << RTPGetErrorString(status) << std::endl;  
  204.                             exit(-1);  
  205.                         }  
  206.                         t++;  
  207.                     //  Sleep(100);  
  208.                     }  
  209.                     else if(t
  210.                     {  
  211.                         //printf("dddd2");  
  212.                         memset(sendbuf,0,1500);  
  213.                         //session.SetDefaultMark(false);  
  214.                         //设置FU INDICATOR,并将这个HEADER填入sendbuf[12]  
  215.                         fu_ind =(FU_INDICATOR*)&sendbuf[0]; //将sendbuf[12]的地址赋给fu_ind,之后对fu_ind的写入就将写入sendbuf中;  
  216.                         fu_ind->F=n->forbidden_bit;  
  217.                         fu_ind->NRI=n->nal_reference_idc>>5;  
  218.                         fu_ind->TYPE=28;  
  219.   
  220.                         //设置FU HEADER,并将这个HEADER填入sendbuf[13]  
  221.                         fu_hdr =(FU_HEADER*)&sendbuf[1];  
  222.                         //fu_hdr->E=0;  
  223.                         fu_hdr->R=0;  
  224.                         fu_hdr->S=0;  
  225.                         fu_hdr->E=0;  
  226.                         fu_hdr->TYPE=n->nal_unit_type;  
  227.   
  228.                         nalu_payload=&sendbuf[2];//同理将sendbuf[14]的地址赋给nalu_payload  
  229.                         memcpy(nalu_payload,n->buf+t*MAX_RTP_PKT_LENGTH+1,MAX_RTP_PKT_LENGTH);//去掉起始前缀的nalu剩余内容写入sendbuf[14]开始的字符串。  
  230.   
  231.                         //status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2);  
  232.                         status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2,96,false,0);  
  233.                         if (status < 0)  
  234.                         {  
  235.                             std::cerr << RTPGetErrorString(status) << std::endl;  
  236.                             exit(-1);  
  237.                         }  
  238.                         t++;  
  239.                     }  
  240.                 }  
  241.             }  
  242.   
  243. #endif  
  244.   
  245. #if 0  
  246.         session.BeginDataAccess();  
  247.         if (session.GotoFirstSource())  
  248.         {  
  249.             do  
  250.             {  
  251.                 RTPPacket *packet;  
  252.   
  253.                 while ((packet = session.GetNextPacket()) != 0)  
  254.                 {  
  255.                     std::cout << "Got packet with "  
  256.                               << "extended sequence number "  
  257.                               << packet->GetExtendedSequenceNumber()  
  258.                               << " from SSRC " << packet->GetSSRC()  
  259.                               << std::endl;  
  260.                     session.DeletePacket(packet);  
  261.                 }  
  262.             } while (session.GotoNextSource());  
  263.         }  
  264.         session.EndDataAccess();  
  265. #endif  
  266.         RTPTime::Wait(delay);  
  267.   
  268.         RTPTime t = RTPTime::CurrentTime();  
  269.         t -= starttime;  
  270.         if (t > RTPTime(60.0))  
  271.             break;  
  272.     }  
  273.     printf("over\n");  
  274.     delay = RTPTime(10.0);  
  275.     session.BYEDestroy(delay,"Time's up",9);  
  276.   
  277.   
  278.     //一些清理工作…  
  279. }  

这些代码等所用到提到的全部东西都上传到了我的github中,大家可以到这找到我的完整的工程。

https://github.com/xyyangkun/test_jrtp.git

你可能感兴趣的:(嵌入式)