RTP解包

同前篇类似,修改自vc下的程序,跟打包相反,原理就是从udp接收一个数据包,判断这个数据包是单个发送还是分片发送,进而获取rtp包中的h264NAL数据,并加上0x00000001起始字节一并写进文件中即可。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. #include <stdlib.h>  
  4.   
  5. #include <string.h>  
  6.   
  7. #include <sys/socket.h>  
  8.   
  9. #include <netinet/in.h>  
  10. #include <arpa/inet.h>  
  11.   
  12. #include <unistd.h>  
  13.   
  14. #include <errno.h>  
  15.   
  16. #include <sys/types.h>  
  17.   
  18. #include <fcntl.h>  
  19.   
  20. typedef struct  
  21. {  
  22.     unsigned char version;              //!< Version, 2 bits, MUST be 0x2  
  23.     unsigned char padding;              //!< Padding bit, Padding MUST NOT be used  
  24.     unsigned char extension;            //!< Extension, MUST be zero  
  25.     unsigned char cc;                   //!< CSRC count, normally 0 in the absence of RTP mixers           
  26.     unsigned char marker;               //!< Marker bit  
  27.     unsigned char pt;                   //!< 7 bits, Payload Type, dynamically established  
  28.     unsigned int seq_no;                //!< RTP sequence number, incremented by one for each sent packet   
  29.     unsigned int timestamp;        //!< timestamp, 27 MHz for H.264  
  30.     unsigned int ssrc;             //!< Synchronization Source, chosen randomly  
  31.     unsigned char * payload;      //!< the payload including payload headers  
  32.     unsigned int paylen;           //!< length of payload in bytes  
  33. } RTPpacket_t;  
  34.   
  35. typedef struct   
  36. {  
  37.     /*  0                   1                   2                   3 
  38.     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
  39.     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
  40.     |V=2|P|X|  CC   |M|     PT      |       sequence number         | 
  41.     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
  42.     |                           timestamp                           | 
  43.     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
  44.     |           synchronization source (SSRC) identifier            | 
  45.     +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 
  46.     |            contributing source (CSRC) identifiers             | 
  47.     |                             ....                              | 
  48.     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
  49.     */  
  50.     //intel 的cpu 是intel为小端字节序(低端存到底地址) 而网络流为大端字节序(高端存到低地址)  
  51.     /*intel 的cpu : 高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端 
  52.      在内存中存储 : 
  53.      低->4001(内存地址)version:2 
  54.          4002(内存地址)padding:1 
  55.          4003(内存地址)extension:1 
  56.      高->4004(内存地址)csrc_len:4 
  57.  
  58.      网络传输解析 : 高端->version:2->padding:1->extension:1->csrc_len:4->低端  (为正确的文档描述格式) 
  59.  
  60.      存入接收内存 : 
  61.      低->4001(内存地址)version:2 
  62.          4002(内存地址)padding:1 
  63.          4003(内存地址)extension:1 
  64.      高->4004(内存地址)csrc_len:4 
  65.      本地内存解析 :高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端 , 
  66.      即: 
  67.      unsigned char csrc_len:4;        // expect 0  
  68.      unsigned char extension:1;       // expect 1 
  69.      unsigned char padding:1;         // expect 0  
  70.      unsigned char version:2;         // expect 2  
  71.     */  
  72.     /* byte 0 */  
  73.      unsigned char csrc_len:4;        /* expect 0 */  
  74.      unsigned char extension:1;       /* expect 1, see RTP_OP below */  
  75.      unsigned char padding:1;         /* expect 0 */  
  76.      unsigned char version:2;         /* expect 2 */  
  77.     /* byte 1 */  
  78.      unsigned char payloadtype:7;     /* RTP_PAYLOAD_RTSP */  
  79.      unsigned char marker:1;          /* expect 1 */  
  80.     /* bytes 2,3 */  
  81.      unsigned int seq_no;              
  82.     /* bytes 4-7 */  
  83.      unsigned int timestamp;          
  84.     /* bytes 8-11 */  
  85.      unsigned int ssrc;              /* stream number is used here. */  
  86. } RTP_FIXED_HEADER;  
  87.   
  88.   
  89. typedef struct  
  90. {  
  91.     unsigned char forbidden_bit;           //! Should always be FALSE  
  92.     unsigned char nal_reference_idc;       //! NALU_PRIORITY_xxxx  
  93.     unsigned char nal_unit_type;           //! NALU_TYPE_xxxx    
  94.     unsigned int startcodeprefix_len;      //! 前缀字节数  
  95.     unsigned int len;                      //! 包含nal 头的nal 长度,从第一个00000001到下一个000000001的长度  
  96.     unsigned int max_size;                 //! 做多一个nal 的长度  
  97.     unsigned char * buf;                   //! 包含nal 头的nal 数据  
  98.     unsigned int lost_packets;             //! 预留  
  99. } NALU_t;  
  100.   
  101. /* 
  102. +---------------+ 
  103. |0|1|2|3|4|5|6|7| 
  104. +-+-+-+-+-+-+-+-+ 
  105. |F|NRI|  Type   | 
  106. +---------------+ 
  107. */  
  108. typedef struct   
  109. {  
  110.     //byte 0  
  111.     unsigned char TYPE:5;  
  112.     unsigned char NRI:2;  
  113.     unsigned char F:1;          
  114. } NALU_HEADER; // 1 BYTE   
  115.   
  116. /* 
  117. +---------------+ 
  118. |0|1|2|3|4|5|6|7| 
  119. +-+-+-+-+-+-+-+-+ 
  120. |F|NRI|  Type   | 
  121. +---------------+ 
  122. */  
  123. typedef struct   
  124. {  
  125.     //byte 0  
  126.     unsigned char TYPE:5;  
  127.     unsigned char NRI:2;   
  128.     unsigned char F:1;                
  129. } FU_INDICATOR; // 1 BYTE   
  130.   
  131. /* 
  132. +---------------+ 
  133. |0|1|2|3|4|5|6|7| 
  134. +-+-+-+-+-+-+-+-+ 
  135. |S|E|R|  Type   | 
  136. +---------------+ 
  137. */  
  138. typedef struct   
  139. {  
  140.     //byte 0  
  141.     unsigned char TYPE:5;  
  142.     unsigned char R:1;  
  143.     unsigned char E:1;  
  144.     unsigned char S:1;      
  145. } FU_HEADER;   // 1 BYTES   
  146.   
  147. #define  MAXDATASIZE 1500  
  148. #define PORT    1234  
  149. #define BUFFER_SIZE 10  
  150.   
  151. FILE * poutfile =  NULL;      
  152.   
  153. char * outputfilename = "./receive.264";  
  154.   
  155. int  OpenBitstreamFile (char *fn)  
  156. {  
  157.     if (NULL == (poutfile = fopen(fn, "wb")))  
  158.     {  
  159.         printf("Error: Open input file error\n");  
  160.         getchar();  
  161.     }  
  162.     return 1;  
  163. }  
  164.   
  165. NALU_t *AllocNALU(int buffersize)  
  166. {  
  167.     NALU_t *n;  
  168.   
  169.     if ((n = (NALU_t*)calloc (1, sizeof(NALU_t))) == NULL)  
  170.     {  
  171.         printf("AllocNALU Error: Allocate Meory To NALU_t Failed ");  
  172.         exit(0);  
  173.     }  
  174.     return n;  
  175. }  
  176.   
  177. void FreeNALU(NALU_t *n)  
  178. {  
  179.     if (n)  
  180.     {  
  181.         free (n);  
  182.     }  
  183. }  
  184.   
  185. /* 
  186. *bufIn:rtppackage 
  187. *len: the lengthe of rtppackage 
  188. */  
  189. void rtp_unpackage(char *bufIn,int len)  
  190. {  
  191.     unsigned char recvbuf[1500];  
  192.     RTPpacket_t *p = NULL;   
  193.     RTP_FIXED_HEADER * rtp_hdr = NULL;  
  194.     NALU_HEADER * nalu_hdr = NULL;  
  195.     NALU_t * n  = NULL;  
  196.     FU_INDICATOR    *fu_ind = NULL;  
  197.     FU_HEADER       *fu_hdr= NULL;  
  198.     int total_bytes = 0;                 //当前包传出的数据  
  199.     static int total_recved = 0;         //一共传输的数据  
  200.     int fwrite_number = 0;               //存入文件的数据长度  
  201.   
  202.     memcpy(recvbuf,bufIn, len);          //复制rtp包   
  203.     printf("包长度+ rtp头:   = %d\n",len);  
  204.   
  205.     //  
  206.     //begin rtp_payload and rtp_header  
  207.   
  208.     p = (RTPpacket_t*)&recvbuf[0];  
  209.     if ((p = malloc (sizeof (RTPpacket_t)))== NULL)  
  210.     {  
  211.         printf ("RTPpacket_t MMEMORY ERROR\n");  
  212.     }  
  213.     if ((p->payload = malloc (MAXDATASIZE))== NULL)  
  214.     {  
  215.         printf ("RTPpacket_t payload MMEMORY ERROR\n");  
  216.     }  
  217.   
  218.     if ((rtp_hdr = malloc(sizeof(RTP_FIXED_HEADER))) == NULL)  
  219.     {  
  220.         printf("RTP_FIXED_HEADER MEMORY ERROR\n");  
  221.     }  
  222.       
  223.     rtp_hdr =(RTP_FIXED_HEADER*)&recvbuf[0];   
  224.     printf("版本号     : %d\n",rtp_hdr->version);  
  225.     p->version  = rtp_hdr->version;  
  226.     p->padding  = rtp_hdr->padding;  
  227.     p->extension  = rtp_hdr->extension;  
  228.     p->cc = rtp_hdr->csrc_len;  
  229.     printf("标志位     : %d\n",rtp_hdr->marker);  
  230.     p->marker = rtp_hdr->marker;  
  231.     printf("负载类型    :%d\n",rtp_hdr->payloadtype);  
  232.     p->pt = rtp_hdr->payloadtype;  
  233.     printf("包号      : %d \n",rtp_hdr->seq_no);  
  234.     p->seq_no = rtp_hdr->seq_no;  
  235.     printf("时间戳     : %d\n",rtp_hdr->timestamp);  
  236.     p->timestamp = rtp_hdr->timestamp;  
  237.     printf("帧号      : %d\n",rtp_hdr->ssrc);  
  238.     p->ssrc = rtp_hdr->ssrc;  
  239.       
  240.     //end rtp_payload and rtp_header  
  241.     //  
  242.     //begin nal_hdr  
  243.     if (!(n = AllocNALU(800000)))          //为结构体nalu_t及其成员buf分配空间。返回值为指向nalu_t存储空间的指针  
  244.     {  
  245.         printf("NALU_t MMEMORY ERROR\n");  
  246.     }  
  247.     if ((nalu_hdr = malloc(sizeof(NALU_HEADER))) == NULL)  
  248.     {  
  249.         printf("NALU_HEADER MEMORY ERROR\n");  
  250.     }  
  251.   
  252.     nalu_hdr =(NALU_HEADER*)&recvbuf[12];                        //网络传输过来的字节序 ,当存入内存还是和文档描述的相反,只要匹配网络字节序和文档描述即可传输正确。  
  253.     printf("forbidden_zero_bit: %d\n",nalu_hdr->F);              //网络传输中的方式为:F->NRI->TYPE.. 内存中存储方式为 TYPE->NRI->F (和nal头匹配)。  
  254.     n->forbidden_bit= nalu_hdr->F << 7;                          //内存中的字节序。  
  255.     printf("nal_reference_idc:  %d\n",nalu_hdr->NRI);  
  256.     n->nal_reference_idc = nalu_hdr->NRI << 5;                        
  257.     printf("nal 负载类型:       %d\n",nalu_hdr->TYPE);  
  258.     n->nal_unit_type = nalu_hdr->TYPE;  
  259.   
  260.     //end nal_hdr  
  261.     //  
  262.     //开始解包  
  263.     if ( nalu_hdr->TYPE  == 0)  
  264.     {  
  265.         printf("这个包有错误,0无定义\n");  
  266.     }  
  267.     else if ( nalu_hdr->TYPE >0 &&  nalu_hdr->TYPE < 24)  //单包  
  268.     {  
  269.         printf("当前包为单包\n");  
  270.         putc(0x00, poutfile);  
  271.         putc(0x00, poutfile);  
  272.         putc(0x00, poutfile);  
  273.         putc(0x01, poutfile);   //写进起始字节0x00000001  
  274.         total_bytes +=4;  
  275.         memcpy(p->payload,&recvbuf[13],len-13);    
  276.         p->paylen = len-13;  
  277.         fwrite(nalu_hdr,1,1,poutfile);  //写NAL_HEADER  
  278.         total_bytes += 1;  
  279.         fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);  //写NAL数据  
  280.         total_bytes = p->paylen;  
  281.         printf("包长度 + nal= %d\n",total_bytes);  
  282.     }  
  283.     else if ( nalu_hdr->TYPE == 24)                    //STAP-A   单一时间的组合包  
  284.     {  
  285.         printf("当前包为STAP-A\n");  
  286.     }  
  287.     else if ( nalu_hdr->TYPE == 25)                    //STAP-B   单一时间的组合包  
  288.     {  
  289.         printf("当前包为STAP-B\n");  
  290.     }  
  291.     else if (nalu_hdr->TYPE == 26)                     //MTAP16   多个时间的组合包  
  292.     {  
  293.         printf("当前包为MTAP16\n");  
  294.     }  
  295.     else if ( nalu_hdr->TYPE == 27)                    //MTAP24   多个时间的组合包  
  296.     {  
  297.         printf("当前包为MTAP24\n");  
  298.     }  
  299.      else if ( nalu_hdr->TYPE == 28)                    //FU-A分片包,解码顺序和传输顺序相同  
  300.     {  
  301.         if ((fu_ind = malloc(sizeof(FU_INDICATOR))) == NULL)  
  302.         {  
  303.             printf("FU_INDICATOR MEMORY ERROR\n");  
  304.         }  
  305.         if ((fu_hdr = malloc(sizeof(FU_HEADER))) == NULL)  
  306.         {  
  307.             printf("FU_HEADER MEMORY ERROR\n");  
  308.         }  
  309.   
  310.         fu_ind=(FU_INDICATOR*)&recvbuf[12];     //分片包用的是FU_INDICATOR而不是NALU_HEADER  
  311.         printf("FU_INDICATOR->F     :%d\n",fu_ind->F);  
  312.         n->forbidden_bit = fu_ind->F << 7;  
  313.         printf("FU_INDICATOR->NRI   :%d\n",fu_ind->NRI);  
  314.         n->nal_reference_idc = fu_ind->NRI << 5;                        
  315.         printf("FU_INDICATOR->TYPE  :%d\n",fu_ind->TYPE);  
  316.         n->nal_unit_type = fu_ind->TYPE;  
  317.   
  318.         fu_hdr=(FU_HEADER*)&recvbuf[13];        //FU_HEADER赋值  
  319.         printf("FU_HEADER->S        :%d\n",fu_hdr->S);  
  320.         printf("FU_HEADER->E        :%d\n",fu_hdr->E);  
  321.         printf("FU_HEADER->R        :%d\n",fu_hdr->R);  
  322.         printf("FU_HEADER->TYPE     :%d\n",fu_hdr->TYPE);  
  323.         n->nal_unit_type = fu_hdr->TYPE;               //应用的是FU_HEADER的TYPE  
  324.   
  325.         if (rtp_hdr->marker == 1)                      //分片包最后一个包  
  326.         {  
  327.             printf("当前包为FU-A分片包最后一个包\n");  
  328.             memcpy(p->payload,&recvbuf[14],len - 14);  
  329.             p->paylen = len - 14;  
  330.             fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);  //写NAL数据  
  331.             total_bytes = p->paylen;  
  332.             printf("包长度 + FU = %d\n",total_bytes);    
  333.         }  
  334.         else if (rtp_hdr->marker == 0)                 //分片包 但不是最后一个包  
  335.         {  
  336.             if (fu_hdr->S == 1)                        //分片的第一个包  
  337.             {  
  338.                 unsigned char F;  
  339.                 unsigned char NRI;  
  340.                 unsigned char TYPE;  
  341.                 unsigned char nh;  
  342.                 printf("当前包为FU-A分片包第一个包\n");  
  343.                 putc(0x00, poutfile);  
  344.                 putc(0x00, poutfile);  
  345.                 putc(0x00, poutfile);  
  346.                 putc(0x01, poutfile);               //写起始字节码0x00000001  
  347.                 total_bytes += 4;  
  348.                   
  349.                 F = fu_ind->F << 7;  
  350.                 NRI = fu_ind->NRI << 5;  
  351.                 TYPE = fu_hdr->TYPE;                                            //应用的是FU_HEADER的TYPE  
  352.                 //nh = n->forbidden_bit|n->nal_reference_idc|n->nal_unit_type;  //二进制文件也是按 大字节序存储  
  353.                 nh = F | NRI | TYPE;  
  354.   
  355.                 putc(nh,poutfile);              //写NAL HEADER  
  356.   
  357.                 total_bytes +=1;  
  358.                 memcpy(p->payload,&recvbuf[14],len - 14);  
  359.                 p->paylen = len - 14;  
  360.                 fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);  //写NAL数据  
  361.                 total_bytes = p->paylen;  
  362.                 printf("包长度 + FU_First = %d\n",total_bytes);      
  363.             }  
  364.             else                                      //如果不是第一个包  
  365.             {  
  366.                 printf("当前包为FU-A分片包\n");  
  367.                 memcpy(p->payload,&recvbuf[14],len - 14);  
  368.                 p->paylen= len - 14;  
  369.                 fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);  //写NAL数据  
  370.                 total_bytes = p->paylen;  
  371.                 printf("包长度 + FU = %d\n",total_bytes);    
  372.             }     
  373.         }  
  374.     }  
  375.     else if ( nalu_hdr->TYPE == 29)                //FU-B分片包,解码顺序和传输顺序相同  
  376.     {  
  377.         if (rtp_hdr->marker == 1)                  //分片包最后一个包  
  378.         {  
  379.             printf("当前包为FU-B分片包最后一个包\n");  
  380.   
  381.         }  
  382.         else if (rtp_hdr->marker == 0)             //分片包 但不是最后一个包  
  383.         {  
  384.             printf("当前包为FU-B分片包\n");  
  385.         }  
  386.     }  
  387.     else  
  388.     {  
  389.         printf("这个包有错误,30-31 没有定义\n");  
  390.     }  
  391.     total_recved += total_bytes;  
  392.     printf("total_recved = %d\n",total_recved);  
  393.     memset(recvbuf,0,1500);  
  394.     free (p->payload);  
  395.     free (p);  
  396.     FreeNALU(n);  
  397.     //结束解包  
  398.     //  
  399.     return ;  
  400. }  
  401.   
  402.   
  403. int main()  
  404. {  
  405.     char recvbuf[MAXDATASIZE];  //加上头最大传输数据 1500  
  406.     int sockfd;    
  407.     int client_fd;    
  408.     int sin_size;    
  409.     char sendbuf[BUFFER_SIZE];  
  410.     struct sockaddr_in server_sockaddr, client_sockaddr;    
  411.   
  412.     int receive_bytes = 0;  
  413.   
  414.     OpenBitstreamFile(outputfilename);   
  415.       
  416.     //  
  417.     //socket 操作  
  418.       
  419.     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)  
  420.     {  
  421.         perror("socket");  
  422.         exit(1);  
  423.     }//建立socket链接,数据报socket,IPv4协议  
  424.     printf("create socket success!\n");  
  425.   
  426.     server_sockaddr.sin_family = AF_INET;    
  427.     server_sockaddr.sin_addr.s_addr = INADDR_ANY;//0.0.0.0不确定地址    
  428.     server_sockaddr.sin_port = htons(PORT);    
  429.     bzero(&(server_sockaddr.sin_zero), 8);  //填充0以保持与struct sockaddr同样大小  
  430.   
  431.     if (bind(sockfd, (struct sockaddr *) &server_sockaddr,    
  432.           sizeof(struct sockaddr)) < 0)     
  433.     {  
  434.         perror("ERROR on binding");  
  435.         exit(1);   
  436.     }   
  437.     printf("bind success!\n");  
  438.   
  439.     sin_size = sizeof(struct sockaddr_in);  
  440.     printf("waiting for client connection...\n");  
  441.     //接收从客户端发来的数据  
  442.     while((receive_bytes = recvfrom(sockfd, recvbuf, MAXDATASIZE, 0, (struct sockaddr *)&client_sockaddr, &sin_size)) >0)  
  443.     {  
  444.         if(strncmp(recvbuf, "over",4) == 0)  
  445.   
  446.         {  
  447.   
  448.             break;  
  449.   
  450.         }  
  451.         poutfile = fopen(outputfilename,"ab+");  
  452.         rtp_unpackage(recvbuf,receive_bytes);  
  453.         fclose(poutfile);  
  454.     }  
  455.     strcpy(sendbuf, "success");  
  456.     sendto( sockfd, sendbuf, BUFFER_SIZE, 0 ,(struct sockaddr *)&client_sockaddr, sin_size);  
  457.     close(client_fd);  
  458.     close(sockfd);  
  459.     return 0;  
  460. }  
因为这里用的是recvfrom,因此将上一篇的打包发送中socket的send修改成sendto即可。还有一点是udp发送的速度很快,这里因为要将数据写进文件中,速度肯定没有接受数据快,因此在打包发送端每发送完一个rtp数据包延迟一段时间才行,这里我延时了10ms。
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值