H264 RTP解包 111
来源:互联网 发布:人生到处知何似 编辑:程序博客网 时间:2024/06/07 16:32
同前篇类似,修改自vc下的程序,跟打包相反,原理就是从udp接收一个数据包,判断这个数据包是单个发送还是分片发送,进而获取rtp包中的h264NAL数据,并加上0x00000001起始字节一并写进文件中即可。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <fcntl.h>
- typedef struct
- {
- unsigned char version; //!< Version, 2 bits, MUST be 0x2
- unsigned char padding; //!< Padding bit, Padding MUST NOT be used
- unsigned char extension; //!< Extension, MUST be zero
- unsigned char cc; //!< CSRC count, normally 0 in the absence of RTP mixers
- unsigned char marker; //!< Marker bit
- unsigned char pt; //!< 7 bits, Payload Type, dynamically established
- unsigned int seq_no; //!< RTP sequence number, incremented by one for each sent packet
- unsigned int timestamp; //!< timestamp, 27 MHz for H.264
- unsigned int ssrc; //!< Synchronization Source, chosen randomly
- unsigned char * payload; //!< the payload including payload headers
- unsigned int paylen; //!< length of payload in bytes
- } RTPpacket_t;
- typedef struct
- {
- /* 0 1 2 3
- 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
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |V=2|P|X| CC |M| PT | sequence number |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | timestamp |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | synchronization source (SSRC) identifier |
- +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- | contributing source (CSRC) identifiers |
- | .... |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- //intel 的cpu 是intel为小端字节序(低端存到底地址) 而网络流为大端字节序(高端存到低地址)
- /*intel 的cpu : 高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端
- 在内存中存储 :
- 低->4001(内存地址)version:2
- 4002(内存地址)padding:1
- 4003(内存地址)extension:1
- 高->4004(内存地址)csrc_len:4
- 网络传输解析 : 高端->version:2->padding:1->extension:1->csrc_len:4->低端 (为正确的文档描述格式)
- 存入接收内存 :
- 低->4001(内存地址)version:2
- 4002(内存地址)padding:1
- 4003(内存地址)extension:1
- 高->4004(内存地址)csrc_len:4
- 本地内存解析 :高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端 ,
- 即:
- unsigned char csrc_len:4; // expect 0
- unsigned char extension:1; // expect 1
- unsigned char padding:1; // expect 0
- unsigned char version:2; // expect 2
- */
- /* byte 0 */
- unsigned char csrc_len:4; /* expect 0 */
- unsigned char extension:1; /* expect 1, see RTP_OP below */
- unsigned char padding:1; /* expect 0 */
- unsigned char version:2; /* expect 2 */
- /* byte 1 */
- unsigned char payloadtype:7; /* RTP_PAYLOAD_RTSP */
- unsigned char marker:1; /* expect 1 */
- /* bytes 2,3 */
- unsigned int seq_no;
- /* bytes 4-7 */
- unsigned int timestamp;
- /* bytes 8-11 */
- unsigned int ssrc; /* stream number is used here. */
- } RTP_FIXED_HEADER;
- typedef struct
- {
- unsigned char forbidden_bit; //! Should always be FALSE
- unsigned char nal_reference_idc; //! NALU_PRIORITY_xxxx
- unsigned char nal_unit_type; //! NALU_TYPE_xxxx
- unsigned int startcodeprefix_len; //! 前缀字节数
- unsigned int len; //! 包含nal 头的nal 长度,从第一个00000001到下一个000000001的长度
- unsigned int max_size; //! 做多一个nal 的长度
- unsigned char * buf; //! 包含nal 头的nal 数据
- unsigned int lost_packets; //! 预留
- } NALU_t;
- /*
- +---------------+
- |0|1|2|3|4|5|6|7|
- +-+-+-+-+-+-+-+-+
- |F|NRI| Type |
- +---------------+
- */
- typedef struct
- {
- //byte 0
- unsigned char TYPE:5;
- unsigned char NRI:2;
- unsigned char F:1;
- } NALU_HEADER; // 1 BYTE
- /*
- +---------------+
- |0|1|2|3|4|5|6|7|
- +-+-+-+-+-+-+-+-+
- |F|NRI| Type |
- +---------------+
- */
- typedef struct
- {
- //byte 0
- unsigned char TYPE:5;
- unsigned char NRI:2;
- unsigned char F:1;
- } FU_INDICATOR; // 1 BYTE
- /*
- +---------------+
- |0|1|2|3|4|5|6|7|
- +-+-+-+-+-+-+-+-+
- |S|E|R| Type |
- +---------------+
- */
- typedef struct
- {
- //byte 0
- unsigned char TYPE:5;
- unsigned char R:1;
- unsigned char E:1;
- unsigned char S:1;
- } FU_HEADER; // 1 BYTES
- #define MAXDATASIZE 1500
- #define PORT 1234
- #define BUFFER_SIZE 10
- FILE * poutfile = NULL;
- char * outputfilename = "./receive.264";
- int OpenBitstreamFile (char *fn)
- {
- if (NULL == (poutfile = fopen(fn, "wb")))
- {
- printf("Error: Open input file error\n");
- getchar();
- }
- return 1;
- }
- NALU_t *AllocNALU(int buffersize)
- {
- NALU_t *n;
- if ((n = (NALU_t*)calloc (1, sizeof(NALU_t))) == NULL)
- {
- printf("AllocNALU Error: Allocate Meory To NALU_t Failed ");
- exit(0);
- }
- return n;
- }
- void FreeNALU(NALU_t *n)
- {
- if (n)
- {
- free (n);
- }
- }
- /*
- *bufIn:rtppackage
- *len: the lengthe of rtppackage
- */
- void rtp_unpackage(char *bufIn,int len)
- {
- unsigned char recvbuf[1500];
- RTPpacket_t *p = NULL;
- RTP_FIXED_HEADER * rtp_hdr = NULL;
- NALU_HEADER * nalu_hdr = NULL;
- NALU_t * n = NULL;
- FU_INDICATOR *fu_ind = NULL;
- FU_HEADER *fu_hdr= NULL;
- int total_bytes = 0; //当前包传出的数据
- static int total_recved = 0; //一共传输的数据
- int fwrite_number = 0; //存入文件的数据长度
- memcpy(recvbuf,bufIn, len); //复制rtp包
- printf("包长度+ rtp头: = %d\n",len);
- //////////////////////////////////////////////////////////////////////////
- //begin rtp_payload and rtp_header
- p = (RTPpacket_t*)&recvbuf[0];
- if ((p = malloc (sizeof (RTPpacket_t)))== NULL)
- {
- printf ("RTPpacket_t MMEMORY ERROR\n");
- }
- if ((p->payload = malloc (MAXDATASIZE))== NULL)
- {
- printf ("RTPpacket_t payload MMEMORY ERROR\n");
- }
- if ((rtp_hdr = malloc(sizeof(RTP_FIXED_HEADER))) == NULL)
- {
- printf("RTP_FIXED_HEADER MEMORY ERROR\n");
- }
- rtp_hdr =(RTP_FIXED_HEADER*)&recvbuf[0];
- printf("版本号 : %d\n",rtp_hdr->version);
- p->version = rtp_hdr->version;
- p->padding = rtp_hdr->padding;
- p->extension = rtp_hdr->extension;
- p->cc = rtp_hdr->csrc_len;
- printf("标志位 : %d\n",rtp_hdr->marker);
- p->marker = rtp_hdr->marker;
- printf("负载类型 :%d\n",rtp_hdr->payloadtype);
- p->pt = rtp_hdr->payloadtype;
- printf("包号 : %d \n",rtp_hdr->seq_no);
- p->seq_no = rtp_hdr->seq_no;
- printf("时间戳 : %d\n",rtp_hdr->timestamp);
- p->timestamp = rtp_hdr->timestamp;
- printf("帧号 : %d\n",rtp_hdr->ssrc);
- p->ssrc = rtp_hdr->ssrc;
- //end rtp_payload and rtp_header
- //////////////////////////////////////////////////////////////////////////
- //begin nal_hdr
- if (!(n = AllocNALU(800000))) //为结构体nalu_t及其成员buf分配空间。返回值为指向nalu_t存储空间的指针
- {
- printf("NALU_t MMEMORY ERROR\n");
- }
- if ((nalu_hdr = malloc(sizeof(NALU_HEADER))) == NULL)
- {
- printf("NALU_HEADER MEMORY ERROR\n");
- }
- nalu_hdr =(NALU_HEADER*)&recvbuf[12]; //网络传输过来的字节序 ,当存入内存还是和文档描述的相反,只要匹配网络字节序和文档描述即可传输正确。
- printf("forbidden_zero_bit: %d\n",nalu_hdr->F); //网络传输中的方式为:F->NRI->TYPE.. 内存中存储方式为 TYPE->NRI->F (和nal头匹配)。
- n->forbidden_bit= nalu_hdr->F << 7; //内存中的字节序。
- printf("nal_reference_idc: %d\n",nalu_hdr->NRI);
- n->nal_reference_idc = nalu_hdr->NRI << 5;
- printf("nal 负载类型: %d\n",nalu_hdr->TYPE);
- n->nal_unit_type = nalu_hdr->TYPE;
- //end nal_hdr
- //////////////////////////////////////////////////////////////////////////
- //开始解包
- if ( nalu_hdr->TYPE == 0)
- {
- printf("这个包有错误,0无定义\n");
- }
- else if ( nalu_hdr->TYPE >0 && nalu_hdr->TYPE < 24) //单包
- {
- printf("当前包为单包\n");
- putc(0x00, poutfile);
- putc(0x00, poutfile);
- putc(0x00, poutfile);
- putc(0x01, poutfile); //写进起始字节0x00000001
- total_bytes +=4;
- memcpy(p->payload,&recvbuf[13],len-13);
- p->paylen = len-13;
- fwrite(nalu_hdr,1,1,poutfile); //写NAL_HEADER
- total_bytes += 1;
- fwrite_number = fwrite(p->payload,1,p->paylen,poutfile); //写NAL数据
- total_bytes = p->paylen;
- printf("包长度 + nal= %d\n",total_bytes);
- }
- else if ( nalu_hdr->TYPE == 24) //STAP-A 单一时间的组合包
- {
- printf("当前包为STAP-A\n");
- }
- else if ( nalu_hdr->TYPE == 25) //STAP-B 单一时间的组合包
- {
- printf("当前包为STAP-B\n");
- }
- else if (nalu_hdr->TYPE == 26) //MTAP16 多个时间的组合包
- {
- printf("当前包为MTAP16\n");
- }
- else if ( nalu_hdr->TYPE == 27) //MTAP24 多个时间的组合包
- {
- printf("当前包为MTAP24\n");
- }
- else if ( nalu_hdr->TYPE == 28) //FU-A分片包,解码顺序和传输顺序相同
- {
- if ((fu_ind = malloc(sizeof(FU_INDICATOR))) == NULL)
- {
- printf("FU_INDICATOR MEMORY ERROR\n");
- }
- if ((fu_hdr = malloc(sizeof(FU_HEADER))) == NULL)
- {
- printf("FU_HEADER MEMORY ERROR\n");
- }
- fu_ind=(FU_INDICATOR*)&recvbuf[12]; //分片包用的是FU_INDICATOR而不是NALU_HEADER
- printf("FU_INDICATOR->F :%d\n",fu_ind->F);
- n->forbidden_bit = fu_ind->F << 7;
- printf("FU_INDICATOR->NRI :%d\n",fu_ind->NRI);
- n->nal_reference_idc = fu_ind->NRI << 5;
- printf("FU_INDICATOR->TYPE :%d\n",fu_ind->TYPE);
- n->nal_unit_type = fu_ind->TYPE;
- fu_hdr=(FU_HEADER*)&recvbuf[13]; //FU_HEADER赋值
- printf("FU_HEADER->S :%d\n",fu_hdr->S);
- printf("FU_HEADER->E :%d\n",fu_hdr->E);
- printf("FU_HEADER->R :%d\n",fu_hdr->R);
- printf("FU_HEADER->TYPE :%d\n",fu_hdr->TYPE);
- n->nal_unit_type = fu_hdr->TYPE; //应用的是FU_HEADER的TYPE
- if (rtp_hdr->marker == 1) //分片包最后一个包
- {
- printf("当前包为FU-A分片包最后一个包\n");
- memcpy(p->payload,&recvbuf[14],len - 14);
- p->paylen = len - 14;
- fwrite_number = fwrite(p->payload,1,p->paylen,poutfile); //写NAL数据
- total_bytes = p->paylen;
- printf("包长度 + FU = %d\n",total_bytes);
- }
- else if (rtp_hdr->marker == 0) //分片包 但不是最后一个包
- {
- if (fu_hdr->S == 1) //分片的第一个包
- {
- unsigned char F;
- unsigned char NRI;
- unsigned char TYPE;
- unsigned char nh;
- printf("当前包为FU-A分片包第一个包\n");
- putc(0x00, poutfile);
- putc(0x00, poutfile);
- putc(0x00, poutfile);
- putc(0x01, poutfile); //写起始字节码0x00000001
- total_bytes += 4;
- F = fu_ind->F << 7;
- NRI = fu_ind->NRI << 5;
- TYPE = fu_hdr->TYPE; //应用的是FU_HEADER的TYPE
- //nh = n->forbidden_bit|n->nal_reference_idc|n->nal_unit_type; //二进制文件也是按 大字节序存储
- nh = F | NRI | TYPE;
- putc(nh,poutfile); //写NAL HEADER
- total_bytes +=1;
- memcpy(p->payload,&recvbuf[14],len - 14);
- p->paylen = len - 14;
- fwrite_number = fwrite(p->payload,1,p->paylen,poutfile); //写NAL数据
- total_bytes = p->paylen;
- printf("包长度 + FU_First = %d\n",total_bytes);
- }
- else //如果不是第一个包
- {
- printf("当前包为FU-A分片包\n");
- memcpy(p->payload,&recvbuf[14],len - 14);
- p->paylen= len - 14;
- fwrite_number = fwrite(p->payload,1,p->paylen,poutfile); //写NAL数据
- total_bytes = p->paylen;
- printf("包长度 + FU = %d\n",total_bytes);
- }
- }
- }
- else if ( nalu_hdr->TYPE == 29) //FU-B分片包,解码顺序和传输顺序相同
- {
- if (rtp_hdr->marker == 1) //分片包最后一个包
- {
- printf("当前包为FU-B分片包最后一个包\n");
- }
- else if (rtp_hdr->marker == 0) //分片包 但不是最后一个包
- {
- printf("当前包为FU-B分片包\n");
- }
- }
- else
- {
- printf("这个包有错误,30-31 没有定义\n");
- }
- total_recved += total_bytes;
- printf("total_recved = %d\n",total_recved);
- memset(recvbuf,0,1500);
- free (p->payload);
- free (p);
- FreeNALU(n);
- //结束解包
- //////////////////////////////////////////////////////////////////////////
- return ;
- }
- int main()
- {
- char recvbuf[MAXDATASIZE]; //加上头最大传输数据 1500
- int sockfd;
- int client_fd;
- int sin_size;
- char sendbuf[BUFFER_SIZE];
- struct sockaddr_in server_sockaddr, client_sockaddr;
- int receive_bytes = 0;
- OpenBitstreamFile(outputfilename);
- //////////////////////////////////////////////////////////////////////////
- //socket 操作
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- {
- perror("socket");
- exit(1);
- }//建立socket链接,数据报socket,IPv4协议
- printf("create socket success!\n");
- server_sockaddr.sin_family = AF_INET;
- server_sockaddr.sin_addr.s_addr = INADDR_ANY;//0.0.0.0不确定地址
- server_sockaddr.sin_port = htons(PORT);
- bzero(&(server_sockaddr.sin_zero), 8); //填充0以保持与struct sockaddr同样大小
- if (bind(sockfd, (struct sockaddr *) &server_sockaddr,
- sizeof(struct sockaddr)) < 0)
- {
- perror("ERROR on binding");
- exit(1);
- }
- printf("bind success!\n");
- sin_size = sizeof(struct sockaddr_in);
- printf("waiting for client connection...\n");
- //接收从客户端发来的数据
- while((receive_bytes = recvfrom(sockfd, recvbuf, MAXDATASIZE, 0, (struct sockaddr *)&client_sockaddr, &sin_size)) >0)
- {
- if(strncmp(recvbuf, "over",4) == 0)
- {
- break;
- }
- poutfile = fopen(outputfilename,"ab+");
- rtp_unpackage(recvbuf,receive_bytes);
- fclose(poutfile);
- }
- strcpy(sendbuf, "success");
- sendto( sockfd, sendbuf, BUFFER_SIZE, 0 ,(struct sockaddr *)&client_sockaddr, sin_size);
- close(client_fd);
- close(sockfd);
- return 0;
- }
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <fcntl.h>typedef struct{unsigned char version; //!< Version, 2 bits, MUST be 0x2unsigned char padding; //!< Padding bit, Padding MUST NOT be usedunsigned char extension;//!< Extension, MUST be zerounsigned char cc; //!< CSRC count, normally 0 in the absence of RTP mixers unsigned char marker; //!< Marker bitunsigned char pt; //!< 7 bits, Payload Type, dynamically establishedunsigned int seq_no; //!< RTP sequence number, incremented by one for each sent packet unsigned int timestamp; //!< timestamp, 27 MHz for H.264unsigned int ssrc; //!< Synchronization Source, chosen randomlyunsigned char * payload; //!< the payload including payload headersunsigned int paylen; //!< length of payload in bytes} RTPpacket_t;typedef struct {/* 0 1 2 30 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+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|V=2|P|X| CC |M| PT | sequence number |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| timestamp |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| synchronization source (SSRC) identifier |+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+| contributing source (CSRC) identifiers || .... |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *///intel 的cpu 是intel为小端字节序(低端存到底地址) 而网络流为大端字节序(高端存到低地址)/*intel 的cpu : 高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端 在内存中存储 : 低->4001(内存地址)version:2 4002(内存地址)padding:1 4003(内存地址)extension:1 高->4004(内存地址)csrc_len:4 网络传输解析 : 高端->version:2->padding:1->extension:1->csrc_len:4->低端 (为正确的文档描述格式) 存入接收内存 : 低->4001(内存地址)version:2 4002(内存地址)padding:1 4003(内存地址)extension:1 高->4004(内存地址)csrc_len:4 本地内存解析 :高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端 , 即: unsigned char csrc_len:4; // expect 0 unsigned char extension:1; // expect 1 unsigned char padding:1; // expect 0 unsigned char version:2; // expect 2 *//* byte 0 */ unsigned char csrc_len:4; /* expect 0 */ unsigned char extension:1; /* expect 1, see RTP_OP below */ unsigned char padding:1; /* expect 0 */ unsigned char version:2; /* expect 2 *//* byte 1 */ unsigned char payloadtype:7; /* RTP_PAYLOAD_RTSP */ unsigned char marker:1; /* expect 1 *//* bytes 2,3 */ unsigned int seq_no; /* bytes 4-7 */ unsigned int timestamp; /* bytes 8-11 */ unsigned int ssrc; /* stream number is used here. */} RTP_FIXED_HEADER;typedef struct{unsigned char forbidden_bit; //! Should always be FALSEunsigned char nal_reference_idc; //! NALU_PRIORITY_xxxxunsigned char nal_unit_type; //! NALU_TYPE_xxxx unsigned int startcodeprefix_len; //! 前缀字节数unsigned int len; //! 包含nal 头的nal 长度,从第一个00000001到下一个000000001的长度unsigned int max_size; //! 做多一个nal 的长度unsigned char * buf; //! 包含nal 头的nal 数据unsigned int lost_packets; //! 预留} NALU_t;/*+---------------+|0|1|2|3|4|5|6|7|+-+-+-+-+-+-+-+-+|F|NRI| Type |+---------------+*/typedef struct {//byte 0unsigned char TYPE:5;unsigned char NRI:2;unsigned char F:1; } NALU_HEADER; // 1 BYTE /*+---------------+|0|1|2|3|4|5|6|7|+-+-+-+-+-+-+-+-+|F|NRI| Type |+---------------+*/typedef struct {//byte 0unsigned char TYPE:5;unsigned char NRI:2; unsigned char F:1; } FU_INDICATOR; // 1 BYTE /*+---------------+|0|1|2|3|4|5|6|7|+-+-+-+-+-+-+-+-+|S|E|R| Type |+---------------+*/typedef struct {//byte 0unsigned char TYPE:5;unsigned char R:1;unsigned char E:1;unsigned char S:1; } FU_HEADER; // 1 BYTES #define MAXDATASIZE 1500#define PORT1234#define BUFFER_SIZE10FILE * poutfile = NULL;char * outputfilename = "./receive.264";int OpenBitstreamFile (char *fn){if (NULL == (poutfile = fopen(fn, "wb"))){printf("Error: Open input file error\n");getchar();}return 1;}NALU_t *AllocNALU(int buffersize){NALU_t *n;if ((n = (NALU_t*)calloc (1, sizeof(NALU_t))) == NULL){printf("AllocNALU Error: Allocate Meory To NALU_t Failed ");exit(0);}return n;}void FreeNALU(NALU_t *n){if (n){free (n);}}/**bufIn:rtppackage*len: the lengthe of rtppackage*/void rtp_unpackage(char *bufIn,int len){ unsigned char recvbuf[1500];RTPpacket_t *p = NULL; RTP_FIXED_HEADER * rtp_hdr = NULL;NALU_HEADER * nalu_hdr = NULL;NALU_t * n = NULL;FU_INDICATOR*fu_ind = NULL;FU_HEADER*fu_hdr= NULL;int total_bytes = 0; //当前包传出的数据static int total_recved = 0; //一共传输的数据int fwrite_number = 0; //存入文件的数据长度memcpy(recvbuf,bufIn, len); //复制rtp包 printf("包长度+ rtp头: = %d\n",len);////////////////////////////////////////////////////////////////////////////begin rtp_payload and rtp_headerp = (RTPpacket_t*)&recvbuf[0];if ((p = malloc (sizeof (RTPpacket_t)))== NULL){printf ("RTPpacket_t MMEMORY ERROR\n");}if ((p->payload = malloc (MAXDATASIZE))== NULL){printf ("RTPpacket_t payload MMEMORY ERROR\n");}if ((rtp_hdr = malloc(sizeof(RTP_FIXED_HEADER))) == NULL){printf("RTP_FIXED_HEADER MEMORY ERROR\n");} rtp_hdr =(RTP_FIXED_HEADER*)&recvbuf[0]; printf("版本号 : %d\n",rtp_hdr->version);p->version = rtp_hdr->version;p->padding = rtp_hdr->padding;p->extension = rtp_hdr->extension;p->cc = rtp_hdr->csrc_len;printf("标志位 : %d\n",rtp_hdr->marker);p->marker = rtp_hdr->marker;printf("负载类型:%d\n",rtp_hdr->payloadtype);p->pt = rtp_hdr->payloadtype;printf("包号 : %d \n",rtp_hdr->seq_no);p->seq_no = rtp_hdr->seq_no;printf("时间戳 : %d\n",rtp_hdr->timestamp);p->timestamp = rtp_hdr->timestamp;printf("帧号 : %d\n",rtp_hdr->ssrc);p->ssrc = rtp_hdr->ssrc;//end rtp_payload and rtp_header////////////////////////////////////////////////////////////////////////////begin nal_hdrif (!(n = AllocNALU(800000))) //为结构体nalu_t及其成员buf分配空间。返回值为指向nalu_t存储空间的指针{printf("NALU_t MMEMORY ERROR\n");}if ((nalu_hdr = malloc(sizeof(NALU_HEADER))) == NULL){printf("NALU_HEADER MEMORY ERROR\n");}nalu_hdr =(NALU_HEADER*)&recvbuf[12]; //网络传输过来的字节序 ,当存入内存还是和文档描述的相反,只要匹配网络字节序和文档描述即可传输正确。printf("forbidden_zero_bit: %d\n",nalu_hdr->F); //网络传输中的方式为:F->NRI->TYPE.. 内存中存储方式为 TYPE->NRI->F (和nal头匹配)。n->forbidden_bit= nalu_hdr->F << 7; //内存中的字节序。printf("nal_reference_idc: %d\n",nalu_hdr->NRI);n->nal_reference_idc = nalu_hdr->NRI << 5; printf("nal 负载类型: %d\n",nalu_hdr->TYPE);n->nal_unit_type = nalu_hdr->TYPE;//end nal_hdr////////////////////////////////////////////////////////////////////////////开始解包if ( nalu_hdr->TYPE == 0){printf("这个包有错误,0无定义\n");}else if ( nalu_hdr->TYPE >0 && nalu_hdr->TYPE < 24) //单包{printf("当前包为单包\n");putc(0x00, poutfile);putc(0x00, poutfile);putc(0x00, poutfile);putc(0x01, poutfile);//写进起始字节0x00000001total_bytes +=4;memcpy(p->payload,&recvbuf[13],len-13);p->paylen = len-13; fwrite(nalu_hdr,1,1,poutfile);//写NAL_HEADERtotal_bytes += 1;fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);//写NAL数据total_bytes = p->paylen;printf("包长度 + nal= %d\n",total_bytes);}else if ( nalu_hdr->TYPE == 24) //STAP-A 单一时间的组合包{printf("当前包为STAP-A\n");}else if ( nalu_hdr->TYPE == 25) //STAP-B 单一时间的组合包{printf("当前包为STAP-B\n");}else if (nalu_hdr->TYPE == 26) //MTAP16 多个时间的组合包{printf("当前包为MTAP16\n");}else if ( nalu_hdr->TYPE == 27) //MTAP24 多个时间的组合包{printf("当前包为MTAP24\n");} else if ( nalu_hdr->TYPE == 28) //FU-A分片包,解码顺序和传输顺序相同{if ((fu_ind = malloc(sizeof(FU_INDICATOR))) == NULL){printf("FU_INDICATOR MEMORY ERROR\n");}if ((fu_hdr = malloc(sizeof(FU_HEADER))) == NULL){printf("FU_HEADER MEMORY ERROR\n");}fu_ind=(FU_INDICATOR*)&recvbuf[12];//分片包用的是FU_INDICATOR而不是NALU_HEADERprintf("FU_INDICATOR->F :%d\n",fu_ind->F);n->forbidden_bit = fu_ind->F << 7;printf("FU_INDICATOR->NRI :%d\n",fu_ind->NRI);n->nal_reference_idc = fu_ind->NRI << 5; printf("FU_INDICATOR->TYPE :%d\n",fu_ind->TYPE);n->nal_unit_type = fu_ind->TYPE;fu_hdr=(FU_HEADER*)&recvbuf[13];//FU_HEADER赋值printf("FU_HEADER->S :%d\n",fu_hdr->S);printf("FU_HEADER->E :%d\n",fu_hdr->E);printf("FU_HEADER->R :%d\n",fu_hdr->R);printf("FU_HEADER->TYPE :%d\n",fu_hdr->TYPE);n->nal_unit_type = fu_hdr->TYPE; //应用的是FU_HEADER的TYPEif (rtp_hdr->marker == 1) //分片包最后一个包{printf("当前包为FU-A分片包最后一个包\n");memcpy(p->payload,&recvbuf[14],len - 14);p->paylen = len - 14;fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);//写NAL数据total_bytes = p->paylen;printf("包长度 + FU = %d\n",total_bytes);}else if (rtp_hdr->marker == 0) //分片包 但不是最后一个包{if (fu_hdr->S == 1) //分片的第一个包{unsigned char F;unsigned char NRI;unsigned char TYPE;unsigned char nh;printf("当前包为FU-A分片包第一个包\n");putc(0x00, poutfile);putc(0x00, poutfile);putc(0x00, poutfile);putc(0x01, poutfile);//写起始字节码0x00000001total_bytes += 4; F = fu_ind->F << 7;NRI = fu_ind->NRI << 5;TYPE = fu_hdr->TYPE; //应用的是FU_HEADER的TYPE//nh = n->forbidden_bit|n->nal_reference_idc|n->nal_unit_type; //二进制文件也是按 大字节序存储nh = F | NRI | TYPE;putc(nh,poutfile);//写NAL HEADERtotal_bytes +=1;memcpy(p->payload,&recvbuf[14],len - 14);p->paylen = len - 14;fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);//写NAL数据total_bytes = p->paylen;printf("包长度 + FU_First = %d\n",total_bytes);}else //如果不是第一个包{printf("当前包为FU-A分片包\n");memcpy(p->payload,&recvbuf[14],len - 14);p->paylen= len - 14;fwrite_number = fwrite(p->payload,1,p->paylen,poutfile);//写NAL数据total_bytes = p->paylen;printf("包长度 + FU = %d\n",total_bytes);}}}else if ( nalu_hdr->TYPE == 29) //FU-B分片包,解码顺序和传输顺序相同{if (rtp_hdr->marker == 1) //分片包最后一个包{printf("当前包为FU-B分片包最后一个包\n");}else if (rtp_hdr->marker == 0) //分片包 但不是最后一个包{printf("当前包为FU-B分片包\n");}}else{printf("这个包有错误,30-31 没有定义\n");}total_recved += total_bytes;printf("total_recved = %d\n",total_recved);memset(recvbuf,0,1500);free (p->payload);free (p);FreeNALU(n);//结束解包////////////////////////////////////////////////////////////////////////// return ;}int main(){char recvbuf[MAXDATASIZE]; //加上头最大传输数据 1500int sockfd; int client_fd; int sin_size; char sendbuf[BUFFER_SIZE];struct sockaddr_in server_sockaddr, client_sockaddr; intreceive_bytes = 0;OpenBitstreamFile(outputfilename); ////////////////////////////////////////////////////////////////////////////socket 操作if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){perror("socket");exit(1);}//建立socket链接,数据报socket,IPv4协议printf("create socket success!\n");server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_addr.s_addr = INADDR_ANY;//0.0.0.0不确定地址 server_sockaddr.sin_port = htons(PORT); bzero(&(server_sockaddr.sin_zero), 8); //填充0以保持与struct sockaddr同样大小if (bind(sockfd, (struct sockaddr *) &server_sockaddr, sizeof(struct sockaddr)) < 0) {perror("ERROR on binding");exit(1); } printf("bind success!\n");sin_size = sizeof(struct sockaddr_in);printf("waiting for client connection...\n");//接收从客户端发来的数据while((receive_bytes = recvfrom(sockfd, recvbuf, MAXDATASIZE, 0, (struct sockaddr *)&client_sockaddr, &sin_size)) >0){if(strncmp(recvbuf, "over",4) == 0){break;}poutfile = fopen(outputfilename,"ab+");rtp_unpackage(recvbuf,receive_bytes);fclose(poutfile);}strcpy(sendbuf, "success");sendto( sockfd, sendbuf, BUFFER_SIZE, 0 ,(struct sockaddr *)&client_sockaddr, sin_size);close(client_fd);close(sockfd);return 0;}因为这里用的是recvfrom,因此将上一篇的打包发送中socket的send修改成sendto即可。还有一点是udp发送的速度很快,这里因为要将数据写进文件中,速度肯定没有接受数据快,因此在打包发送端每发送完一个rtp数据包延迟一段时间才行,这里我延时了10ms。
- H264 RTP解包 111
- H264 RTP解包
- rtp 解包h264
- H264 RTP解包
- h264基础及rtp分包解包
- h264基础及rtp分包解包
- rtp h264打包和解包
- java、android可用的rtp封包解包h264
- 如何将H264封装为RTP包
- 十二 h264 rtp包的时间戳
- H264码流打包成RTP包
- Wireshark提取RTP包中的H264码流
- rtp的封包与拆包h264
- H264打包RTP包流程准备
- H264码流打包成RTP包
- H264码流打包成RTP包
- RTP 包格式 详细解析 -- H264 nalu 封装rtp 方式。
- H264 ~~~RTP
- 31天重构学习笔记30. 尽快返回
- 31天重构学习笔记31. 使用多态代替条件判断
- 准备写一篇如何学习英语的文章
- 同步博客到CSDN
- 31天重构学习笔记重新整理下载
- H264 RTP解包 111
- 定制UIImagePickController遇到的设备和照片方向问题
- MySQL实现文本文件导入数据库以及将表格导出到文本文件
- Disable一个Form里面subgrid
- 到底哪里的字符编码影响了你?
- 实战oracle存储过程常用实用函数
- Java中HashMap遍历的方式
- 在SQL中关于时间日期的操作
- 自动消失的UIAlert