//这个函数输入为一个NAL结构体,主要功能为得到一个完整的NALU并保存在NALU_t的buf中,获取他的长度,填充F,IDC,TYPE位。 //并且返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度 int GetAnnexbNALU (NALU_t *nalu) { int pos = 0; int StartCodeFound, rewind; unsigned char *Buf; if ((Buf = (unsigned char*)calloc (nalu->max_size , sizeof(char))) == NULL) printf ("GetAnnexbNALU: Could not allocate Buf memory\n"); nalu->startcodeprefix_len=3;//初始化码流序列的开始字符为3个字节 if (3 != fread (Buf, 1, 3, bits))//从码流中读3个字节 { free(Buf); return 0; } info2 = FindStartCode2 (Buf);//判断是否为0x000001 if(info2 != 1) { //如果不是,再读一个字节 if(1 != fread(Buf+3, 1, 1, bits))//读一个字节 { free(Buf); return 0; } info3 = FindStartCode3 (Buf);//判断是否为0x00000001 if (info3 != 1)//如果不是,返回-1 { free(Buf); return -1; } else { //如果是0x00000001,得到开始前缀为4个字节 pos = 4; nalu->startcodeprefix_len = 4; } } else { //如果是0x000001,得到开始前缀为3个字节 nalu->startcodeprefix_len = 3; pos = 3; } //查找下一个开始字符的标志位 StartCodeFound = 0; info2 = 0; info3 = 0; while (!StartCodeFound) { if (feof (bits))//判断是否到了文件尾 { nalu->len = (pos-1)-nalu->startcodeprefix_len; memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len); nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit free(Buf); return pos-1; } Buf[pos++] = fgetc (bits);//读一个字节到BUF中 info3 = FindStartCode3(&Buf[pos-4]);//判断是否为0x00000001 if(info3 != 1) info2 = FindStartCode2(&Buf[pos-3]);//判断是否为0x000001 StartCodeFound = (info2 == 1 || info3 == 1); } // Here, we have found another start code (and read length of startcode bytes more than we should // have. Hence, go back in the file rewind = (info3 == 1)? -4 : -3; if (0 != fseek (bits, rewind, SEEK_CUR))//把文件指针指向前一个NALU的末尾 { free(Buf); printf("GetAnnexbNALU: Cannot fseek in the bit stream file"); } // Here the Start code, the complete NALU, and the next start code is in the Buf. // The size of Buf is pos, pos+rewind are the number of bytes excluding the next // start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code nalu->len = (pos+rewind)-nalu->startcodeprefix_len; memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//拷贝一个完整NALU,不拷贝起始前缀0x000001或0x00000001 nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit free(Buf); return (pos+rewind);//返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度 }
//这个函数输入为一个NAL结构体,主要功能为得到一个完整的NALU并保存在NALU_t的buf中, //获取他的长度,填充F,IDC,TYPE位。 //并且返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度 int GetAnnexbNALU (sp<ABuffer> nalu) { int pos = 0; int StartCodeFound, rewind; // unsigned char *Buf; int info2,info3,startcodeprefix_len,len; static unsigned char Buf[50000]; startcodeprefix_len=3;//初始化码流序列的开始字符为3个字节 if (3 != fread (Buf, 1, 3, bits))//从码流中读3个字节 { //free(Buf); return 0; } info2 = FindStartCode2 (Buf);//判断是否为0x000001 if(info2 != 1) { //如果不是,再读一个字节 if(1 != fread(Buf+3, 1, 1, bits))//读一个字节 { //free(Buf); return 0; } info3 = FindStartCode3 (Buf);//判断是否为0x00000001 if (info3 != 1)//如果不是,返回-1 { //free(Buf); return -1; } else { //如果是0x00000001,得到开始前缀为4个字节 pos = 4; startcodeprefix_len = 4; } } else { //如果是0x000001,得到开始前缀为3个字节 startcodeprefix_len = 3; pos = 3; } //查找下一个开始字符的标志位 StartCodeFound = 0; info2 = 0; info3 = 0; while (!StartCodeFound) { if (feof (bits))//判断是否到了文件尾 { //return 0; len = (pos-1)- startcodeprefix_len; memcpy (nalu->data(), &Buf[startcodeprefix_len], len); //free(Buf); printf("lcy 1991 len %d\n",len); return pos-1; } Buf[pos++] = fgetc (bits);//读一个字节到BUF中 info3 = FindStartCode3(&Buf[pos-4]);//判断是否为0x00000001 if(info3 != 1) info2 = FindStartCode2(&Buf[pos-3]);//判断是否为0x000001 StartCodeFound = (info2 == 1 || info3 == 1); } // Here, we have found another start code (and read length of startcode bytes more than we should // have. Hence, go back in the file rewind = (info3 == 1)? -4 : -3; if (0 != fseek (bits, rewind, SEEK_CUR))//把文件指针指向前一个NALU的末尾 { //free(Buf); printf("GetAnnexbNALU: Cannot fseek in the bit stream file"); } // Here the Start code, the complete NALU, and the next start code is in the Buf. // The size of Buf is pos, pos+rewind are the number of bytes excluding the next // start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code len = (pos+rewind)-startcodeprefix_len; memcpy (nalu->data(), &Buf[startcodeprefix_len], len);//拷贝一个完整NALU,不拷贝起始前缀0x000001或0x00000001 //free(Buf); printf("memcpy2\n"); return (pos+rewind);//返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度 }
void CRTPRecv::SendH264Nalu(unsigned char* m_h264Buf,int buflen) { //时间戳 //int TimesTampInc=3600; //Mark标志 //int Mark = 1; //NAL单元(非发送结构) NALU_t Nalu; //待处理的单帧数据指针s unsigned char *pSendbuf=NULL; int SendLen=0; //发送的数据缓冲 char sendbuf[1430]; memset(sendbuf,0,1430); //上一个startcode位置 int LastStartPos=0; //本次STARTCODE位置 int StartPos=0; //前导码为 0x00 00 01 或者 0x00 00 00 01 int DataCount=3; unsigned char *pData=m_h264Buf; int res=0; while (DataCount<buflen) { res=FindStartCode3(pData+DataCount-3); if (res!=true) { //未找到前导码 if (DataCount!=buflen-1) { DataCount++; continue; } else { //最后一段数据 StartPos = buflen; } } else { //找到前导码 0x00 00 01 StartPos=DataCount-3; res=FindStartCode4(pData+DataCount-4); if(res==true) { //找到前导码 0x00 00 00 01 StartPos=DataCount-4; } } //切一个nal进行处理 pSendbuf = pData+LastStartPos; SendLen = StartPos-LastStartPos; LastStartPos = StartPos; DataCount++; if (SendLen==0) { //第一个前导码不用处理 continue; } int frontFlag=0; //去除前导码0x000001 或者0x00000001 if( 0x01 == pSendbuf[2] ) { pSendbuf = &pSendbuf[3]; SendLen -= 3; frontFlag=3; } else if(0x01==pSendbuf[3]) { pSendbuf = &pSendbuf[4]; SendLen -= 4; frontFlag=4; } if (SendLen==0) { //前导码后没有数据 LOG_WARN("NULL 264 packet"); return; } //如果前导码为0x00 00 00 01 表示上一帧已经结束 发送分界nal /*if (frontFlag==4) { m_TimesTampInc=3600; char buf[6]; memset(buf,0,6); buf[0]=0x09; buf[1]=0x30; SendPacket(buf,6,H264,1,m_TimesTampInc); m_TimesTampInc=0; }*/ //解析nal头 NALU_t na; na.forbidden_bit = pSendbuf[0] & 0x80; na.nal_reference_idc = (pSendbuf[0] & 0x60)>>5; na.nal_unit_type = pSendbuf[0] & 0x1f; int status=0; //单包 if ( SendLen <= MAX_RTP_PKT_LENGTH ) { //SetDefaultMark(true); status = this->SendPacket((void *)pSendbuf,SendLen,H264,1,TIMESTAMP); } //分片 else if(SendLen > MAX_RTP_PKT_LENGTH) { FU_INDICATOR *pstFuInd; FU_HEADER *pstFuHdr; char *pNaluPayLoad; //解析nal头 Nalu.forbidden_bit = pSendbuf[0] & 0x80; Nalu.nal_reference_idc = pSendbuf[0] & 0x60; Nalu.nal_unit_type = pSendbuf[0] & 0x1f; pSendbuf+=1; SendLen-=1; //分片数量 int PackCount=0; //最后一个分片长度 int RemainLen=0; PackCount = SendLen / MAX_RTP_PKT_LENGTH; RemainLen = SendLen % MAX_RTP_PKT_LENGTH; int PackNumber=0;//用指示当前发送的是第几个分片RTP包 while (PackNumber<=PackCount) { pstFuInd = (FU_INDICATOR*)&sendbuf[0]; pstFuInd->F = Nalu.forbidden_bit; pstFuInd->NRI = Nalu.nal_reference_idc >> 5; pstFuInd->TYPE = NALU_TYPE_FU_A; //第一个分片 if (PackNumber==0) { pstFuHdr = (FU_HEADER*)&sendbuf[1]; pstFuHdr->E = 0; pstFuHdr->R = 0; pstFuHdr->S = 1; pstFuHdr->TYPE = Nalu.nal_unit_type; pNaluPayLoad = &sendbuf[2]; memcpy(pNaluPayLoad,pSendbuf+PackNumber*MAX_RTP_PKT_LENGTH,MAX_RTP_PKT_LENGTH); //SetDefaultMark(false); status = this->SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2,H264,0,0); PackNumber++; continue; } //最后一个分片 else if (((PackNumber==PackCount-1)&&RemainLen==0)||((PackNumber==PackCount)&&(RemainLen!=0))) { pstFuHdr = (FU_HEADER*)&sendbuf[1]; pstFuHdr->E = 1; pstFuHdr->R = 0; pstFuHdr->S = 0; pstFuHdr->TYPE = Nalu.nal_unit_type; pNaluPayLoad = &sendbuf[2]; //SetDefaultMark(true); if (RemainLen==0) { memcpy(pNaluPayLoad,pSendbuf+PackNumber*MAX_RTP_PKT_LENGTH,MAX_RTP_PKT_LENGTH); status = this->SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2,H264,1,0); } else { memcpy(pNaluPayLoad,pSendbuf+PackNumber*MAX_RTP_PKT_LENGTH,RemainLen); status = this->SendPacket((void *)sendbuf,RemainLen+2,H264,1,TIMESTAMP); } break; } //中间分片 else { pstFuHdr = (FU_HEADER*)&sendbuf[1]; pstFuHdr->E = 0; pstFuHdr->R = 0; pstFuHdr->S = 0; pstFuHdr->TYPE = Nalu.nal_unit_type; pNaluPayLoad = &sendbuf[2]; memcpy(pNaluPayLoad,pSendbuf+PackNumber*MAX_RTP_PKT_LENGTH,MAX_RTP_PKT_LENGTH); //SetDefaultMark(false); status = this->SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2,H264,0,0); PackNumber++; continue; } } } }